diff options
Diffstat (limited to 'sql')
111 files changed, 12509 insertions, 8494 deletions
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 86a710f87c6..02da3c31c3e 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -758,8 +758,8 @@ bool get_next_time(const Time_zone *time_zone, my_time_t *next, if (seconds) { - longlong seconds_diff; - long microsec_diff; + ulonglong seconds_diff; + ulong microsec_diff; bool negative= calc_time_diff(&local_now, &local_start, 1, &seconds_diff, µsec_diff); if (!negative) diff --git a/sql/event_parse_data.cc b/sql/event_parse_data.cc index b2ff80626db..d20d322d864 100644 --- a/sql/event_parse_data.cc +++ b/sql/event_parse_data.cc @@ -472,7 +472,7 @@ Event_parse_data::report_bad_value(const char *item_name, Item *bad_item) { char buff[120]; String str(buff,(uint32) sizeof(buff), system_charset_info); - String *str2= bad_item->fixed? bad_item->val_str(&str):NULL; + String *str2= bad_item->is_fixed() ? bad_item->val_str(&str) : NULL; my_error(ER_WRONG_VALUE, MYF(0), item_name, str2? str2->c_ptr_safe():"NULL"); } diff --git a/sql/events.cc b/sql/events.cc index fcad115c199..af020d5240e 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -401,7 +401,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data) my_message_sql(ER_STARTUP, "Event Error: An error occurred while creating query " "string, before writing it into binary log.", - MYF(ME_NOREFRESH)); + MYF(ME_ERROR_LOG)); ret= true; } else @@ -824,12 +824,13 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) */ if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS) { - DBUG_ASSERT(thd->lex->select_lex.db.str); - if (!is_infoschema_db(&thd->lex->select_lex.db) && // There is no events in I_S - check_access(thd, EVENT_ACL, thd->lex->select_lex.db.str, + DBUG_ASSERT(thd->lex->first_select_lex()->db.str); + if (!is_infoschema_db(&thd->lex->first_select_lex()->db) && // There is no events in I_S + check_access(thd, EVENT_ACL, thd->lex->first_select_lex()->db.str, NULL, NULL, 0, 0)) DBUG_RETURN(1); - db= normalize_db_name(thd->lex->select_lex.db.str, db_tmp, sizeof(db_tmp)); + db= normalize_db_name(thd->lex->first_select_lex()->db.str, + db_tmp, sizeof(db_tmp)); } ret= db_repository->fill_schema_events(thd, tables, db); @@ -924,7 +925,7 @@ Events::init(THD *thd, bool opt_noacl_or_bootstrap) my_message(ER_STARTUP, "Event Scheduler: An error occurred when initializing " "system tables. Disabling the Event Scheduler.", - MYF(ME_NOREFRESH)); + MYF(ME_ERROR_LOG)); /* Disable the scheduler since the system tables are not up to date */ opt_event_scheduler= EVENTS_OFF; goto end; @@ -946,7 +947,7 @@ Events::init(THD *thd, bool opt_noacl_or_bootstrap) { my_message_sql(ER_STARTUP, "Event Scheduler: Error while loading from mysql.event table.", - MYF(ME_NOREFRESH)); + MYF(ME_ERROR_LOG)); res= TRUE; /* fatal error: request unireg_abort */ goto end; } @@ -1163,7 +1164,7 @@ Events::load_events_from_db(THD *thd) { my_message_sql(ER_STARTUP, "Event Scheduler: Failed to open table mysql.event", - MYF(ME_NOREFRESH)); + MYF(ME_ERROR_LOG)); DBUG_RETURN(TRUE); } @@ -1189,7 +1190,7 @@ Events::load_events_from_db(THD *thd) "Event Scheduler: " "Error while loading events from mysql.event. " "The table probably contains bad data or is corrupted", - MYF(ME_NOREFRESH)); + MYF(ME_ERROR_LOG)); delete et; goto end; } @@ -1228,9 +1229,9 @@ Events::load_events_from_db(THD *thd) } my_printf_error(ER_STARTUP, "Event Scheduler: Loaded %d event%s", - MYF(ME_NOREFRESH | + MYF(ME_ERROR_LOG | (global_system_variables.log_warnings) ? - ME_JUST_INFO: 0), + ME_NOTE: 0), count, (count == 1) ? "" : "s"); ret= FALSE; diff --git a/sql/field.cc b/sql/field.cc index 7eb277e23d8..743f12f3cc9 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -62,8 +62,12 @@ const char field_separator=','; #define BLOB_PACK_LENGTH_TO_MAX_LENGH(arg) \ ((ulong) ((1LL << MY_MIN(arg, 4) * 8) - 1)) -#define ASSERT_COLUMN_MARKED_FOR_READ DBUG_ASSERT(!table || (!table->read_set || bitmap_is_set(table->read_set, field_index))) -#define ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED DBUG_ASSERT(is_stat_field || !table || (!table->write_set || bitmap_is_set(table->write_set, field_index) || (table->vcol_set && bitmap_is_set(table->vcol_set, field_index)))) +#define ASSERT_COLUMN_MARKED_FOR_READ \ + DBUG_ASSERT(!table || !table->read_set || \ + bitmap_is_set(table->read_set, field_index)) +#define ASSERT_COLUMN_MARKED_FOR_WRITE \ + DBUG_ASSERT(is_stat_field || !table || !table->write_set || \ + bitmap_is_set(table->write_set, field_index)) #define FLAGSTR(S,F) ((S) & (F) ? #F " " : "") @@ -80,15 +84,14 @@ const int FIELDTYPE_LAST= 254; const int FIELDTYPE_NUM= FIELDTYPE_TEAR_FROM + (FIELDTYPE_LAST - FIELDTYPE_TEAR_TO); -static inline int field_type2index (enum_field_types field_type) +static inline int merge_type2index(enum_field_types merge_type) { - DBUG_ASSERT(real_type_to_type(field_type) < FIELDTYPE_TEAR_FROM || - real_type_to_type(field_type) > FIELDTYPE_TEAR_TO); - DBUG_ASSERT(field_type <= FIELDTYPE_LAST); - field_type= real_type_to_type(field_type); - if (field_type < FIELDTYPE_TEAR_FROM) - return field_type; - return FIELDTYPE_TEAR_FROM + (field_type - FIELDTYPE_TEAR_TO) - 1; + DBUG_ASSERT(merge_type < FIELDTYPE_TEAR_FROM || + merge_type > FIELDTYPE_TEAR_TO); + DBUG_ASSERT(merge_type <= FIELDTYPE_LAST); + if (merge_type < FIELDTYPE_TEAR_FROM) + return merge_type; + return FIELDTYPE_TEAR_FROM + (merge_type - FIELDTYPE_TEAR_TO) - 1; } @@ -913,31 +916,37 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]= } }; -/** - Return type of which can carry value of both given types in UNION result. - - @param a type for merging - @param b type for merging - - @return - type of field -*/ - -enum_field_types Field::field_type_merge(enum_field_types a, - enum_field_types b) -{ - return field_types_merge_rules[field_type2index(a)] - [field_type2index(b)]; -} const Type_handler * Type_handler::aggregate_for_result_traditional(const Type_handler *a, const Type_handler *b) { - enum_field_types ta= a->real_field_type(); - enum_field_types tb= b->real_field_type(); - return - Type_handler::get_handler_by_real_type(Field::field_type_merge(ta, tb)); + if (a == b) + { + /* + If two traditional handlers are equal, quickly return "a". + Some handlers (e.g. Type_handler_bool) pretend to be traditional, + but in fact they are not traditional in full extent, they are + only sub-types for now (and don't have a corresponding Field_xxx yet). + Here we preserve such handlers during aggregation. + As a result, COALESCE(true,true) preserves the "boolean" data type. + + Need to do this conversion for deprecated data types, + similar to what field_type_merge_rules[][] does. + */ + switch (a->field_type()) { + case MYSQL_TYPE_DECIMAL: return &type_handler_newdecimal; + case MYSQL_TYPE_DATE: return &type_handler_newdate; + case MYSQL_TYPE_VAR_STRING: return &type_handler_varchar; + default: break; + } + return a; + } + enum_field_types ta= a->traditional_merge_field_type(); + enum_field_types tb= b->traditional_merge_field_type(); + enum_field_types res= field_types_merge_rules[merge_type2index(ta)] + [merge_type2index(tb)]; + return Type_handler::get_handler_by_real_type(res); } @@ -1924,14 +1933,6 @@ Field::unpack(uchar* to, const uchar *from, const uchar *from_end, } -my_decimal *Field::val_decimal(my_decimal *decimal) -{ - /* This never have to be called */ - DBUG_ASSERT(0); - return 0; -} - - void Field_num::add_zerofill_and_unsigned(String &res) const { if (unsigned_flag) @@ -2033,7 +2034,7 @@ longlong Field::convert_decimal2longlong(const my_decimal *val, int Field_int::store_decimal(const my_decimal *val) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int err= 0; longlong i= convert_decimal2longlong(val, unsigned_flag, &err); return MY_TEST(err | store(i, unsigned_flag)); @@ -2201,7 +2202,7 @@ void Field_num::make_send_field(Send_field *field) int Field_str::store_decimal(const my_decimal *d) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; double val; /* TODO: use decimal2string? */ int err= warn_if_overflow(my_decimal2double(E_DEC_FATAL_ERROR & @@ -2273,7 +2274,7 @@ bool Field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) int Field::store_time_dec(const MYSQL_TIME *ltime, uint dec) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; char buff[MAX_DATE_STRING_REP_LENGTH]; uint length= (uint) my_TIME_to_str(ltime, buff, dec); /* Avoid conversion when field character set is ASCII compatible */ @@ -2331,6 +2332,36 @@ Field *Field::new_key_field(MEM_ROOT *root, TABLE *new_table, } +/** + Create field for temporary table from given field. + + @param thd Thread handler + @param table Temporary table + @param maybe_null_arg If the result field should be NULL-able, + even if the original field is NOT NULL, e.g. for: + - OUTER JOIN fields + - WITH ROLLUP fields + - arguments of aggregate functions, e.g. SUM(column1) + @retval NULL, on error + @retval pointer to the new field created, on success. +*/ + +Field *Field::create_tmp_field(MEM_ROOT *mem_root, TABLE *new_table, + bool maybe_null_arg) +{ + Field *new_field; + + if ((new_field= make_new_field(mem_root, new_table, new_table == table))) + { + new_field->init_for_tmp_table(this, new_table); + new_field->flags|= flags & NO_DEFAULT_VALUE_FLAG; + if (maybe_null_arg) + new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join + } + return new_field; +} + + /* This is used to generate a field in TABLE from TABLE_SHARE */ Field *Field::clone(MEM_ROOT *root, TABLE *new_table) @@ -2500,7 +2531,7 @@ void Field_decimal::overflow(bool negative) int Field_decimal::store(const char *from_arg, size_t len, CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; char buff[STRING_BUFFER_USUAL_SIZE]; String tmp(buff,sizeof(buff), &my_charset_bin); const uchar *from= (uchar*) from_arg; @@ -2866,7 +2897,7 @@ int Field_decimal::store(const char *from_arg, size_t len, CHARSET_INFO *cs) int Field_decimal::store(double nr) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; if (unsigned_flag && nr < 0) { overflow(1); @@ -2904,7 +2935,7 @@ int Field_decimal::store(double nr) int Field_decimal::store(longlong nr, bool unsigned_val) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; char buff[22]; uint length, int_part; char fyllchar; @@ -3131,7 +3162,7 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value, Otherwise sets maximal number that can be stored in the field. @param decimal_value my_decimal - @param [OUT] native_error the error returned by my_decimal2binary(). + @param [OUT] native_error the error returned by my_decimal::to_binary(). @retval 0 ok @@ -3142,7 +3173,7 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value, bool Field_new_decimal::store_value(const my_decimal *decimal_value, int *native_error) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; DBUG_ENTER("Field_new_decimal::store_value"); #ifndef DBUG_OFF @@ -3169,8 +3200,8 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value, } #endif - *native_error= my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, - decimal_value, ptr, precision, dec); + *native_error= decimal_value->to_binary(ptr, precision, dec, + E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW); if (unlikely(*native_error == E_DEC_OVERFLOW)) { @@ -3178,7 +3209,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value, DBUG_PRINT("info", ("overflow")); set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); set_value_on_overflow(&buff, decimal_value->sign()); - my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec); + buff.to_binary(ptr, precision, dec); error= 1; } DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (uchar *) ptr, @@ -3200,7 +3231,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) int Field_new_decimal::store(const char *from, size_t length, CHARSET_INFO *charset_arg) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; my_decimal decimal_value; THD *thd= get_thd(); DBUG_ENTER("Field_new_decimal::store(char*)"); @@ -3284,7 +3315,7 @@ int Field_new_decimal::store(const char *from, size_t length, int Field_new_decimal::store(double nr) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; my_decimal decimal_value; int err; THD *thd= get_thd(); @@ -3309,7 +3340,7 @@ int Field_new_decimal::store(double nr) int Field_new_decimal::store(longlong nr, bool unsigned_val) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; my_decimal decimal_value; int err; @@ -3331,7 +3362,7 @@ int Field_new_decimal::store(longlong nr, bool unsigned_val) int Field_new_decimal::store_decimal(const my_decimal *decimal_value) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; return store_value(decimal_value); } @@ -3343,37 +3374,6 @@ int Field_new_decimal::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg) } -double Field_new_decimal::val_real(void) -{ - ASSERT_COLUMN_MARKED_FOR_READ; - double dbl; - my_decimal decimal_value; - my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl); - return dbl; -} - - -longlong Field_new_decimal::val_int(void) -{ - ASSERT_COLUMN_MARKED_FOR_READ; - longlong i; - my_decimal decimal_value; - my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), - unsigned_flag, &i); - return i; -} - - -ulonglong Field_new_decimal::val_uint(void) -{ - ASSERT_COLUMN_MARKED_FOR_READ; - longlong i; - my_decimal decimal_value; - my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), true, &i); - return i; -} - - my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value) { ASSERT_COLUMN_MARKED_FOR_READ; @@ -3386,27 +3386,6 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value) } -String *Field_new_decimal::val_str(String *val_buffer, - String *val_ptr __attribute__((unused))) -{ - ASSERT_COLUMN_MARKED_FOR_READ; - my_decimal decimal_value; - uint fixed_precision= zerofill ? precision : 0; - my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), - fixed_precision, dec, '0', val_buffer); - val_buffer->set_charset(&my_charset_numeric); - return val_buffer; -} - - -bool Field_new_decimal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) -{ - my_decimal value; - return decimal_to_datetime_with_warn(val_decimal(&value), - ltime, fuzzydate, field_name.str); -} - - int Field_new_decimal::cmp(const uchar *a,const uchar*b) { return memcmp(a, b, bin_size); @@ -3561,8 +3540,8 @@ Item *Field_new_decimal::get_equal_const_item(THD *thd, const Context &ctx, if (const_item->field_type() != MYSQL_TYPE_NEWDECIMAL || const_item->decimal_scale() != decimals()) { - my_decimal *val, val_buffer, val_buffer2; - if (!(val= const_item->val_decimal(&val_buffer))) + VDec val(const_item); + if (val.is_null()) { DBUG_ASSERT(0); return const_item; @@ -3572,9 +3551,9 @@ Item *Field_new_decimal::get_equal_const_item(THD *thd, const Context &ctx, See comments about truncation in the same place in Field_time::get_equal_const_item(). */ - my_decimal_round(E_DEC_FATAL_ERROR, val, decimals(), true, &val_buffer2); - return new (thd->mem_root) Item_decimal(thd, field_name.str, - &val_buffer2, + my_decimal tmp; + val.round_to(&tmp, decimals(), TRUNCATE); + return new (thd->mem_root) Item_decimal(thd, field_name.str, &tmp, decimals(), field_length); } break; @@ -3600,7 +3579,7 @@ int Field_int::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg) int Field_tiny::store(const char *from,size_t len,CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error; longlong rnd; @@ -3612,7 +3591,7 @@ int Field_tiny::store(const char *from,size_t len,CHARSET_INFO *cs) int Field_tiny::store(double nr) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; nr=rint(nr); if (unsigned_flag) @@ -3655,7 +3634,7 @@ int Field_tiny::store(double nr) int Field_tiny::store(longlong nr, bool unsigned_val) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; if (unsigned_flag) @@ -3760,7 +3739,7 @@ void Field_tiny::sql_type(String &res) const int Field_short::store(const char *from,size_t len,CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int store_tmp; int error; longlong rnd; @@ -3774,7 +3753,7 @@ int Field_short::store(const char *from,size_t len,CHARSET_INFO *cs) int Field_short::store(double nr) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; int16 res; nr=rint(nr); @@ -3819,7 +3798,7 @@ int Field_short::store(double nr) int Field_short::store(longlong nr, bool unsigned_val) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; int16 res; @@ -3934,7 +3913,7 @@ void Field_short::sql_type(String &res) const int Field_medium::store(const char *from,size_t len,CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int store_tmp; int error; longlong rnd; @@ -3948,7 +3927,7 @@ int Field_medium::store(const char *from,size_t len,CHARSET_INFO *cs) int Field_medium::store(double nr) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; nr=rint(nr); if (unsigned_flag) @@ -3994,7 +3973,7 @@ int Field_medium::store(double nr) int Field_medium::store(longlong nr, bool unsigned_val) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; if (unsigned_flag) @@ -4132,7 +4111,7 @@ void Field_medium::sql_type(String &res) const int Field_long::store(const char *from,size_t len,CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; long store_tmp; int error; longlong rnd; @@ -4146,7 +4125,7 @@ int Field_long::store(const char *from,size_t len,CHARSET_INFO *cs) int Field_long::store(double nr) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; int32 res; nr=rint(nr); @@ -4191,7 +4170,7 @@ int Field_long::store(double nr) int Field_long::store(longlong nr, bool unsigned_val) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; int32 res; @@ -4305,7 +4284,7 @@ void Field_long::sql_type(String &res) const int Field_longlong::store(const char *from,size_t len,CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; char *end; ulonglong tmp; @@ -4328,7 +4307,7 @@ int Field_longlong::store(const char *from,size_t len,CHARSET_INFO *cs) int Field_longlong::store(double nr) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; Converter_double_to_longlong conv(nr, unsigned_flag); if (unlikely(conv.error())) @@ -4341,7 +4320,7 @@ int Field_longlong::store(double nr) int Field_longlong::store(longlong nr, bool unsigned_val) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; if (unlikely(nr < 0)) // Only possible error @@ -4452,7 +4431,7 @@ void Field_longlong::sql_type(String &res) const void Field_longlong::set_max() { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; set_notnull(); int8store(ptr, unsigned_flag ? ULONGLONG_MAX : LONGLONG_MAX); } @@ -4489,7 +4468,7 @@ int Field_float::store(const char *from,size_t len,CHARSET_INFO *cs) int Field_float::store(double nr) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= truncate_double(&nr, field_length, not_fixed ? NOT_FIXED_DEC : dec, unsigned_flag, FLT_MAX); @@ -4668,7 +4647,7 @@ int Field_double::store(const char *from,size_t len,CHARSET_INFO *cs) int Field_double::store(double nr) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= truncate_double(&nr, field_length, not_fixed ? NOT_FIXED_DEC : dec, unsigned_flag, DBL_MAX); @@ -4814,13 +4793,6 @@ Converter_double_to_longlong::push_warning(THD *thd, } -int Field_real::store_decimal(const my_decimal *dm) -{ - double dbl; - my_decimal2double(E_DEC_FATAL_ERROR, dm, &dbl); - return store(dbl); -} - int Field_real::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg) { return store(TIME_to_double(ltime)); @@ -5048,58 +5020,55 @@ my_time_t Field_timestamp::get_timestamp(const uchar *pos, } -int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, - const ErrConv *str, - int was_cut, - bool have_smth_to_conv) +int Field_timestamp::store_TIME_with_warning(THD *thd, const Datetime *dt, + const ErrConv *str, int was_cut) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; - uint error = 0; - my_time_t timestamp; + ASSERT_COLUMN_MARKED_FOR_WRITE; + static const timeval zero= {0, (uint) 0 }; - if (MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) || !have_smth_to_conv) - { - error= 1; - set_datetime_warning(WARN_DATA_TRUNCATED, - str, MYSQL_TIMESTAMP_DATETIME, 1); - } - else if (MYSQL_TIME_WARN_HAVE_NOTES(was_cut)) + // Handle totally bad values + if (!dt->is_valid_datetime()) { - error= 3; - set_datetime_warning(Sql_condition::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, - str, MYSQL_TIMESTAMP_DATETIME, 1); + set_datetime_warning(WARN_DATA_TRUNCATED, str, MYSQL_TIMESTAMP_DATETIME, 1); + store_TIMEVAL(zero); + return 1; } - /* Only convert a correct date (not a zero date) */ - if (have_smth_to_conv && l_time->month) + + // Handle values that do not need DATETIME to TIMESTAMP conversion + if (!dt->get_mysql_time()->month) { - uint conversion_error; - timestamp= TIME_to_timestamp(thd, l_time, &conversion_error); - if (timestamp == 0 && l_time->second_part == 0) - conversion_error= ER_WARN_DATA_OUT_OF_RANGE; - if (unlikely(conversion_error)) - { - set_datetime_warning(conversion_error, - str, MYSQL_TIMESTAMP_DATETIME, !error); - error= 1; - } + /* + Zero date is allowed by the current sql_mode. Store zero timestamp. + Return success or a warning about non-fatal truncation, e.g.: + INSERT INTO t1 (ts) VALUES ('0000-00-00 00:00:00 some tail'); + */ + store_TIMEVAL(zero); + return store_TIME_return_code_with_warnings(was_cut, str, + MYSQL_TIMESTAMP_DATETIME); } - else + + // Convert DATETIME to TIMESTAMP + uint conversion_error; + const MYSQL_TIME *l_time= dt->get_mysql_time(); + my_time_t timestamp= TIME_to_timestamp(thd, l_time, &conversion_error); + if (timestamp == 0 && l_time->second_part == 0) { - timestamp= 0; - l_time->second_part= 0; + set_datetime_warning(ER_WARN_DATA_OUT_OF_RANGE, str, MYSQL_TIMESTAMP_DATETIME, 1); + store_TIMEVAL(zero); + return 1; // date was fine but pointed to a DST gap } - store_TIME(timestamp, l_time->second_part); - return error; -} + // Adjust and store the value + store_TIMEVAL(Timeval(timestamp, l_time->second_part).trunc(decimals())); -static bool -copy_or_convert_to_datetime(THD *thd, const MYSQL_TIME *from, MYSQL_TIME *to) -{ - if (from->time_type == MYSQL_TIMESTAMP_TIME) - return time_to_datetime(thd, from, to); - *to= *from; - return false; + // Calculate return value and send warnings if needed + if (unlikely(conversion_error)) // e.g. DATETIME in the DST gap + { + set_datetime_warning(conversion_error, str, MYSQL_TIMESTAMP_DATETIME, 1); + return 1; + } + return store_TIME_return_code_with_warnings(was_cut, str, + MYSQL_TIMESTAMP_DATETIME); } @@ -5112,55 +5081,41 @@ sql_mode_t Field_timestamp::sql_mode_for_timestamp(THD *thd) const int Field_timestamp::store_time_dec(const MYSQL_TIME *ltime, uint dec) { - int unused; + int warn; ErrConvTime str(ltime); THD *thd= get_thd(); - MYSQL_TIME l_time; - bool valid= !copy_or_convert_to_datetime(thd, ltime, &l_time) && - !check_date(&l_time, pack_time(&l_time) != 0, - sql_mode_for_timestamp(thd), &unused); - return store_TIME_with_warning(thd, &l_time, &str, false, valid); + Datetime dt(thd, &warn, ltime, sql_mode_for_timestamp(thd)); + return store_TIME_with_warning(thd, &dt, &str, warn); } int Field_timestamp::store(const char *from,size_t len,CHARSET_INFO *cs) { - MYSQL_TIME l_time; - MYSQL_TIME_STATUS status; - bool have_smth_to_conv; ErrConvString str(from, len, cs); THD *thd= get_thd(); - - have_smth_to_conv= !str_to_datetime(cs, from, len, &l_time, - sql_mode_for_timestamp(thd), &status); - return store_TIME_with_warning(thd, &l_time, &str, - status.warnings, have_smth_to_conv); + int error; + Datetime dt(&error, from, len, cs, sql_mode_for_timestamp(thd)); + return store_TIME_with_warning(thd, &dt, &str, error); } int Field_timestamp::store(double nr) { - MYSQL_TIME l_time; int error; ErrConvDouble str(nr); THD *thd= get_thd(); - - longlong tmp= double_to_datetime(nr, &l_time, sql_mode_for_timestamp(thd), - &error); - return store_TIME_with_warning(thd, &l_time, &str, error, tmp != -1); + Datetime dt(&error, nr, sql_mode_for_timestamp(thd)); + return store_TIME_with_warning(thd, &dt, &str, error); } int Field_timestamp::store(longlong nr, bool unsigned_val) { - MYSQL_TIME l_time; int error; ErrConvInteger str(nr, unsigned_val); THD *thd= get_thd(); - - longlong tmp= number_to_datetime(nr, 0, &l_time, sql_mode_for_timestamp(thd), - &error); - return store_TIME_with_warning(thd, &l_time, &str, error, tmp != -1); + Datetime dt(&error, nr, unsigned_val, sql_mode_for_timestamp(thd)); + return store_TIME_with_warning(thd, &dt, &str, error); } @@ -5422,10 +5377,10 @@ static longlong read_lowendian(const uchar *from, uint bytes) } } -void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) +void Field_timestamp_hires::store_TIMEVAL(const timeval &tv) { - mi_int4store(ptr, timestamp); - store_bigendian(sec_part_shift(sec_part, dec), ptr+4, sec_part_bytes(dec)); + mi_int4store(ptr, tv.tv_sec); + store_bigendian(sec_part_shift(tv.tv_usec, dec), ptr+4, sec_part_bytes(dec)); } my_time_t Field_timestamp_hires::get_timestamp(const uchar *pos, @@ -5456,23 +5411,11 @@ my_decimal *Field_timestamp_with_dec::val_decimal(my_decimal *d) int Field_timestamp::store_decimal(const my_decimal *d) { - ulonglong nr; - ulong sec_part; int error; - MYSQL_TIME ltime; - longlong tmp; THD *thd= get_thd(); ErrConvDecimal str(d); - - if (my_decimal2seconds(d, &nr, &sec_part)) - { - tmp= -1; - error= 2; - } - else - tmp= number_to_datetime(nr, sec_part, <ime, sql_mode_for_timestamp(thd), - &error); - return store_TIME_with_warning(thd, <ime, &str, error, tmp != -1); + Datetime dt(&error, d, sql_mode_for_timestamp(thd)); + return store_TIME_with_warning(thd, &dt, &str, error); } int Field_timestamp_with_dec::set_time() @@ -5516,19 +5459,15 @@ void Field_timestamp_with_dec::make_send_field(Send_field *field) ** MySQL-5.6 compatible TIMESTAMP(N) **************************************************************/ -void Field_timestampf::store_TIME(my_time_t timestamp, ulong sec_part) +void Field_timestampf::store_TIMEVAL(const timeval &tm) { - struct timeval tm; - tm.tv_sec= timestamp; - tm.tv_usec= sec_part; - my_timeval_trunc(&tm, dec); my_timestamp_to_binary(&tm, ptr, dec); } void Field_timestampf::set_max() { DBUG_ENTER("Field_timestampf::set_max"); - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; DBUG_ASSERT(dec == TIME_SECOND_PART_DIGITS); set_notnull(); @@ -5596,107 +5535,78 @@ void Field_temporal::set_warnings(Sql_condition::enum_warning_level trunc_level, 3 Datetime value that was cut (warning level NOTE) This is used by opt_range.cc:get_mm_leaf(). */ -int Field_temporal_with_date::store_TIME_with_warning(MYSQL_TIME *ltime, +int Field_temporal_with_date::store_TIME_with_warning(const Datetime *dt, const ErrConv *str, - int was_cut, - int have_smth_to_conv) + int was_cut) { Sql_condition::enum_warning_level trunc_level= Sql_condition::WARN_LEVEL_WARN; - int ret= 2; + timestamp_type ts_type= type_handler()->mysql_timestamp_type(); - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; - - if (was_cut == 0 && have_smth_to_conv == 0) // special case: zero date + ASSERT_COLUMN_MARKED_FOR_WRITE; + // Handle totally bad values + if (!dt->is_valid_datetime()) { - was_cut= MYSQL_TIME_WARN_OUT_OF_RANGE; + static const Datetime zero; + store_TIME(zero.get_mysql_time()); + if (was_cut == 0) // special case: zero date + { + set_warnings(trunc_level, str, MYSQL_TIME_WARN_OUT_OF_RANGE, ts_type); + return 2; + } + set_warnings(trunc_level, str, MYSQL_TIME_WARN_TRUNCATED, ts_type); + return 1; } - else if (!have_smth_to_conv) + // Adjust and store the value + if (ts_type == MYSQL_TIMESTAMP_DATE) { - bzero(ltime, sizeof(*ltime)); - was_cut= MYSQL_TIME_WARN_TRUNCATED; - ret= 1; + if (!dt->hhmmssff_is_zero()) + was_cut|= MYSQL_TIME_NOTE_TRUNCATED; + store_TIME(dt->get_mysql_time()); } - else if (!MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) && - (MYSQL_TIME_WARN_HAVE_NOTES(was_cut) || - (type_handler()->mysql_timestamp_type() == MYSQL_TIMESTAMP_DATE && - (ltime->hour || ltime->minute || ltime->second || ltime->second_part)))) + else if (dt->fraction_remainder(decimals())) { - trunc_level= Sql_condition::WARN_LEVEL_NOTE; - was_cut|= MYSQL_TIME_WARN_TRUNCATED; - ret= 3; + Datetime truncated(dt->trunc(decimals())); + store_TIME(truncated.get_mysql_time()); } - set_warnings(trunc_level, str, was_cut, - type_handler()->mysql_timestamp_type()); - store_TIME(ltime); - return was_cut ? ret : 0; + else + store_TIME(dt->get_mysql_time()); + // Caclulate return value and send warnings if needed + return store_TIME_return_code_with_warnings(was_cut, str, ts_type); } int Field_temporal_with_date::store(const char *from, size_t len, CHARSET_INFO *cs) { - MYSQL_TIME ltime; - MYSQL_TIME_STATUS status; - THD *thd= get_thd(); + int error; ErrConvString str(from, len, cs); - bool func_res= !str_to_datetime(cs, from, len, <ime, - sql_mode_for_dates(thd), - &status); - return store_TIME_with_warning(<ime, &str, status.warnings, func_res); + Datetime dt(&error, from, len, cs, sql_mode_for_dates(get_thd())); + return store_TIME_with_warning(&dt, &str, error); } - int Field_temporal_with_date::store(double nr) { - int error= 0; - MYSQL_TIME ltime; - THD *thd= get_thd(); + int error; ErrConvDouble str(nr); - - longlong tmp= double_to_datetime(nr, <ime, - (uint) sql_mode_for_dates(thd), &error); - return store_TIME_with_warning(<ime, &str, error, tmp != -1); + Datetime dt(&error, nr, sql_mode_for_dates(get_thd())); + return store_TIME_with_warning(&dt, &str, error); } int Field_temporal_with_date::store(longlong nr, bool unsigned_val) { int error; - MYSQL_TIME ltime; - longlong tmp; - THD *thd= get_thd(); ErrConvInteger str(nr, unsigned_val); - - tmp= number_to_datetime(nr, 0, <ime, sql_mode_for_dates(thd), &error); - - return store_TIME_with_warning(<ime, &str, error, tmp != -1); + Datetime dt(&error, nr, unsigned_val, sql_mode_for_dates(get_thd())); + return store_TIME_with_warning(&dt, &str, error); } - int Field_temporal_with_date::store_time_dec(const MYSQL_TIME *ltime, uint dec) { - int error= 0, have_smth_to_conv= 1; + int error; ErrConvTime str(ltime); - MYSQL_TIME l_time; - - if (copy_or_convert_to_datetime(get_thd(), ltime, &l_time)) - { - /* - Set have_smth_to_conv and error in a way to have - store_TIME_with_warning do bzero(). - */ - have_smth_to_conv= false; - error= MYSQL_TIME_WARN_OUT_OF_RANGE; - } - else - { - /* - We don't perform range checking here since values stored in TIME - structure always fit into DATETIME range. - */ - have_smth_to_conv= !check_date(&l_time, pack_time(&l_time) != 0, - sql_mode_for_dates(get_thd()), &error); - } - return store_TIME_with_warning(&l_time, &str, error, have_smth_to_conv); + THD *thd= get_thd(); + Datetime dt(thd, &error, ltime, sql_mode_for_dates(thd)); + return store_TIME_with_warning(&dt, &str, error); } @@ -5761,7 +5671,7 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd, case ANY_SUBST: if (!is_temporal_type_with_date(const_item->field_type())) { - Datetime dt(thd, const_item, TIME_FUZZY_DATES | TIME_INVALID_DATES); + Datetime dt(thd, const_item, Datetime::comparison_flags_for_get_date()); if (!dt.is_valid_datetime()) return NULL; return new (thd->mem_root) @@ -5782,36 +5692,28 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd, ** In number context: HHMMSS ** Stored as a 3 byte unsigned int ****************************************************************************/ -int Field_time::store_TIME_with_warning(MYSQL_TIME *ltime, - const ErrConv *str, - int was_cut, - int have_smth_to_conv) +int Field_time::store_TIME_with_warning(const Time *t, + const ErrConv *str, int warn) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; - - if (!have_smth_to_conv) + ASSERT_COLUMN_MARKED_FOR_WRITE; + // Handle totally bad values + if (!t->is_valid_time()) { - bzero(ltime, sizeof(*ltime)); - store_TIME(ltime); + static const Datetime zero; + store_TIME(zero.get_mysql_time()); set_warnings(Sql_condition::WARN_LEVEL_WARN, str, MYSQL_TIME_WARN_TRUNCATED); return 1; } - if (ltime->year != 0 || ltime->month != 0) - { - ltime->year= ltime->month= ltime->day= 0; - was_cut|= MYSQL_TIME_NOTE_TRUNCATED; - } - my_time_trunc(ltime, decimals()); - store_TIME(ltime); - if (!MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) && - MYSQL_TIME_WARN_HAVE_NOTES(was_cut)) + // Adjust and store the value + if (t->fraction_remainder(decimals())) { - set_warnings(Sql_condition::WARN_LEVEL_NOTE, str, - was_cut | MYSQL_TIME_WARN_TRUNCATED); - return 3; + Time truncated(t->trunc(decimals())); + store_TIME(truncated.get_mysql_time()); } - set_warnings(Sql_condition::WARN_LEVEL_WARN, str, was_cut); - return was_cut ? 2 : 0; + else + store_TIME(t->get_mysql_time()); + // Calculate return value and send warnings if needed + return store_TIME_return_code_with_warnings(warn, str, MYSQL_TIMESTAMP_TIME); } @@ -5828,88 +5730,37 @@ void Field_time::store_TIME(const MYSQL_TIME *ltime) int Field_time::store(const char *from,size_t len,CHARSET_INFO *cs) { - MYSQL_TIME ltime; - MYSQL_TIME_STATUS status; ErrConvString str(from, len, cs); - bool have_smth_to_conv= - !str_to_time(cs, from, len, <ime, sql_mode_for_dates(get_thd()), - &status); - - return store_TIME_with_warning(<ime, &str, - status.warnings, have_smth_to_conv); -} - - -/** - subtract a given number of days from DATETIME, return TIME - - optimized version of calc_time_diff() - - @note it might generate TIME values outside of the valid TIME range! -*/ -static void calc_datetime_days_diff(MYSQL_TIME *ltime, long days) -{ - long daydiff= calc_daynr(ltime->year, ltime->month, ltime->day) - days; - ltime->year= ltime->month= 0; - if (daydiff >=0 ) - { - ltime->day= daydiff; - ltime->time_type= MYSQL_TIMESTAMP_TIME; - } - else - { - longlong timediff= ((((daydiff * 24LL + - ltime->hour) * 60LL + - ltime->minute) * 60LL + - ltime->second) * 1000000LL + - ltime->second_part); - unpack_time(timediff, ltime, MYSQL_TIMESTAMP_TIME); - } + int error; + Time tm(&error, from, len, cs, sql_mode_for_dates(get_thd())); + return store_TIME_with_warning(&tm, &str, error); } int Field_time::store_time_dec(const MYSQL_TIME *ltime, uint dec) { - MYSQL_TIME l_time= *ltime; ErrConvTime str(ltime); - int was_cut= 0; - - if (curdays && l_time.time_type != MYSQL_TIMESTAMP_TIME) - calc_datetime_days_diff(&l_time, curdays); - - int have_smth_to_conv= !check_time_range(&l_time, decimals(), &was_cut); - return store_TIME_with_warning(&l_time, &str, was_cut, have_smth_to_conv); + int warn; + Time tm(&warn, ltime, curdays); + return store_TIME_with_warning(&tm, &str, warn); } int Field_time::store(double nr) { - MYSQL_TIME ltime; ErrConvDouble str(nr); int was_cut; - bool neg= nr < 0; - if (neg) - nr= -nr; - int have_smth_to_conv= !number_to_time(neg, (ulonglong) nr, - (ulong)((nr - floor(nr)) * TIME_SECOND_PART_FACTOR), - <ime, &was_cut); - - return store_TIME_with_warning(<ime, &str, was_cut, have_smth_to_conv); + Time tm(&was_cut, nr); + return store_TIME_with_warning(&tm, &str, was_cut); } int Field_time::store(longlong nr, bool unsigned_val) { - MYSQL_TIME ltime; ErrConvInteger str(nr, unsigned_val); int was_cut; - if (nr < 0 && unsigned_val) - nr= 99991231235959LL + 1; - int have_smth_to_conv= !number_to_time(nr < 0, - (ulonglong) (nr < 0 ? -nr : nr), - 0, <ime, &was_cut); - - return store_TIME_with_warning(<ime, &str, was_cut, have_smth_to_conv); + Time tm(&was_cut, nr, unsigned_val); + return store_TIME_with_warning(&tm, &str, was_cut); } @@ -6064,16 +5915,10 @@ void Field_time_hires::store_TIME(const MYSQL_TIME *ltime) int Field_time::store_decimal(const my_decimal *d) { - ulonglong nr; - ulong sec_part; ErrConvDecimal str(d); - MYSQL_TIME ltime; int was_cut; - bool neg= my_decimal2seconds(d, &nr, &sec_part); - - int have_smth_to_conv= !number_to_time(neg, nr, sec_part, <ime, &was_cut); - - return store_TIME_with_warning(<ime, &str, was_cut, have_smth_to_conv); + Time tm(&was_cut, d); + return store_TIME_with_warning(&tm, &str, was_cut); } @@ -6113,14 +5958,28 @@ bool Field_time::can_be_substituted_to_equal_item(const Context &ctx, Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) { + /* + Old mode conversion from DATETIME with non-zero YYYYMMDD part + to TIME works very inconsistently. Possible variants: + - truncate the YYYYMMDD part + - add (MM*33+DD)*24 to hours + - add (MM*31+DD)*24 to hours + Let's disallow propagation of DATETIME with non-zero YYYYMMDD + as an equal constant for a TIME field. + */ + Time::datetime_to_time_mode_t mode= + (thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST) ? + Time::DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY : + Time::DATETIME_TO_TIME_MINUS_CURRENT_DATE; + switch (ctx.subst_constraint()) { case ANY_SUBST: if (const_item->field_type() != MYSQL_TYPE_TIME) { - MYSQL_TIME ltime; // Get the value of const_item with conversion from DATETIME to TIME - ulonglong fuzzydate= Time::comparison_flags_for_get_date(); - if (const_item->get_time_with_conversion(thd, <ime, fuzzydate)) + Time tm(const_item, + Time::Options(Time::comparison_flags_for_get_date(), mode)); + if (!tm.is_valid_time()) return NULL; /* Replace a DATE/DATETIME constant to a TIME constant: @@ -6132,8 +5991,9 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx, (assuming CURRENT_DATE is '2015-08-30' */ - return new (thd->mem_root) Item_time_literal(thd, <ime, - ltime.second_part ? + return new (thd->mem_root) Item_time_literal(thd, tm.get_mysql_time(), + tm.get_mysql_time()-> + second_part ? TIME_SECOND_PART_DIGITS : 0); } @@ -6142,8 +6002,8 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx, if (const_item->field_type() != MYSQL_TYPE_TIME || const_item->decimals != decimals()) { - MYSQL_TIME ltime; - if (const_item->get_time_with_conversion(thd, <ime, TIME_TIME_ONLY)) + Time tm(const_item, Time::Options(TIME_TIME_ONLY, mode)); + if (!tm.is_valid_time()) return NULL; /* Note, the value returned in "ltime" can have more fractional @@ -6159,7 +6019,8 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx, The optimized WHERE will return with "Impossible WHERE", without having to do the full table scan. */ - return new (thd->mem_root) Item_time_literal(thd, <ime, decimals()); + return new (thd->mem_root) Item_time_literal(thd, tm.get_mysql_time(), + decimals()); } break; } @@ -6253,7 +6114,7 @@ bool Field_timef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) int Field_year::store(const char *from, size_t len,CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; char *end; int error; longlong nr= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error); @@ -6301,7 +6162,7 @@ int Field_year::store(double nr) int Field_year::store(longlong nr, bool unsigned_val) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; if (nr < 0 || (nr >= 100 && nr <= 1900) || nr > 2155) { *ptr= 0; @@ -6395,7 +6256,7 @@ void Field_year::sql_type(String &res) const ** Stored as a 4 byte unsigned int ****************************************************************************/ -void Field_date::store_TIME(MYSQL_TIME *ltime) +void Field_date::store_TIME(const MYSQL_TIME *ltime) { uint tmp= ltime->year*10000L + ltime->month*100+ltime->day; int4store(ptr,tmp); @@ -6488,7 +6349,7 @@ void Field_date::sql_type(String &res) const ** In number context: YYYYMMDD ****************************************************************************/ -void Field_newdate::store_TIME(MYSQL_TIME *ltime) +void Field_newdate::store_TIME(const MYSQL_TIME *ltime) { uint tmp= ltime->year*16*32 + ltime->month*32+ltime->day; int3store(ptr,tmp); @@ -6594,7 +6455,7 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx, if (!is_temporal_type_with_date(const_item->field_type())) { // Get the value of const_item with conversion from TIME to DATETIME - Datetime dt(thd, const_item, TIME_FUZZY_DATES | TIME_INVALID_DATES); + Datetime dt(thd, const_item, Datetime::comparison_flags_for_get_date()); if (!dt.is_valid_datetime()) return NULL; /* @@ -6639,7 +6500,7 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx, ** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int. ****************************************************************************/ -void Field_datetime::store_TIME(MYSQL_TIME *ltime) +void Field_datetime::store_TIME(const MYSQL_TIME *ltime) { ulonglong tmp= TIME_to_ulonglong_datetime(ltime); int8store(ptr,tmp); @@ -6777,13 +6638,14 @@ int Field_datetime::set_time() thd->variables.time_zone->gmt_sec_to_TIME(&now_time, thd->query_start()); now_time.second_part= thd->query_start_sec_part(); set_notnull(); + my_time_trunc(&now_time, decimals()); store_TIME(&now_time); thd->time_zone_used= 1; return 0; } -void Field_datetime_hires::store_TIME(MYSQL_TIME *ltime) +void Field_datetime_hires::store_TIME(const MYSQL_TIME *ltime) { ulonglong packed= sec_part_shift(pack_time(ltime), dec); store_bigendian(packed, ptr, Field_datetime_hires::pack_length()); @@ -6791,24 +6653,10 @@ void Field_datetime_hires::store_TIME(MYSQL_TIME *ltime) int Field_temporal_with_date::store_decimal(const my_decimal *d) { - ulonglong nr; - ulong sec_part; int error; - MYSQL_TIME ltime; - longlong tmp; - THD *thd= get_thd(); ErrConvDecimal str(d); - - if (my_decimal2seconds(d, &nr, &sec_part)) - { - tmp= -1; - error= 2; - } - else - tmp= number_to_datetime(nr, sec_part, <ime, sql_mode_for_dates(thd), - &error); - - return store_TIME_with_warning(<ime, &str, error, tmp != -1); + Datetime tm(&error, d, sql_mode_for_dates(get_thd())); + return store_TIME_with_warning(&tm, &str, error); } bool Field_datetime_with_dec::send_binary(Protocol *protocol) @@ -6881,9 +6729,8 @@ int Field_datetimef::reset() return 0; } -void Field_datetimef::store_TIME(MYSQL_TIME *ltime) +void Field_datetimef::store_TIME(const MYSQL_TIME *ltime) { - my_time_trunc(ltime, decimals()); longlong tmp= TIME_to_longlong_datetime_packed(ltime); my_datetime_packed_to_binary(tmp, ptr, dec); } @@ -6993,7 +6840,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end, int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; uint copy_length; int rc; @@ -7039,7 +6886,7 @@ int Field_str::store(longlong nr, bool unsigned_val) int Field_str::store(double nr) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; uint local_char_length= MY_MIN(sizeof(buff), field_length / field_charset->mbmaxlen); @@ -7076,9 +6923,8 @@ uint Field_str::is_equal(Create_field *new_field) int Field_longstr::store_decimal(const my_decimal *d) { - char buff[DECIMAL_MAX_STR_LENGTH+1]; - String str(buff, sizeof(buff), &my_charset_numeric); - my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str); + StringBuffer<DECIMAL_MAX_STR_LENGTH+1> str; + d->to_string(&str); return store(str.ptr(), str.length(), str.charset()); } @@ -7295,11 +7141,12 @@ void Field_string::sql_type(String &res) const size_t length; length= cs->cset->snprintf(cs,(char*) res.ptr(), - res.alloced_length(), "%s(%d)", + res.alloced_length(), "%s(%d)%s", (type() == MYSQL_TYPE_VAR_STRING ? (has_charset() ? "varchar" : "varbinary") : (has_charset() ? "char" : "binary")), - (int) field_length / charset()->mbmaxlen); + (int) field_length / charset()->mbmaxlen, + type() == MYSQL_TYPE_VAR_STRING ? "/*old*/" : ""); res.length(length); if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) && has_charset() && (charset()->state & MY_CS_BINSORT)) @@ -7536,7 +7383,7 @@ int Field_varstring::save_field_metadata(uchar *metadata_ptr) int Field_varstring::store(const char *from,size_t length,CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; uint copy_length; int rc; @@ -8073,7 +7920,7 @@ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr, int Field_varstring_compressed::store(const char *from, size_t length, CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; uint compressed_length; int rc= compress((char*) get_data(), field_length, from, (uint) length, Field_varstring_compressed::max_display_length(), @@ -8205,7 +8052,7 @@ int Field_blob::copy_value(Field_blob *from) int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; size_t copy_length, new_length; uint copy_len; char *tmp; @@ -8693,7 +8540,7 @@ uint Field_blob::is_equal(Create_field *new_field) int Field_blob_compressed::store(const char *from, size_t length, CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; uint compressed_length; uint max_length= max_data_length(); uint to_length= (uint) MY_MIN(max_length, @@ -9036,7 +8883,7 @@ void Field_enum::store_type(ulonglong value) int Field_enum::store(const char *from,size_t length,CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int err= 0; char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); @@ -9088,7 +8935,7 @@ int Field_enum::store(double nr) int Field_enum::store(longlong nr, bool unsigned_val) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; if ((ulonglong) nr > typelib->count || nr == 0) { @@ -9219,7 +9066,7 @@ Field *Field_enum::make_new_field(MEM_ROOT *root, TABLE *new_table, int Field_set::store(const char *from,size_t length,CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; bool got_warning= 0; int err= 0; char *not_used; @@ -9259,7 +9106,7 @@ int Field_set::store(const char *from,size_t length,CHARSET_INFO *cs) int Field_set::store(longlong nr, bool unsigned_val) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int error= 0; ulonglong max_nr; @@ -9638,7 +9485,7 @@ uint Field_bit::is_equal(Create_field *new_field) int Field_bit::store(const char *from, size_t length, CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int delta; for (; length && !*from; from++, length--) // skip left 0's @@ -10074,7 +9921,7 @@ Field_bit_as_char::Field_bit_as_char(uchar *ptr_arg, uint32 len_arg, int Field_bit_as_char::store(const char *from, size_t length, CHARSET_INFO *cs) { - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + ASSERT_COLUMN_MARKED_FOR_WRITE; int delta; uchar bits= (uchar) (field_length & 7); @@ -10568,322 +10415,90 @@ uint pack_length_to_packflag(uint type) } -Field *make_field(TABLE_SHARE *share, - MEM_ROOT *mem_root, - uchar *ptr, uint32 field_length, - uchar *null_pos, uchar null_bit, - uint pack_flag, - const Type_handler *handler, - CHARSET_INFO *field_charset, - Field::geometry_type geom_type, uint srid, - Field::utype unireg_check, - TYPELIB *interval, - const LEX_CSTRING *field_name, - uint32 flags) +uint Column_definition_attributes::pack_flag_to_pack_length() const { - uchar *UNINIT_VAR(bit_ptr); - uchar UNINIT_VAR(bit_offset); + uint type= f_packtype(pack_flag); // 0..15 + DBUG_ASSERT(type < 16); + switch (type) { + case MYSQL_TYPE_TINY: return 1; + case MYSQL_TYPE_SHORT: return 2; + case MYSQL_TYPE_LONG: return 4; + case MYSQL_TYPE_LONGLONG: return 8; + case MYSQL_TYPE_INT24: return 3; + } + return 0; // This should not happen +} + +Field *Column_definition_attributes::make_field(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const Record_addr *rec, + const Type_handler *handler, + const LEX_CSTRING *field_name, + uint32 flags) + const +{ + DBUG_ASSERT(length <= UINT_MAX32); DBUG_PRINT("debug", ("field_type: %s, field_length: %u, interval: %p, pack_flag: %s%s%s%s%s", - handler->name().ptr(), field_length, interval, + handler->name().ptr(), (uint) length, interval, FLAGSTR(pack_flag, FIELDFLAG_BINARY), FLAGSTR(pack_flag, FIELDFLAG_INTERVAL), FLAGSTR(pack_flag, FIELDFLAG_NUMBER), FLAGSTR(pack_flag, FIELDFLAG_PACK), FLAGSTR(pack_flag, FIELDFLAG_BLOB))); - if (handler == &type_handler_row) - { - DBUG_ASSERT(field_length == 0); - DBUG_ASSERT(f_maybe_null(pack_flag)); - return new (mem_root) Field_row(ptr, field_name); - } - - if (handler->real_field_type() == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag)) - { - bit_ptr= null_pos; - bit_offset= null_bit; - if (f_maybe_null(pack_flag)) // if null field - { - bit_ptr+= (null_bit == 7); // shift bit_ptr and bit_offset - bit_offset= (bit_offset + 1) & 7; - } - } - - if (!f_maybe_null(pack_flag)) - { - null_pos=0; - null_bit=0; - } - else - { - null_bit= ((uchar) 1) << null_bit; - } - - - if (f_is_alpha(pack_flag)) - { - if (!f_is_packed(pack_flag)) - { - enum_field_types field_type= handler->real_field_type(); - if (field_type == MYSQL_TYPE_STRING || - field_type == MYSQL_TYPE_DECIMAL || // 3.23 or 4.0 string - field_type == MYSQL_TYPE_VAR_STRING) - return new (mem_root) - Field_string(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - field_charset); - if (field_type == MYSQL_TYPE_VARCHAR) - { - if (unireg_check == Field::TMYSQL_COMPRESSED) - return new (mem_root) - Field_varstring_compressed( - ptr, field_length, - HA_VARCHAR_PACKLENGTH(field_length), - null_pos, null_bit, - unireg_check, field_name, - share, field_charset, zlib_compression_method); - - return new (mem_root) - Field_varstring(ptr,field_length, - HA_VARCHAR_PACKLENGTH(field_length), - null_pos,null_bit, - unireg_check, field_name, - share, - field_charset); - } - return 0; // Error - } - - // MYSQL_TYPE_VAR_STRING is handled above - DBUG_ASSERT(f_packtype(pack_flag) != MYSQL_TYPE_VAR_STRING); - const Type_handler *tmp; - tmp= Type_handler::get_handler_by_real_type((enum_field_types) - f_packtype(pack_flag)); - uint pack_length= tmp->calc_pack_length(field_length); - -#ifdef HAVE_SPATIAL - if (f_is_geom(pack_flag)) - { - status_var_increment(current_thd->status_var.feature_gis); - return new (mem_root) - Field_geom(ptr,null_pos,null_bit, - unireg_check, field_name, share, - pack_length, geom_type, srid); - } -#endif - if (f_is_blob(pack_flag)) - { - if (unireg_check == Field::TMYSQL_COMPRESSED) - return new (mem_root) - Field_blob_compressed(ptr, null_pos, null_bit, - unireg_check, field_name, share, - pack_length, field_charset, zlib_compression_method); - - return new (mem_root) - Field_blob(ptr,null_pos,null_bit, - unireg_check, field_name, share, - pack_length, field_charset); - } - if (interval) - { - if (f_is_enum(pack_flag)) - return new (mem_root) - Field_enum(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - pack_length, interval, field_charset); - else - return new (mem_root) - Field_set(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - pack_length, interval, field_charset); - } - } - - switch (handler->real_field_type()) { - case MYSQL_TYPE_DECIMAL: - return new (mem_root) - Field_decimal(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - f_decimals(pack_flag), - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag) == 0); - case MYSQL_TYPE_NEWDECIMAL: - return new (mem_root) - Field_new_decimal(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - f_decimals(pack_flag), - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag) == 0); - case MYSQL_TYPE_FLOAT: - { - int decimals= f_decimals(pack_flag); - if (decimals == FLOATING_POINT_DECIMALS) - decimals= NOT_FIXED_DEC; - return new (mem_root) - Field_float(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - decimals, - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag)== 0); - } - case MYSQL_TYPE_DOUBLE: - { - int decimals= f_decimals(pack_flag); - if (decimals == FLOATING_POINT_DECIMALS) - decimals= NOT_FIXED_DEC; - return new (mem_root) - Field_double(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - decimals, - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag)== 0); - } - case MYSQL_TYPE_TINY: - return new (mem_root) - Field_tiny(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag) == 0); - case MYSQL_TYPE_SHORT: - return new (mem_root) - Field_short(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag) == 0); - case MYSQL_TYPE_INT24: - return new (mem_root) - Field_medium(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag) == 0); - case MYSQL_TYPE_LONG: - return new (mem_root) - Field_long(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag) == 0); - case MYSQL_TYPE_LONGLONG: - if (flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG)) - { - return new (mem_root) - Field_vers_trx_id(ptr, field_length, null_pos, null_bit, - unireg_check, field_name, - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag) == 0); - } - else - { - return new (mem_root) - Field_longlong(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag) == 0); - } - case MYSQL_TYPE_TIMESTAMP: - { - uint dec= field_length > MAX_DATETIME_WIDTH ? - field_length - MAX_DATETIME_WIDTH - 1: 0; - return new_Field_timestamp(mem_root, ptr, null_pos, null_bit, unireg_check, - field_name, share, dec); - } - case MYSQL_TYPE_TIMESTAMP2: - { - uint dec= field_length > MAX_DATETIME_WIDTH ? - field_length - MAX_DATETIME_WIDTH - 1: 0; - return new (mem_root) - Field_timestampf(ptr, null_pos, null_bit, unireg_check, - field_name, share, dec); - } - case MYSQL_TYPE_YEAR: - return new (mem_root) - Field_year(ptr,field_length,null_pos,null_bit, - unireg_check, field_name); - case MYSQL_TYPE_DATE: - return new (mem_root) - Field_date(ptr,null_pos,null_bit, - unireg_check, field_name); - case MYSQL_TYPE_NEWDATE: - return new (mem_root) - Field_newdate(ptr,null_pos,null_bit, - unireg_check, field_name); - case MYSQL_TYPE_TIME: - { - uint dec= field_length > MIN_TIME_WIDTH ? - field_length - MIN_TIME_WIDTH - 1: 0; - return new_Field_time(mem_root, ptr, null_pos, null_bit, unireg_check, - field_name, dec); - } - case MYSQL_TYPE_TIME2: - { - uint dec= field_length > MIN_TIME_WIDTH ? - field_length - MIN_TIME_WIDTH - 1: 0; - return new (mem_root) - Field_timef(ptr, null_pos, null_bit, unireg_check, - field_name, dec); - } - case MYSQL_TYPE_DATETIME: - { - uint dec= field_length > MAX_DATETIME_WIDTH ? - field_length - MAX_DATETIME_WIDTH - 1: 0; - return new_Field_datetime(mem_root, ptr, null_pos, null_bit, unireg_check, - field_name, dec); - } - case MYSQL_TYPE_DATETIME2: - { - uint dec= field_length > MAX_DATETIME_WIDTH ? - field_length - MAX_DATETIME_WIDTH - 1: 0; - return new (mem_root) - Field_datetimef(ptr, null_pos, null_bit, unireg_check, - field_name, dec); - } - case MYSQL_TYPE_NULL: - return new (mem_root) - Field_null(ptr, field_length, unireg_check, field_name, - field_charset); - case MYSQL_TYPE_BIT: - return (f_bit_as_char(pack_flag) ? - new (mem_root) - Field_bit_as_char(ptr, field_length, null_pos, null_bit, - unireg_check, field_name) : - new (mem_root) - Field_bit(ptr, field_length, null_pos, null_bit, bit_ptr, - bit_offset, unireg_check, field_name)); - - default: // Impossible (Wrong version) - break; - } - return 0; + Record_addr addr(rec->ptr(), f_maybe_null(pack_flag) ? rec->null() : + Bit_addr()); + /* + Special code for the BIT-alike data types + who store data bits together with NULL-bits. + */ + Bit_addr bit(rec->null()); + if (f_maybe_null(pack_flag)) + bit.inc(); + return handler->make_table_field_from_def(share, mem_root, field_name, + addr, bit, this, flags); } + bool Field_vers_trx_id::test_if_equality_guarantees_uniqueness(const Item* item) const { - return item->type() == Item::DATE_ITEM; + return item->is_of_type(Item::CONST_ITEM, TIME_RESULT); } +Column_definition_attributes::Column_definition_attributes(const Field *field) + :length(field->character_octet_length() / field->charset()->mbmaxlen), + unireg_check(field->unireg_check), + interval(NULL), + charset(field->charset()), // May be NULL ptr + srid(0), + geom_type(Field::GEOM_GEOMETRY), + pack_flag(0) +{} + + /** Create a field suitable for create of table. */ Column_definition::Column_definition(THD *thd, Field *old_field, Field *orig_field) + :Column_definition_attributes(old_field) { on_update= NULL; field_name= old_field->field_name; - length= old_field->field_length; flags= old_field->flags; - unireg_check=old_field->unireg_check; pack_length=old_field->pack_length(); key_length= old_field->key_length(); set_handler(old_field->type_handler()); - charset= old_field->charset(); // May be NULL ptr comment= old_field->comment; decimals= old_field->decimals(); vcol_info= old_field->vcol_info; option_list= old_field->option_list; - pack_flag= 0; compression_method_ptr= 0; versioning= VERSIONING_NOT_SET; invisible= old_field->invisible; + interval_list.empty(); // prepare_interval_field() needs this + char_length= (uint) length; if (orig_field) { @@ -10901,66 +10516,9 @@ Column_definition::Column_definition(THD *thd, Field *old_field, check_constraint= 0; } - switch (real_field_type()) { - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - length/= charset->mbmaxlen; - key_length/= charset->mbmaxlen; - break; - case MYSQL_TYPE_STRING: - /* Change CHAR -> VARCHAR if dynamic record length */ - if (old_field->type() == MYSQL_TYPE_VAR_STRING) - set_handler(&type_handler_varchar); - /* fall through */ - - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - case MYSQL_TYPE_VARCHAR: - case MYSQL_TYPE_VAR_STRING: - /* This is corrected in create_length_to_internal_length */ - length= (length+charset->mbmaxlen-1) / charset->mbmaxlen - - MY_TEST(old_field->compression_method()); - break; -#ifdef HAVE_SPATIAL - case MYSQL_TYPE_GEOMETRY: - geom_type= ((Field_geom*)old_field)->geom_type; - srid= ((Field_geom*)old_field)->srid; - break; -#endif - case MYSQL_TYPE_YEAR: - if (length != 4) - { - char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; - my_snprintf(buff, sizeof(buff), "YEAR(%llu)", length); - push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, - ER_WARN_DEPRECATED_SYNTAX, - ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX), - buff, "YEAR(4)"); - } - break; - case MYSQL_TYPE_FLOAT: - case MYSQL_TYPE_DOUBLE: - /* - Floating points are stored with FLOATING_POINT_DECIMALS but internally - in MariaDB used with NOT_FIXED_DEC, which is >= FLOATING_POINT_DECIMALS. - */ - if (decimals >= FLOATING_POINT_DECIMALS) - decimals= NOT_FIXED_DEC; - break; - default: - break; - } - - if (flags & (ENUM_FLAG | SET_FLAG)) - interval= ((Field_enum*) old_field)->typelib; - else - interval=0; + type_handler()->Column_definition_reuse_fix_attributes(thd, this, old_field); - interval_list.empty(); // prepare_interval_field() needs this - - char_length= (uint)length; + type_handler()->Column_definition_implicit_upgrade(this); /* Copy the default (constant/function) from the column object orig_field, if @@ -11042,11 +10600,11 @@ Column_definition::redefine_stage1_common(const Column_definition *dup_field, uint32 Field_blob::char_length() const { - return Field_blob::octet_length(); + return Field_blob::character_octet_length(); } -uint32 Field_blob::octet_length() const +uint32 Field_blob::character_octet_length() const { switch (packlength) { diff --git a/sql/field.h b/sql/field.h index 2037802df9a..ed61afe01eb 100644 --- a/sql/field.h +++ b/sql/field.h @@ -48,6 +48,9 @@ class Item_equal; class Virtual_tmp_table; class Qualified_column_ident; class Table_ident; +class SEL_ARG; +class RANGE_OPT_PARAM; +struct KEY_PART; enum enum_check_fields { @@ -467,31 +470,6 @@ inline bool is_temporal_type_with_date(enum_field_types type) } -/** - Convert temporal real types as retuned by field->real_type() - to field type as returned by field->type(). - - @param real_type Real type. - @retval Field type. -*/ -inline enum_field_types real_type_to_type(enum_field_types real_type) -{ - switch (real_type) - { - case MYSQL_TYPE_TIME2: - return MYSQL_TYPE_TIME; - case MYSQL_TYPE_DATETIME2: - return MYSQL_TYPE_DATETIME; - case MYSQL_TYPE_TIMESTAMP2: - return MYSQL_TYPE_TIMESTAMP; - case MYSQL_TYPE_NEWDATE: - return MYSQL_TYPE_DATE; - /* Note: NEWDECIMAL is a type, not only a real_type */ - default: return real_type; - } -} - - enum enum_vcol_info_type { VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED, @@ -835,7 +813,7 @@ public: return nr < 0 ? 0 : (ulonglong) nr; } virtual bool val_bool(void)= 0; - virtual my_decimal *val_decimal(my_decimal *); + virtual my_decimal *val_decimal(my_decimal *)=0; inline String *val_str(String *str) { return val_str(str, str); } /* val_str(buf1, buf2) gets two buffers and should use them as follows: @@ -872,6 +850,10 @@ public: to be quoted when used in constructing an SQL query. */ virtual bool str_needs_quotes() { return FALSE; } + const Type_handler *type_handler_for_comparison() const + { + return type_handler()->type_handler_for_comparison(); + } Item_result result_type () const { return type_handler()->result_type(); @@ -880,7 +862,6 @@ public: { return type_handler()->cmp_type(); } - static enum_field_types field_type_merge(enum_field_types, enum_field_types); virtual bool eq(Field *field) { return (ptr == field->ptr && null_ptr == field->null_ptr && @@ -1245,6 +1226,12 @@ public: virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table, uchar *new_ptr, uint32 length, uchar *new_null_ptr, uint new_null_bit); + Field *create_tmp_field(MEM_ROOT *root, TABLE *new_table, + bool maybe_null_arg); + Field *create_tmp_field(MEM_ROOT *root, TABLE *new_table) + { + return create_tmp_field(root, new_table, maybe_null()); + } Field *clone(MEM_ROOT *mem_root, TABLE *new_table); Field *clone(MEM_ROOT *mem_root, TABLE *new_table, my_ptrdiff_t diff, bool stat_flag= FALSE); @@ -1395,6 +1382,59 @@ protected: } int warn_if_overflow(int op_result); Copy_func *get_identical_copy_func() const; + bool can_optimize_scalar_range(const RANGE_OPT_PARAM *param, + const KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, + const Item *value) const; + uchar *make_key_image(MEM_ROOT *mem_root, const KEY_PART *key_part); + SEL_ARG *get_mm_leaf_int(RANGE_OPT_PARAM *param, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value, + bool unsigned_field); + /* + Make a leaf tree for the cases when the value was stored + to the field exactly, without any truncation, rounding or adjustments. + For example, if we stored an INT value into an INT column, + and value->save_in_field_no_warnings() returned 0, + we know that the value was stored exactly. + */ + SEL_ARG *stored_field_make_mm_leaf_exact(RANGE_OPT_PARAM *param, + KEY_PART *key_part, + scalar_comparison_op op, + Item *value); + /* + Make a leaf tree for the cases when we don't know if + the value was stored to the field without any data loss, + or was modified to a smaller or a greater value. + Used for the data types whose methods Field::store*() + silently adjust the value. This is the most typical case. + */ + SEL_ARG *stored_field_make_mm_leaf(RANGE_OPT_PARAM *param, + KEY_PART *key_part, + scalar_comparison_op op, Item *value); + /* + Make a leaf tree when an INT value was stored into a field of INT type, + and some truncation happened. Tries to adjust the range search condition + when possible, e.g. "tinytint < 300" -> "tinyint <= 127". + Can also return SEL_ARG_IMPOSSIBLE(), and NULL (not sargable). + */ + SEL_ARG *stored_field_make_mm_leaf_bounded_int(RANGE_OPT_PARAM *param, + KEY_PART *key_part, + scalar_comparison_op op, + Item *value, + bool unsigned_field); + /* + Make a leaf tree when some truncation happened during + value->save_in_field_no_warning(this), and we cannot yet adjust the range + search condition for the current combination of the field and the value + data types. + Returns SEL_ARG_IMPOSSIBLE() for "=" and "<=>". + Returns NULL (not sargable) for other comparison operations. + */ + SEL_ARG *stored_field_make_mm_leaf_truncated(RANGE_OPT_PARAM *prm, + scalar_comparison_op, + Item *value); public: void set_table_name(String *alias) { @@ -1405,6 +1445,19 @@ public: orig_table= table= table_arg; set_table_name(&table_arg->alias); } + virtual void init_for_tmp_table(Field *org_field, TABLE *new_table) + { + init(new_table); + orig_table= org_field->orig_table; + vcol_info= 0; + cond_selectivity= 1.0; + next_equal_field= NULL; + option_list= NULL; + option_struct= NULL; + if (org_field->type() == MYSQL_TYPE_VAR_STRING || + org_field->type() == MYSQL_TYPE_VARCHAR) + new_table->s->db_create_options|= HA_OPTION_PACK_RECORD; + } void init_for_make_new_field(TABLE *new_table_arg, TABLE *orig_table_arg) { init(new_table_arg); @@ -1431,12 +1484,21 @@ public: /* convert decimal to longlong with overflow check */ longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, int *err); + /* + Maximum number of bytes in character representation. + - For string types it is equal to the field capacity, in bytes. + - For non-string types it represents the longest possible string length + after conversion to string. + */ + virtual uint32 character_octet_length() const + { + return field_length; + } /* The max. number of characters */ virtual uint32 char_length() const { return field_length / charset()->mbmaxlen; } - virtual geometry_type get_geometry_type() { /* shouldn't get here. */ @@ -1554,6 +1616,10 @@ public: const Item *item, bool is_eq_func) const; + virtual SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value)= 0; + bool can_optimize_outer_join_table_elimination(const Item_bool_func *cond, const Item *item) const { @@ -1715,6 +1781,9 @@ public: { return pos_in_interval_val_real(min, max); } + SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value); }; @@ -1752,6 +1821,7 @@ public: enum Derivation derivation(void) const { return field_derivation; } bool binary() const { return field_charset == &my_charset_bin; } uint32 max_display_length() const { return field_length; } + uint32 character_octet_length() const { return field_length; } uint32 char_length() const { return field_length / field_charset->mbmaxlen; } Information_schema_character_attributes information_schema_character_attributes() const @@ -1771,6 +1841,9 @@ public: return pos_in_interval_val_str(min, max, length_size()); } bool test_if_equality_guarantees_uniqueness(const Item *const_item) const; + SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value); }; /* base class for Field_string, Field_varstring and Field_blob */ @@ -1883,7 +1956,7 @@ public: return Field_num::memcpy_field_possible(from) && field_length >= from->field_length; } - int store_decimal(const my_decimal *); + int store_decimal(const my_decimal *dec) { return store(dec->to_double()); } int store_time_dec(const MYSQL_TIME *ltime, uint dec); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); my_decimal *val_decimal(my_decimal *); @@ -1966,8 +2039,8 @@ public: } int save_in_field(Field *to) { - my_decimal buff; - return to->store_decimal(val_decimal(&buff)); + my_decimal tmp(ptr, precision, dec); + return to->store_decimal(&tmp); } bool memcpy_field_possible(const Field *from) const { @@ -1983,17 +2056,33 @@ public: int store(longlong nr, bool unsigned_val); int store_time_dec(const MYSQL_TIME *ltime, uint dec); int store_decimal(const my_decimal *); - double val_real(void); - longlong val_int(void); - ulonglong val_uint(void); + double val_real(void) + { + return my_decimal(ptr, precision, dec).to_double(); + } + longlong val_int(void) + { + return my_decimal(ptr, precision, dec).to_longlong(unsigned_flag); + } + ulonglong val_uint(void) + { + return (ulonglong) my_decimal(ptr, precision, dec).to_longlong(true); + } my_decimal *val_decimal(my_decimal *); - String *val_str(String*, String *); - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + String *val_str(String *val_buffer, String *val_ptr __attribute__((unused))) + { + uint fixed_precision= zerofill ? precision : 0; + return my_decimal(ptr, precision, dec). + to_string(val_buffer, fixed_precision, dec, '0'); + } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return my_decimal(ptr, precision, dec). + to_datetime_with_warn(ltime, fuzzydate, field_name.str); + } bool val_bool() { - my_decimal decimal_value; - my_decimal *val= val_decimal(&decimal_value); - return val ? !my_decimal_is_zero(val) : 0; + return my_decimal(ptr, precision, dec).to_bool(); } int cmp(const uchar *, const uchar *); void sort_string(uchar *buff, uint length); @@ -2068,6 +2157,12 @@ public: uint32 prec= type_limits_int()->precision(); return Information_schema_numeric_attributes(prec, 0); } + SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value) + { + return get_mm_leaf_int(param, key_part, cond, op, value, unsigned_flag); + } }; @@ -2416,6 +2511,11 @@ public: if (dec_arg >= FLOATING_POINT_DECIMALS) dec_arg= NOT_FIXED_DEC; } + void init_for_tmp_table(Field *org_field, TABLE *new_table) + { + Field::init_for_tmp_table(org_field, new_table); + not_fixed= true; + } const Type_handler *type_handler() const { return &type_handler_double; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } int store(const char *to,size_t length,CHARSET_INFO *charset); @@ -2494,6 +2594,20 @@ class Field_temporal: public Field { protected: Item *get_equal_const_item_datetime(THD *thd, const Context &ctx, Item *const_item); + int store_TIME_return_code_with_warnings(int warn, const ErrConv *str, + timestamp_type ts_type) + { + if (!MYSQL_TIME_WARN_HAVE_WARNINGS(warn) && + MYSQL_TIME_WARN_HAVE_NOTES(warn)) + { + set_warnings(Sql_condition::WARN_LEVEL_NOTE, str, + warn | MYSQL_TIME_WARN_TRUNCATED, ts_type); + return 3; + } + set_warnings(Sql_condition::WARN_LEVEL_WARN, str, warn, ts_type); + return warn ? 2 : 0; + } + public: Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, @@ -2544,6 +2658,9 @@ public: { return true; } + SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value); }; @@ -2556,9 +2673,10 @@ public: */ class Field_temporal_with_date: public Field_temporal { protected: - int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, - int was_cut, int have_smth_to_conv); - virtual void store_TIME(MYSQL_TIME *ltime) = 0; + int store_TIME_with_warning(const Datetime *ltime, const ErrConv *str, + int was_cut); + void store_TIME_with_trunc(const Time *); + virtual void store_TIME(const MYSQL_TIME *ltime) = 0; virtual bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const = 0; bool validate_MMDD(bool not_zero_date, uint month, uint day, @@ -2590,8 +2708,12 @@ public: class Field_timestamp :public Field_temporal { protected: sql_mode_t sql_mode_for_timestamp(THD *thd) const; - int store_TIME_with_warning(THD *, MYSQL_TIME *, const ErrConv *, - int warnings, bool have_smth_to_conv); + int store_TIME_with_warning(THD *, const Datetime *, + const ErrConv *, int warn); + virtual void store_TIMEVAL(const timeval &tv) + { + int4store(ptr, tv.tv_sec); + } public: Field_timestamp(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, @@ -2631,9 +2753,9 @@ public: { return get_timestamp(ptr, sec_part); } - virtual void store_TIME(my_time_t timestamp, ulong sec_part) + void store_TIME(my_time_t timestamp, ulong sec_part) { - int4store(ptr,timestamp); + store_TIMEVAL(Timeval(timestamp, sec_part).trunc(decimals())); } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); uchar *pack(uchar *to, const uchar *from, @@ -2703,6 +2825,7 @@ class Field_timestamp_hires :public Field_timestamp_with_dec { { return Type_handler_timestamp::sec_part_bytes(dec); } + void store_TIMEVAL(const timeval &tv); public: Field_timestamp_hires(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, @@ -2715,7 +2838,6 @@ public: DBUG_ASSERT(dec); } my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; - void store_TIME(my_time_t timestamp, ulong sec_part); int cmp(const uchar *,const uchar *); uint32 pack_length() const { return 4 + sec_part_bytes(dec); } uint size_of() const { return sizeof(*this); } @@ -2731,6 +2853,7 @@ class Field_timestampf :public Field_timestamp_with_dec { *metadata_ptr= (uchar) decimals(); return 1; } + void store_TIMEVAL(const timeval &tv); public: Field_timestampf(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, @@ -2759,7 +2882,6 @@ public: } void set_max(); bool is_max(); - void store_TIME(my_time_t timestamp, ulong sec_part); my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; my_time_t get_timestamp(ulong *sec_part) const { @@ -2777,7 +2899,10 @@ public: :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, 1, 1) {} - const Type_handler *type_handler() const { return &type_handler_year; } + const Type_handler *type_handler() const + { + return field_length == 2 ? &type_handler_year2 : &type_handler_year; + } Copy_func *get_copy_func(const Field *from) const { if (eq_def(from)) @@ -2824,14 +2949,31 @@ public: }; -class Field_date :public Field_temporal_with_date { - void store_TIME(MYSQL_TIME *ltime); +class Field_date_common: public Field_temporal_with_date +{ +public: + Field_date_common(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, + const LEX_CSTRING *field_name_arg) + :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, + null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg) + {} + SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value); +}; + + +class Field_date :public Field_date_common +{ + void store_TIME(const MYSQL_TIME *ltime); bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; public: Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) - :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg) {} + :Field_date_common(ptr_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg) {} const Type_handler *type_handler() const { return &type_handler_date; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } @@ -2859,14 +3001,15 @@ public: }; -class Field_newdate :public Field_temporal_with_date { - void store_TIME(MYSQL_TIME *ltime); +class Field_newdate :public Field_date_common +{ + void store_TIME(const MYSQL_TIME *ltime); bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; public: Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) - :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg) + :Field_date_common(ptr_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg) {} const Type_handler *type_handler() const { return &type_handler_newdate; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; } @@ -2895,8 +3038,7 @@ class Field_time :public Field_temporal { long curdays; protected: virtual void store_TIME(const MYSQL_TIME *ltime); - int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, - int was_cut, int have_smth_to_conv); + int store_TIME_with_warning(const Time *ltime, const ErrConv *str, int warn); void set_warnings(Sql_condition::enum_warning_level level, const ErrConv *str, int was_cut) { @@ -3054,7 +3196,7 @@ public: class Field_datetime :public Field_temporal_with_date { - void store_TIME(MYSQL_TIME *ltime); + void store_TIME(const MYSQL_TIME *ltime); bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; public: Field_datetime(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg, @@ -3147,7 +3289,7 @@ public: DATETIME(1..6) */ class Field_datetime_hires :public Field_datetime_with_dec { - void store_TIME(MYSQL_TIME *ltime); + void store_TIME(const MYSQL_TIME *ltime); bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; public: Field_datetime_hires(uchar *ptr_arg, uchar *null_ptr_arg, @@ -3170,7 +3312,7 @@ public: DATETIME(0..6) - MySQL56 version */ class Field_datetimef :public Field_datetime_with_dec { - void store_TIME(MYSQL_TIME *ltime); + void store_TIME(const MYSQL_TIME *ltime); bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; int save_field_metadata(uchar *metadata_ptr) { @@ -3475,6 +3617,7 @@ private: str.append(STRING_WITH_LEN(" /*!100301 COMPRESSED*/")); } uint32 max_display_length() const { return field_length - 1; } + uint32 character_octet_length() const { return field_length - 1; } uint32 char_length() const { return (field_length - 1) / field_charset->mbmaxlen; @@ -3607,7 +3750,7 @@ public: Information_schema_character_attributes information_schema_character_attributes() const { - uint32 octets= Field_blob::octet_length(); + uint32 octets= Field_blob::character_octet_length(); uint32 chars= octets / field_charset->mbminlen; return Information_schema_character_attributes(octets, chars); } @@ -3773,7 +3916,7 @@ public: { return charset() == &my_charset_bin ? FALSE : TRUE; } uint32 max_display_length() const; uint32 char_length() const; - uint32 octet_length() const; + uint32 character_octet_length() const; uint is_equal(Create_field *new_field); friend void TABLE::remember_blob_values(String *blob_storage); @@ -4181,6 +4324,12 @@ public: } void hash(ulong *nr, ulong *nr2); + SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value) + { + return get_mm_leaf_int(param, key_part, cond, op, value, true); + } private: virtual size_t do_last_null_byte() const; int save_field_metadata(uchar *first_byte); @@ -4225,21 +4374,53 @@ public: extern const LEX_CSTRING null_clex_str; -Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, - uchar *ptr, uint32 field_length, - uchar *null_pos, uchar null_bit, - uint pack_flag, const Type_handler *handler, - CHARSET_INFO *cs, - Field::geometry_type geom_type, uint srid, - Field::utype unireg_check, - TYPELIB *interval, const LEX_CSTRING *field_name, - uint32 flags); +class Column_definition_attributes +{ +public: + /* + At various stages in execution this can be length of field in bytes or + max number of characters. + */ + ulonglong length; + Field::utype unireg_check; + TYPELIB *interval; // Which interval to use + CHARSET_INFO *charset; + uint32 srid; + Field::geometry_type geom_type; + uint pack_flag; + Column_definition_attributes() + :length(0), + unireg_check(Field::NONE), + interval(NULL), + charset(&my_charset_bin), + srid(0), + geom_type(Field::GEOM_GEOMETRY), + pack_flag(0) + { } + Column_definition_attributes(const Field *field); + Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, + const Record_addr *rec, + const Type_handler *handler, + const LEX_CSTRING *field_name, + uint32 flags) const; + uint temporal_dec(uint intlen) const + { + return (uint) (length > intlen ? length - intlen - 1 : 0); + } + uint pack_flag_to_pack_length() const; + void frm_pack_basic(uchar *buff) const; + void frm_pack_charset(uchar *buff) const; + void frm_unpack_basic(const uchar *buff); + bool frm_unpack_charset(TABLE_SHARE *share, const uchar *buff); +}; + /* Create field class for CREATE TABLE */ class Column_definition: public Sql_alloc, - public Type_handler_hybrid_field_type + public Type_handler_hybrid_field_type, + public Column_definition_attributes { /** Create "interval" from "interval_list". @@ -4294,11 +4475,6 @@ public: WITHOUT_VERSIONING }; Item *on_update; // ON UPDATE NOW() - /* - At various stages in execution this can be length of field in bytes or - max number of characters. - */ - ulonglong length; field_visibility_t invisible; /* The value of `length' as set by parser: is the number of characters @@ -4306,15 +4482,9 @@ public: */ uint32 char_length; uint decimals, flags, pack_length, key_length; - Field::utype unireg_check; - TYPELIB *interval; // Which interval to use List<String> interval_list; - CHARSET_INFO *charset; - uint32 srid; - Field::geometry_type geom_type; engine_option_value *option_list; - uint pack_flag; /* This is additinal data provided for any computed(virtual) field. @@ -4332,11 +4502,9 @@ public: :Type_handler_hybrid_field_type(&type_handler_null), compression_method_ptr(0), comment(null_clex_str), - on_update(NULL), length(0), invisible(VISIBLE), decimals(0), - flags(0), pack_length(0), key_length(0), unireg_check(Field::NONE), - interval(0), charset(&my_charset_bin), - srid(0), geom_type(Field::GEOM_GEOMETRY), - option_list(NULL), pack_flag(0), + on_update(NULL), invisible(VISIBLE), decimals(0), + flags(0), pack_length(0), key_length(0), + option_list(NULL), vcol_info(0), default_value(0), check_constraint(0), versioning(VERSIONING_NOT_SET) { @@ -4466,20 +4634,18 @@ public: } Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, - uchar *ptr, uchar *null_pos, uchar null_bit, + const Record_addr *addr, const LEX_CSTRING *field_name_arg) const { - return ::make_field(share, mem_root, ptr, - (uint32)length, null_pos, null_bit, - pack_flag, type_handler(), charset, - geom_type, srid, unireg_check, interval, - field_name_arg, flags); + return Column_definition_attributes::make_field(share, mem_root, addr, + type_handler(), + field_name_arg, flags); } Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *field_name_arg) const { - return make_field(share, mem_root, (uchar *) 0, (uchar *) "", 0, - field_name_arg); + Record_addr addr(true); + return make_field(share, mem_root, &addr, field_name_arg); } /* Return true if default is an expression that must be saved explicitely */ bool has_default_expression(); @@ -4801,7 +4967,7 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name, #define FIELDFLAG_DEC_SHIFT 8 #define FIELDFLAG_MAX_DEC 63U -#define MTYP_TYPENR(type) (type & 127U) /* Remove bits from type */ +#define MTYP_TYPENR(type) ((type) & 127U) // Remove bits from type #define f_is_dec(x) ((x) & FIELDFLAG_DECIMAL) #define f_is_num(x) ((x) & FIELDFLAG_NUMBER) diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 64d0bc6c452..f413dec82be 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -413,8 +413,8 @@ void Field::do_field_real(Copy_field *copy) void Field::do_field_decimal(Copy_field *copy) { - my_decimal value; - copy->to_field->store_decimal(copy->from_field->val_decimal(&value)); + my_decimal value(copy->from_field); + copy->to_field->store_decimal(&value); } diff --git a/sql/filesort.cc b/sql/filesort.cc index a4be9e4acfa..6901cee043f 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -258,7 +258,7 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, } if (memory_available < min_sort_memory) { - my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR + ME_FATALERROR)); + my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR_LOG + ME_FATAL)); goto err; } tracker->report_sort_buffer_size(sort->sort_buffer_size()); @@ -710,7 +710,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select, uchar *ref_pos, *next_pos, ref_buff[MAX_REFLENGTH]; TABLE *sort_form; handler *file; - MY_BITMAP *save_read_set, *save_write_set, *save_vcol_set; + MY_BITMAP *save_read_set, *save_write_set; Item *sort_cond; ha_rows retval; DBUG_ENTER("find_all_keys"); @@ -745,13 +745,11 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select, /* Remember original bitmaps */ save_read_set= sort_form->read_set; save_write_set= sort_form->write_set; - save_vcol_set= sort_form->vcol_set; /* Set up temporary column read map for columns used by sort */ DBUG_ASSERT(save_read_set != &sort_form->tmp_set); bitmap_clear_all(&sort_form->tmp_set); - sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set, - &sort_form->tmp_set); + sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set); register_used_fields(param); if (quick_select) select->quick->add_used_key_part_to_set(); @@ -809,16 +807,12 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select, */ MY_BITMAP *tmp_read_set= sort_form->read_set; MY_BITMAP *tmp_write_set= sort_form->write_set; - MY_BITMAP *tmp_vcol_set= sort_form->vcol_set; if (select->cond->with_subquery()) - sort_form->column_bitmaps_set(save_read_set, save_write_set, - save_vcol_set); + sort_form->column_bitmaps_set(save_read_set, save_write_set); write_record= (select->skip_record(thd) > 0); if (select->cond->with_subquery()) - sort_form->column_bitmaps_set(tmp_read_set, - tmp_write_set, - tmp_vcol_set); + sort_form->column_bitmaps_set(tmp_read_set, tmp_write_set); } else write_record= true; @@ -864,7 +858,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select, } /* Signal we should use orignal column read and write maps */ - sort_form->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set); + sort_form->column_bitmaps_set(save_read_set, save_write_set); if (unlikely(thd->is_error())) DBUG_RETURN(HA_POS_ERROR); @@ -872,8 +866,8 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select, DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos)); if (unlikely(error != HA_ERR_END_OF_FILE)) { - file->print_error(error,MYF(ME_ERROR | ME_WAITTANG)); // purecov: inspected - DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */ + file->print_error(error,MYF(ME_ERROR_LOG)); + DBUG_RETURN(HA_POS_ERROR); } if (indexpos && idx && write_keys(param, fs_info, idx, buffpek_pointers, tempfile)) @@ -885,7 +879,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select, DBUG_RETURN(retval); err: - sort_form->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set); + sort_form->column_bitmaps_set(save_read_set, save_write_set); DBUG_RETURN(HA_POS_ERROR); } /* find_all_keys */ @@ -1122,9 +1116,8 @@ Type_handler_decimal_result::make_sort_key(uchar *to, Item *item, } *to++= 1; } - my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, to, - item->max_length - (item->decimals ? 1 : 0), - item->decimals); + dec_val->to_binary(to, item->max_length - (item->decimals ? 1 : 0), + item->decimals); } diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 7e04cabc765..262e791ec7a 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -6809,7 +6809,7 @@ FT_INFO *ha_partition::ft_init_ext(uint flags, uint inx, String *key) sizeof(FT_INFO *) * m_tot_parts, NullS))) { - my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL)); DBUG_RETURN(NULL); } ft_target->part_ft_info= tmp_ft_info; @@ -10648,8 +10648,6 @@ int ha_partition::check_misplaced_rows(uint read_part_id, bool do_repair) { /* Only need to read the partitioning fields. */ bitmap_union(table->read_set, &m_part_info->full_part_field_set); - if (table->vcol_set) - bitmap_union(table->vcol_set, &m_part_info->full_part_field_set); } if ((result= m_file[read_part_id]->ha_rnd_init(1))) diff --git a/sql/handler.cc b/sql/handler.cc index 306b0868d15..943722af3b3 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -295,7 +295,7 @@ handler *get_ha_partition(partition_info *part_info) } else { - my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), static_cast<int>(sizeof(ha_partition))); } DBUG_RETURN(((handler*) partition)); @@ -2543,7 +2543,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, dummy_share.table_name= *alias; dummy_table.alias.set(alias->str, alias->length, table_alias_charset); file->change_table_ptr(&dummy_table, &dummy_share); - file->print_error(error, MYF(intercept ? ME_JUST_WARNING : 0)); + file->print_error(error, MYF(intercept ? ME_WARNING : 0)); } if (intercept) error= 0; @@ -3600,7 +3600,7 @@ void handler::print_error(int error, myf errflag) if (ha_thd()->transaction_rollback_request) { /* Ensure this becomes a true error */ - errflag&= ~(ME_JUST_WARNING | ME_JUST_INFO); + errflag&= ~(ME_WARNING | ME_NOTE); } int textno= -1; // impossible value @@ -3735,14 +3735,14 @@ void handler::print_error(int error, myf errflag) { textno=ER_RECORD_FILE_FULL; /* Write the error message to error log */ - errflag|= ME_NOREFRESH; + errflag|= ME_ERROR_LOG; break; } case HA_ERR_INDEX_FILE_FULL: { textno=ER_INDEX_FILE_FULL; /* Write the error message to error log */ - errflag|= ME_NOREFRESH; + errflag|= ME_ERROR_LOG; break; } case HA_ERR_LOCK_WAIT_TIMEOUT: @@ -3869,14 +3869,14 @@ void handler::print_error(int error, myf errflag) if (unlikely(fatal_error)) { /* Ensure this becomes a true error */ - errflag&= ~(ME_JUST_WARNING | ME_JUST_INFO); + errflag&= ~(ME_WARNING | ME_NOTE); if ((debug_assert_if_crashed_table || global_system_variables.log_warnings > 1)) { /* Log error to log before we crash or if extended warnings are requested */ - errflag|= ME_NOREFRESH; + errflag|= ME_ERROR_LOG; } } @@ -4048,7 +4048,8 @@ static bool update_frm_version(TABLE *table) int4store(version, MYSQL_VERSION_ID); - if ((result= (int)mysql_file_pwrite(file, (uchar*) version, 4, 51L, MYF_RW))) + if ((result= (int)mysql_file_pwrite(file, (uchar*) version, 4, 51L, + MYF(MY_WME+MY_NABP)))) goto err; table->s->mysql_version= MYSQL_VERSION_ID; @@ -4969,7 +4970,7 @@ int ha_create_table(THD *thd, const char *path, { if (!thd->is_error()) my_error(ER_CANT_CREATE_TABLE, MYF(0), db, table_name, error); - table.file->print_error(error, MYF(ME_JUST_WARNING)); + table.file->print_error(error, MYF(ME_WARNING)); PSI_CALL_drop_table_share(temp_table, share.db.str, (uint)share.db.length, share.table_name.str, (uint)share.table_name.length); } diff --git a/sql/handler.h b/sql/handler.h index e3ab87b941b..68a54cc207a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -3226,7 +3226,7 @@ public: /* True if changes to the table is persistent (no rollback) - This is manly used to decide how to log changes to the table in + This is mainly used to decide how to log changes to the table in the binary log. */ bool has_transactions() diff --git a/sql/item.cc b/sql/item.cc index 8fa3a0b741b..f6198e1df68 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -118,7 +118,7 @@ void Item::push_note_converted_to_positive_complement(THD *thd) longlong Item::val_datetime_packed_result() { MYSQL_TIME ltime, tmp; - if (get_date_result(<ime, TIME_FUZZY_DATES | TIME_INVALID_DATES)) + if (get_date_result(<ime, Datetime::comparison_flags_for_get_date())) return 0; if (ltime.time_type != MYSQL_TIMESTAMP_TIME) return pack_time(<ime); @@ -128,50 +128,6 @@ longlong Item::val_datetime_packed_result() } -/** - Get date/time/datetime. - If DATETIME or DATE result is returned, it's converted to TIME. -*/ -bool Item::get_time_with_conversion(THD *thd, MYSQL_TIME *ltime, - ulonglong fuzzydate) -{ - if (get_date(ltime, fuzzydate)) - return true; - if (ltime->time_type != MYSQL_TIMESTAMP_TIME) - { - MYSQL_TIME ltime2; - if ((thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST) && - (ltime->year || ltime->day || ltime->month)) - { - /* - Old mode conversion from DATETIME with non-zero YYYYMMDD part - to TIME works very inconsistently. Possible variants: - - truncate the YYYYMMDD part - - add (MM*33+DD)*24 to hours - - add (MM*31+DD)*24 to hours - Let's return TRUE here, to disallow equal field propagation. - Note, If we start to use this method in more pieces of the code other - than equal field propagation, we should probably return - TRUE only if some flag in fuzzydate is set. - */ - return true; - } - if (datetime_to_time_with_warn(thd, ltime, <ime2, TIME_SECOND_PART_DIGITS)) - { - /* - If the time difference between CURRENT_DATE and ltime - did not fit into the supported TIME range, then we set the - difference to the maximum possible value in the supported TIME range - */ - DBUG_ASSERT(0); - return (null_value= true); - } - *ltime= ltime2; - } - return false; -} - - /* For the items which don't have its own fast val_str_ascii() implementation we provide a generic slower version, @@ -253,36 +209,6 @@ String *Item::val_string_from_int(String *str) } -String *Item::val_string_from_decimal(String *str) -{ - my_decimal dec_buf, *dec= val_decimal(&dec_buf); - if (null_value) - return 0; - my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf); - my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, 0, str); - return str; -} - - -/* - All val_xxx_from_date() must call this method, to expose consistent behaviour - regarding SQL_MODE when converting DATE/DATETIME to other data types. -*/ -bool Item::get_temporal_with_sql_mode(MYSQL_TIME *ltime) -{ - return get_date(ltime, field_type() == MYSQL_TYPE_TIME - ? TIME_TIME_ONLY - : sql_mode_for_dates(current_thd)); -} - - -bool Item::is_null_from_temporal() -{ - MYSQL_TIME ltime; - return get_temporal_with_sql_mode(<ime); -} - - longlong Item::val_int_from_str(int *error) { char buff[MAX_FIELD_WIDTH]; @@ -333,21 +259,6 @@ longlong Item::val_int_unsigned_typecast_from_int() } -String *Item::val_string_from_date(String *str) -{ - MYSQL_TIME ltime; - if (get_temporal_with_sql_mode(<ime) || - str->alloc(MAX_DATE_STRING_REP_LENGTH)) - { - null_value= 1; - return (String *) 0; - } - str->length(my_TIME_to_str(<ime, const_cast<char*>(str->ptr()), decimals)); - str->set_charset(&my_charset_numeric); - return str; -} - - my_decimal *Item::val_decimal_from_real(my_decimal *decimal_value) { double nr= val_real(); @@ -379,89 +290,6 @@ my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value) } -my_decimal *Item::val_decimal_from_date(my_decimal *decimal_value) -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - if (get_temporal_with_sql_mode(<ime)) - { - my_decimal_set_zero(decimal_value); - null_value= 1; // set NULL, stop processing - return 0; - } - return date2my_decimal(<ime, decimal_value); -} - - -my_decimal *Item::val_decimal_from_time(my_decimal *decimal_value) -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - if (get_time(<ime)) - { - my_decimal_set_zero(decimal_value); - return 0; - } - return date2my_decimal(<ime, decimal_value); -} - - -longlong Item::val_int_from_date() -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - if (get_temporal_with_sql_mode(<ime)) - return 0; - longlong v= TIME_to_ulonglong(<ime); - return ltime.neg ? -v : v; -} - - -double Item::val_real_from_date() -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - if (get_temporal_with_sql_mode(<ime)) - return 0; - return TIME_to_double(<ime); -} - - -double Item::val_real_from_decimal() -{ - /* Note that fix_fields may not be called for Item_avg_field items */ - double result; - my_decimal value_buff, *dec_val= val_decimal(&value_buff); - if (null_value) - return 0.0; - my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &result); - return result; -} - - -longlong Item::val_int_from_decimal() -{ - /* Note that fix_fields may not be called for Item_avg_field items */ - longlong result; - my_decimal value, *dec_val= val_decimal(&value); - if (null_value) - return 0; - my_decimal2int(E_DEC_FATAL_ERROR, dec_val, unsigned_flag, &result); - 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; @@ -515,11 +343,11 @@ int Item::save_str_value_in_field(Field *field, String *result) Item::Item(THD *thd): is_expensive_cache(-1), rsize(0), name(null_clex_str), orig_name(0), - fixed(0), is_autogenerated_name(TRUE) + is_autogenerated_name(TRUE) { DBUG_ASSERT(thd); marker= 0; - maybe_null=null_value=with_sum_func=with_window_func=with_field=0; + maybe_null= null_value= with_window_func= with_field= false; in_rollup= 0; with_param= 0; @@ -563,11 +391,9 @@ Item::Item(THD *thd, Item *item): maybe_null(item->maybe_null), in_rollup(item->in_rollup), null_value(item->null_value), - with_sum_func(item->with_sum_func), with_param(item->with_param), with_window_func(item->with_window_func), with_field(item->with_field), - fixed(item->fixed), is_autogenerated_name(item->is_autogenerated_name) { next= thd->free_list; // Put in free list @@ -637,7 +463,6 @@ void Item::cleanup() { DBUG_ENTER("Item::cleanup"); DBUG_PRINT("enter", ("this: %p", this)); - fixed= 0; marker= 0; join_tab_idx= MAX_TABLES; if (orig_name) @@ -657,7 +482,7 @@ void Item::cleanup() bool Item::cleanup_processor(void *arg) { - if (fixed) + if (is_fixed()) cleanup(); return FALSE; } @@ -749,7 +574,8 @@ Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg, :Item_result_field(thd), orig_db_name(NullS), orig_table_name(view_arg->table_name.str), orig_field_name(*field_name_arg), - context(&view_arg->view->select_lex.context), + /* TODO: suspicious use of first_select_lex */ + context(&view_arg->view->first_select_lex()->context), db_name(NullS), table_name(view_arg->alias.str), field_name(*field_name_arg), alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX), @@ -943,12 +769,15 @@ bool Item_field::register_field_in_read_map(void *arg) { TABLE *table= (TABLE *) arg; int res= 0; + if (table && table != field->table) + return res; + if (field->vcol_info && - !bitmap_fast_test_and_set(field->table->vcol_set, field->field_index)) + !bitmap_fast_test_and_set(field->table->read_set, field->field_index)) { res= field->vcol_info->expr->walk(&Item::register_field_in_read_map,1,arg); } - if (field->table == table || !table) + else bitmap_set_bit(field->table->read_set, field->field_index); return res; } @@ -1176,7 +1005,7 @@ bool Item::check_type_scalar(const char *opname) const This hack in Item_outer_ref should probably be refactored eventually. Discuss with Sanja. */ - DBUG_ASSERT(fixed || type() == REF_ITEM); + DBUG_ASSERT(is_fixed() || type() == REF_ITEM); const Type_handler *handler= type_handler(); if (handler->is_scalar_type()) return false; @@ -1325,7 +1154,6 @@ Item *Item_cache::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) unlikely(!(cache= new (thd->mem_root) Item_cache_str(thd, conv)))) return NULL; // Safe conversion is not possible, or OEM cache->setup(thd, conv); - cache->fixed= false; // Make Item::fix_fields() happy return cache; } @@ -1376,7 +1204,7 @@ Item *Item::const_charset_converter(THD *thd, CHARSET_INFO *tocs, const char *func_name) { DBUG_ASSERT(const_item()); - DBUG_ASSERT(fixed); + DBUG_ASSERT(is_fixed()); StringBuffer<64>tmp; String *s= val_str(&tmp); MEM_ROOT *mem_root= thd->mem_root; @@ -1456,26 +1284,6 @@ bool Item::get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate) } -bool Item::get_date_from_year(MYSQL_TIME *ltime, ulonglong fuzzydate) -{ - longlong value= val_int(); - DBUG_ASSERT(unsigned_flag || value >= 0); - if (max_length == 2) - { - if (value < 70) - value+= 2000; - else if (value <= 1900) - value+= 1900; - } - value*= 10000; /* make it YYYYMMHH */ - if (null_value || int_to_datetime_with_warn(false, value, - ltime, fuzzydate, - field_name_or_null())) - return null_value|= make_zero_date(ltime, fuzzydate); - return null_value= false; -} - - bool Item::get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate) { double value= val_real(); @@ -1486,17 +1294,6 @@ bool Item::get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate) } -bool Item::get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate) -{ - my_decimal value, *res; - if (!(res= val_decimal(&value)) || - decimal_to_datetime_with_warn(res, ltime, fuzzydate, - field_name_or_null())) - return null_value|= make_zero_date(ltime, fuzzydate); - return null_value= false; -} - - bool Item::get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate) { char buff[40]; @@ -1535,21 +1332,6 @@ bool Item::make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate) return !(fuzzydate & TIME_FUZZY_DATES); } -bool Item::get_seconds(ulonglong *sec, ulong *sec_part) -{ - if (decimals == 0) - { // optimize for an important special case - longlong val= val_int(); - bool neg= val < 0 && !unsigned_flag; - *sec= neg ? -val : val; - *sec_part= 0; - return neg; - } - my_decimal tmp, *dec= val_decimal(&tmp); - if (!dec) - return 0; - return my_decimal2seconds(dec, sec, sec_part); -} const MY_LOCALE *Item::locale_from_val_str() { @@ -1686,7 +1468,7 @@ Query_fragment::Query_fragment(THD *thd, sp_head *sphead, *****************************************************************************/ Item_sp_variable::Item_sp_variable(THD *thd, const LEX_CSTRING *sp_var_name) - :Item(thd), m_thd(0), m_name(*sp_var_name) + :Item_fixed_hybrid(thd), m_thd(0), m_name(*sp_var_name) #ifndef DBUG_OFF , m_sp(0) #endif @@ -1698,7 +1480,7 @@ bool Item_sp_variable::fix_fields_from_item(THD *thd, Item **, const Item *it) { m_thd= thd; /* NOTE: this must be set before any this_xxx() */ - DBUG_ASSERT(it->fixed); + DBUG_ASSERT(it->is_fixed()); max_length= it->max_length; decimals= it->decimals; @@ -1819,10 +1601,10 @@ Item_splocal::Item_splocal(THD *thd, Rewritable_query_parameter(pos_in_q, len_in_q), Type_handler_hybrid_field_type(handler), m_rcontext_handler(rh), - m_var_idx(sp_var_idx) + m_var_idx(sp_var_idx), + m_type(handler == &type_handler_row ? ROW_ITEM : CONST_ITEM) { maybe_null= TRUE; - m_type= sp_map_item_type(handler); } @@ -2175,54 +1957,25 @@ bool Item_name_const::is_null() Item_name_const::Item_name_const(THD *thd, Item *name_arg, Item *val): - Item(thd), value_item(val), name_item(name_arg) + Item_fixed_hybrid(thd), value_item(val), name_item(name_arg) { Item::maybe_null= TRUE; - valid_args= true; - if (!name_item->basic_const_item()) - goto err; - - if (value_item->basic_const_item()) - return; // ok - - if (value_item->type() == FUNC_ITEM) - { - Item_func *value_func= (Item_func *) value_item; - if (value_func->functype() != Item_func::COLLATE_FUNC && - value_func->functype() != Item_func::NEG_FUNC) - goto err; - - if (value_func->key_item()->basic_const_item()) - return; // ok - } - -err: - valid_args= false; - my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST"); } Item::Type Item_name_const::type() const { /* - As - 1. one can try to create the Item_name_const passing non-constant - arguments, although it's incorrect and - 2. the type() method can be called before the fix_fields() to get - type information for a further type cast, e.g. - if (item->type() == FIELD_ITEM) - ((Item_field *) item)->... - we return NULL_ITEM in the case to avoid wrong casting. - - valid_args guarantees value_item->basic_const_item(); if type is - FUNC_ITEM, then we have a fudged item_func_neg() on our hands - and return the underlying type. + + We are guarenteed that value_item->basic_const_item(), if not + an error is thrown that WRONG ARGUMENTS are supplied to + NAME_CONST function. + If type is FUNC_ITEM, then we have a fudged item_func_neg() + on our hands and return the underlying type. For Item_func_set_collation() e.g. NAME_CONST('name', 'value' COLLATE collation) we return its 'value' argument type. */ - if (!valid_args) - return NULL_ITEM; Item::Type value_type= value_item->type(); if (value_type == FUNC_ITEM) { @@ -2365,7 +2118,7 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, else { /* Not a SUM() function */ - if (unlikely((!with_sum_func && !(split_flags & SPLIT_SUM_SELECT)))) + if (unlikely((!with_sum_func() && !(split_flags & SPLIT_SUM_SELECT)))) { /* This is not a SUM function and there are no SUM functions inside. @@ -2373,7 +2126,7 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, */ return; } - if (likely(with_sum_func || + if (likely(with_sum_func() || (type() == FUNC_ITEM && (((Item_func *) this)->functype() == Item_func::ISNOTNULLTEST_FUNC || @@ -2748,7 +2501,7 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, else thd->change_item_tree(arg, conv); - if (conv->fix_fields(thd, arg)) + if (conv->fix_fields_if_needed(thd, arg)) { res= TRUE; break; // we cannot return here, we need to restore "arena". @@ -2897,7 +2650,7 @@ bool Item_sp::execute(THD *thd, bool *null_value, Item **args, uint arg_count) if (unlikely(execute_impl(thd, args, arg_count))) { *null_value= 1; - context->process_error(thd); + process_error(thd); if (thd->killed) thd->send_kill_message(); return true; @@ -2930,7 +2683,7 @@ Item_sp::execute_impl(THD *thd, Item **args, uint arg_count) DBUG_ENTER("Item_sp::execute_impl"); - if (context->security_ctx) + if (context && context->security_ctx) { /* Set view definer security context */ thd->security_ctx= context->security_ctx; @@ -3109,7 +2862,10 @@ Item_field::Item_field(THD *thd, Field *f) have_privileges(0), any_privileges(0) { set_field(f); - + /* + field_name and table_name should not point to garbage + if this item is to be reused + */ orig_table_name= table_name; orig_field_name= field_name; with_field= 1; @@ -3645,6 +3401,48 @@ longlong Item_field::val_int_endpoint(bool left_endp, bool *incl_endp) return null_value? LONGLONG_MIN : res; } + +bool Item_basic_value::eq(const Item *item, bool binary_cmp) const +{ + const Item_const *c0, *c1; + const Type_handler *h0, *h1; + /* + - Test get_item_const() for NULL filters out Item_param + bound in a way that needs a data type conversion + (e.g. non-integer value in a LIMIT clause). + Item_param::get_item_const() return NULL in such cases. + - Test for type_handler_for_comparison() equality makes sure + that values of different data type groups do not get detected + as equal (e.g. numbers vs strings, time vs datetime). + - Test for cast_to_int_type_handler() equality distinguishes + values with dual properties. For example, VARCHAR 'abc' and hex + hybrid 0x616263 are equal in string context, but they are not equal + if the hybrid appears in integer context (it behaves as integer then). + Here we have no full information about the context, so treat them + as not equal. + QQ: We could pass Value_source::Context here instead of + "bool binary_cmp", to make substitution more delicate. + See Field::get_equal_const_item(). + */ + bool res= (c0= get_item_const()) && + (c1= item->get_item_const()) && + (h0= type_handler())->type_handler_for_comparison() == + (h1= item->type_handler())->type_handler_for_comparison() && + h0->cast_to_int_type_handler()->type_handler_for_comparison() == + h1->cast_to_int_type_handler()->type_handler_for_comparison() && + h0->Item_const_eq(c0, c1, binary_cmp); + DBUG_EXECUTE_IF("Item_basic_value", + push_warning_printf(current_thd, + Sql_condition::WARN_LEVEL_NOTE, + ER_UNKNOWN_ERROR, "%seq=%d a=%s b=%s", + binary_cmp ? "bin_" : "", (int) res, + DbugStringItemTypeValue(current_thd, this).c_ptr(), + DbugStringItemTypeValue(current_thd, item).c_ptr() + );); + return res; +} + + /** Create an item from a string we KNOW points to a valid longlong end \\0 terminated number string. @@ -3664,7 +3462,6 @@ Item_int::Item_int(THD *thd, const char *str_arg, size_t length): the field name. */ name.length= !str_arg[max_length] ? max_length : strlen(str_arg); - fixed= 1; } @@ -3676,8 +3473,6 @@ my_decimal *Item_int::val_decimal(my_decimal *decimal_value) String *Item_int::val_str(String *str) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); str->set_int(value, unsigned_flag, collation.collation); return str; } @@ -3714,8 +3509,6 @@ Item_uint::Item_uint(THD *thd, const char *str_arg, longlong i, uint length): String *Item_uint::val_str(String *str) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); str->set((ulonglong) value, collation.collation); return str; } @@ -3737,7 +3530,6 @@ Item_decimal::Item_decimal(THD *thd, const char *str_arg, size_t length, name.str= str_arg; name.length= safe_strlen(str_arg); decimals= (uint8) decimal_value.frac; - fixed= 1; max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg + decimals, decimals, @@ -3749,7 +3541,6 @@ Item_decimal::Item_decimal(THD *thd, longlong val, bool unsig): { int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value); decimals= (uint8) decimal_value.frac; - fixed= 1; max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg + decimals, decimals, @@ -3762,7 +3553,6 @@ Item_decimal::Item_decimal(THD *thd, double val, int precision, int scale): { double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value); decimals= (uint8) decimal_value.frac; - fixed= 1; max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg + decimals, decimals, @@ -3779,16 +3569,14 @@ Item_decimal::Item_decimal(THD *thd, const char *str, const my_decimal *val_arg, name.length= safe_strlen(str); decimals= (uint8) decimal_par; max_length= length; - fixed= 1; } -Item_decimal::Item_decimal(THD *thd, my_decimal *value_par): +Item_decimal::Item_decimal(THD *thd, const my_decimal *value_par): Item_num(thd) { my_decimal2decimal(value_par, &decimal_value); decimals= (uint8) decimal_value.frac; - fixed= 1; max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg + decimals, decimals, @@ -3797,63 +3585,15 @@ Item_decimal::Item_decimal(THD *thd, my_decimal *value_par): Item_decimal::Item_decimal(THD *thd, const uchar *bin, int precision, int scale): - Item_num(thd) + Item_num(thd), + decimal_value(bin, precision, scale) { - binary2my_decimal(E_DEC_FATAL_ERROR, bin, - &decimal_value, precision, scale); decimals= (uint8) decimal_value.frac; - fixed= 1; max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, unsigned_flag); } -longlong Item_decimal::val_int() -{ - longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &result); - return result; -} - -double Item_decimal::val_real() -{ - double result; - my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result); - return result; -} - -String *Item_decimal::val_str(String *result) -{ - result->set_charset(&my_charset_numeric); - my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, result); - return result; -} - -void Item_decimal::print(String *str, enum_query_type query_type) -{ - my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, &str_value); - str->append(str_value); -} - - -bool Item_decimal::eq(const Item *item, bool binary_cmp) const -{ - if (type() == item->type() && item->basic_const_item()) - { - /* - We need to cast off const to call val_decimal(). This should - be OK for a basic constant. Additionally, we can pass 0 as - a true decimal constant will return its internal decimal - storage and ignore the argument. - */ - Item *arg= (Item*) item; - my_decimal *value= arg->val_decimal(0); - return !my_decimal_cmp(&decimal_value, value); - } - return 0; -} - - void Item_decimal::set_decimal_value(my_decimal *value_par) { my_decimal2decimal(value_par, &decimal_value); @@ -3875,8 +3615,6 @@ Item *Item_decimal::clone_item(THD *thd) String *Item_float::val_str(String *str) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); str->set_real(value, decimals, &my_charset_numeric); return str; } @@ -3884,8 +3622,6 @@ String *Item_float::val_str(String *str) my_decimal *Item_float::val_decimal(my_decimal *decimal_value) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value); return (decimal_value); } @@ -3946,7 +3682,6 @@ void Item_string::print(String *str, enum_query_type query_type) double Item_string::val_real() { - DBUG_ASSERT(fixed == 1); return double_from_string_with_check(&str_value); } @@ -3957,7 +3692,6 @@ double Item_string::val_real() */ longlong Item_string::val_int() { - DBUG_ASSERT(fixed == 1); return longlong_from_string_with_check(&str_value); } @@ -3970,23 +3704,17 @@ my_decimal *Item_string::val_decimal(my_decimal *decimal_value) double Item_null::val_real() { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; } longlong Item_null::val_int() { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); null_value=1; return 0; } /* ARGSUSED */ String *Item_null::val_str(String *str) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); null_value=1; return 0; } @@ -3999,8 +3727,6 @@ my_decimal *Item_null::val_decimal(my_decimal *decimal_value) bool Item_null::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); make_zero_date(ltime, fuzzydate); return (null_value= true); } @@ -4050,8 +3776,6 @@ Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg, */ 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), m_empty_string_is_null(false), indicator(STMT_INDICATOR_NONE), m_out_param_info(NULL), @@ -4090,7 +3814,6 @@ void Item_param::set_null() max_length= 0; decimals= 0; state= NULL_VALUE; - fix_type(Item::NULL_ITEM); DBUG_VOID_RETURN; } @@ -4105,7 +3828,6 @@ void Item_param::set_int(longlong i, uint32 max_length_arg) decimals= 0; maybe_null= 0; null_value= 0; - fix_type(Item::INT_ITEM); DBUG_VOID_RETURN; } @@ -4120,7 +3842,6 @@ void Item_param::set_double(double d) decimals= NOT_FIXED_DEC; maybe_null= 0; null_value= 0; - fix_type(Item::REAL_ITEM); DBUG_VOID_RETURN; } @@ -4153,7 +3874,6 @@ void Item_param::set_decimal(const char *str, ulong length) decimals, unsigned_flag); maybe_null= 0; null_value= 0; - fix_type(Item::DECIMAL_ITEM); DBUG_VOID_RETURN; } @@ -4171,7 +3891,6 @@ void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg) decimals, unsigned_flag); maybe_null= 0; null_value= 0; - fix_type(Item::DECIMAL_ITEM); } @@ -4183,7 +3902,6 @@ void Item_param::fix_temporal(uint32 max_length_arg, uint decimals_arg) decimals= decimals_arg; maybe_null= 0; null_value= 0; - fix_type(Item::DATE_ITEM); } @@ -4268,7 +3986,6 @@ bool Item_param::set_str(const char *str, ulong length, null_value= 0; /* max_length and decimals are set after charset conversion */ /* sic: str may be not null-terminated, don't add DBUG_PRINT here */ - fix_type(Item::STRING_ITEM); DBUG_RETURN(FALSE); } @@ -4302,7 +4019,6 @@ bool Item_param::set_longdata(const char *str, ulong length) state= LONG_DATA_VALUE; maybe_null= 0; null_value= 0; - fix_type(Item::STRING_ITEM); DBUG_RETURN(FALSE); } @@ -4404,16 +4120,6 @@ void Item_param::reset() state= NO_VALUE; maybe_null= 1; null_value= 0; - fixed= false; - /* - Don't reset item_type to PARAM_ITEM: it's only needed to guard - us from item optimizations at prepare stage, when item doesn't yet - contain a literal of some kind. - In all other cases when this object is accessed its value is - set (this assumption is guarded by 'state' and - DBUG_ASSERTS(state != NO_VALUE) in all Item_param::get_* - methods). - */ DBUG_VOID_RETURN; } @@ -4505,11 +4211,7 @@ double Item_param::PValue::val_real() const case INT_RESULT: return (double) integer; case DECIMAL_RESULT: - { - double result; - my_decimal2double(E_DEC_FATAL_ERROR, &m_decimal, &result); - return result; - } + return m_decimal.to_double(); case STRING_RESULT: return double_from_string_with_check(&m_string); case TIME_RESULT: @@ -4534,11 +4236,7 @@ longlong Item_param::PValue::val_int(const Type_std_attributes *attr) const case INT_RESULT: return integer; case DECIMAL_RESULT: - { - longlong i; - my_decimal2int(E_DEC_FATAL_ERROR, &m_decimal, attr->unsigned_flag, &i); - return i; - } + return m_decimal.to_longlong(attr->unsigned_flag); case STRING_RESULT: return longlong_from_string_with_check(&m_string); case TIME_RESULT: @@ -4588,7 +4286,7 @@ String *Item_param::PValue::val_str(String *str, str->set(integer, &my_charset_bin); return str; case DECIMAL_RESULT: - if (my_decimal2string(E_DEC_FATAL_ERROR, &m_decimal, 0, 0, 0, str) <= 1) + if (m_decimal.to_string_native(str, 0, 0, 0) <= 1) return str; return NULL; case TIME_RESULT: @@ -4629,8 +4327,7 @@ const String *Item_param::value_query_val_str(THD *thd, String *str) const str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin); return str; case DECIMAL_RESULT: - if (my_decimal2string(E_DEC_FATAL_ERROR, &value.m_decimal, - 0, 0, 0, str) > 1) + if (value.m_decimal.to_string_native(str, 0, 0, 0) > 1) return &my_null_string; return str; case TIME_RESULT: @@ -4735,11 +4432,20 @@ bool Item_param::convert_str_value(THD *thd) bool Item_param::basic_const_item() const { - DBUG_ASSERT(fixed || state == NO_VALUE); - if (state == NO_VALUE || - (state == SHORT_DATA_VALUE && type_handler()->cmp_type() == TIME_RESULT)) - return FALSE; - return TRUE; + switch (state) { + case LONG_DATA_VALUE: + case NULL_VALUE: + return true; + case SHORT_DATA_VALUE: + return type_handler()->cmp_type() != TIME_RESULT; + case DEFAULT_VALUE: + case IGNORE_VALUE: + invalid_default_param(); + return false; + case NO_VALUE: + break; + } + return false; } @@ -4800,48 +4506,6 @@ Item_param::clone_item(THD *thd) } -bool Item_param::value_eq(const Item *item, bool binary_cmp) const -{ - switch (value.type_handler()->cmp_type()) { - case INT_RESULT: - return int_eq(value.integer, item); - case REAL_RESULT: - return real_eq(value.real, item); - case STRING_RESULT: - return str_eq(&value.m_string, item, binary_cmp); - case DECIMAL_RESULT: - case TIME_RESULT: - case ROW_RESULT: - break; - } - return false; -} - - -bool -Item_param::eq(const Item *item, bool binary_cmp) const -{ - if (!basic_const_item()) - return FALSE; - - // There's no "default". See comments in Item_param::save_in_field(). - switch (state) { - case IGNORE_VALUE: - case DEFAULT_VALUE: - invalid_default_param(); - return false; - case NULL_VALUE: - return null_eq(item); - case SHORT_DATA_VALUE: - case LONG_DATA_VALUE: - return value_eq(item, binary_cmp); - case NO_VALUE: - return false; - } - DBUG_ASSERT(0); // Garbage - return FALSE; -} - /* End of Item_param related */ void Item_param::print(String *str, enum_query_type query_type) @@ -4895,12 +4559,10 @@ Item_param::set_param_type_and_swap_value(Item_param *src) { Type_std_attributes::set(src); set_handler(src->type_handler()); - item_type= src->item_type; maybe_null= src->maybe_null; null_value= src->null_value; state= src->state; - fixed= src->fixed; value.swap(src->value); } @@ -4910,7 +4572,6 @@ void Item_param::set_default() { m_is_settable_routine_parameter= false; state= DEFAULT_VALUE; - fixed= true; /* When Item_param is set to DEFAULT_VALUE: - its val_str() and val_decimal() return NULL @@ -4926,7 +4587,6 @@ void Item_param::set_ignore() { m_is_settable_routine_parameter= false; state= IGNORE_VALUE; - fixed= true; null_value= true; } @@ -5230,37 +4890,19 @@ int Item_copy_decimal::save_in_field(Field *field, bool no_conversions) String *Item_copy_decimal::val_str(String *result) { - if (null_value) - return (String *) 0; - result->set_charset(&my_charset_bin); - my_decimal2string(E_DEC_FATAL_ERROR, &cached_value, 0, 0, 0, result); - return result; + return null_value ? NULL : cached_value.to_string(result); } double Item_copy_decimal::val_real() { - if (null_value) - return 0.0; - else - { - double result; - my_decimal2double(E_DEC_FATAL_ERROR, &cached_value, &result); - return result; - } + return null_value ? 0.0 : cached_value.to_double(); } longlong Item_copy_decimal::val_int() { - if (null_value) - return 0; - else - { - longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, &cached_value, unsigned_flag, &result); - return result; - } + return null_value ? 0 : cached_value.to_longlong(unsigned_flag); } @@ -5277,17 +4919,6 @@ void Item_copy_decimal::copy() Functions to convert item to field (for send_result_set_metadata) */ -/* ARGSUSED */ -bool Item::fix_fields(THD *thd, Item **ref) -{ - - // We do not check fields which are fixed during construction - DBUG_ASSERT(fixed == 0 || basic_const_item()); - fixed= 1; - return FALSE; -} - - void Item_ref_null_helper::save_val(Field *to) { DBUG_ASSERT(fixed == 1); @@ -5636,7 +5267,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) ref->alias_name_used= TRUE; /* If this is a non-aggregated field inside HAVING, search in GROUP BY. */ - if (select->having_fix_field && !ref->with_sum_func && group_list) + if (select->having_fix_field && !ref->with_sum_func() && group_list) { group_by_ref= find_field_in_group_list(ref, group_list); @@ -5678,7 +5309,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) ref->name.str, "forward reference in item list"); return NULL; } - DBUG_ASSERT((*select_ref)->fixed); + DBUG_ASSERT((*select_ref)->is_fixed()); return &select->ref_pointer_array[counter]; } if (group_by_ref) @@ -5801,7 +5432,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) Name_resolution_context *outer_context= 0; SELECT_LEX *select= 0; /* Currently derived tables cannot be correlated */ - if (current_sel->master_unit()->first_select()->linkage != + if (current_sel->master_unit()->first_select()->get_linkage() != DERIVED_TABLE_TYPE) outer_context= context->outer_context; @@ -5955,7 +5586,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) return -1; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { - DBUG_ASSERT(*ref && (*ref)->fixed); + DBUG_ASSERT(*ref && (*ref)->is_fixed()); prev_subselect_item->used_tables_and_const_cache_join(*ref); break; } @@ -5997,7 +5628,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) Item_ref *rf; /* Should have been checked in resolve_ref_in_select_and_group(). */ - DBUG_ASSERT(*ref && (*ref)->fixed); + DBUG_ASSERT(*ref && (*ref)->is_fixed()); /* Here, a subset of actions performed by Item_ref::set_properties is not enough. So we pass ptr to NULL into Item_[direct]_ref @@ -6573,7 +6204,7 @@ Item *Item_field::replace_equal_field(THD *thd, uchar *arg) comparison context, and it's safe to replace it to the constant from item_equal. */ - DBUG_ASSERT(type_handler()->type_handler_for_comparison()->cmp_type() == + DBUG_ASSERT(type_handler_for_comparison()->cmp_type() == item_equal->compare_type_handler()->cmp_type()); return const_item2; } @@ -6945,12 +6576,11 @@ int Item::save_real_in_field(Field *field, bool no_conversions) int Item::save_decimal_in_field(Field *field, bool no_conversions) { - my_decimal decimal_value; - my_decimal *value= val_decimal(&decimal_value); - if (null_value) + VDec value(this); + if (value.is_null()) return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); - return field->store_decimal(value); + return field->store_decimal(value.ptr()); } @@ -7017,14 +6647,18 @@ Item_string::make_string_literal_concat(THD *thd, const LEX_CSTRING *str) */ Item *Item_string::make_odbc_literal(THD *thd, const LEX_CSTRING *typestr) { - enum_field_types type= odbc_temporal_literal_type(typestr); - Item *res= type == MYSQL_TYPE_STRING ? this : - create_temporal_literal(thd, val_str(NULL), type, false); + Item_literal *res; + const Type_handler *h; + if (collation.repertoire == MY_REPERTOIRE_ASCII && + str_value.length() < MAX_DATE_STRING_REP_LENGTH * 4 && + (h= Type_handler::odbc_literal_type_handler(typestr)) && + (res= h->create_literal_item(thd, val_str(NULL), false))) + return res; /* - create_temporal_literal() returns NULL if failed to parse the string, + h->create_literal_item() returns NULL if failed to parse the string, or the string format did not match the type, e.g.: {d'2001-01-01 10:10:10'} */ - return res ? res : this; + return this; } @@ -7227,7 +6861,6 @@ Item_float::Item_float(THD *thd, const char *str_arg, size_t length): name.length= strlen(str_arg); decimals=(uint8) nr_of_decimals(str_arg, str_arg+length); max_length=(uint32)length; - fixed= 1; } @@ -7283,7 +6916,6 @@ void Item_hex_constant::hex_string_init(THD *thd, const char *str, size_t str_le } *ptr=0; // Keep purify happy collation.set(&my_charset_bin, DERIVATION_COERCIBLE); - fixed= 1; unsigned_flag= 1; } @@ -7362,19 +6994,9 @@ Item_bin_string::Item_bin_string(THD *thd, const char *str, size_t str_length): ptr[0]= 0; collation.set(&my_charset_bin, DERIVATION_COERCIBLE); - fixed= 1; } -bool Item_temporal_literal::eq(const Item *item, bool binary_cmp) const -{ - return - item->basic_const_item() && type() == item->type() && - field_type() == ((Item_temporal_literal *) item)->field_type() && - !my_time_compare(&cached_time, - &((Item_temporal_literal *) item)->cached_time); -} - void Item_date_literal::print(String *str, enum_query_type query_type) { str->append("DATE'"); @@ -7393,7 +7015,6 @@ Item *Item_date_literal::clone_item(THD *thd) bool Item_date_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { - DBUG_ASSERT(fixed); fuzzy_date |= sql_mode_for_dates(current_thd); *ltime= cached_time; return (null_value= check_date_with_warn(ltime, fuzzy_date, @@ -7419,7 +7040,6 @@ Item *Item_datetime_literal::clone_item(THD *thd) bool Item_datetime_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { - DBUG_ASSERT(fixed); fuzzy_date |= sql_mode_for_dates(current_thd); *ltime= cached_time; return (null_value= check_date_with_warn(ltime, fuzzy_date, @@ -7445,7 +7065,6 @@ Item *Item_time_literal::clone_item(THD *thd) bool Item_time_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { - DBUG_ASSERT(fixed); *ltime= cached_time; if (fuzzy_date & TIME_TIME_ONLY) return (null_value= false); @@ -7565,7 +7184,7 @@ void Item_field::update_null_value() no_errors= thd->no_errors; thd->no_errors= 1; - Item::update_null_value(); + type_handler()->Item_update_null_value(this); thd->no_errors= no_errors; } @@ -7616,6 +7235,231 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg) } +/** + @brief + Prepare AND/OR formula for extraction of a pushable condition + + @param checker the checker callback function to be applied to the nodes + of the tree of the object + @param arg parameter to be passed to the checker + + @details + This method recursively traverses this AND/OR condition and for each + subformula of the condition it checks whether it can be usable for the + extraction of a pushable condition. The criteria of pushability of + a subformula is checked by the callback function 'checker' with one + parameter arg. The subformulas that are not usable are marked with + the flag NO_EXTRACTION_FL. + @note + This method is called before any call of build_pushable_cond. + The flag NO_EXTRACTION_FL set in a subformula allows to avoid building + clones for the subformulas that are not used in the pushable condition. + @note + This method is called for pushdown conditions into materialized + derived tables/views optimization. + Item::pushable_cond_checker_for_derived() is passed as the actual callback + function. + Also it is called for pushdown conditions in materialized IN subqueries. + Item::pushable_cond_checker_for_subquery is passed as the actual + callback function. +*/ + +void Item::check_pushable_cond(Pushdown_checker checker, uchar *arg) +{ + clear_extraction_flag(); + if (type() == Item::COND_ITEM) + { + bool and_cond= ((Item_cond*) this)->functype() == Item_func::COND_AND_FUNC; + List_iterator<Item> li(*((Item_cond*) this)->argument_list()); + uint count= 0; + Item *item; + while ((item=li++)) + { + item->check_pushable_cond(checker, arg); + if (item->get_extraction_flag() != NO_EXTRACTION_FL) + count++; + else if (!and_cond) + break; + } + if ((and_cond && count == 0) || item) + { + set_extraction_flag(NO_EXTRACTION_FL); + if (and_cond) + li.rewind(); + while ((item= li++)) + item->clear_extraction_flag(); + } + } + else if (!((this->*checker) (arg))) + set_extraction_flag(NO_EXTRACTION_FL); +} + + +/** + @brief + Build condition extractable from this condition for pushdown + + @param thd the thread handle + @param checker the checker callback function to be applied to the + equal items of multiple equality items + @param arg parameter to be passed to the checker + + @details + This method finds out what condition that can be pushed down can be + extracted from this condition. If such condition C exists the + method builds the item for it. The method uses the flag NO_EXTRACTION_FL + set by the preliminary call of the method check_pushable_cond() to figure + out whether a subformula is pushable or not. + In the case when this item is a multiple equality a checker method is + called to find the equal fields to build a new equality that can be + pushed down. + @note + The built condition C is always implied by the condition cond + (cond => C). The method tries to build the most restrictive such + condition (i.e. for any other condition C' such that cond => C' + we have C => C'). + @note + The build item is not ready for usage: substitution for the field items + has to be done and it has to be re-fixed. + @note + This method is called for pushdown conditions into materialized + derived tables/views optimization. + Item::pushable_equality_checker_for_derived() is passed as the actual + callback function. + Also it is called for pushdown conditions into materialized IN subqueries. + Item::pushable_equality_checker_for_subquery() is passed as the actual + callback function. + + @retval + the built condition pushable into if such a condition exists + NULL if there is no such a condition +*/ + +Item *Item::build_pushable_cond(THD *thd, + Pushdown_checker checker, + uchar *arg) +{ + bool is_multiple_equality= type() == Item::FUNC_ITEM && + ((Item_func*) this)->functype() == Item_func::MULT_EQUAL_FUNC; + + if (get_extraction_flag() == NO_EXTRACTION_FL) + return 0; + + if (type() == Item::COND_ITEM) + { + bool cond_and= false; + Item_cond *new_cond; + if (((Item_cond*) this)->functype() == Item_func::COND_AND_FUNC) + { + cond_and= true; + new_cond= new (thd->mem_root) Item_cond_and(thd); + } + else + new_cond= new (thd->mem_root) Item_cond_or(thd); + if (!new_cond) + return 0; + List_iterator<Item> li(*((Item_cond*) this)->argument_list()); + Item *item; + bool is_fix_needed= false; + + while ((item=li++)) + { + if (item->get_extraction_flag() == NO_EXTRACTION_FL) + { + if (!cond_and) + return 0; + continue; + } + Item *fix= item->build_pushable_cond(thd, checker, arg); + if (!fix && !cond_and) + return 0; + if (!fix) + continue; + + if (fix->type() == Item::COND_ITEM && + ((Item_cond*) fix)->functype() == Item_func::COND_AND_FUNC) + is_fix_needed= true; + + if (new_cond->argument_list()->push_back(fix, thd->mem_root)) + return 0; + } + if (is_fix_needed && new_cond->fix_fields(thd, 0)) + return 0; + + switch (new_cond->argument_list()->elements) + { + case 0: + return 0; + case 1: + return new_cond->argument_list()->head(); + default: + return new_cond; + } + } + else if (is_multiple_equality) + { + Item *new_cond= NULL; + int i= 0; + Item_equal *item_equal= (Item_equal *) this; + Item *left_item = item_equal->get_const(); + Item_equal_fields_iterator it(*item_equal); + Item *item; + Item *right_item; + if (!left_item) + { + while ((item=it++)) + { + left_item= ((item->*checker) (arg)) ? item : NULL; + if (left_item) + break; + } + } + if (!left_item) + return 0; + while ((item=it++)) + { + right_item= ((item->*checker) (arg)) ? item : NULL; + if (!right_item) + continue; + Item_func_eq *eq= 0; + Item *left_item_clone= left_item->build_clone(thd); + Item *right_item_clone= item->build_clone(thd); + if (left_item_clone && right_item_clone) + { + left_item_clone->set_item_equal(NULL); + right_item_clone->set_item_equal(NULL); + eq= new (thd->mem_root) Item_func_eq(thd, right_item_clone, + left_item_clone); + } + if (eq) + { + i++; + switch (i) + { + case 1: + new_cond= eq; + break; + case 2: + new_cond= new (thd->mem_root) Item_cond_and(thd, new_cond, eq); + break; + default: + if (((Item_cond_and*)new_cond)->argument_list()->push_back(eq, + thd->mem_root)) + return 0; + break; + } + } + } + if (new_cond && new_cond->fix_fields(thd, &new_cond)) + return 0; + return new_cond; + } + else if (get_extraction_flag() != NO_EXTRACTION_FL) + return build_clone(thd); + return 0; +} + + static Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel) { @@ -7735,18 +7579,18 @@ Item *Item_direct_view_ref::derived_field_transformer_for_where(THD *thd, } static -Grouping_tmp_field *find_matching_grouping_field(Item *item, - st_select_lex *sel) +Field_pair *find_matching_grouping_field(Item *item, + st_select_lex *sel) { DBUG_ASSERT(item->type() == Item::FIELD_ITEM || (item->type() == Item::REF_ITEM && ((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF)); - List_iterator<Grouping_tmp_field> li(sel->grouping_tmp_fields); - Grouping_tmp_field *gr_field; + List_iterator<Field_pair> li(sel->grouping_tmp_fields); + Field_pair *gr_field; Item_field *field_item= (Item_field *) (item->real_item()); while ((gr_field= li++)) { - if (field_item->field == gr_field->tmp_field) + if (field_item->field == gr_field->field) return gr_field; } Item_equal *item_equal= item->get_item_equal(); @@ -7760,7 +7604,7 @@ Grouping_tmp_field *find_matching_grouping_field(Item *item, li.rewind(); while ((gr_field= li++)) { - if (field_item->field == gr_field->tmp_field) + if (field_item->field == gr_field->field) return gr_field; } } @@ -7769,26 +7613,25 @@ Grouping_tmp_field *find_matching_grouping_field(Item *item, } -Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd, - uchar *arg) +Item *Item_field::grouping_field_transformer_for_where(THD *thd, uchar *arg) { st_select_lex *sel= (st_select_lex *)arg; - Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel); + Field_pair *gr_field= find_matching_grouping_field(this, sel); if (gr_field) - return gr_field->producing_item->build_clone(thd); + return gr_field->corresponding_item->build_clone(thd); return this; } Item * -Item_direct_view_ref::derived_grouping_field_transformer_for_where(THD *thd, - uchar *arg) +Item_direct_view_ref::grouping_field_transformer_for_where(THD *thd, + uchar *arg) { if (!item_equal) return this; st_select_lex *sel= (st_select_lex *)arg; - Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel); - return gr_field->producing_item->build_clone(thd); + Field_pair *gr_field= find_matching_grouping_field(this, sel); + return gr_field->corresponding_item->build_clone(thd); } void Item_field::print(String *str, enum_query_type query_type) @@ -7824,7 +7667,7 @@ Item_ref::Item_ref(THD *thd, Name_resolution_context *context_arg, /* This constructor used to create some internals references over fixed items */ - if ((set_properties_only= (ref && *ref && (*ref)->fixed))) + if ((set_properties_only= (ref && *ref && (*ref)->is_fixed()))) set_properties(); } @@ -7873,7 +7716,7 @@ Item_ref::Item_ref(THD *thd, TABLE_LIST *view_arg, Item **item, /* This constructor is used to create some internal references over fixed items */ - if ((set_properties_only= (ref && *ref && (*ref)->fixed))) + if ((set_properties_only= (ref && *ref && (*ref)->is_fixed()))) set_properties(); } @@ -7999,7 +7842,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) goto error; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { - DBUG_ASSERT(*ref && (*ref)->fixed); + DBUG_ASSERT(*ref && (*ref)->is_fixed()); prev_subselect_item->used_tables_and_const_cache_join(*ref); break; } @@ -8122,7 +7965,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) goto error; } /* Should be checked in resolve_ref_in_select_and_group(). */ - DBUG_ASSERT(*ref && (*ref)->fixed); + DBUG_ASSERT(*ref && (*ref)->is_fixed()); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, this); /* @@ -8147,13 +7990,13 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) */ if (!((*ref)->type() == REF_ITEM && ((Item_ref *)(*ref))->ref_type() == OUTER_REF) && - (((*ref)->with_sum_func && name.str && - !(current_sel->linkage != GLOBAL_OPTIONS_TYPE && + (((*ref)->with_sum_func() && name.str && + !(current_sel->get_linkage() != GLOBAL_OPTIONS_TYPE && current_sel->having_fix_field)) || - !(*ref)->fixed)) + !(*ref)->is_fixed())) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), - name.str, ((*ref)->with_sum_func? + name.str, ((*ref)->with_sum_func() ? "reference to group function": "forward reference in item list")); goto error; @@ -8179,7 +8022,7 @@ void Item_ref::set_properties() We have to remember if we refer to a sum function, to ensure that split_sum_func() doesn't try to change the reference. */ - with_sum_func= (*ref)->with_sum_func; + copy_with_sum_func(*ref); with_param= (*ref)->with_param; with_window_func= (*ref)->with_window_func; with_field= (*ref)->with_field; @@ -8602,10 +8445,10 @@ Item_cache_wrapper::~Item_cache_wrapper() Item_cache_wrapper::Item_cache_wrapper(THD *thd, Item *item_arg): Item_result_field(thd), orig_item(item_arg), expr_cache(NULL), expr_value(NULL) { - DBUG_ASSERT(orig_item->fixed); + DBUG_ASSERT(orig_item->is_fixed()); Type_std_attributes::set(orig_item); maybe_null= orig_item->maybe_null; - with_sum_func= orig_item->with_sum_func; + copy_with_sum_func(orig_item); with_param= orig_item->with_param; with_field= orig_item->with_field; name= item_arg->name; @@ -8664,7 +8507,7 @@ void Item_cache_wrapper::print(String *str, enum_query_type query_type) bool Item_cache_wrapper::fix_fields(THD *thd __attribute__((unused)), Item **it __attribute__((unused))) { - DBUG_ASSERT(orig_item->fixed); + DBUG_ASSERT(orig_item->is_fixed()); DBUG_ASSERT(fixed); return FALSE; } @@ -8994,7 +8837,7 @@ int Item_cache_wrapper::save_in_field(Field *to, bool no_conversions) Item* Item_cache_wrapper::get_tmp_table_item(THD *thd) { - if (!orig_item->with_sum_func && !orig_item->const_item()) + if (!orig_item->with_sum_func() && !orig_item->const_item()) return new (thd->mem_root) Item_temptable_field(thd, result_field); return copy_or_same(thd); } @@ -9024,7 +8867,7 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) /* view fild reference must be defined */ DBUG_ASSERT(*ref); /* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */ - if ((*ref)->fixed) + if ((*ref)->is_fixed()) { Item *ref_item= (*ref)->real_item(); if (ref_item->type() == Item::FIELD_ITEM) @@ -9310,7 +9153,6 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) if (arg->fix_fields_if_needed(thd, &arg)) goto error; - real_arg= arg->real_item(); if (real_arg->type() != FIELD_ITEM) { @@ -9526,7 +9368,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) { DBUG_ASSERT(fixed == 0); /* We should only check that arg is in first table */ - if (!arg->fixed) + if (!arg->is_fixed()) { bool res; TABLE_LIST *orig_next_table= context->last_name_resolution_table; @@ -9738,7 +9580,7 @@ void Item_trigger_field::cleanup() Since special nature of Item_trigger_field we should not do most of things from Item_field::cleanup() or Item_ident::cleanup() here. */ - Item::cleanup(); + Item_fixed_hybrid::cleanup(); } @@ -9799,73 +9641,14 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) { - Item_result res_type=item_cmp_type(field->result_type(), - item->result_type()); - /* - We have to check field->cmp_type() instead of res_type, - as result_type() - and thus res_type - can never be TIME_RESULT (yet). - */ - if (field->cmp_type() == TIME_RESULT) + Type_handler_hybrid_field_type cmp(field->type_handler_for_comparison()); + if (cmp.aggregate_for_comparison(item->type_handler_for_comparison())) { - MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time; - if (field->type() == MYSQL_TYPE_TIME) - { - field->get_time(&field_time); - item->get_time(&item_time); - } - else - { - field->get_date(&field_time, TIME_INVALID_DATES); - item->get_date(&item_time, TIME_INVALID_DATES); - if (item_time.time_type == MYSQL_TIMESTAMP_TIME) - if (time_to_datetime(thd, &item_time, item_time_cmp= &item_time2)) - return 1; - } - return my_time_compare(&field_time, item_time_cmp); - } - if (res_type == STRING_RESULT) - { - char item_buff[MAX_FIELD_WIDTH]; - char field_buff[MAX_FIELD_WIDTH]; - - String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin); - String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin); - String *item_result= item->val_str(&item_tmp); - /* - Some implementations of Item::val_str(String*) actually modify - the field Item::null_value, hence we can't check it earlier. - */ - if (item->null_value) - return 0; - String *field_result= field->val_str(&field_tmp); - return sortcmp(field_result, item_result, field->charset()); - } - if (res_type == INT_RESULT) - return 0; // Both are of type int - if (res_type == DECIMAL_RESULT) - { - my_decimal item_buf, *item_val, - field_buf, *field_val; - item_val= item->val_decimal(&item_buf); - if (item->null_value) - return 0; - field_val= field->val_decimal(&field_buf); - return my_decimal_cmp(field_val, item_val); - } - /* - The patch for Bug#13463415 started using this function for comparing - BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode. - Prefixing the auto variables with volatile fixes the problem.... - */ - volatile double result= item->val_real(); - if (item->null_value) + // At fix_fields() time we checked that "field" and "item" are comparable + DBUG_ASSERT(0); return 0; - volatile double field_result= field->val_real(); - if (field_result < result) - return -1; - else if (field_result > result) - return 1; - return 0; + } + return cmp.type_handler()->stored_field_cmp_to_item(thd, field, item); } @@ -9928,7 +9711,6 @@ bool Item_cache_int::cache_value() String *Item_cache_int::val_str(String *str) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return NULL; str->set_int(value, unsigned_flag, default_charset()); @@ -9938,7 +9720,6 @@ String *Item_cache_int::val_str(String *str) my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return NULL; int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val); @@ -9947,7 +9728,6 @@ my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) double Item_cache_int::val_real() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0.0; return (double) value; @@ -9955,7 +9735,6 @@ double Item_cache_int::val_real() longlong Item_cache_int::val_int() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0; return value; @@ -9995,82 +9774,6 @@ Item_cache_temporal::Item_cache_temporal(THD *thd, const Type_handler *handler) } -longlong Item_cache_temporal::val_datetime_packed() -{ - DBUG_ASSERT(fixed == 1); - if (Item_cache_temporal::field_type() == MYSQL_TYPE_TIME) - return Item::val_datetime_packed(); // TIME-to-DATETIME conversion needed - if ((!value_cached && !cache_value()) || null_value) - { - null_value= TRUE; - return 0; - } - return value; -} - - -longlong Item_cache_temporal::val_time_packed() -{ - DBUG_ASSERT(fixed == 1); - if (Item_cache_temporal::field_type() != MYSQL_TYPE_TIME) - return Item::val_time_packed(); // DATETIME-to-TIME conversion needed - if ((!value_cached && !cache_value()) || null_value) - { - null_value= TRUE; - return 0; - } - return value; -} - - -String *Item_cache_temporal::val_str(String *str) -{ - DBUG_ASSERT(fixed == 1); - if (!has_value()) - { - null_value= true; - return NULL; - } - return val_string_from_date(str); -} - - -my_decimal *Item_cache_temporal::val_decimal(my_decimal *decimal_value) -{ - DBUG_ASSERT(fixed == 1); - if ((!value_cached && !cache_value()) || null_value) - { - null_value= true; - return NULL; - } - return val_decimal_from_date(decimal_value); -} - - -longlong Item_cache_temporal::val_int() -{ - DBUG_ASSERT(fixed == 1); - if ((!value_cached && !cache_value()) || null_value) - { - null_value= true; - return 0; - } - return val_int_from_date(); -} - - -double Item_cache_temporal::val_real() -{ - DBUG_ASSERT(fixed == 1); - if ((!value_cached && !cache_value()) || null_value) - { - null_value= true; - return 0; - } - return val_real_from_date(); -} - - bool Item_cache_temporal::cache_value() { if (!example) @@ -10185,7 +9888,6 @@ bool Item_cache_real::cache_value() double Item_cache_real::val_real() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0.0; return value; @@ -10193,7 +9895,6 @@ double Item_cache_real::val_real() longlong Item_cache_real::val_int() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0; return (longlong) rint(value); @@ -10202,7 +9903,6 @@ longlong Item_cache_real::val_int() String* Item_cache_real::val_str(String *str) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return NULL; str->set_real(value, decimals, default_charset()); @@ -10212,7 +9912,6 @@ String* Item_cache_real::val_str(String *str) my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return NULL; double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); @@ -10247,38 +9946,22 @@ bool Item_cache_decimal::cache_value() double Item_cache_decimal::val_real() { - DBUG_ASSERT(fixed); - double res; - if (!has_value()) - return 0.0; - my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res); - return res; + return !has_value() ? 0.0 : decimal_value.to_double(); } longlong Item_cache_decimal::val_int() { - DBUG_ASSERT(fixed); - longlong res; - if (!has_value()) - return 0; - my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res); - return res; + return !has_value() ? 0 : decimal_value.to_longlong(unsigned_flag); } String* Item_cache_decimal::val_str(String *str) { - DBUG_ASSERT(fixed); - if (!has_value()) - return NULL; - my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE, - &decimal_value); - my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str); - return str; + return !has_value() ? NULL : + decimal_value.to_string_round(str, decimals, &decimal_value); } my_decimal *Item_cache_decimal::val_decimal(my_decimal *val) { - DBUG_ASSERT(fixed); if (!has_value()) return NULL; return &decimal_value; @@ -10295,9 +9978,8 @@ Item *Item_cache_decimal::convert_to_basic_const_item(THD *thd) new_item= (Item*) new (thd->mem_root) Item_null(thd); else { - my_decimal decimal_value; - my_decimal *result= val_decimal(&decimal_value); - new_item= (Item*) new (thd->mem_root) Item_decimal(thd, result); + VDec tmp(this); + new_item= (Item*) new (thd->mem_root) Item_decimal(thd, tmp.ptr()); } return new_item; } @@ -10330,7 +10012,6 @@ bool Item_cache_str::cache_value() double Item_cache_str::val_real() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0.0; return value ? double_from_string_with_check(value) : 0.0; @@ -10339,7 +10020,6 @@ double Item_cache_str::val_real() longlong Item_cache_str::val_int() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0; return value ? longlong_from_string_with_check(value) : 0; @@ -10348,7 +10028,6 @@ longlong Item_cache_str::val_int() String* Item_cache_str::val_str(String *str) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0; return value; @@ -10357,7 +10036,6 @@ String* Item_cache_str::val_str(String *str) my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return NULL; return value ? decimal_from_string_with_check(decimal_val, value) : 0; @@ -10550,7 +10228,7 @@ bool Item_type_holder::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) void Item_result_field::cleanup() { DBUG_ENTER("Item_result_field::cleanup()"); - Item::cleanup(); + Item_fixed_hybrid::cleanup(); result_field= 0; DBUG_VOID_RETURN; } diff --git a/sql/item.h b/sql/item.h index 48b060095af..c013781f30f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -99,7 +99,10 @@ class sp_head; class Protocol; struct TABLE_LIST; void item_init(void); /* Init item functions */ +class Item_basic_value; +class Item_result_field; class Item_field; +class Item_ref; class Item_param; class user_var_entry; class JOIN; @@ -107,6 +110,7 @@ struct KEY_FIELD; struct SARGABLE_PARAM; class RANGE_OPT_PARAM; class SEL_TREE; +class With_sum_func_cache; enum precedence { LOWEST_PRECEDENCE, @@ -595,6 +599,7 @@ typedef bool (Item::*Item_processor) (void *arg); typedef bool (Item::*Item_analyzer) (uchar **argp); typedef Item* (Item::*Item_transformer) (THD *thd, uchar *arg); typedef void (*Cond_traverser) (const Item *item, void *arg); +typedef bool (Item::*Pushdown_checker) (uchar *arg); struct st_cond_statistic; @@ -627,6 +632,85 @@ public: String_copier_for_item(THD *thd): m_thd(thd) { } }; + +/** + A helper class describing what kind of Item created a temporary field. + - If m_field is set, then the temporary field was created from Field + (e.g. when the Item was Item_field, or Item_ref pointing to Item_field) + - If m_default_field is set, then there is a usable DEFAULT value. + (e.g. when the Item is Item_field) + - If m_item_result_field is set, then the temporary field was created + from certain sub-types of Item_result_field (e.g. Item_func) + See create_tmp_field() in sql_select.cc for details. +*/ + +class Tmp_field_src +{ + Field *m_field; + Field *m_default_field; + Item_result_field *m_item_result_field; +public: + Tmp_field_src() + :m_field(0), + m_default_field(0), + m_item_result_field(0) + { } + Field *field() const { return m_field; } + Field *default_field() const { return m_default_field; } + Item_result_field *item_result_field() const { return m_item_result_field; } + void set_field(Field *field) { m_field= field; } + void set_default_field(Field *field) { m_default_field= field; } + void set_item_result_field(Item_result_field *item) + { m_item_result_field= item; } +}; + + +/** + Parameters for create_tmp_field_ex(). + See create_tmp_field() in sql_select.cc for details. +*/ + +class Tmp_field_param +{ + bool m_group; + bool m_modify_item; + bool m_table_cant_handle_bit_fields; + bool m_make_copy_field; +public: + Tmp_field_param(bool group, + bool modify_item, + bool table_cant_handle_bit_fields, + bool make_copy_field) + :m_group(group), + m_modify_item(modify_item), + m_table_cant_handle_bit_fields(table_cant_handle_bit_fields), + m_make_copy_field(make_copy_field) + { } + bool group() const { return m_group; } + bool modify_item() const { return m_modify_item; } + bool table_cant_handle_bit_fields() const + { return m_table_cant_handle_bit_fields; } + bool make_copy_field() const { return m_make_copy_field; } + void set_modify_item(bool to) { m_modify_item= to; } +}; + + +class Item_const +{ +public: + virtual ~Item_const() {} + virtual const Type_all_attributes *get_type_all_attributes_from_const() const= 0; + virtual bool const_is_null() const { return false; } + virtual const longlong *const_ptr_longlong() const { return NULL; } + virtual const double *const_ptr_double() const { return NULL; } + virtual const my_decimal *const_ptr_my_decimal() const { return NULL; } + virtual const MYSQL_TIME *const_ptr_mysql_time() const { return NULL; } + virtual const String *const_ptr_string() const { return NULL; } +}; + + +/****************************************************************************/ + class Item: public Value_source, public Type_all_attributes { @@ -651,16 +735,26 @@ public: static void operator delete(void *ptr, MEM_ROOT *mem_root) {} enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, - WINDOW_FUNC_ITEM, STRING_ITEM, - INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM, - COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM, - PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, - FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, + WINDOW_FUNC_ITEM, + /* + NOT NULL literal-alike constants, which do not change their + value during an SQL statement execution, but can optionally + change their value between statements: + - Item_literal - real NOT NULL constants + - Item_param - can change between statements + - Item_splocal - can change between statements + - Item_user_var_as_out_param - hack + Note, Item_user_var_as_out_param actually abuses the type code. + It should be moved out of the Item tree eventually. + */ + CONST_ITEM, + NULL_ITEM, // Item_null or Item_param bound to NULL + COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM, + PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, + FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, - PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM, - XPATH_NODESET, XPATH_NODESET_CMP, - VIEW_FIXER_ITEM, EXPR_CACHE_ITEM, - DATE_ITEM}; + PARAM_ITEM, TRIGGER_FIELD_ITEM, + EXPR_CACHE_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; @@ -702,11 +796,34 @@ protected: */ Field *tmp_table_field_from_field_type(TABLE *table) { + DBUG_ASSERT(is_fixed()); const Type_handler *h= type_handler()->type_handler_for_tmp_table(this); return h->make_and_init_table_field(&name, Record_addr(maybe_null), *this, table); } + /** + Create a temporary field for a simple Item, which does not + need any special action after the field creation: + - is not an Item_field descendant (and not a reference to Item_field) + - is not an Item_result_field descendant + - does not need to copy any DEFAULT value to the result Field + - does not need to set Field::is_created_from_null_item for the result + See create_tmp_field_ex() for details on parameters and return values. + */ + Field *create_tmp_field_ex_simple(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) + { + DBUG_ASSERT(!param->make_copy_field()); + DBUG_ASSERT(!is_result_field()); + DBUG_ASSERT(type() != NULL_ITEM); + return tmp_table_field_from_field_type(table); + } Field *create_tmp_field_int(TABLE *table, uint convert_int_length); + Field *tmp_table_field_from_field_type_maybe_null(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param, + bool is_explicit_null); void push_note_converted_to_negative_complement(THD *thd); void push_note_converted_to_positive_complement(THD *thd); @@ -714,21 +831,21 @@ protected: /* Helper methods, to get an Item value from another Item */ double val_real_from_item(Item *item) { - DBUG_ASSERT(fixed == 1); + DBUG_ASSERT(is_fixed()); double value= item->val_real(); null_value= item->null_value; return value; } longlong val_int_from_item(Item *item) { - DBUG_ASSERT(fixed == 1); + DBUG_ASSERT(is_fixed()); longlong value= item->val_int(); null_value= item->null_value; return value; } String *val_str_from_item(Item *item, String *str) { - DBUG_ASSERT(fixed == 1); + DBUG_ASSERT(is_fixed()); String *res= item->val_str(str); if (res) res->set_charset(collation.collation); @@ -738,7 +855,7 @@ protected: } my_decimal *val_decimal_from_item(Item *item, my_decimal *decimal_value) { - DBUG_ASSERT(fixed == 1); + DBUG_ASSERT(is_fixed()); my_decimal *value= item->val_decimal(decimal_value); if ((null_value= item->null_value)) value= NULL; @@ -750,6 +867,7 @@ protected: null_value= MY_TEST(rc || item->null_value); return rc; } +public: /* This method is used if the item was not null but convertion to TIME/DATE/DATETIME failed. We return a zero date if allowed, @@ -757,12 +875,12 @@ protected: */ bool make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate); -public: /* Cache val_str() into the own buffer, e.g. to evaluate constant expressions with subqueries in the ORDER/GROUP clauses. */ String *val_str() { return val_str(&str_value); } + virtual Item_func *get_item_func() { return NULL; } const MY_LOCALE *locale_from_val_str(); @@ -782,14 +900,12 @@ public: bool in_rollup; /* If used in GROUP BY list of a query with ROLLUP */ bool null_value; /* if item is null */ - bool with_sum_func; /* True if item contains a sum func */ bool with_param; /* True if contains an SP parameter */ bool with_window_func; /* True if item contains a window func */ /** True if any item except Item_sum contains a field. Set during parsing. */ bool with_field; - bool fixed; /* If item fixed with fix_fields */ bool is_autogenerated_name; /* indicate was name of this Item autogenerated or set by user */ // alloc & destruct is done as start of select on THD::mem_root @@ -819,7 +935,7 @@ public: bool fix_fields_if_needed(THD *thd, Item **ref) { - return fixed ? false : fix_fields(thd, ref); + return is_fixed() ? false : fix_fields(thd, ref); } bool fix_fields_if_needed_for_scalar(THD *thd, Item **ref) { @@ -833,7 +949,27 @@ public: { return fix_fields_if_needed_for_scalar(thd, ref); } - virtual bool fix_fields(THD *, Item **); + /* + By default we assume that an Item is fixed by the contstructor. + */ + virtual bool fix_fields(THD *, Item **) + { + /* + This should not normally be called, because usually before + fix_fields() we check is_fixed() to be false. + But historically we allow fix_fields() to be called for Items + who return basic_const_item()==true. + */ + DBUG_ASSERT(is_fixed()); + DBUG_ASSERT(basic_const_item()); + return false; + } + virtual bool is_fixed() const { return true; } + virtual void unfix_fields() + { + DBUG_ASSERT(0); + } + /* Fix after some tables has been pulled out. Basically re-calculate all attributes that are dependent on the tables. @@ -853,7 +989,10 @@ public: but rather uses intermediate type conversion items. Then the method is supposed to be applied recursively. */ - virtual inline void quick_fix_field() { fixed= 1; } + virtual void quick_fix_field() + { + DBUG_ASSERT(0); + } bool save_in_value(struct st_value *value) { @@ -882,6 +1021,21 @@ public: return type_handler()->field_type(); } virtual const Type_handler *type_handler() const= 0; + /** + Detects if an Item has a fixed data type which is known + even before fix_fields(). + Currently it's important only to find Items with a fixed boolean + data type. More item types can be marked in the future as having + a fixed data type (e.g. all literals, all fixed type functions, etc). + + @retval NULL if the Item type is not known before fix_fields() + @retval the pointer to the data type handler, if the data type + is known before fix_fields(). + */ + virtual const Type_handler *fixed_type_handler() const + { + return NULL; + } const Type_handler *type_handler_for_comparison() const { return type_handler()->type_handler_for_comparison(); @@ -890,13 +1044,9 @@ public: { return type_handler(); } - virtual const Type_handler *cast_to_int_type_handler() const - { - return type_handler(); - } - virtual const Type_handler *type_handler_for_system_time() const + const Type_handler *cast_to_int_type_handler() const { - return real_type_handler(); + return real_type_handler()->cast_to_int_type_handler(); } /* result_type() of an item specifies how the value should be returned */ Item_result result_type() const @@ -952,6 +1102,10 @@ public: return type_handler()->Item_get_cache(thd, this); } virtual enum Type type() const =0; + bool is_of_type(Type t, Item_result cmp) const + { + return type() == t && cmp_type() == cmp; + } /* real_type() is the type of base item. This is same as type() for most items, except Item_ref() and Item_cache_wrapper() where it @@ -1048,7 +1202,6 @@ public: { 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(); /* @@ -1214,7 +1367,7 @@ public: { return type_handler()->Item_val_bool(this); } - virtual String *val_nodeset(String*) { return 0; } + virtual String *val_raw(String*) { return 0; } /* save_val() is method of val_* family which stores value in the given @@ -1229,28 +1382,15 @@ public: /* Helper functions, see item_sum.cc */ String *val_string_from_real(String *str); String *val_string_from_int(String *str); - String *val_string_from_decimal(String *str); - String *val_string_from_date(String *str); my_decimal *val_decimal_from_real(my_decimal *decimal_value); my_decimal *val_decimal_from_int(my_decimal *decimal_value); my_decimal *val_decimal_from_string(my_decimal *decimal_value); - my_decimal *val_decimal_from_date(my_decimal *decimal_value); - my_decimal *val_decimal_from_time(my_decimal *decimal_value); - longlong val_int_from_decimal(); - longlong val_int_from_date(); longlong val_int_from_real() { - DBUG_ASSERT(fixed == 1); + DBUG_ASSERT(is_fixed()); return Converter_double_to_longlong_with_warn(val_real(), false).result(); } longlong val_int_from_str(int *error); - double val_real_from_decimal(); - double val_real_from_date(); - - // Get TIME, DATE or DATETIME using proper sql_mode flags for the field type - bool get_temporal_with_sql_mode(MYSQL_TIME *ltime); - // Check NULL value for a TIME, DATE or DATETIME expression - bool is_null_from_temporal(); int save_time_in_field(Field *field, bool no_conversions); int save_date_in_field(Field *field, bool no_conversions); @@ -1310,6 +1450,14 @@ public: a constant expression. Used in the optimizer to propagate basic constants. */ virtual bool basic_const_item() const { return 0; } + /* + Test if "this" is an ORDER position (rather than an expression). + Notes: + - can be called before fix_fields(). + - local SP variables (even of integer types) are always expressions, not + positions. (And they can't be used before fix_fields is called for them). + */ + virtual bool is_order_clause_position() const { return false; } /* cloning of constant items (0 if it is not const) */ virtual Item *clone_item(THD *thd) { return 0; } virtual Item* build_clone(THD *thd) { return get_copy(thd); } @@ -1464,58 +1612,20 @@ public: Item **ref, uint flags); virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)= 0; bool get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate); - bool get_date_from_year(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate); - bool get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_time(MYSQL_TIME *ltime) { return get_date(ltime, Time::flags_for_get_date()); } - /* - Get time with automatic DATE/DATETIME to TIME conversion, - by subtracting CURRENT_DATE. - - Performce a reverse operation to CAST(time AS DATETIME) - Suppose: - - we have a set of items (typically with the native MYSQL_TYPE_TIME type) - whose item->get_date() return TIME1 value, and - - CAST(AS DATETIME) for the same Items return DATETIME1, - after applying time-to-datetime conversion to TIME1. - - then all items (typically of the native MYSQL_TYPE_{DATE|DATETIME} types) - whose get_date() return DATETIME1 must also return TIME1 from - get_time_with_conversion() - - @param thd - the thread, its variables.old_mode is checked - to decide if use simple YYYYMMDD truncation (old mode), - or perform full DATETIME-to-TIME conversion with - CURRENT_DATE subtraction. - @param[out] ltime - store the result here - @param fuzzydate - flags to be used for the get_date() call. - Normally, should include TIME_TIME_ONLY, to let - the called low-level routines, e.g. str_to_date(), - know that we prefer TIME rather that DATE/DATETIME - and do less conversion outside of the low-level - routines. - - @returns true - on error, e.g. get_date() returned NULL value, - or get_date() returned DATETIME/DATE with non-zero - YYYYMMDD part. - @returns false - on success - */ - bool get_time_with_conversion(THD *thd, MYSQL_TIME *ltime, - ulonglong fuzzydate); // Get a DATE or DATETIME value in numeric packed format for comparison virtual longlong val_datetime_packed() { - ulonglong fuzzydate= TIME_FUZZY_DATES | TIME_INVALID_DATES; - Datetime dt(current_thd, this, fuzzydate); - return dt.is_valid_datetime() ? pack_time(dt.get_mysql_time()) : 0; + ulonglong fuzzydate= Datetime::comparison_flags_for_get_date(); + return Datetime(current_thd, this, fuzzydate).to_packed(); } // Get a TIME value in numeric packed format for comparison virtual longlong val_time_packed() { - Time tm(this, Time::comparison_flags_for_get_date()); - return tm.is_valid_time() ? pack_time(tm.get_mysql_time()) : 0; + return Time(this, Time::comparison_flags_for_get_date()).to_packed(); } longlong val_datetime_packed_result(); longlong val_time_packed_result() @@ -1525,13 +1635,6 @@ public: return get_date_result(<ime, fuzzydate) ? 0 : pack_time(<ime); } - // Get a temporal value in packed DATE/DATETIME or TIME format - longlong val_temporal_packed(enum_field_types f_type) - { - return f_type == MYSQL_TYPE_TIME ? val_time_packed() : - val_datetime_packed(); - } - bool get_seconds(ulonglong *sec, ulong *sec_part); virtual bool get_date_result(MYSQL_TIME *ltime, ulonglong fuzzydate) { return get_date(ltime,fuzzydate); } /* @@ -1548,35 +1651,7 @@ public: */ virtual void update_null_value () { - switch (cmp_type()) { - case INT_RESULT: - (void) val_int(); - break; - case REAL_RESULT: - (void) val_real(); - break; - case DECIMAL_RESULT: - { - my_decimal tmp; - (void) val_decimal(&tmp); - } - break; - case TIME_RESULT: - { - MYSQL_TIME ltime; - (void) get_temporal_with_sql_mode(<ime); - } - break; - case STRING_RESULT: - { - StringBuffer<MAX_FIELD_WIDTH> tmp; - (void) val_str(&tmp); - } - break; - case ROW_RESULT: - DBUG_ASSERT(0); - null_value= true; - } + return type_handler()->Item_update_null_value(this); } /* @@ -1594,10 +1669,9 @@ public: set field of temporary table for Item which can be switched on temporary table during query processing (grouping and so on) */ - virtual void set_result_field(Field *field) {} virtual bool is_result_field() { return 0; } - virtual bool is_bool_type() { return false; } virtual bool is_json_type() { return false; } + virtual bool is_bool_literal() const { return false; } /* This is to handle printing of default values */ virtual bool need_parentheses_in_default() { return false; } virtual void save_in_result_field(bool no_conversions) {} @@ -1708,7 +1782,15 @@ public: or can be converted to such an exression using equalities. Not to be used for AND/OR formulas. */ - virtual bool excl_dep_on_grouping_fields(st_select_lex *sel) { return false; } + virtual bool excl_dep_on_grouping_fields(st_select_lex *sel) + { return false; } + /* + TRUE if the expression depends only on fields from the left part of + IN subquery or can be converted to such an expression using equalities. + Not to be used for AND/OR formulas. + */ + virtual bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) + { return false; } virtual bool switch_to_nullable_fields_processor(void *arg) { return 0; } virtual bool find_function_processor (void *arg) { return 0; } @@ -1868,11 +1950,17 @@ public: return Type_handler::type_handler_long_or_longlong(max_char_length()); } - virtual Field *create_tmp_field(bool group, TABLE *table) - { - return tmp_table_field_from_field_type(table); - } - + /** + Create field for temporary table. + @param table Temporary table + @param [OUT] src Who created the fields + @param param Create parameters + @retval NULL (on error) + @retval a pointer to a newly create Field (on success) + */ + virtual Field *create_tmp_field_ex(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param)= 0; virtual Item_field *field_for_view_update() { return 0; } virtual Item *neg_transformer(THD *thd) { return NULL; } @@ -1884,8 +1972,12 @@ public: { return this; } virtual Item *derived_field_transformer_for_where(THD *thd, uchar *arg) { return this; } - virtual Item *derived_grouping_field_transformer_for_where(THD *thd, - uchar *arg) + virtual Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) + { return this; } + /* Now is not used. */ + virtual Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) + { return this; } + virtual Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) { return this; } virtual Item *in_predicate_to_in_subs_transformer(THD *thd, uchar *arg) { return this; } @@ -1939,6 +2031,7 @@ public: delete this; } + virtual const Item_const *get_item_const() const { return NULL; } virtual Item_splocal *get_item_splocal() { return 0; } virtual Rewritable_query_parameter *get_rewritable_query_parameter() { return 0; } @@ -2012,13 +2105,16 @@ public: /* Return TRUE if the item points to a column of an outer-joined table. */ - virtual bool is_outer_field() const { DBUG_ASSERT(fixed); return FALSE; } + virtual bool is_outer_field() const { DBUG_ASSERT(is_fixed()); return FALSE; } /** Checks if this item or any of its decendents contains a subquery. This is a replacement of the former Item::has_subquery() and Item::with_subselect. */ - virtual bool with_subquery() const { DBUG_ASSERT(fixed); return false; } + virtual bool with_subquery() const { DBUG_ASSERT(is_fixed()); return false; } + + virtual bool with_sum_func() const { return false; } + virtual With_sum_func_cache* get_with_sum_func_cache() { return NULL; } Item* set_expr_cache(THD *thd); @@ -2082,6 +2178,33 @@ public: { marker &= ~EXTRACTION_MASK; } + void check_pushable_cond(Pushdown_checker excl_dep_func, uchar *arg); + bool pushable_cond_checker_for_derived(uchar *arg) + { + return excl_dep_on_table(*((table_map *)arg)); + } + bool pushable_cond_checker_for_subquery(uchar *arg) + { + return excl_dep_on_in_subq_left_part((Item_in_subselect *)arg); + } + Item *get_corresponding_field_in_insubq(Item_in_subselect *subq_pred); + Item *build_pushable_cond(THD *thd, + Pushdown_checker checker, + uchar *arg); + /* + Checks if this item depends only on the arg table + */ + bool pushable_equality_checker_for_derived(uchar *arg) + { + return (used_tables() == *((table_map *)arg)); + } + /* + Checks if this item consists in the left part of arg IN subquery predicate + */ + bool pushable_equality_checker_for_subquery(uchar *arg) + { + return get_corresponding_field_in_insubq((Item_in_subselect *)arg); + } }; MEM_ROOT *get_thd_memroot(THD *thd); @@ -2096,6 +2219,66 @@ inline Item* get_item_copy (THD *thd, T* item) } +#ifndef DBUG_OFF +/** + A helper class to print the data type and the value for an Item + in debug builds. +*/ +class DbugStringItemTypeValue: public StringBuffer<128> +{ +public: + DbugStringItemTypeValue(THD *thd, const Item *item) + { + append('('); + append(item->type_handler()->name().ptr()); + append(')'); + const_cast<Item*>(item)->print(this, QT_EXPLAIN); + } +}; +#endif + +class With_sum_func_cache +{ +protected: + bool m_with_sum_func; // True if the owner item contains a sum func +public: + With_sum_func_cache() + :m_with_sum_func(false) + { } + With_sum_func_cache(const Item *a) + :m_with_sum_func(a->with_sum_func()) + { } + With_sum_func_cache(const Item *a, const Item *b) + :m_with_sum_func(a->with_sum_func() || b->with_sum_func()) + { } + With_sum_func_cache(const Item *a, const Item *b, const Item *c) + :m_with_sum_func(a->with_sum_func() || b->with_sum_func() || + c->with_sum_func()) + { } + With_sum_func_cache(const Item *a, const Item *b, const Item *c, + const Item *d) + :m_with_sum_func(a->with_sum_func() || b->with_sum_func() || + c->with_sum_func() || d->with_sum_func()) + { } + With_sum_func_cache(const Item *a, const Item *b, const Item *c, + const Item *d, const Item *e) + :m_with_sum_func(a->with_sum_func() || b->with_sum_func() || + c->with_sum_func() || d->with_sum_func() || + e->with_sum_func()) + { } + void set_with_sum_func() { m_with_sum_func= true; } + void reset_with_sum_func() { m_with_sum_func= false; } + void copy_with_sum_func(const Item *item) + { + m_with_sum_func= item->with_sum_func(); + } + void join_with_sum_func(const Item *item) + { + m_with_sum_func|= item->with_sum_func(); + } +}; + + /* This class is a replacement for the former member Item::with_subselect. Determines if the descendant Item is a subselect or some of @@ -2210,6 +2393,17 @@ protected: } return true; } + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) + { + for (uint i= 0; i < arg_count; i++) + { + if (args[i]->const_item()) + continue; + if (!args[i]->excl_dep_on_in_subq_left_part(subq_pred)) + return false; + } + return true; + } public: Item_args(void) :args(NULL), arg_count(0) @@ -2261,6 +2455,30 @@ public: { args[arg_count++]= item; } + /** + Extract row elements from the given position. + For example, for this input: (1,2),(3,4),(5,6) + pos=0 will extract (1,3,5) + pos=1 will extract (2,4,6) + @param thd - current thread, to allocate memory on its mem_root + @param rows - an array of compatible ROW-type items + @param pos - the element position to extract + */ + bool alloc_and_extract_row_elements(THD *thd, const Item_args *rows, uint pos) + { + DBUG_ASSERT(rows->argument_count() > 0); + DBUG_ASSERT(rows->arguments()[0]->cols() > pos); + if (alloc_arguments(thd, rows->argument_count())) + return true; + for (uint i= 0; i < rows->argument_count(); i++) + { + DBUG_ASSERT(rows->arguments()[0]->cols() == rows->arguments()[i]->cols()); + Item *arg= rows->arguments()[i]->element_index(pos); + add_argument(arg); + } + DBUG_ASSERT(argument_count() == rows->argument_count()); + return false; + } inline Item **arguments() const { return args; } inline uint argument_count() const { return arg_count; } inline void remove_arguments() { arg_count=0; } @@ -2295,27 +2513,39 @@ public: class Item_string; -/** - A common class for Item_basic_constant and Item_param -*/ -class Item_basic_value :public Item +class Item_fixed_hybrid: public Item { - bool is_basic_value(const Item *item, Type type_arg) const - { - return item->basic_const_item() && item->type() == type_arg; - } - bool is_basic_value(Type type_arg) const +public: + bool fixed; // If item was fixed with fix_fields +public: + Item_fixed_hybrid(THD *thd): Item(thd), fixed(false) + { } + Item_fixed_hybrid(THD *thd, Item_fixed_hybrid *item) + :Item(thd, item), fixed(item->fixed) + { } + bool fix_fields(THD *thd, Item **ref) { - return basic_const_item() && type() == type_arg; + DBUG_ASSERT(!fixed); + fixed= true; + return false; } - bool str_eq(const String *value, - const String *other, CHARSET_INFO *cs, bool binary_cmp) const + void cleanup() { - return binary_cmp ? - value->bin_eq(other) : - collation.collation == cs && value->eq(other, collation.collation); + Item::cleanup(); + fixed= false; } + void quick_fix_field() { fixed= true; } + void unfix_fields() { fixed= false; } + bool is_fixed() const { return fixed; } +}; + +/** + A common class for Item_basic_constant and Item_param +*/ +class Item_basic_value :public Item, + public Item_const +{ protected: // Value metadata, e.g. to make string processing easier class Metadata: private MY_STRING_METADATA @@ -2352,66 +2582,40 @@ protected: fix_charset_and_length(str.charset(), dv, Metadata(&str)); } Item_basic_value(THD *thd): Item(thd) {} - /* - In the xxx_eq() methods below we need to cast off "const" to - call val_xxx(). This is OK for Item_basic_constant and Item_param. - */ - bool null_eq(const Item *item) const - { - DBUG_ASSERT(is_basic_value(NULL_ITEM)); - return item->type() == NULL_ITEM; - } - bool str_eq(const String *value, const Item *item, bool binary_cmp) const - { - DBUG_ASSERT(is_basic_value(STRING_ITEM)); - return is_basic_value(item, STRING_ITEM) && - str_eq(value, ((Item_basic_value*)item)->val_str(NULL), - item->collation.collation, binary_cmp); - } - bool real_eq(double value, const Item *item) const - { - DBUG_ASSERT(is_basic_value(REAL_ITEM)); - return is_basic_value(item, REAL_ITEM) && - value == ((Item_basic_value*)item)->val_real(); - } - bool int_eq(longlong value, const Item *item) const +public: + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) { - DBUG_ASSERT(is_basic_value(INT_ITEM)); - return is_basic_value(item, INT_ITEM) && - value == ((Item_basic_value*)item)->val_int() && - (value >= 0 || item->unsigned_flag == unsigned_flag); + + /* + create_tmp_field_ex() for this type of Items is called for: + - CREATE TABLE ... SELECT + - In ORDER BY: SELECT max(a) FROM t1 GROUP BY a ORDER BY 'const'; + - In CURSORS: + DECLARE c CURSOR FOR SELECT 'test'; + OPEN c; + */ + return tmp_table_field_from_field_type_maybe_null(table, src, param, + type() == Item::NULL_ITEM); } + bool eq(const Item *item, bool binary_cmp) const; + const Type_all_attributes *get_type_all_attributes_from_const() const + { return this; } }; class Item_basic_constant :public Item_basic_value { - table_map used_table_map; public: - Item_basic_constant(THD *thd): Item_basic_value(thd), used_table_map(0) {}; - void set_used_tables(table_map map) { used_table_map= map; } - table_map used_tables() const { return used_table_map; } - bool check_vcol_func_processor(void *arg) { return FALSE;} + Item_basic_constant(THD *thd): Item_basic_value(thd) {}; + bool check_vcol_func_processor(void *arg) { return false; } + const Item_const *get_item_const() const { return this; } virtual Item_basic_constant *make_string_literal_concat(THD *thd, const LEX_CSTRING *) { DBUG_ASSERT(0); return this; } - /* to prevent drop fixed flag (no need parent cleanup call) */ - void cleanup() - { - /* - Restore the original field name as it might not have been allocated - in the statement memory. If the name is auto generated, it must be - done again between subsequent executions of a prepared statement. - */ - if (orig_name) - { - name.str= orig_name; - name.length= strlen(orig_name); - } - } }; @@ -2422,7 +2626,7 @@ public: - CASE expression (Item_case_expr); *****************************************************************************/ -class Item_sp_variable :public Item +class Item_sp_variable :public Item_fixed_hybrid { protected: /* @@ -2462,6 +2666,11 @@ public: inline bool const_item() const; + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + return create_tmp_field_ex_simple(table, src, param); + } inline int save_in_field(Field *field, bool no_conversions); inline bool send(Protocol *protocol, st_value *buffer); bool check_vcol_func_processor(void *arg) @@ -2565,6 +2774,20 @@ public: */ Field *create_field_for_create_select(TABLE *table) { return create_table_field_from_handler(table); } + + bool is_valid_limit_clause_variable_with_error() const + { + /* + In case if the variable has an anchored data type, e.g.: + DECLARE a TYPE OF t1.a; + type_handler() is set to &type_handler_null and this + function detects such variable as not valid in LIMIT. + */ + if (type_handler()->is_limit_clause_valid_type()) + return true; + my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0)); + return false; + } }; @@ -2711,11 +2934,10 @@ inline enum Item::Type Item_case_expr::type() const extract a common base with class Item_ref, too. */ -class Item_name_const : public Item +class Item_name_const : public Item_fixed_hybrid { Item *value_item; Item *name_item; - bool valid_args; public: Item_name_const(THD *thd, Item *name_arg, Item *val); @@ -2740,6 +2962,17 @@ public: return TRUE; } + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + /* + We can get to here when using a CURSOR for a query with NAME_CONST(): + DECLARE c CURSOR FOR SELECT NAME_CONST('x','y') FROM t1; + OPEN c; + */ + return tmp_table_field_from_field_type_maybe_null(table, src, param, + type() == Item::NULL_ITEM); + } int save_in_field(Field *field, bool no_conversions) { return value_item->save_in_field(field, no_conversions); @@ -2757,12 +2990,24 @@ public: { return get_item_copy<Item_name_const>(thd, this); } }; -class Item_num: public Item_basic_constant + +class Item_literal: public Item_basic_constant { public: - Item_num(THD *thd): Item_basic_constant(thd) { collation.set_numeric(); } + Item_literal(THD *thd): Item_basic_constant(thd) + { } + enum Type type() const { return CONST_ITEM; } + bool check_partition_func_processor(void *int_arg) { return false;} + bool const_item() const { return true; } + bool basic_const_item() const { return true; } +}; + + +class Item_num: public Item_literal +{ +public: + Item_num(THD *thd): Item_literal(thd) { collation.set_numeric(); } Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); - bool check_partition_func_processor(void *int_arg) { return FALSE;} bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) { return type_handler()->Item_get_date(this, ltime, fuzzydate); @@ -2774,24 +3019,26 @@ public: class st_select_lex; -class Item_result_field :public Item /* Item with result field */ +class Item_result_field :public Item_fixed_hybrid /* Item with result field */ { public: Field *result_field; /* Save result here */ - Item_result_field(THD *thd): Item(thd), result_field(0) {} + Item_result_field(THD *thd): Item_fixed_hybrid(thd), result_field(0) {} // Constructor used for Item_sum/Item_cond_and/or (see Item comment) Item_result_field(THD *thd, Item_result_field *item): - Item(thd, item), result_field(item->result_field) + Item_fixed_hybrid(thd, item), result_field(item->result_field) {} ~Item_result_field() {} /* Required with gcc 2.95 */ Field *get_tmp_table_field() { return result_field; } + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param); + void get_tmp_field_src(Tmp_field_src *src, const Tmp_field_param *param); /* This implementation of used_tables() used by Item_avg_field and Item_variance_field which work when only temporary table left, so theu return table map of the temporary table. */ table_map used_tables() const { return 1; } - void set_result_field(Field *field) { result_field= field; } bool is_result_field() { return true; } void save_in_result_field(bool no_conversions) { @@ -2884,6 +3131,12 @@ public: Type_std_attributes::set(par_field->type_std_attributes()); } enum Type type() const { return FIELD_ITEM; } + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + DBUG_ASSERT(0); + return 0; + } double val_real() { return field->val_real(); } longlong val_int() { return field->val_int(); } String *val_str(String *str) { return field->val_str(str); } @@ -2989,16 +3242,17 @@ public: const Type_handler *handler= field->type_handler(); return handler->type_handler_for_item_field(); } - const Type_handler *cast_to_int_type_handler() const - { - return field->type_handler()->cast_to_int_type_handler(); - } const Type_handler *real_type_handler() const { if (field->is_created_from_null_item) return &type_handler_null; return field->type_handler(); } + Field *create_tmp_field_from_item_field(TABLE *new_table, + Item_ref *orig_item, + const Tmp_field_param *param); + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param); TYPELIB *get_typelib() const { return field->get_typelib(); } enum_monotonicity_info get_monotonicity_info() const { @@ -3016,13 +3270,7 @@ public: TABLE *tab= field->table; tab->covering_keys.intersect(field->part_of_key); if (tab->read_set) - bitmap_fast_test_and_set(tab->read_set, field->field_index); - /* - Do not mark a self-referecing virtual column. - Such virtual columns are reported as invalid. - */ - if (field->vcol_info && tab->vcol_set) - tab->mark_virtual_col(field); + tab->mark_column_with_deps(field); } } void update_used_tables() @@ -3099,10 +3347,13 @@ public: virtual Item *update_value_transformer(THD *thd, uchar *select_arg); Item *derived_field_transformer_for_having(THD *thd, uchar *arg); Item *derived_field_transformer_for_where(THD *thd, uchar *arg); - Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg); + Item *grouping_field_transformer_for_where(THD *thd, uchar *arg); + Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg); + Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg); virtual void print(String *str, enum_query_type query_type); bool excl_dep_on_table(table_map tab_map); bool excl_dep_on_grouping_fields(st_select_lex *sel); + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred); bool cleanup_excluding_fields_processor(void *arg) { return field ? 0 : cleanup_processor(arg); } bool cleanup_excluding_const_fields_processor(void *arg) @@ -3207,11 +3458,9 @@ public: max_length= 0; name.str= name_par ? name_par : "NULL"; name.length= strlen(name.str); - fixed= 1; collation.set(cs, DERIVATION_IGNORABLE, MY_REPERTOIRE_ASCII); } enum Type type() const { return NULL_ITEM; } - bool eq(const Item *item, bool binary_cmp) const { return null_eq(item); } double val_real(); longlong val_int(); String *val_str(String *str); @@ -3223,6 +3472,7 @@ public: const Type_handler *type_handler() const { return &type_handler_null; } bool basic_const_item() const { return 1; } Item *clone_item(THD *thd); + bool const_is_null() const { return true; } bool is_null() { return 1; } virtual inline void print(String *str, enum_query_type query_type) @@ -3248,6 +3498,12 @@ public: { return result_field->type(); } + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + DBUG_ASSERT(0); + return NULL; + } void save_in_result_field(bool no_conversions) { save_in_field(result_field, no_conversions); @@ -3315,8 +3571,8 @@ class Item_param :public Item_basic_value, All Item_param::set_xxx() make sure to do so. In the state with an assigned value: - Item_param::basic_const_item() returns true - - Item::type() returns NULL_ITEM, INT_ITEM, REAL_ITEM, DECIMAL_ITEM, - DATE_ITEM, STRING_ITEM, depending on the value assigned. + - Item::type() returns NULL_ITEM or CONST_ITEM, + depending on the value assigned. So in this state Item_param behaves in many cases like a literal. When Item_param::cleanup() is called: @@ -3339,14 +3595,6 @@ class Item_param :public Item_basic_value, DEFAULT_VALUE, IGNORE_VALUE } state; - enum Type item_type; - - void fix_type(Type type) - { - item_type= type; - fixed= true; - } - void fix_temporal(uint32 max_length_arg, uint decimals_arg); struct CONVERSION_INFO @@ -3445,7 +3693,6 @@ class Item_param :public Item_basic_value, PValue value; const String *value_query_val_str(THD *thd, String* str) const; - bool value_eq(const Item *item, bool binary_cmp) const; Item *value_clone_item(THD *thd); bool can_return_value() const; @@ -3469,9 +3716,57 @@ public: enum Type type() const { - DBUG_ASSERT(fixed || state == NO_VALUE); - return item_type; + // Don't pretend to be a constant unless value for this item is set. + switch (state) { + case NO_VALUE: return PARAM_ITEM; + case NULL_VALUE: return NULL_ITEM; + case SHORT_DATA_VALUE: return CONST_ITEM; + case LONG_DATA_VALUE: return CONST_ITEM; + case DEFAULT_VALUE: return PARAM_ITEM; + case IGNORE_VALUE: return PARAM_ITEM; + } + DBUG_ASSERT(0); + return PARAM_ITEM; + } + + bool is_order_clause_position() const + { + return state == SHORT_DATA_VALUE && + type_handler()->is_order_clause_position_type(); + } + + const Item_const *get_item_const() const + { + switch (state) { + case SHORT_DATA_VALUE: + case LONG_DATA_VALUE: + case NULL_VALUE: + return this; + case IGNORE_VALUE: + case DEFAULT_VALUE: + case NO_VALUE: + break; + } + return NULL; + } + + bool const_is_null() const { return state == NULL_VALUE; } + bool can_return_const_value(Item_result type) const + { + return can_return_value() && + value.type_handler()->cmp_type() == type && + type_handler()->cmp_type() == type; } + const longlong *const_ptr_longlong() const + { return can_return_const_value(INT_RESULT) ? &value.integer : NULL; } + const double *const_ptr_double() const + { return can_return_const_value(REAL_RESULT) ? &value.real : NULL; } + const my_decimal *const_ptr_my_decimal() const + { return can_return_const_value(DECIMAL_RESULT) ? &value.m_decimal : NULL; } + const MYSQL_TIME *const_ptr_mysql_time() const + { return can_return_const_value(TIME_RESULT) ? &value.time : NULL; } + const String *const_ptr_string() const + { return can_return_const_value(STRING_RESULT) ? &value.m_string : NULL; } double val_real() { @@ -3566,8 +3861,14 @@ public: so no one will use parameters value in fix_fields still parameter is constant during execution. */ + bool const_item() const + { + return state != NO_VALUE; + } virtual table_map used_tables() const - { return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; } + { + return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; + } virtual void print(String *str, enum_query_type query_type); bool is_null() { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; } @@ -3597,12 +3898,6 @@ public: */ Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); Item *clone_item(THD *thd); - /* - Implement by-value equality evaluation if parameter value - is set and is a basic constant (integer, real or string). - Otherwise return FALSE. - */ - bool eq(const Item *item, bool binary_cmp) const; void set_param_type_and_swap_value(Item_param *from); Rewritable_query_parameter *get_rewritable_query_parameter() @@ -3640,50 +3935,44 @@ public: longlong value; Item_int(THD *thd, int32 i,size_t length= MY_INT32_NUM_DECIMAL_DIGITS): Item_num(thd), value((longlong) i) - { max_length=(uint32)length; fixed= 1; } + { max_length=(uint32)length; } Item_int(THD *thd, longlong i,size_t length= MY_INT64_NUM_DECIMAL_DIGITS): Item_num(thd), value(i) - { max_length=(uint32)length; fixed= 1; } + { max_length=(uint32)length; } Item_int(THD *thd, ulonglong i, size_t length= MY_INT64_NUM_DECIMAL_DIGITS): Item_num(thd), value((longlong)i) - { max_length=(uint32)length; fixed= 1; unsigned_flag= 1; } + { max_length=(uint32)length; unsigned_flag= 1; } Item_int(THD *thd, const char *str_arg,longlong i,size_t length): Item_num(thd), value(i) { max_length=(uint32)length; name.str= str_arg; name.length= safe_strlen(name.str); - fixed= 1; } Item_int(THD *thd, const char *str_arg,longlong i,size_t length, bool flag): Item_num(thd), value(i) { max_length=(uint32)length; name.str= str_arg; name.length= safe_strlen(name.str); - fixed= 1; unsigned_flag= flag; } Item_int(THD *thd, const char *str_arg, size_t length=64); - enum Type type() const { return INT_ITEM; } const Type_handler *type_handler() const { 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; } + const longlong *const_ptr_longlong() const { return &value; } + longlong val_int() { return value; } + longlong val_int_min() const { return value; } + double val_real() { return (double) value; } my_decimal *val_decimal(my_decimal *); String *val_str(String*); int save_in_field(Field *field, bool no_conversions); - bool basic_const_item() const { return 1; } + bool is_order_clause_position() const { return true; } Item *clone_item(THD *thd); virtual void print(String *str, enum_query_type query_type); Item *neg(THD *thd); uint decimal_precision() const { return (uint) (max_length - MY_TEST(value < 0)); } - bool eq(const Item *item, bool binary_cmp) const - { return int_eq(value, item); } Item *get_copy(THD *thd) { return get_item_copy<Item_int>(thd, this); } }; @@ -3699,8 +3988,20 @@ class Item_bool :public Item_int public: Item_bool(THD *thd, const char *str_arg, longlong i): Item_int(thd, str_arg, i, 1) {} - bool is_bool_type() { return true; } + Item_bool(THD *thd, bool i) :Item_int(thd, (longlong) i, 1) { } + bool is_bool_literal() const { return true; } Item *neg_transformer(THD *thd); + const Type_handler *type_handler() const + { return &type_handler_bool; } + const Type_handler *fixed_type_handler() const + { return &type_handler_bool; } + void quick_fix_field() + { + /* + We can get here when Item_bool is created instead of a constant + predicate at various condition optimization stages in sql_select. + */ + } }; @@ -3710,8 +4011,7 @@ public: Item_uint(THD *thd, const char *str_arg, size_t length); Item_uint(THD *thd, ulonglong i): Item_int(thd, i, 10) {} Item_uint(THD *thd, const char *str_arg, longlong i, uint length); - double val_real() - { DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); } + double val_real() { return ulonglong2double((ulonglong)value); } String *val_str(String*); Item *clone_item(THD *thd); virtual void print(String *str, enum_query_type query_type); @@ -3750,24 +4050,26 @@ public: CHARSET_INFO *charset); Item_decimal(THD *thd, const char *str, const my_decimal *val_arg, uint decimal_par, uint length); - Item_decimal(THD *thd, my_decimal *value_par); + Item_decimal(THD *thd, const my_decimal *value_par); Item_decimal(THD *thd, longlong val, bool unsig); Item_decimal(THD *thd, double val, int precision, int scale); Item_decimal(THD *thd, const uchar *bin, int precision, int scale); - enum Type type() const { return DECIMAL_ITEM; } const Type_handler *type_handler() const { return &type_handler_newdecimal; } - longlong val_int(); - double val_real(); - String *val_str(String*); + longlong val_int() { return decimal_value.to_longlong(unsigned_flag); } + double val_real() { return decimal_value.to_double(); } + String *val_str(String *to) { return decimal_value.to_string(to); } my_decimal *val_decimal(my_decimal *val) { return &decimal_value; } + const my_decimal *const_ptr_my_decimal() const { return &decimal_value; } int save_in_field(Field *field, bool no_conversions); - bool basic_const_item() const { return 1; } Item *clone_item(THD *thd); - virtual void print(String *str, enum_query_type query_type); + virtual void print(String *str, enum_query_type query_type) + { + decimal_value.to_string(&str_value); + str->append(str_value); + } Item *neg(THD *thd); uint decimal_precision() const { return decimal_value.precision(); } - bool eq(const Item *, bool binary_cmp) const; void set_decimal_value(my_decimal *value_par); Item *get_copy(THD *thd) { return get_item_copy<Item_decimal>(thd, this); } @@ -3787,21 +4089,18 @@ public: name.length= safe_strlen(str); decimals=(uint8) decimal_par; max_length= length; - fixed= 1; } Item_float(THD *thd, double value_par, uint decimal_par): Item_num(thd), presentation(0), value(value_par) { decimals= (uint8) decimal_par; - fixed= 1; } int save_in_field(Field *field, bool no_conversions); - enum Type type() const { return REAL_ITEM; } const Type_handler *type_handler() const { return &type_handler_double; } - double val_real() { DBUG_ASSERT(fixed == 1); return value; } + const double *const_ptr_double() const { return &value; } + double val_real() { return value; } longlong val_int() { - DBUG_ASSERT(fixed == 1); if (value <= (double) LONGLONG_MIN) { return LONGLONG_MIN; @@ -3814,12 +4113,9 @@ public: } String *val_str(String*); my_decimal *val_decimal(my_decimal *); - bool basic_const_item() const { return 1; } Item *clone_item(THD *thd); Item *neg(THD *thd); virtual void print(String *str, enum_query_type query_type); - bool eq(const Item *item, bool binary_cmp) const - { return real_eq(value, item); } Item *get_copy(THD *thd) { return get_item_copy<Item_float>(thd, this); } }; @@ -3846,14 +4142,12 @@ public: }; -class Item_string :public Item_basic_constant +class Item_string :public Item_literal { protected: void fix_from_value(Derivation dv, const Metadata metadata) { fix_charset_and_length(str_value.charset(), dv, metadata); - // it is constant => can be used without fix_fields (and frequently used) - fixed= 1; } void fix_and_set_name_from_value(THD *thd, Derivation dv, const Metadata metadata) @@ -3864,41 +4158,41 @@ protected: protected: /* Just create an item and do not fill string representation */ Item_string(THD *thd, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE): - Item_basic_constant(thd) + Item_literal(thd) { collation.set(cs, dv); max_length= 0; set_name(thd, NULL, 0, system_charset_info); decimals= NOT_FIXED_DEC; - fixed= 1; } public: - Item_string(THD *thd, CHARSET_INFO *csi, const char *str_arg, uint length_arg): - Item_basic_constant(thd) + Item_string(THD *thd, CHARSET_INFO *csi, const char *str_arg, uint length_arg) + :Item_literal(thd) { collation.set(csi, DERIVATION_COERCIBLE); set_name(thd, NULL, 0, system_charset_info); decimals= NOT_FIXED_DEC; - fixed= 1; str_value.copy(str_arg, length_arg, csi); max_length= str_value.numchars() * csi->mbmaxlen; } // Constructors with the item name set from its value Item_string(THD *thd, const char *str, uint length, CHARSET_INFO *cs, - Derivation dv, uint repertoire): Item_basic_constant(thd) + Derivation dv, uint repertoire) + :Item_literal(thd) { str_value.set_or_copy_aligned(str, length, cs); fix_and_set_name_from_value(thd, dv, Metadata(&str_value, repertoire)); } Item_string(THD *thd, const char *str, size_t length, - CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE): - Item_basic_constant(thd) + CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) + :Item_literal(thd) { str_value.set_or_copy_aligned(str, length, cs); fix_and_set_name_from_value(thd, dv, Metadata(&str_value)); } Item_string(THD *thd, const String *str, CHARSET_INFO *tocs, uint *conv_errors, - Derivation dv, uint repertoire): Item_basic_constant(thd) + Derivation dv, uint repertoire) + :Item_literal(thd) { if (str_value.copy(str, tocs, conv_errors)) str_value.set("", 0, tocs); // EOM ? @@ -3907,16 +4201,16 @@ public: } // Constructors with an externally provided item name Item_string(THD *thd, const char *name_par, const char *str, size_t length, - CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE): - Item_basic_constant(thd) + CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) + :Item_literal(thd) { str_value.set_or_copy_aligned(str, length, cs); fix_from_value(dv, Metadata(&str_value)); set_name(thd, name_par,safe_strlen(name_par), system_charset_info); } Item_string(THD *thd, const char *name_par, const char *str, size_t length, - CHARSET_INFO *cs, Derivation dv, uint repertoire): - Item_basic_constant(thd) + CHARSET_INFO *cs, Derivation dv, uint repertoire) + :Item_literal(thd) { str_value.set_or_copy_aligned(str, length, cs); fix_from_value(dv, Metadata(&str_value, repertoire)); @@ -3926,12 +4220,14 @@ public: { str_value.print(to); } - enum Type type() const { return STRING_ITEM; } double val_real(); longlong val_int(); + const String *const_ptr_string() const + { + return &str_value; + } String *val_str(String*) { - DBUG_ASSERT(fixed == 1); return (String*) &str_value; } my_decimal *val_decimal(my_decimal *); @@ -3941,11 +4237,6 @@ public: } int save_in_field(Field *field, bool no_conversions); const Type_handler *type_handler() const { return &type_handler_varchar; } - bool basic_const_item() const { return 1; } - bool eq(const Item *item, bool binary_cmp) const - { - return str_eq(&str_value, item, binary_cmp); - } Item *clone_item(THD *thd); Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) { @@ -3957,7 +4248,6 @@ public: max_length= str_value.numchars() * collation.collation->mbmaxlen; } virtual void print(String *str, enum_query_type query_type); - bool check_partition_func_processor(void *int_arg) {return FALSE;} /** Return TRUE if character-set-introducer was explicitly specified in the @@ -3986,34 +4276,6 @@ public: String *check_well_formed_result(bool send_error) { return Item::check_well_formed_result(&str_value, send_error); } - enum_field_types odbc_temporal_literal_type(const LEX_CSTRING *type_str) const - { - /* - If string is a reasonably short pure ASCII string literal, - try to parse known ODBC style date, time or timestamp literals, - e.g: - SELECT {d'2001-01-01'}; - SELECT {t'10:20:30'}; - SELECT {ts'2001-01-01 10:20:30'}; - */ - if (collation.repertoire == MY_REPERTOIRE_ASCII && - str_value.length() < MAX_DATE_STRING_REP_LENGTH * 4) - { - if (type_str->length == 1) - { - if (type_str->str[0] == 'd') /* {d'2001-01-01'} */ - return MYSQL_TYPE_DATE; - else if (type_str->str[0] == 't') /* {t'10:20:30'} */ - return MYSQL_TYPE_TIME; - } - else if (type_str->length == 2) /* {ts'2001-01-01 10:20:30'} */ - { - if (type_str->str[0] == 't' && type_str->str[1] == 's') - return MYSQL_TYPE_DATETIME; - } - } - return MYSQL_TYPE_STRING; // Not a temporal literal - } Item_basic_constant *make_string_literal_concat(THD *thd, const LEX_CSTRING *); Item *make_odbc_literal(THD *thd, const LEX_CSTRING *typestr); @@ -4200,35 +4462,27 @@ public: /** Item_hex_constant -- a common class for hex literals: X'HHHH' and 0xHHHH */ -class Item_hex_constant: public Item_basic_constant +class Item_hex_constant: public Item_literal { private: void hex_string_init(THD *thd, const char *str, size_t str_length); public: - Item_hex_constant(THD *thd): Item_basic_constant(thd) + Item_hex_constant(THD *thd): Item_literal(thd) { hex_string_init(thd, "", 0); } Item_hex_constant(THD *thd, const char *str, size_t str_length): - Item_basic_constant(thd) + Item_literal(thd) { hex_string_init(thd, str, str_length); } - enum Type type() const { return VARBIN_ITEM; } const Type_handler *type_handler() const { return &type_handler_varchar; } virtual Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) { return const_charset_converter(thd, tocs, true); } - bool check_partition_func_processor(void *int_arg) {return FALSE;} - bool basic_const_item() const { return 1; } - bool eq(const Item *item, bool binary_cmp) const - { - return item->basic_const_item() && item->type() == type() && - item->cast_to_int_type_handler() == cast_to_int_type_handler() && - str_value.bin_eq(&((Item_hex_constant*)item)->str_value); - } - String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; } + const String *const_ptr_string() const { return &str_value; } + String *val_str(String*) { return &str_value; } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) { return type_handler()->Item_get_date(this, ltime, fuzzydate); @@ -4247,22 +4501,18 @@ public: Item_hex_hybrid(THD *thd): Item_hex_constant(thd) {} Item_hex_hybrid(THD *thd, const char *str, size_t str_length): Item_hex_constant(thd, str, str_length) {} + const Type_handler *type_handler() const { return &type_handler_hex_hybrid; } uint decimal_precision() const; double val_real() { - DBUG_ASSERT(fixed == 1); return (double) (ulonglong) Item_hex_hybrid::val_int(); } longlong val_int() { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); return longlong_from_hex_hybrid(str_value.ptr(), str_value.length()); } my_decimal *val_decimal(my_decimal *decimal_value) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); longlong value= Item_hex_hybrid::val_int(); int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value); return decimal_value; @@ -4272,14 +4522,6 @@ public: field->set_notnull(); return field->store_hex_hybrid(str_value.ptr(), str_value.length()); } - const Type_handler *cast_to_int_type_handler() const - { - return &type_handler_longlong; - } - const Type_handler *type_handler_for_system_time() const - { - return &type_handler_longlong; - } void print(String *str, enum_query_type query_type); Item *get_copy(THD *thd) { return get_item_copy<Item_hex_hybrid>(thd, this); } @@ -4303,12 +4545,10 @@ public: Item_hex_constant(thd, str, str_length) {} longlong val_int() { - DBUG_ASSERT(fixed == 1); return longlong_from_string_with_check(&str_value); } double val_real() { - DBUG_ASSERT(fixed == 1); return double_from_string_with_check(&str_value); } my_decimal *val_decimal(my_decimal *decimal_value) @@ -4334,7 +4574,7 @@ public: }; -class Item_temporal_literal :public Item_basic_constant +class Item_temporal_literal :public Item_literal { protected: MYSQL_TIME cached_time; @@ -4344,37 +4584,21 @@ public: @param ltime DATE value. */ Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime) - :Item_basic_constant(thd) + :Item_literal(thd) { collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII); decimals= 0; cached_time= *ltime; } Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime, uint dec_arg): - Item_basic_constant(thd) + Item_literal(thd) { collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII); decimals= dec_arg; cached_time= *ltime; } - bool basic_const_item() const { return true; } - bool const_item() const { return true; } - enum Type type() const { return DATE_ITEM; } - bool eq(const Item *item, bool binary_cmp) const; - - bool check_partition_func_processor(void *int_arg) {return FALSE;} - bool is_null() - { return is_null_from_temporal(); } - bool get_date_with_sql_mode(MYSQL_TIME *to); - String *val_str(String *str) - { return val_string_from_date(str); } - longlong val_int() - { return val_int_from_date(); } - double val_real() - { return val_real_from_date(); } - my_decimal *val_decimal(my_decimal *decimal_value) - { return val_decimal_from_date(decimal_value); } + const MYSQL_TIME *const_ptr_mysql_time() const { return &cached_time; } int save_in_field(Field *field, bool no_conversions) { return save_date_in_field(field, no_conversions); } }; @@ -4390,7 +4614,6 @@ public: :Item_temporal_literal(thd, ltime) { max_length= MAX_DATE_WIDTH; - fixed= 1; /* If date has zero month or day, it can return NULL in case of NO_ZERO_DATE or NO_ZERO_IN_DATE. @@ -4403,6 +4626,10 @@ public: const Type_handler *type_handler() const { return &type_handler_newdate; } void print(String *str, enum_query_type query_type); Item *clone_item(THD *thd); + longlong val_int() { return Date(this).to_longlong(); } + double val_real() { return Date(this).to_double(); } + String *val_str(String *to) { return Date(this).to_string(to); } + my_decimal *val_decimal(my_decimal *to) { return Date(this).to_decimal(to); } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); Item *get_copy(THD *thd) { return get_item_copy<Item_date_literal>(thd, this); } @@ -4419,11 +4646,14 @@ public: Item_temporal_literal(thd, ltime, dec_arg) { max_length= MIN_TIME_WIDTH + (decimals ? decimals + 1 : 0); - fixed= 1; } const Type_handler *type_handler() const { return &type_handler_time2; } void print(String *str, enum_query_type query_type); Item *clone_item(THD *thd); + longlong val_int() { return Time(this).to_longlong(); } + double val_real() { return Time(this).to_double(); } + String *val_str(String *to) { return Time(this).to_string(to, decimals); } + my_decimal *val_decimal(my_decimal *to) { return Time(this).to_decimal(to); } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); Item *get_copy(THD *thd) { return get_item_copy<Item_time_literal>(thd, this); } @@ -4440,13 +4670,22 @@ public: Item_temporal_literal(thd, ltime, dec_arg) { max_length= MAX_DATETIME_WIDTH + (decimals ? decimals + 1 : 0); - fixed= 1; // See the comment on maybe_null in Item_date_literal maybe_null= !ltime->month || !ltime->day; } const Type_handler *type_handler() const { return &type_handler_datetime2; } void print(String *str, enum_query_type query_type); Item *clone_item(THD *thd); + longlong val_int() { return Datetime(this).to_longlong(); } + double val_real() { return Datetime(this).to_double(); } + String *val_str(String *to) + { + return Datetime(this).to_string(to, decimals); + } + my_decimal *val_decimal(my_decimal *to) + { + return Datetime(this).to_decimal(to); + } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); Item *get_copy(THD *thd) { return get_item_copy<Item_datetime_literal>(thd, this); } @@ -4697,8 +4936,10 @@ struct st_sp_security_context; class Item_sp { -public: +protected: + // Can be NULL in some non-SELECT queries Name_resolution_context *context; +public: sp_name *m_name; sp_head *m_sp; TABLE *dummy_table; @@ -4720,9 +4961,15 @@ public: bool execute_impl(THD *thd, Item **args, uint arg_count); bool init_result_field(THD *thd, uint max_length, uint maybe_null, bool *null_value, LEX_CSTRING *name); + void process_error(THD *thd) + { + if (context) + context->process_error(thd); + } }; -class Item_ref :public Item_ident +class Item_ref :public Item_ident, + protected With_sum_func_cache { protected: void set_properties(); @@ -4758,7 +5005,8 @@ public: /* Constructor need to process subselect with temporary tables (see Item) */ Item_ref(THD *thd, Item_ref *item) - :Item_ident(thd, item), set_properties_only(0), ref(item->ref) {} + :Item_ident(thd, item), With_sum_func_cache(*item), + set_properties_only(0), ref(item->ref) {} enum Type type() const { return REF_ITEM; } enum Type real_type() const { return ref ? (*ref)->type() : REF_ITEM; } @@ -4796,6 +5044,8 @@ public: Field *get_tmp_table_field() { return result_field ? result_field : (*ref)->get_tmp_table_field(); } Item *get_tmp_table_item(THD *thd); + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param); table_map used_tables() const; void update_used_tables(); COND *build_equal_items(THD *thd, COND_EQUAL *inherited, @@ -4925,6 +5175,8 @@ public: } bool excl_dep_on_grouping_fields(st_select_lex *sel) { return (*ref)->excl_dep_on_grouping_fields(sel); } + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) + { return (*ref)->excl_dep_on_in_subq_left_part(subq_pred); } bool cleanup_excluding_fields_processor(void *arg) { Item *item= real_item(); @@ -4941,6 +5193,8 @@ public: return 0; return cleanup_processor(arg); } + bool with_sum_func() const { return m_with_sum_func; } + With_sum_func_cache* get_with_sum_func_cache() { return this; } }; @@ -5028,7 +5282,8 @@ class Expression_cache_tracker; */ class Item_cache_wrapper :public Item_result_field, - public With_subquery_cache + public With_subquery_cache, + protected With_sum_func_cache { private: /* Pointer on the cached expression */ @@ -5056,6 +5311,8 @@ public: enum Type type() const { return EXPR_CACHE_ITEM; } enum Type real_type() const { return orig_item->type(); } bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; } + bool with_sum_func() const { return m_with_sum_func; } + With_sum_func_cache* get_with_sum_func_cache() { return this; } bool set_cache(THD *thd); Expression_cache_tracker* init_tracker(MEM_ROOT *mem_root); @@ -5231,10 +5488,12 @@ public: } bool excl_dep_on_table(table_map tab_map); bool excl_dep_on_grouping_fields(st_select_lex *sel); + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred); Item *derived_field_transformer_for_having(THD *thd, uchar *arg); Item *derived_field_transformer_for_where(THD *thd, uchar *arg); - Item *derived_grouping_field_transformer_for_where(THD *thd, - uchar *arg); + Item *grouping_field_transformer_for_where(THD *thd, uchar *arg); + Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg); + Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg); void save_val(Field *to) { @@ -5500,12 +5759,12 @@ protected: */ Item_copy(THD *thd, Item *i): Item(thd) { + DBUG_ASSERT(i->is_fixed()); item= i; null_value=maybe_null=item->maybe_null; Type_std_attributes::set(item); name= item->name; set_handler(item->type_handler()); - fixed= item->fixed; } public: @@ -5533,6 +5792,12 @@ public: const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + DBUG_ASSERT(0); + return NULL; + } void make_send_field(THD *thd, Send_field *field) { item->make_send_field(thd, field); } table_map used_tables() const { return (table_map) 1L; } @@ -5676,7 +5941,7 @@ public: longlong val_int(); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) { - return get_date_from_decimal(ltime, fuzzydate); + return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this); } void copy(); Item *get_copy(THD *thd) @@ -6015,7 +6280,7 @@ public: for any value. */ -class Item_cache: public Item_basic_constant, +class Item_cache: public Item, public Type_handler_hybrid_field_type { protected: @@ -6034,25 +6299,27 @@ protected: cache_value() will set this flag to TRUE. */ bool value_cached; + + table_map used_table_map; public: Item_cache(THD *thd): - Item_basic_constant(thd), + Item(thd), Type_handler_hybrid_field_type(&type_handler_string), example(0), cached_field(0), - value_cached(0) + value_cached(0), + used_table_map(0) { - fixed= 1; maybe_null= 1; null_value= 1; } protected: Item_cache(THD *thd, const Type_handler *handler): - Item_basic_constant(thd), + Item(thd), Type_handler_hybrid_field_type(handler), example(0), cached_field(0), - value_cached(0) + value_cached(0), + used_table_map(0) { - fixed= 1; maybe_null= 1; null_value= 1; } @@ -6067,10 +6334,18 @@ public: cached_field= ((Item_field *)item)->field; return 0; }; + + void set_used_tables(table_map map) { used_table_map= map; } + table_map used_tables() const { return used_table_map; } enum Type type() const { return CACHE_ITEM; } const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + return create_tmp_field_ex_simple(table, src, param); + } virtual void keep_array() {} virtual void print(String *str, enum_query_type query_type); @@ -6101,7 +6376,7 @@ public: void cleanup() { clear(); - Item_basic_constant::cleanup(); + Item::cleanup(); } /** Check if saved item has a non-NULL value. @@ -6153,7 +6428,11 @@ public: { return convert_to_basic_const_item(thd); } Item *derived_field_transformer_for_where(THD *thd, uchar *arg) { return convert_to_basic_const_item(thd); } - Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg) + Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) + { return convert_to_basic_const_item(thd); } + Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) + { return convert_to_basic_const_item(thd); } + Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) { return convert_to_basic_const_item(thd); } }; @@ -6185,9 +6464,13 @@ public: class Item_cache_year: public Item_cache_int { public: - Item_cache_year(THD *thd): Item_cache_int(thd, &type_handler_year) { } + Item_cache_year(THD *thd, const Type_handler *handler) + :Item_cache_int(thd, handler) { } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) - { return get_date_from_year(ltime, fuzzydate); } + { + return null_value= + VYear(this).to_mysql_time_with_warn(ltime, fuzzydate, NULL); + } }; @@ -6196,12 +6479,6 @@ class Item_cache_temporal: public Item_cache_int protected: Item_cache_temporal(THD *thd, const Type_handler *handler); public: - String* val_str(String *str); - my_decimal *val_decimal(my_decimal *); - longlong val_int(); - longlong val_datetime_packed(); - longlong val_time_packed(); - double val_real(); bool cache_value(); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); int save_in_field(Field *field, bool no_conversions); @@ -6226,6 +6503,31 @@ public: Item *get_copy(THD *thd) { return get_item_copy<Item_cache_time>(thd, this); } Item *make_literal(THD *); + longlong val_datetime_packed() + { + ulonglong fuzzy= Datetime::comparison_flags_for_get_date(); + return has_value() ? Datetime(current_thd, this, fuzzy).to_longlong() : 0; + } + longlong val_time_packed() + { + return has_value() ? value : 0; + } + longlong val_int() + { + return has_value() ? Time(this).to_longlong() : 0; + } + double val_real() + { + return has_value() ? Time(this).to_double() : 0; + } + String *val_str(String *to) + { + return has_value() ? Time(this).to_string(to, decimals) : NULL; + } + my_decimal *val_decimal(my_decimal *to) + { + return has_value() ? Time(this).to_decimal(to) : NULL; + } }; @@ -6237,6 +6539,30 @@ public: Item *get_copy(THD *thd) { return get_item_copy<Item_cache_datetime>(thd, this); } Item *make_literal(THD *); + longlong val_datetime_packed() + { + return has_value() ? value : 0; + } + longlong val_time_packed() + { + return Time(this, Time::comparison_flags_for_get_date()).to_packed(); + } + longlong val_int() + { + return has_value() ? Datetime(this).to_longlong() : 0; + } + double val_real() + { + return has_value() ? Datetime(this).to_double() : 0; + } + String *val_str(String *to) + { + return has_value() ? Datetime(this).to_string(to, decimals) : NULL; + } + my_decimal *val_decimal(my_decimal *to) + { + return has_value() ? Datetime(this).to_decimal(to) : NULL; + } }; @@ -6248,6 +6574,24 @@ public: Item *get_copy(THD *thd) { return get_item_copy<Item_cache_date>(thd, this); } Item *make_literal(THD *); + longlong val_datetime_packed() + { + return has_value() ? value : 0; + } + longlong val_time_packed() + { + return Time(this, Time::comparison_flags_for_get_date()).to_packed(); + } + longlong val_int() { return has_value() ? Date(this).to_longlong() : 0; } + double val_real() { return has_value() ? Date(this).to_double() : 0; } + String *val_str(String *to) + { + return has_value() ? Date(this).to_string(to) : NULL; + } + my_decimal *val_decimal(my_decimal *to) + { + return has_value() ? Date(this).to_decimal(to) : NULL; + } }; @@ -6283,7 +6627,7 @@ public: String* val_str(String *str); my_decimal *val_decimal(my_decimal *); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) - { return get_date_from_decimal(ltime, fuzzydate); } + { return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this); } bool cache_value(); Item *convert_to_basic_const_item(THD *thd); Item *get_copy(THD *thd) @@ -6441,7 +6785,7 @@ public: Type_handler_hybrid_field_type(item->real_type_handler()), enum_set_typelib(0) { - DBUG_ASSERT(item->fixed); + DBUG_ASSERT(item->is_fixed()); maybe_null= item->maybe_null; } Item_type_holder(THD *thd, @@ -6476,7 +6820,8 @@ public: my_decimal *val_decimal(my_decimal *); String *val_str(String*); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - Field *create_tmp_field(bool group, TABLE *table) + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) { return Item_type_holder::real_type_handler()-> make_and_init_table_field(&name, Record_addr(maybe_null), @@ -6616,4 +6961,39 @@ inline void Virtual_column_info::print(String* str) expr->print_for_table_def(str); } +inline bool TABLE::mark_column_with_deps(Field *field) +{ + bool res; + if (!(res= bitmap_fast_test_and_set(read_set, field->field_index))) + { + if (field->vcol_info) + mark_virtual_column_deps(field); + } + return res; +} + +inline bool TABLE::mark_virtual_column_with_deps(Field *field) +{ + bool res; + DBUG_ASSERT(field->vcol_info); + if (!(res= bitmap_fast_test_and_set(read_set, field->field_index))) + mark_virtual_column_deps(field); + return res; +} + +inline void TABLE::mark_virtual_column_deps(Field *field) +{ + DBUG_ASSERT(field->vcol_info); + DBUG_ASSERT(field->vcol_info->expr); + field->vcol_info->expr->walk(&Item::register_field_in_read_map, 1, 0); +} + +inline void TABLE::use_all_stored_columns() +{ + bitmap_set_all(read_set); + if (Field **vf= vfield) + for (; *vf; vf++) + bitmap_clear_bit(read_set, (*vf)->field_index); +} + #endif /* SQL_ITEM_INCLUDED */ diff --git a/sql/item_buff.cc b/sql/item_buff.cc index 4d03462d7c3..3467fda79c7 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -225,16 +225,15 @@ Cached_item_decimal::Cached_item_decimal(Item *it) bool Cached_item_decimal::cmp() { - my_decimal tmp; - my_decimal *ptmp= item->val_decimal(&tmp); - if (null_value != item->null_value || - (!item->null_value && my_decimal_cmp(&value, ptmp))) + VDec tmp(item); + if (null_value != tmp.is_null() || + (!tmp.is_null() && tmp.cmp(&value))) { - null_value= item->null_value; + null_value= tmp.is_null(); /* Save only not null values */ if (!null_value) { - my_decimal2decimal(ptmp, &value); + my_decimal2decimal(tmp.ptr(), &value); return TRUE; } return FALSE; @@ -245,17 +244,9 @@ bool Cached_item_decimal::cmp() int Cached_item_decimal::cmp_read_only() { - my_decimal tmp; - my_decimal *ptmp= item->val_decimal(&tmp); + VDec tmp(item); if (null_value) - { - if (item->null_value) - return 0; - else - return -1; - } - if (item->null_value) - return 1; - return my_decimal_cmp(&value, ptmp); + return tmp.is_null() ? 0 : -1; + return tmp.is_null() ? 1 : value.cmp(tmp.ptr()); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 4a7a44b3399..fb6d99b9498 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -34,29 +34,6 @@ #include "sql_time.h" // make_truncated_value_warning #include "sql_base.h" // dynamic_column_error_message -/** - find an temporal type (item) that others will be converted to - for the purpose of comparison. - - this is the type that will be used in warnings like - "Incorrect <<TYPE>> value". -*/ -static Item *find_date_time_item(Item **args, uint nargs, uint col) -{ - Item *date_arg= 0, **arg, **arg_end; - for (arg= args, arg_end= args + nargs; arg != arg_end ; arg++) - { - Item *item= arg[0]->element_index(col); - if (item->cmp_type() != TIME_RESULT) - continue; - if (item->field_type() == MYSQL_TYPE_DATETIME) - return item; - if (!date_arg) - date_arg= item; - } - return date_arg; -} - /* Compare row signature of two expressions @@ -818,17 +795,15 @@ int Arg_comparator::compare_real() int Arg_comparator::compare_decimal() { - my_decimal decimal1; - my_decimal *val1= (*a)->val_decimal(&decimal1); - if (!(*a)->null_value) + VDec val1(*a); + if (!val1.is_null()) { - my_decimal decimal2; - my_decimal *val2= (*b)->val_decimal(&decimal2); - if (!(*b)->null_value) + VDec val2(*b); + if (!val2.is_null()) { if (set_null) owner->null_value= 0; - return my_decimal_cmp(val1, val2); + return val1.cmp(val2); } } if (set_null) @@ -847,12 +822,10 @@ int Arg_comparator::compare_e_real() int Arg_comparator::compare_e_decimal() { - my_decimal decimal1, decimal2; - my_decimal *val1= (*a)->val_decimal(&decimal1); - my_decimal *val2= (*b)->val_decimal(&decimal2); - if ((*a)->null_value || (*b)->null_value) - return MY_TEST((*a)->null_value && (*b)->null_value); - return MY_TEST(my_decimal_cmp(val1, val2) == 0); + VDec val1(*a), val2(*b); + if (val1.is_null() || val2.is_null()) + return MY_TEST(val1.is_null() && val2.is_null()); + return MY_TEST(val1.cmp(val2) == 0); } @@ -1292,7 +1265,7 @@ bool Item_in_optimizer::fix_left(THD *thd) used_tables_cache= args[0]->used_tables(); } eval_not_null_tables(NULL); - with_sum_func= args[0]->with_sum_func; + copy_with_sum_func(args[0]); with_param= args[0]->with_param || args[1]->with_param; with_field= args[0]->with_field; if ((const_item_cache= args[0]->const_item())) @@ -1300,11 +1273,11 @@ bool Item_in_optimizer::fix_left(THD *thd) cache->store(args[0]); cache->cache_value(); } - if (args[1]->fixed) + if (args[1]->is_fixed()) { /* to avoid overriding is called to update left expression */ used_tables_and_const_cache_join(args[1]); - with_sum_func= with_sum_func || args[1]->with_sum_func; + join_with_sum_func(args[1]); } DBUG_RETURN(0); } @@ -1340,7 +1313,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) if (args[1]->maybe_null) maybe_null=1; m_with_subquery= true; - with_sum_func= with_sum_func || args[1]->with_sum_func; + join_with_sum_func(args[1]); with_field= with_field || args[1]->with_field; with_param= args[0]->with_param || args[1]->with_param; used_tables_and_const_cache_join(args[1]); @@ -1895,7 +1868,7 @@ bool Item_func_interval::fix_length_and_dec() max_length= 2; used_tables_and_const_cache_join(row); not_null_tables_cache= row->not_null_tables(); - with_sum_func= with_sum_func || row->with_sum_func; + join_with_sum_func(row); with_param= with_param || row->with_param; with_field= with_field || row->with_field; return FALSE; @@ -1974,11 +1947,11 @@ longlong Item_func_interval::val_int() ((el->result_type() == DECIMAL_RESULT) || (el->result_type() == INT_RESULT))) { - my_decimal e_dec_buf, *e_dec= el->val_decimal(&e_dec_buf); + VDec e_dec(el); /* Skip NULL ranges. */ - if (el->null_value) + if (e_dec.is_null()) continue; - if (my_decimal_cmp(e_dec, dec) > 0) + if (e_dec.cmp(dec) > 0) return i - 1; } else @@ -2124,23 +2097,25 @@ bool Item_func_between::fix_length_and_dec_temporal(THD *thd) } -longlong Item_func_between::val_int_cmp_temporal() +longlong Item_func_between::val_int_cmp_datetime() { - enum_field_types f_type= m_comparator.type_handler()->field_type(); - longlong value= args[0]->val_temporal_packed(f_type), a, b; + longlong value= args[0]->val_datetime_packed(), a, b; if ((null_value= args[0]->null_value)) return 0; - a= args[1]->val_temporal_packed(f_type); - b= args[2]->val_temporal_packed(f_type); - if (!args[1]->null_value && !args[2]->null_value) - return (longlong) ((value >= a && value <= b) != negated); - if (args[1]->null_value && args[2]->null_value) - null_value= true; - else if (args[1]->null_value) - null_value= value <= b; // not null if false range. - else - null_value= value >= a; - return (longlong) (!null_value && negated); + a= args[1]->val_datetime_packed(); + b= args[2]->val_datetime_packed(); + return val_int_cmp_int_finalize(value, a, b); +} + + +longlong Item_func_between::val_int_cmp_time() +{ + longlong value= args[0]->val_time_packed(), a, b; + if ((null_value= args[0]->null_value)) + return 0; + a= args[1]->val_time_packed(); + b= args[2]->val_time_packed(); + return val_int_cmp_int_finalize(value, a, b); } @@ -2179,39 +2154,41 @@ longlong Item_func_between::val_int_cmp_int() return 0; /* purecov: inspected */ a= args[1]->val_int(); b= args[2]->val_int(); + return val_int_cmp_int_finalize(value, a, b); +} + + +bool Item_func_between::val_int_cmp_int_finalize(longlong value, + longlong a, + longlong b) +{ if (!args[1]->null_value && !args[2]->null_value) return (longlong) ((value >= a && value <= b) != negated); if (args[1]->null_value && args[2]->null_value) null_value= true; else if (args[1]->null_value) - { null_value= value <= b; // not null if false range. - } else - { null_value= value >= a; - } return (longlong) (!null_value && negated); } longlong Item_func_between::val_int_cmp_decimal() { - my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf), - a_buf, *a_dec, b_buf, *b_dec; - if ((null_value=args[0]->null_value)) + VDec dec(args[0]); + if ((null_value= dec.is_null())) return 0; /* purecov: inspected */ - a_dec= args[1]->val_decimal(&a_buf); - b_dec= args[2]->val_decimal(&b_buf); - if (!args[1]->null_value && !args[2]->null_value) - return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 && - my_decimal_cmp(dec, b_dec) <= 0) != negated); - if (args[1]->null_value && args[2]->null_value) + VDec a_dec(args[1]), b_dec(args[2]); + if (!a_dec.is_null() && !b_dec.is_null()) + return (longlong) ((dec.cmp(a_dec) >= 0 && + dec.cmp(b_dec) <= 0) != negated); + if (a_dec.is_null() && b_dec.is_null()) null_value= true; - else if (args[1]->null_value) - null_value= (my_decimal_cmp(dec, b_dec) <= 0); + else if (a_dec.is_null()) + null_value= (dec.cmp(b_dec) <= 0); else - null_value= (my_decimal_cmp(dec, a_dec) >= 0); + null_value= (dec.cmp(a_dec) >= 0); return (longlong) (!null_value && negated); } @@ -3664,9 +3641,18 @@ void in_time::set(uint pos,Item *item) buff->unsigned_flag= 1L; } -uchar *in_temporal::get_value_internal(Item *item, enum_field_types f_type) +uchar *in_datetime::get_value(Item *item) { - tmp.val= item->val_temporal_packed(f_type); + tmp.val= item->val_datetime_packed(); + if (item->null_value) + return 0; + tmp.unsigned_flag= 1L; + return (uchar*) &tmp; +} + +uchar *in_time::get_value(Item *item) +{ + tmp.val= item->val_time_packed(); if (item->null_value) return 0; tmp.unsigned_flag= 1L; @@ -3878,39 +3864,15 @@ 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"); - THD *thd= current_thd; - if (!alloc_comparators(thd, item->cols())) + DBUG_ASSERT(comparators); + DBUG_ASSERT(n == item->cols()); + item->bring_value(); + item->null_value= 0; + for (uint i=0; i < n; i++) { - item->bring_value(); - item->null_value= 0; - for (uint i=0; i < n; i++) - { - if (!comparators[i]) - { - /** - Comparators for the row elements that have temporal data types - are installed at initialization time by prepare_comparators(). - Here we install comparators for the other data types. - There is a bug in the below code. See MDEV-11511. - When performing: - (predicant0,predicant1) IN ((value00,value01),(value10,value11)) - It uses only the data type and the collation of the predicant - elements only. It should be fixed to aggregate the data type and - the collation for all elements at the N-th positions of the - predicate and all values: - - predicate0, value00, value01 - - predicate1, value10, value11 - */ - Item *elem= item->element_index(i); - const Type_handler *handler= elem->type_handler(); - DBUG_ASSERT(elem->cmp_type() != TIME_RESULT); - if (!(comparators[i]= - handler->make_cmp_item(thd, elem->collation.collation))) - break; // new failed - } - comparators[i]->store_value(item->element_index(i)); - item->null_value|= item->element_index(i)->null_value; - } + DBUG_ASSERT(comparators[i]); + comparators[i]->store_value(item->element_index(i)); + item->null_value|= item->element_index(i)->null_value; } DBUG_VOID_RETURN; } @@ -4003,9 +3965,8 @@ int cmp_item_decimal::cmp_not_null(const Value *val) int cmp_item_decimal::cmp(Item *arg) { - my_decimal tmp_buf, *tmp= arg->val_decimal(&tmp_buf); - return (m_null_value || arg->null_value) ? - UNKNOWN : (my_decimal_cmp(&value, tmp) != 0); + VDec tmp(arg); + return m_null_value || tmp.is_null() ? UNKNOWN : (tmp.cmp(&value) != 0); } @@ -4022,14 +3983,6 @@ cmp_item* cmp_item_decimal::make_same() } -void cmp_item_temporal::store_value_internal(Item *item, - enum_field_types f_type) -{ - value= item->val_temporal_packed(f_type); - m_null_value= item->null_value; -} - - int cmp_item_datetime::cmp_not_null(const Value *val) { DBUG_ASSERT(!val->is_null()); @@ -4290,25 +4243,84 @@ bool Item_func_in::value_list_convert_const_to_int(THD *thd) } -/** - Historically this code installs comparators at initialization time - for temporal ROW elements only. All other comparators are installed later, - during the first store_value(). This causes the bug MDEV-11511. - See also comments in cmp_item_row::store_value(). -*/ -bool cmp_item_row::prepare_comparators(THD *thd, Item **args, uint arg_count) +bool cmp_item_row:: + aggregate_row_elements_for_comparison(THD *thd, + Type_handler_hybrid_field_type *cmp, + Item_args *tmp, + const char *funcname, + uint col, + uint level) { + DBUG_EXECUTE_IF("cmp_item", + { + for (uint i= 0 ; i < tmp->argument_count(); i++) + { + Item *arg= tmp->arguments()[i]; + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_UNKNOWN_ERROR, "DBUG: %s[%d,%d] handler=%s", + String_space(level).c_ptr(), col, i, + arg->type_handler()->name().ptr()); + } + } + ); + bool err= cmp->aggregate_for_comparison(funcname, tmp->arguments(), + tmp->argument_count(), true); + DBUG_EXECUTE_IF("cmp_item", + { + if (!err) + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_UNKNOWN_ERROR, "DBUG: %s=> handler=%s", + String_space(level).c_ptr(), + cmp->type_handler()->name().ptr()); + } + ); + return err; +} + + +bool cmp_item_row::prepare_comparators(THD *thd, const char *funcname, + const Item_args *args, uint level) +{ + DBUG_EXECUTE_IF("cmp_item", + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_UNKNOWN_ERROR, "DBUG: %sROW(%d args) level=%d", + String_space(level).c_ptr(), + args->argument_count(), level);); + DBUG_ASSERT(args->argument_count() > 0); + if (alloc_comparators(thd, args->arguments()[0]->cols())) + return true; + DBUG_ASSERT(n == args->arguments()[0]->cols()); for (uint col= 0; col < n; col++) { - Item *date_arg= find_date_time_item(args, arg_count, col); - if (date_arg) + Item_args tmp; + Type_handler_hybrid_field_type cmp; + + if (tmp.alloc_and_extract_row_elements(thd, args, col) || + aggregate_row_elements_for_comparison(thd, &cmp, &tmp, + funcname, col, level + 1)) + return true; + + /* + There is a legacy bug (MDEV-11511) in the code below, + which should be fixed eventually. + When performing: + (predicant0,predicant1) IN ((value00,value01),(value10,value11)) + It uses only the data type and the collation of the predicant + elements only. It should be fixed to take into account the data type and + the collation for all elements at the N-th positions of the + predicate and all values: + - predicate0, value00, value01 + - predicate1, value10, value11 + */ + Item *item0= args->arguments()[0]->element_index(col); + CHARSET_INFO *collation= item0->collation.collation; + if (!(comparators[col]= cmp.type_handler()->make_cmp_item(thd, collation))) + return true; + if (cmp.type_handler() == &type_handler_row) { - // TODO: do like the scalar comparators do - const Type_handler *h= date_arg->type_handler(); - comparators[col]= h->field_type() == MYSQL_TYPE_TIME ? - (cmp_item *) new (thd->mem_root) cmp_item_time() : - (cmp_item *) new (thd->mem_root) cmp_item_datetime(); - if (!comparators[col]) + // Prepare comparators for ROW elements recursively + cmp_item_row *row= static_cast<cmp_item_row*>(comparators[col]); + if (row->prepare_comparators(thd, funcname, &tmp, level + 1)) return true; } } @@ -4318,19 +4330,10 @@ bool cmp_item_row::prepare_comparators(THD *thd, Item **args, uint arg_count) bool Item_func_in::fix_for_row_comparison_using_bisection(THD *thd) { - uint cols= args[0]->cols(); if (unlikely(!(array= new (thd->mem_root) in_row(thd, arg_count-1, 0)))) return true; cmp_item_row *cmp= &((in_row*)array)->tmp; - if (cmp->alloc_comparators(thd, cols) || - cmp->prepare_comparators(thd, args, arg_count)) - return true; - /* - Only DATETIME items comparators were initialized. - Call store_value() to setup others. - */ - cmp->store_value(args[0]); - if (unlikely(thd->is_fatal_error)) // OOM + if (cmp->prepare_comparators(thd, func_name(), this, 0)) return true; fix_in_vector(); return false; @@ -4369,8 +4372,7 @@ bool Item_func_in::fix_for_row_comparison_using_cmp_items(THD *thd) DBUG_ASSERT(get_comparator_type_handler(0) == &type_handler_row); DBUG_ASSERT(get_comparator_cmp_item(0)); cmp_item_row *cmp_row= (cmp_item_row*) get_comparator_cmp_item(0); - return cmp_row->alloc_comparators(thd, args[0]->cols()) || - cmp_row->prepare_comparators(thd, args, arg_count); + return cmp_row->prepare_comparators(thd, func_name(), this, 0); } @@ -4641,7 +4643,7 @@ Item_cond::fix_fields(THD *thd, Item **ref) const_item_cache= FALSE; } - with_sum_func|= item->with_sum_func; + join_with_sum_func(item); with_param|= item->with_param; with_field|= item->with_field; m_with_subquery|= item->with_subquery(); @@ -6295,76 +6297,53 @@ void Item_equal::add_const(THD *thd, Item *c) equal_items.push_front(c, thd->mem_root); return; } - Item *const_item= get_const(); - switch (Item_equal::compare_type_handler()->cmp_type()) { - case TIME_RESULT: - { - enum_field_types f_type= context_field->field_type(); - longlong value0= c->val_temporal_packed(f_type); - longlong value1= const_item->val_temporal_packed(f_type); - cond_false= c->null_value || const_item->null_value || value0 != value1; - break; - } - case STRING_RESULT: - { - String *str1, *str2; - /* - Suppose we have an expression (with a string type field) like this: - WHERE field=const1 AND field=const2 ... - - For all pairs field=constXXX we know that: - - - Item_func_eq::fix_length_and_dec() performed collation and character - set aggregation and added character set converters when needed. - Note, the case like: - WHERE field=const1 COLLATE latin1_bin AND field=const2 - is not handled here, because the field would be replaced to - Item_func_set_collation, which cannot get into Item_equal. - So all constXXX that are handled by Item_equal - already have compatible character sets with "field". - - - Also, Field_str::test_if_equality_guarantees_uniqueness() guarantees - that the comparison collation of all equalities handled by Item_equal - match the the collation of the field. - - Therefore, at Item_equal::add_const() time all constants constXXX - should be directly comparable to each other without an additional - character set conversion. - It's safe to do val_str() for "const_item" and "c" and compare - them according to the collation of the *field*. - - So in a script like this: - CREATE TABLE t1 (a VARCHAR(10) COLLATE xxx); - INSERT INTO t1 VALUES ('a'),('A'); - SELECT * FROM t1 WHERE a='a' AND a='A'; - Item_equal::add_const() effectively rewrites the condition to: - SELECT * FROM t1 WHERE a='a' AND 'a' COLLATE xxx='A'; - and then to: - SELECT * FROM t1 WHERE a='a'; // if the two constants were equal - // e.g. in case of latin1_swedish_ci - or to: - SELECT * FROM t1 WHERE FALSE; // if the two constants were not equal - // e.g. in case of latin1_bin - - Note, both "const_item" and "c" can return NULL, e.g.: - SELECT * FROM t1 WHERE a=NULL AND a='const'; - SELECT * FROM t1 WHERE a='const' AND a=NULL; - SELECT * FROM t1 WHERE a='const' AND a=(SELECT MAX(a) FROM t2) - */ - cond_false= !(str1= const_item->val_str(&cmp_value1)) || - !(str2= c->val_str(&cmp_value2)) || - !str1->eq(str2, compare_collation()); - break; - } - default: - { - Item_func_eq *func= new (thd->mem_root) Item_func_eq(thd, c, const_item); - if (func->set_cmp_func()) - return; - func->quick_fix_field(); - cond_false= !func->val_int(); - } - } + + /* + Suppose we have an expression (with a string type field) like this: + WHERE field=const1 AND field=const2 ... + + For all pairs field=constXXX we know that: + + - Item_func_eq::fix_length_and_dec() performed collation and character + set aggregation and added character set converters when needed. + Note, the case like: + WHERE field=const1 COLLATE latin1_bin AND field=const2 + is not handled here, because the field would be replaced to + Item_func_set_collation, which cannot get into Item_equal. + So all constXXX that are handled by Item_equal + already have compatible character sets with "field". + + - Also, Field_str::test_if_equality_guarantees_uniqueness() guarantees + that the comparison collation of all equalities handled by Item_equal + match the the collation of the field. + + Therefore, at Item_equal::add_const() time all constants constXXX + should be directly comparable to each other without an additional + character set conversion. + It's safe to do val_str() for "const_item" and "c" and compare + them according to the collation of the *field*. + + So in a script like this: + CREATE TABLE t1 (a VARCHAR(10) COLLATE xxx); + INSERT INTO t1 VALUES ('a'),('A'); + SELECT * FROM t1 WHERE a='a' AND a='A'; + Item_equal::add_const() effectively rewrites the condition to: + SELECT * FROM t1 WHERE a='a' AND 'a' COLLATE xxx='A'; + and then to: + SELECT * FROM t1 WHERE a='a'; // if the two constants were equal + // e.g. in case of latin1_swedish_ci + or to: + SELECT * FROM t1 WHERE FALSE; // if the two constants were not equal + // e.g. in case of latin1_bin + + Note, both "const_item" and "c" can return NULL, e.g.: + SELECT * FROM t1 WHERE a=NULL AND a='const'; + SELECT * FROM t1 WHERE a='const' AND a=NULL; + SELECT * FROM t1 WHERE a='const' AND a=(SELECT MAX(a) FROM t2) + */ + + cond_false= !Item_equal::compare_type_handler()->Item_eq_value(thd, this, c, + get_const()); if (with_const && equal_items.elements == 1) cond_true= TRUE; if (cond_false || cond_true) @@ -6669,7 +6648,7 @@ bool Item_equal::fix_fields(THD *thd, Item **ref) used_tables_cache|= item->used_tables(); tmp_table_map= item->not_null_tables(); not_null_tables_cache|= tmp_table_map; - DBUG_ASSERT(!item->with_sum_func && !item->with_subquery()); + DBUG_ASSERT(!item->with_sum_func() && !item->with_subquery()); if (item->maybe_null) maybe_null= 1; if (!item->get_item_equal()) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index b34bf1dde19..db1075b1936 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -152,7 +152,8 @@ public: class SEL_ARG; struct KEY_PART; -class Item_bool_func :public Item_int_func +class Item_bool_func :public Item_int_func, + public Type_cmp_attributes { protected: /* @@ -215,9 +216,9 @@ 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; } + const Type_handler *type_handler() const { return &type_handler_bool; } + const Type_handler *fixed_type_handler() const { return &type_handler_bool; } + CHARSET_INFO *compare_collation() const { return NULL; } bool fix_length_and_dec() { decimals=0; max_length=1; return FALSE; } uint decimal_precision() const { return 1; } bool need_parentheses_in_default() { return true; } @@ -891,6 +892,7 @@ class Item_func_between :public Item_func_opt_neg protected: SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *value); + bool val_int_cmp_int_finalize(longlong value, longlong a, longlong b); public: String value0,value1,value2; Item_func_between(THD *thd, Item *a, Item *b, Item *c): @@ -931,7 +933,8 @@ public: { return get_item_copy<Item_func_between>(thd, this); } longlong val_int_cmp_string(); - longlong val_int_cmp_temporal(); + longlong val_int_cmp_datetime(); + longlong val_int_cmp_time(); longlong val_int_cmp_int(); longlong val_int_cmp_real(); longlong val_int_cmp_decimal(); @@ -954,7 +957,7 @@ public: { if (agg_arg_charsets_for_comparison(cmp_collation, args, 2)) return TRUE; - fix_char_length(2); + fix_char_length(2); // returns "1" or "0" or "-1" return FALSE; } Item *get_copy(THD *thd) @@ -1282,7 +1285,11 @@ public: { reset_first_arg_if_needed(); return this; } Item *derived_field_transformer_for_where(THD *thd, uchar *arg) { reset_first_arg_if_needed(); return this; } - Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg) + Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) + { reset_first_arg_if_needed(); return this; } + Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) + { reset_first_arg_if_needed(); return this; } + Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) { reset_first_arg_if_needed(); return this; } }; @@ -1410,8 +1417,6 @@ public: */ class in_temporal :public in_longlong { -protected: - uchar *get_value_internal(Item *item, enum_field_types f_type); public: /* Cache for the left item. */ @@ -1424,8 +1429,6 @@ public: Item_datetime *dt= static_cast<Item_datetime*>(item); dt->set(val->val, type_handler()->mysql_timestamp_type()); } - uchar *get_value(Item *item) - { return get_value_internal(item, type_handler()->field_type()); } friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b); }; @@ -1437,6 +1440,7 @@ public: :in_temporal(thd, elements) {} void set(uint pos,Item *item); + uchar *get_value(Item *item); const Type_handler *type_handler() const { return &type_handler_datetime2; } }; @@ -1448,6 +1452,7 @@ public: :in_temporal(thd, elements) {} void set(uint pos,Item *item); + uchar *get_value(Item *item); const Type_handler *type_handler() const { return &type_handler_time2; } }; @@ -1622,7 +1627,6 @@ class cmp_item_temporal: public cmp_item_scalar { protected: longlong value; - void store_value_internal(Item *item, enum_field_types type); public: cmp_item_temporal() {} int compare(cmp_item *ci); @@ -1637,7 +1641,8 @@ public: { } void store_value(Item *item) { - store_value_internal(item, MYSQL_TYPE_DATETIME); + value= item->val_datetime_packed(); + m_null_value= item->null_value; } int cmp_not_null(const Value *val); int cmp(Item *arg); @@ -1653,7 +1658,8 @@ public: { } void store_value(Item *item) { - store_value_internal(item, MYSQL_TYPE_TIME); + value= item->val_time_packed(); + m_null_value= item->null_value; } int cmp_not_null(const Value *val); int cmp(Item *arg); @@ -2419,12 +2425,19 @@ class cmp_item_row :public cmp_item { cmp_item **comparators; uint n; + bool alloc_comparators(THD *thd, uint n); + bool aggregate_row_elements_for_comparison(THD *thd, + Type_handler_hybrid_field_type *cmp, + Item_args *tmp, + const char *funcname, + uint col, + uint level); public: cmp_item_row(): comparators(0), n(0) {} ~cmp_item_row(); void store_value(Item *item); - bool alloc_comparators(THD *thd, uint n); - bool prepare_comparators(THD *, Item **args, uint arg_count); + bool prepare_comparators(THD *, const char *funcname, + const Item_args *args, uint level); int cmp(Item *arg); int cmp_not_null(const Value *val) { @@ -2505,9 +2518,8 @@ public: { Field *field=((Item_field*) args[0]->real_item())->field; - if (((field->type() == MYSQL_TYPE_DATE) || - (field->type() == MYSQL_TYPE_DATETIME)) && - (field->flags & NOT_NULL_FLAG)) + if ((field->flags & NOT_NULL_FLAG) && + field->type_handler()->cond_notnull_field_isnull_to_field_eq_zero()) return true; } return false; @@ -3082,7 +3094,6 @@ class Item_equal: public Item_bool_func const Type_handler *m_compare_handler; CHARSET_INFO *m_compare_collation; - String cmp_value1, cmp_value2; public: COND_EQUAL *upper_levels; /* multiple equalities of upper and levels */ @@ -3140,6 +3151,8 @@ public: { return used_tables() & tab_map; } + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred); + friend class Item_equal_fields_iterator; bool count_sargable_conds(void *arg); friend class Item_equal_iterator<List_iterator_fast,Item>; @@ -3291,11 +3304,8 @@ public: inline bool is_cond_and(Item *item) { - if (item->type() != Item::COND_ITEM) - return FALSE; - - Item_cond *cond_item= (Item_cond*) item; - return (cond_item->functype() == Item_func::COND_AND_FUNC); + Item_func *func_item= item->get_item_func(); + return func_item && func_item->functype() == Item_func::COND_AND_FUNC; } class Item_cond_or :public Item_cond @@ -3396,11 +3406,8 @@ public: inline bool is_cond_or(Item *item) { - if (item->type() != Item::COND_ITEM) - return FALSE; - - Item_cond *cond_item= (Item_cond*) item; - return (cond_item->functype() == Item_func::COND_OR_FUNC); + Item_func *func_item= item->get_item_func(); + return func_item && func_item->functype() == Item_func::COND_OR_FUNC; } Item *and_expressions(Item *a, Item *b, Item **org_item); diff --git a/sql/item_create.cc b/sql/item_create.cc index ab91e378be3..87bf69f3c96 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -3487,12 +3487,11 @@ Create_sp_func::create_with_db(THD *thd, LEX_CSTRING *db, LEX_CSTRING *name, sph->add_used_routine(lex, thd, qname); if (pkgname.m_name.length) sp_handler_package_body.add_used_routine(lex, thd, &pkgname); + Name_resolution_context *ctx= lex->current_context(); if (arg_count > 0) - func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(), - qname, sph, *item_list); + func= new (thd->mem_root) Item_func_sp(thd, ctx, qname, sph, *item_list); else - func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(), - qname, sph); + func= new (thd->mem_root) Item_func_sp(thd, ctx, qname, sph); lex->safe_to_cache_query= 0; return func; @@ -3637,7 +3636,7 @@ Create_func_addtime Create_func_addtime::s_singleton; Item* Create_func_addtime::create_2_arg(THD *thd, Item *arg1, Item *arg2) { - return new (thd->mem_root) Item_func_add_time(thd, arg1, arg2, 0, 0); + return new (thd->mem_root) Item_func_add_time(thd, arg1, arg2, false); } @@ -6104,7 +6103,26 @@ Create_func_name_const Create_func_name_const::s_singleton; Item* Create_func_name_const::create_2_arg(THD *thd, Item *arg1, Item *arg2) { - return new (thd->mem_root) Item_name_const(thd, arg1, arg2); + if (!arg1->basic_const_item()) + goto err; + + if (arg2->basic_const_item()) + return new (thd->mem_root) Item_name_const(thd, arg1, arg2); + + if (arg2->type() == Item::FUNC_ITEM) + { + Item_func *value_func= (Item_func *) arg2; + if (value_func->functype() != Item_func::COLLATE_FUNC && + value_func->functype() != Item_func::NEG_FUNC) + goto err; + + if (!value_func->key_item()->basic_const_item()) + goto err; + return new (thd->mem_root) Item_name_const(thd, arg1, arg2); + } +err: + my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST"); + return NULL; } @@ -6658,7 +6676,7 @@ Create_func_subtime Create_func_subtime::s_singleton; Item* Create_func_subtime::create_2_arg(THD *thd, Item *arg1, Item *arg2) { - return new (thd->mem_root) Item_func_add_time(thd, arg1, arg2, 0, 1); + return new (thd->mem_root) Item_func_add_time(thd, arg1, arg2, true); } @@ -7433,84 +7451,6 @@ find_qualified_function_builder(THD *thd) } -static bool -have_important_literal_warnings(const MYSQL_TIME_STATUS *status) -{ - return (status->warnings & ~MYSQL_TIME_NOTE_TRUNCATED) != 0; -} - - -/** - Builder for datetime literals: - TIME'00:00:00', DATE'2001-01-01', TIMESTAMP'2001-01-01 00:00:00'. - @param thd The current thread - @param str Character literal - @param length Length of str - @param type Type of literal (TIME, DATE or DATETIME) - @param send_error Whether to generate an error on failure -*/ - -Item *create_temporal_literal(THD *thd, - const char *str, size_t length, - CHARSET_INFO *cs, - enum_field_types type, - bool send_error) -{ - MYSQL_TIME_STATUS status; - MYSQL_TIME ltime; - Item *item= NULL; - sql_mode_t flags= sql_mode_for_dates(thd); - - switch(type) - { - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_NEWDATE: - if (!str_to_datetime(cs, str, length, <ime, flags, &status) && - ltime.time_type == MYSQL_TIMESTAMP_DATE && !status.warnings) - item= new (thd->mem_root) Item_date_literal(thd, <ime); - break; - case MYSQL_TYPE_DATETIME: - if (!str_to_datetime(cs, str, length, <ime, flags, &status) && - ltime.time_type == MYSQL_TIMESTAMP_DATETIME && - !have_important_literal_warnings(&status)) - item= new (thd->mem_root) Item_datetime_literal(thd, <ime, - status.precision); - break; - case MYSQL_TYPE_TIME: - if (!str_to_time(cs, str, length, <ime, 0, &status) && - ltime.time_type == MYSQL_TIMESTAMP_TIME && - !have_important_literal_warnings(&status)) - item= new (thd->mem_root) Item_time_literal(thd, <ime, - status.precision); - break; - default: - DBUG_ASSERT(0); - } - - if (likely(item)) - { - if (status.warnings) // e.g. a note on nanosecond truncation - { - ErrConvString err(str, length, cs); - make_truncated_value_warning(thd, - Sql_condition::time_warn_level(status.warnings), - &err, ltime.time_type, 0); - } - return item; - } - - if (send_error) - { - const char *typestr= - (type == MYSQL_TYPE_DATE) ? "DATE" : - (type == MYSQL_TYPE_TIME) ? "TIME" : "DATETIME"; - ErrConvString err(str, length, thd->variables.character_set_client); - my_error(ER_WRONG_VALUE, MYF(0), typestr, err.ptr()); - } - return NULL; -} - - static List<Item> *create_func_dyncol_prepare(THD *thd, DYNCALL_CREATE_DEF **dfs, List<DYNCALL_CREATE_DEF> &list) diff --git a/sql/item_create.h b/sql/item_create.h index 5983a092cdc..4fb3c07c4ae 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -191,21 +191,6 @@ protected: #endif -Item *create_temporal_literal(THD *thd, - const char *str, size_t length, - CHARSET_INFO *cs, - enum_field_types type, - bool send_error); -inline -Item *create_temporal_literal(THD *thd, const String *str, - enum_field_types type, - bool send_error) -{ - return create_temporal_literal(thd, - str->ptr(), str->length(), str->charset(), - type, send_error); -} - struct Native_func_registry { LEX_CSTRING name; diff --git a/sql/item_func.cc b/sql/item_func.cc index 5693484ad3b..fa14bc58f2e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -145,7 +145,7 @@ void Item_func::sync_with_sum_func_and_with_field(List<Item> &list) Item *item; while ((item= li++)) { - with_sum_func|= item->with_sum_func; + join_with_sum_func(item); with_window_func|= item->with_window_func; with_field|= item->with_field; with_param|= item->with_param; @@ -367,7 +367,7 @@ Item_func::fix_fields(THD *thd, Item **ref) if (item->maybe_null) maybe_null=1; - with_sum_func= with_sum_func || item->with_sum_func; + join_with_sum_func(item); with_param= with_param || item->with_param; with_window_func= with_window_func || item->with_window_func; with_field= with_field || item->with_field; @@ -391,7 +391,7 @@ Item_func::quick_fix_field() { for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) { - if (!(*arg)->fixed) + if (!(*arg)->is_fixed()) (*arg)->quick_fix_field(); } } @@ -737,7 +737,7 @@ void Item_func::signal_divide_by_null() Item *Item_func::get_tmp_table_item(THD *thd) { - if (!with_sum_func && !const_item()) + if (!Item_func::with_sum_func() && !const_item()) return new (thd->mem_root) Item_temptable_field(thd, result_field); return copy_or_same(thd); } @@ -809,50 +809,6 @@ bool Item_func_plus::fix_length_and_dec(void) } -String *Item_func_hybrid_field_type::val_str_from_decimal_op(String *str) -{ - my_decimal decimal_value, *val; - if (!(val= decimal_op_with_null_check(&decimal_value))) - return 0; // null is set - DBUG_ASSERT(!null_value); - my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val); - str->set_charset(collation.collation); - my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str); - return str; -} - -double Item_func_hybrid_field_type::val_real_from_decimal_op() -{ - my_decimal decimal_value, *val; - if (!(val= decimal_op_with_null_check(&decimal_value))) - return 0.0; // null is set - double result; - my_decimal2double(E_DEC_FATAL_ERROR, val, &result); - return result; -} - -longlong Item_func_hybrid_field_type::val_int_from_decimal_op() -{ - my_decimal decimal_value, *val; - if (!(val= decimal_op_with_null_check(&decimal_value))) - return 0; // null is set - longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result); - return result; -} - -bool Item_func_hybrid_field_type::get_date_from_decimal_op(MYSQL_TIME *ltime, - ulonglong fuzzydate) -{ - my_decimal value, *res; - if (!(res= decimal_op_with_null_check(&value)) || - decimal_to_datetime_with_warn(res, ltime, fuzzydate, - field_name_or_null())) - return make_zero_mysql_time(ltime, fuzzydate); - return (null_value= 0); -} - - String *Item_func_hybrid_field_type::val_str_from_int_op(String *str) { longlong nr= int_op(); @@ -884,8 +840,7 @@ bool Item_func_hybrid_field_type::get_date_from_int_op(MYSQL_TIME *ltime, longlong value= int_op(); bool neg= !unsigned_flag && value < 0; if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value, - ltime, fuzzydate, - field_name_or_null())) + ltime, fuzzydate, NULL)) return make_zero_mysql_time(ltime, fuzzydate); return (null_value= 0); } @@ -919,8 +874,7 @@ bool Item_func_hybrid_field_type::get_date_from_real_op(MYSQL_TIME *ltime, ulonglong fuzzydate) { double value= real_op(); - if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate, - field_name_or_null())) + if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate, NULL)) return make_zero_mysql_time(ltime, fuzzydate); return (null_value= 0); } @@ -1051,47 +1005,15 @@ void Item_func_unsigned::print(String *str, enum_query_type query_type) } -String *Item_decimal_typecast::val_str(String *str) -{ - my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); - if (null_value) - return NULL; - my_decimal2string(E_DEC_FATAL_ERROR, tmp, 0, 0, 0, str); - return str; -} - - -double Item_decimal_typecast::val_real() -{ - my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); - double res; - if (null_value) - return 0.0; - my_decimal2double(E_DEC_FATAL_ERROR, tmp, &res); - return res; -} - - -longlong Item_decimal_typecast::val_int() -{ - my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); - longlong res; - if (null_value) - return 0; - my_decimal2int(E_DEC_FATAL_ERROR, tmp, unsigned_flag, &res); - return res; -} - - my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec) { - my_decimal tmp_buf, *tmp= args[0]->val_decimal(&tmp_buf); + VDec tmp(args[0]); bool sign; uint precision; - if ((null_value= args[0]->null_value)) + if ((null_value= tmp.is_null())) return NULL; - my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, dec); + tmp.round_to(dec, decimals, HALF_UP); sign= dec->sign(); if (unsigned_flag) { @@ -1275,17 +1197,13 @@ err: my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1; - my_decimal value2, *val2; - val1= args[0]->val_decimal(&value1); - if ((null_value= args[0]->null_value)) - return 0; - val2= args[1]->val_decimal(&value2); - if (!(null_value= (args[1]->null_value || + VDec2_lazy val(args[0], args[1]); + if (!(null_value= (val.has_null() || check_decimal_overflow(my_decimal_add(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, decimal_value, - val1, val2)) > 3))) + val.m_a.ptr(), + val.m_b.ptr())) > 3))) return decimal_value; return 0; } @@ -1415,18 +1333,13 @@ err: my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1; - my_decimal value2, *val2= - - val1= args[0]->val_decimal(&value1); - if ((null_value= args[0]->null_value)) - return 0; - val2= args[1]->val_decimal(&value2); - if (!(null_value= (args[1]->null_value || - (check_decimal_overflow(my_decimal_sub(E_DEC_FATAL_ERROR & - ~E_DEC_OVERFLOW, - decimal_value, val1, - val2)) > 3)))) + VDec2_lazy val(args[0], args[1]); + if (!(null_value= (val.has_null() || + check_decimal_overflow(my_decimal_sub(E_DEC_FATAL_ERROR & + ~E_DEC_OVERFLOW, + decimal_value, + val.m_a.ptr(), + val.m_b.ptr())) > 3))) return decimal_value; return 0; } @@ -1525,17 +1438,13 @@ err: my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1; - my_decimal value2, *val2; - val1= args[0]->val_decimal(&value1); - if ((null_value= args[0]->null_value)) - return 0; - val2= args[1]->val_decimal(&value2); - if (!(null_value= (args[1]->null_value || - (check_decimal_overflow(my_decimal_mul(E_DEC_FATAL_ERROR & - ~E_DEC_OVERFLOW, - decimal_value, val1, - val2)) > 3)))) + VDec2_lazy val(args[0], args[1]); + if (!(null_value= (val.has_null() || + check_decimal_overflow(my_decimal_mul(E_DEC_FATAL_ERROR & + ~E_DEC_OVERFLOW, + decimal_value, + val.m_a.ptr(), + val.m_b.ptr())) > 3))) return decimal_value; return 0; } @@ -1586,21 +1495,15 @@ double Item_func_div::real_op() my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1; - my_decimal value2, *val2; int err; - - val1= args[0]->val_decimal(&value1); - if ((null_value= args[0]->null_value)) - return 0; - val2= args[1]->val_decimal(&value2); - if ((null_value= args[1]->null_value)) + VDec2_lazy val(args[0], args[1]); + if ((null_value= val.has_null())) return 0; if ((err= check_decimal_overflow(my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW & ~E_DEC_DIV_ZERO, decimal_value, - val1, val2, + val.m_a.ptr(), val.m_b.ptr(), prec_increment))) > 3) { if (err == E_DEC_DIV_ZERO) @@ -1690,20 +1593,14 @@ longlong Item_func_int_div::val_int() if (args[0]->result_type() != INT_RESULT || args[1]->result_type() != INT_RESULT) { - my_decimal tmp; - my_decimal *val0p= args[0]->val_decimal(&tmp); - if ((null_value= args[0]->null_value)) + VDec2_lazy val(args[0], args[1]); + if ((null_value= val.has_null())) return 0; - my_decimal val0= *val0p; - - my_decimal *val1p= args[1]->val_decimal(&tmp); - if ((null_value= args[1]->null_value)) - return 0; - my_decimal val1= *val1p; int err; + my_decimal tmp; if ((err= my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, &tmp, - &val0, &val1, 0)) > 3) + val.m_a.ptr(), val.m_b.ptr(), 0)) > 3) { if (err == E_DEC_DIV_ZERO) signal_divide_by_null(); @@ -1711,8 +1608,7 @@ longlong Item_func_int_div::val_int() } my_decimal truncated; - const bool do_truncate= true; - if (my_decimal_round(E_DEC_FATAL_ERROR, &tmp, 0, do_truncate, &truncated)) + if (tmp.round_to(&truncated, 0, TRUNCATE)) DBUG_ASSERT(false); longlong res; @@ -1814,17 +1710,11 @@ double Item_func_mod::real_op() my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1; - my_decimal value2, *val2; - - val1= args[0]->val_decimal(&value1); - if ((null_value= args[0]->null_value)) - return 0; - val2= args[1]->val_decimal(&value2); - if ((null_value= args[1]->null_value)) + VDec2_lazy val(args[0], args[1]); + if ((null_value= val.has_null())) return 0; switch (my_decimal_mod(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, - val1, val2)) { + val.m_a.ptr(), val.m_b.ptr())) { case E_DEC_TRUNCATED: case E_DEC_OK: return decimal_value; @@ -1894,10 +1784,10 @@ longlong Item_func_neg::int_op() my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value) { - my_decimal val, *value= args[0]->val_decimal(&val); - if (!(null_value= args[0]->null_value)) + VDec value(args[0]); + if (!(null_value= value.is_null())) { - my_decimal2decimal(value, decimal_value); + my_decimal2decimal(value.ptr(), decimal_value); my_decimal_neg(decimal_value); return decimal_value; } @@ -1921,7 +1811,7 @@ void Item_func_neg::fix_length_and_dec_int() longlong val= args[0]->val_int(); if ((ulonglong) val >= (ulonglong) LONGLONG_MIN && ((ulonglong) val != (ulonglong) LONGLONG_MIN || - args[0]->type() != INT_ITEM)) + !args[0]->is_of_type(CONST_ITEM, INT_RESULT))) { /* Ensure that result is converted to DECIMAL, as longlong can't hold @@ -1992,10 +1882,10 @@ longlong Item_func_abs::int_op() my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value) { - my_decimal val, *value= args[0]->val_decimal(&val); - if (!(null_value= args[0]->null_value)) + VDec value(args[0]); + if (!(null_value= value.is_null())) { - my_decimal2decimal(value, decimal_value); + my_decimal2decimal(value.ptr(), decimal_value); if (decimal_value->sign()) my_decimal_neg(decimal_value); return decimal_value; @@ -2317,25 +2207,15 @@ bool Item_func_int_val::fix_length_and_dec() longlong Item_func_ceiling::int_op() { - longlong result; switch (args[0]->result_type()) { case INT_RESULT: - result= args[0]->val_int(); - null_value= args[0]->null_value; - break; + return val_int_from_item(args[0]); case DECIMAL_RESULT: - { - my_decimal dec_buf, *dec; - if ((dec= Item_func_ceiling::decimal_op(&dec_buf))) - my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); - else - result= 0; + return VDec_op(this).to_longlong(unsigned_flag); + default: break; } - default: - result= (longlong)Item_func_ceiling::real_op(); - }; - return result; + return (longlong) Item_func_ceiling::real_op(); } @@ -2353,10 +2233,9 @@ double Item_func_ceiling::real_op() my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value) { - my_decimal val, *value= args[0]->val_decimal(&val); - if (!(null_value= (args[0]->null_value || - my_decimal_ceiling(E_DEC_FATAL_ERROR, value, - decimal_value) > 1))) + VDec value(args[0]); + if (!(null_value= (value.is_null() || + value.round_to(decimal_value, 0, CEILING) > 1))) return decimal_value; return 0; } @@ -2364,25 +2243,19 @@ my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value) longlong Item_func_floor::int_op() { - longlong result; switch (args[0]->result_type()) { case INT_RESULT: - result= args[0]->val_int(); - null_value= args[0]->null_value; - break; + return val_int_from_item(args[0]); case DECIMAL_RESULT: { my_decimal dec_buf, *dec; - if ((dec= Item_func_floor::decimal_op(&dec_buf))) - my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); - else - result= 0; - break; + return (!(dec= Item_func_floor::decimal_op(&dec_buf))) ? 0 : + dec->to_longlong(unsigned_flag); } default: - result= (longlong)Item_func_floor::real_op(); - }; - return result; + break; + } + return (longlong) Item_func_floor::real_op(); } @@ -2400,10 +2273,9 @@ double Item_func_floor::real_op() my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value) { - my_decimal val, *value= args[0]->val_decimal(&val); - if (!(null_value= (args[0]->null_value || - my_decimal_floor(E_DEC_FATAL_ERROR, value, - decimal_value) > 1))) + VDec value(args[0]); + if (!(null_value= (value.is_null() || + value.round_to(decimal_value, 0, FLOOR) > 1))) return decimal_value; return 0; } @@ -2592,16 +2464,16 @@ longlong Item_func_round::int_op() my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) { - my_decimal val, *value= args[0]->val_decimal(&val); + VDec value(args[0]); longlong dec= args[1]->val_int(); if (dec >= 0 || args[1]->unsigned_flag) dec= MY_MIN((ulonglong) dec, decimals); else if (dec < INT_MIN) dec= INT_MIN; - if (!(null_value= (args[0]->null_value || args[1]->null_value || - my_decimal_round(E_DEC_FATAL_ERROR, value, (int) dec, - truncate, decimal_value) > 1))) + if (!(null_value= (value.is_null() || args[1]->null_value || + value.round_to(decimal_value, (uint) dec, + truncate ? TRUNCATE : HALF_UP) > 1))) return decimal_value; return 0; } @@ -3021,14 +2893,14 @@ longlong Item_func_field::val_int() } else if (cmp_type == DECIMAL_RESULT) { - my_decimal dec_arg_buf, *dec_arg, - dec_buf, *dec= args[0]->val_decimal(&dec_buf); - if (args[0]->null_value) + VDec dec(args[0]); + if (dec.is_null()) return 0; + my_decimal dec_arg_buf; for (uint i=1; i < arg_count; i++) { - dec_arg= args[i]->val_decimal(&dec_arg_buf); - if (!args[i]->null_value && !my_decimal_cmp(dec_arg, dec)) + my_decimal *dec_arg= args[i]->val_decimal(&dec_arg_buf); + if (!args[i]->null_value && !dec.cmp(dec_arg)) return (longlong) (i); } } @@ -3281,6 +3153,7 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func, } uint i; Item **arg,**arg_end; + With_sum_func_cache *with_sum_func_cache= func->get_with_sum_func_cache(); for (i=0, arg=arguments, arg_end=arguments+arg_count; arg != arg_end ; arg++,i++) @@ -3304,7 +3177,8 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func, func->collation.set(&my_charset_bin); if (item->maybe_null) func->maybe_null=1; - func->with_sum_func= func->with_sum_func || item->with_sum_func; + if (with_sum_func_cache) + with_sum_func_cache->join_with_sum_func(item); func->with_field= func->with_field || item->with_field; func->with_param= func->with_param || item->with_param; func->With_subquery_cache::join(item); @@ -3608,32 +3482,6 @@ String *Item_func_udf_int::val_str(String *str) } -longlong Item_func_udf_decimal::val_int() -{ - my_bool tmp_null_value; - longlong result; - my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf); - null_value= tmp_null_value; - if (null_value) - return 0; - my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); - return result; -} - - -double Item_func_udf_decimal::val_real() -{ - my_bool tmp_null_value; - double result; - my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf); - null_value= tmp_null_value; - if (null_value) - return 0.0; - my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); - return result; -} - - my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf) { my_decimal *res; @@ -3649,21 +3497,6 @@ my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf) } -String *Item_func_udf_decimal::val_str(String *str) -{ - my_bool tmp_null_value; - my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf); - null_value= tmp_null_value; - if (null_value) - return 0; - if (str->length() < DECIMAL_MAX_STR_LENGTH) - str->length(DECIMAL_MAX_STR_LENGTH); - my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf); - my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, '0', str); - return str; -} - - /* Default max_length is max argument length */ bool Item_func_udf_str::fix_length_and_dec() @@ -3730,7 +3563,7 @@ longlong Item_master_pos_wait::val_int() connection_name.length= con->length(); if (check_master_connection_name(&connection_name)) { - my_error(ER_WRONG_ARGUMENTS, MYF(ME_JUST_WARNING), + my_error(ER_WRONG_ARGUMENTS, MYF(ME_WARNING), "MASTER_CONNECTION_NAME"); goto err; } @@ -4441,7 +4274,7 @@ user_var_entry *get_variable(HASH *hash, LEX_CSTRING *name, if (!my_hash_inited(hash)) return 0; if (!(entry = (user_var_entry*) my_malloc(size, - MYF(MY_WME | ME_FATALERROR | + MYF(MY_WME | ME_FATAL | MY_THREAD_SPECIFIC)))) return 0; entry->name.str=(char*) entry+ ALIGN_SIZE(sizeof(user_var_entry))+ @@ -4696,7 +4529,7 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length, entry->value=0; entry->value= (char*) my_realloc(entry->value, length, MYF(MY_ALLOW_ZERO_PTR | MY_WME | - ME_FATALERROR | + ME_FATAL | MY_THREAD_SPECIFIC)); if (!entry->value) return 1; @@ -4761,11 +4594,7 @@ double user_var_entry::val_real(bool *null_value) case INT_RESULT: return (double) *(longlong*) value; case DECIMAL_RESULT: - { - double result; - my_decimal2double(E_DEC_FATAL_ERROR, (my_decimal *)value, &result); - return result; - } + return ((my_decimal *)value)->to_double(); case STRING_RESULT: return my_atof(value); // This is null terminated case ROW_RESULT: @@ -4790,11 +4619,7 @@ longlong user_var_entry::val_int(bool *null_value) const case INT_RESULT: return *(longlong*) value; case DECIMAL_RESULT: - { - longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, &result); - return result; - } + return ((my_decimal *)value)->to_longlong(false); case STRING_RESULT: { int error; @@ -5531,10 +5356,9 @@ bool Item_func_get_user_var::set_value(THD *thd, bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) { - DBUG_ASSERT(fixed == 0); + DBUG_ASSERT(!is_fixed()); DBUG_ASSERT(thd->lex->exchange); - if (Item::fix_fields(thd, ref) || - !(entry= get_variable(&thd->user_vars, &org_name, 1))) + if (!(entry= get_variable(&thd->user_vars, &org_name, 1))) return TRUE; entry->type= STRING_RESULT; /* @@ -5631,7 +5455,7 @@ void Item_func_get_system_var::update_null_value() THD *thd= current_thd; int save_no_errors= thd->no_errors; thd->no_errors= TRUE; - Item::update_null_value(); + type_handler()->Item_update_null_value(this); thd->no_errors= save_no_errors; } @@ -6471,7 +6295,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) (thd->lex->sql_command == SQLCOM_CREATE_VIEW)) { Security_context *save_security_ctx= thd->security_ctx; - if (context->security_ctx) + if (context && context->security_ctx) thd->security_ctx= context->security_ctx; /* @@ -6486,7 +6310,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) if (res) { - context->process_error(thd); + process_error(thd); DBUG_RETURN(res); } } @@ -6503,7 +6327,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) if (!(m_sp= sp)) { my_missing_function_error(m_name->m_name, ErrConvDQName(m_name).ptr()); - context->process_error(thd); + process_error(thd); DBUG_RETURN(TRUE); } diff --git a/sql/item_func.h b/sql/item_func.h index af29e14fe3a..079775bb971 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -35,12 +35,11 @@ extern "C" /* Bug in BSDI include file */ #include <cmath> -class Item_func :public Item_func_or_sum +class Item_func :public Item_func_or_sum, + protected With_sum_func_cache { void sync_with_sum_func_and_with_field(List<Item> &list); protected: - String *val_str_from_val_str_ascii(String *str, String *str2); - virtual bool check_arguments() const { return check_argument_types_scalar(0, arg_count); @@ -56,6 +55,7 @@ protected: bool check_argument_types_can_return_text(uint start, uint end) const; bool check_argument_types_can_return_date(uint start, uint end) const; bool check_argument_types_can_return_time(uint start, uint end) const; + void print_cast_temporal(String *str, enum_query_type query_type); public: table_map not_null_tables_cache; @@ -77,49 +77,56 @@ public: EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC, NEG_FUNC, GSYSVAR_FUNC, IN_OPTIMIZER_FUNC, DYNCOL_FUNC, JSON_EXTRACT_FUNC }; + static scalar_comparison_op functype_to_scalar_comparison_op(Functype type) + { + switch (type) { + case EQ_FUNC: return SCALAR_CMP_EQ; + case EQUAL_FUNC: return SCALAR_CMP_EQUAL; + case LT_FUNC: return SCALAR_CMP_LT; + case LE_FUNC: return SCALAR_CMP_LE; + case GE_FUNC: return SCALAR_CMP_GE; + case GT_FUNC: return SCALAR_CMP_GT; + default: break; + } + DBUG_ASSERT(0); + return SCALAR_CMP_EQ; + } enum Type type() const { return FUNC_ITEM; } virtual enum Functype functype() const { return UNKNOWN_FUNC; } Item_func(THD *thd): Item_func_or_sum(thd) { - with_sum_func= 0; with_field= 0; with_param= 0; } - Item_func(THD *thd, Item *a): Item_func_or_sum(thd, a) + Item_func(THD *thd, Item *a) + :Item_func_or_sum(thd, a), With_sum_func_cache(a) { - with_sum_func= a->with_sum_func; with_param= a->with_param; with_field= a->with_field; } - Item_func(THD *thd, Item *a, Item *b): - Item_func_or_sum(thd, a, b) + Item_func(THD *thd, Item *a, Item *b) + :Item_func_or_sum(thd, a, b), With_sum_func_cache(a, b) { - with_sum_func= a->with_sum_func || b->with_sum_func; with_param= a->with_param || b->with_param; 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) + Item_func(THD *thd, Item *a, Item *b, Item *c) + :Item_func_or_sum(thd, a, b, c), With_sum_func_cache(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; with_param= a->with_param || b->with_param || c->with_param; } - Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d): - Item_func_or_sum(thd, a, b, c, d) + Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d) + :Item_func_or_sum(thd, a, b, c, d), With_sum_func_cache(a, b, c, d) { - with_sum_func= a->with_sum_func || b->with_sum_func || - c->with_sum_func || d->with_sum_func; with_field= a->with_field || b->with_field || c->with_field || d->with_field; with_param= a->with_param || b->with_param || c->with_param || d->with_param; } - Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e): - Item_func_or_sum(thd, a, b, c, d, e) + Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e) + :Item_func_or_sum(thd, a, b, c, d, e), With_sum_func_cache(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; with_field= a->with_field || b->with_field || c->with_field || d->with_field || e->with_field; with_param= a->with_param || b->with_param || @@ -131,11 +138,10 @@ public: 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), + Item_func(THD *thd, Item_func *item) + :Item_func_or_sum(thd, item), With_sum_func_cache(item), not_null_tables_cache(item->not_null_tables_cache) - { - } + { } bool fix_fields(THD *, Item **ref); void cleanup() { @@ -181,6 +187,8 @@ public: update_null_value(); return null_value; } + String *val_str_from_val_str_ascii(String *str, String *str2); + void signal_divide_by_null(); friend class udf_handler; Field *create_field_for_create_select(TABLE *table) @@ -335,6 +343,11 @@ public: return Item_args::excl_dep_on_grouping_fields(sel); } + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) + { + return Item_args::excl_dep_on_in_subq_left_part(subq_pred); + } + /* We assume the result of any function that has a TIMESTAMP argument to be timezone-dependent, since a TIMESTAMP value in both numeric and string @@ -377,6 +390,10 @@ public: - or replaced to an Item_int_with_ref */ bool setup_args_and_comparator(THD *thd, Arg_comparator *cmp); + + bool with_sum_func() const { return m_with_sum_func; } + With_sum_func_cache* get_with_sum_func_cache() { return this; } + Item_func *get_item_func() { return this; } }; @@ -435,6 +452,193 @@ public: }; +class Item_handled_func: public Item_func +{ +public: + class Handler + { + public: + virtual ~Handler() { } + virtual String *val_str(Item_handled_func *, String *) const= 0; + virtual String *val_str_ascii(Item_handled_func *, String *) const= 0; + virtual double val_real(Item_handled_func *) const= 0; + virtual longlong val_int(Item_handled_func *) const= 0; + virtual my_decimal *val_decimal(Item_handled_func *, my_decimal *) const= 0; + virtual bool get_date(Item_handled_func *, MYSQL_TIME *, ulonglong fuzzydate) const= 0; + virtual const Type_handler *return_type_handler() const= 0; + virtual bool fix_length_and_dec(Item_handled_func *) const= 0; + }; + + /** + Abstract class for functions returning TIME, DATE, DATETIME or string values, + whose data type depends on parameters and is set at fix_fields time. + */ + class Handler_temporal: public Handler + { + public: + String *val_str(Item_handled_func *item, String *to) const + { + StringBuffer<MAX_FIELD_WIDTH> ascii_buf; + return item->val_str_from_val_str_ascii(to, &ascii_buf); + } + }; + + /** + Abstract class for functions returning strings, + which are generated from get_date() results, + when get_date() can return different MYSQL_TIMESTAMP_XXX per row. + */ + class Handler_temporal_string: public Handler_temporal + { + public: + const Type_handler *return_type_handler() const + { + return &type_handler_string; + } + double val_real(Item_handled_func *item) const + { + return Temporal_hybrid(item).to_double(); + } + longlong val_int(Item_handled_func *item) const + { + return Temporal_hybrid(item).to_longlong(); + } + my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const + { + return Temporal_hybrid(item).to_decimal(to); + } + String *val_str_ascii(Item_handled_func *item, String *to) const + { + return Temporal_hybrid(item).to_string(to, item->decimals); + } + }; + + + class Handler_date: public Handler_temporal + { + public: + const Type_handler *return_type_handler() const + { + return &type_handler_newdate; + } + bool fix_length_and_dec(Item_handled_func *item) const + { + item->fix_attributes_date(); + return false; + } + double val_real(Item_handled_func *item) const + { + return Date(item).to_double(); + } + longlong val_int(Item_handled_func *item) const + { + return Date(item).to_longlong(); + } + my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const + { + return Date(item).to_decimal(to); + } + String *val_str_ascii(Item_handled_func *item, String *to) const + { + return Date(item).to_string(to); + } + }; + + + class Handler_time: public Handler_temporal + { + public: + const Type_handler *return_type_handler() const + { + return &type_handler_time2; + } + double val_real(Item_handled_func *item) const + { + return Time(item).to_double(); + } + longlong val_int(Item_handled_func *item) const + { + return Time(item).to_longlong(); + } + my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const + { + return Time(item).to_decimal(to); + } + String *val_str_ascii(Item_handled_func *item, String *to) const + { + return Time(item).to_string(to, item->decimals); + } + }; + + + class Handler_datetime: public Handler_temporal + { + public: + const Type_handler *return_type_handler() const + { + return &type_handler_datetime2; + } + double val_real(Item_handled_func *item) const + { + return Datetime(item).to_double(); + } + longlong val_int(Item_handled_func *item) const + { + return Datetime(item).to_longlong(); + } + my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const + { + return Datetime(item).to_decimal(to); + } + String *val_str_ascii(Item_handled_func *item, String *to) const + { + return Datetime(item).to_string(to, item->decimals); + } + }; + + +protected: + const Handler *m_func_handler; +public: + Item_handled_func(THD *thd, Item *a) + :Item_func(thd, a), m_func_handler(NULL) { } + Item_handled_func(THD *thd, Item *a, Item *b) + :Item_func(thd, a, b), m_func_handler(NULL) { } + void set_func_handler(const Handler *handler) + { + m_func_handler= handler; + } + const Type_handler *type_handler() const + { + return m_func_handler->return_type_handler(); + } + String *val_str(String *to) + { + return m_func_handler->val_str(this, to); + } + String *val_str_ascii(String *to) + { + return m_func_handler->val_str_ascii(this, to); + } + double val_real() + { + return m_func_handler->val_real(this); + } + longlong val_int() + { + return m_func_handler->val_int(this); + } + my_decimal *val_decimal(my_decimal *to) + { + return m_func_handler->val_decimal(this, to); + } + bool get_date(MYSQL_TIME *to, ulonglong fuzzydate) + { + return m_func_handler->get_date(this, to, fuzzydate); + } +}; + + /** Functions that at fix_fields() time determine the returned field type, trying to preserve the exact data type of the arguments. @@ -476,12 +680,6 @@ class Item_func_hybrid_field_type: public Item_hybrid_func DBUG_ASSERT((res != NULL) ^ null_value); return res; } - my_decimal *decimal_op_with_null_check(my_decimal *decimal_buffer) - { - my_decimal *res= decimal_op(decimal_buffer); - DBUG_ASSERT((res != NULL) ^ null_value); - return res; - } bool make_zero_mysql_time(MYSQL_TIME *ltime, ulonglong fuzzydate) { bzero(ltime, sizeof(*ltime)); @@ -494,10 +692,6 @@ public: { return str_op_with_null_check(&str_value); } - my_decimal *val_decimal_from_decimal_op(my_decimal *dec) - { - return decimal_op_with_null_check(dec); - } longlong val_int_from_int_op() { return int_op(); @@ -508,7 +702,6 @@ public: } // Value methods that involve conversion - String *val_str_from_decimal_op(String *str); String *val_str_from_real_op(String *str); String *val_str_from_int_op(String *str); String *val_str_from_date_op(String *str); @@ -522,19 +715,16 @@ public: longlong val_int_from_str_op(); longlong val_int_from_real_op(); - longlong val_int_from_decimal_op(); longlong val_int_from_date_op(); longlong val_int_from_time_op(); double val_real_from_str_op(); - double val_real_from_decimal_op(); double val_real_from_date_op(); double val_real_from_time_op(); double val_real_from_int_op(); bool get_date_from_str_op(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_date_from_real_op(MYSQL_TIME *ltime, ulonglong fuzzydate); - bool get_date_from_decimal_op(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_date_from_int_op(MYSQL_TIME *ltime, ulonglong fuzzydate); public: @@ -976,12 +1166,12 @@ public: fix_char_length(my_decimal_precision_to_length_no_truncation(len, dec, unsigned_flag)); } - String *val_str(String *str); - double val_real(); - longlong val_int(); + String *val_str(String *str) { return VDec(this).to_string(str); } + double val_real() { return VDec(this).to_double(); } + longlong val_int() { return VDec(this).to_longlong(unsigned_flag); } my_decimal *val_decimal(my_decimal*); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) - { return get_date_from_decimal(ltime, fuzzydate); } + { return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this); } const Type_handler *type_handler() const { return &type_handler_newdecimal; } void fix_length_and_dec_generic() {} bool fix_length_and_dec() @@ -2001,6 +2191,18 @@ protected: udf_handler udf; bool is_expensive_processor(void *arg) { return TRUE; } + class VDec_udf: public Dec_ptr_and_buffer + { + public: + VDec_udf(Item_udf_func *func, udf_handler *udf) + { + my_bool tmp_null_value; + m_ptr= udf->val_decimal(&tmp_null_value, &m_buffer); + DBUG_ASSERT(is_null() == (tmp_null_value != 0)); + func->null_value= is_null(); + } + }; + public: Item_udf_func(THD *thd, udf_func *udf_arg): Item_func(thd), udf(udf_arg) {} @@ -2140,10 +2342,19 @@ public: Item_udf_func(thd, udf_arg) {} Item_func_udf_decimal(THD *thd, udf_func *udf_arg, List<Item> &list): Item_udf_func(thd, udf_arg, list) {} - longlong val_int(); - double val_real(); + longlong val_int() + { + return VDec_udf(this, &udf).to_longlong(unsigned_flag); + } + double val_real() + { + return VDec_udf(this, &udf).to_double(); + } my_decimal *val_decimal(my_decimal *); - String *val_str(String *str); + String *val_str(String *str) + { + return VDec_udf(this, &udf).to_string_round(str, decimals); + } const Type_handler *type_handler() const { return &type_handler_newdecimal; } bool fix_length_and_dec() { fix_num_length_and_dec(); return FALSE; } Item *get_copy(THD *thd) @@ -2374,8 +2585,8 @@ 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_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param); Field *create_field_for_create_select(TABLE *table) { return create_table_field_from_handler(table); } bool check_vcol_func_processor(void *arg); @@ -2508,14 +2719,14 @@ 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, +class Item_user_var_as_out_param :public Item_fixed_hybrid, public Load_data_outvar { LEX_CSTRING org_name; user_var_entry *entry; public: Item_user_var_as_out_param(THD *thd, const LEX_CSTRING *a) - :Item(thd) + :Item_fixed_hybrid(thd) { DBUG_ASSERT(a->length < UINT_MAX32); org_name= *a; @@ -2550,8 +2761,14 @@ public: { return 0; } + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + DBUG_ASSERT(0); + return NULL; + } /* We should return something different from FIELD_ITEM here */ - enum Type type() const { return STRING_ITEM;} + enum Type type() const { return CONST_ITEM;} double val_real(); longlong val_int(); String *val_str(String *str); @@ -2863,6 +3080,8 @@ public: const Type_handler *type_handler() const; + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param); Field *create_field_for_create_select(TABLE *table) { return result_type() != STRING_RESULT ? diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 4c2a2fa8b11..1f1b5a6ceed 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -916,7 +916,7 @@ String *Item_func_point::val_str(String *str) if ((null_value= (args[0]->null_value || args[1]->null_value || - str->realloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE * 2)))) + str->alloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE * 2)))) return 0; str->set_charset(&my_charset_bin); diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 0e727829ce7..e6c198fb8b2 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -512,7 +512,7 @@ public: return TRUE; for (unsigned int i= 0; i < arg_count; ++i) { - if (args[i]->fixed && args[i]->field_type() != MYSQL_TYPE_GEOMETRY) + if (args[i]->is_fixed() && args[i]->field_type() != MYSQL_TYPE_GEOMETRY) { String str; args[i]->print(&str, QT_NO_DATA_EXPANSION); diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 2cda8b25a8a..205f2c5d65f 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -1422,7 +1422,7 @@ null_return: static int append_json_value(String *str, Item *item, String *tmp_val) { - if (item->is_bool_type()) + if (item->type_handler()->is_bool_type()) { longlong v_int= item->val_int(); const char *t_f; diff --git a/sql/item_row.cc b/sql/item_row.cc index 8233ba00f06..665c900cb3a 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -60,7 +60,7 @@ bool Item_row::fix_fields(THD *thd, Item **ref) } } maybe_null|= item->maybe_null; - with_sum_func= with_sum_func || item->with_sum_func; + join_with_sum_func(item); with_window_func = with_window_func || item->with_window_func; with_field= with_field || item->with_field; m_with_subquery|= item->with_subquery(); @@ -91,7 +91,7 @@ void Item_row::cleanup() { DBUG_ENTER("Item_row::cleanup"); - Item::cleanup(); + Item_fixed_hybrid::cleanup(); /* Reset to the original values */ used_tables_and_const_cache_init(); with_null= 0; diff --git a/sql/item_row.h b/sql/item_row.h index e0d54403730..278dc88479d 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -33,10 +33,11 @@ Item which stores (x,y,...) and ROW(x,y,...). Note that this can be recursive: ((x,y),(z,t)) is a ROW of ROWs. */ -class Item_row: public Item, +class Item_row: public Item_fixed_hybrid, private Item_args, private Used_tables_and_const_cache, - private With_subquery_cache + private With_subquery_cache, + private With_sum_func_cache { table_map not_null_tables_cache; /** @@ -45,17 +46,25 @@ class Item_row: public Item, */ bool with_null; public: - Item_row(THD *thd, List<Item> &list): - Item(thd), Item_args(thd, list), not_null_tables_cache(0), with_null(0) + Item_row(THD *thd, List<Item> &list) + :Item_fixed_hybrid(thd), Item_args(thd, list), + not_null_tables_cache(0), with_null(0) { } - Item_row(THD *thd, Item_row *row): - Item(thd), Item_args(thd, static_cast<Item_args*>(row)), Used_tables_and_const_cache(), + Item_row(THD *thd, Item_row *row) + :Item_fixed_hybrid(thd), Item_args(thd, static_cast<Item_args*>(row)), + Used_tables_and_const_cache(), + With_sum_func_cache(*row), not_null_tables_cache(0), with_null(0) { } bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; } enum Type type() const { return ROW_ITEM; }; const Type_handler *type_handler() const { return &type_handler_row; } + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + return NULL; // Check with Vicentiu why it's called for Item_row + } void illegal_method_call(const char *); bool is_null() { return null_value; } void make_send_field(THD *thd, Send_field *) @@ -92,6 +101,8 @@ public: void cleanup(); void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List<Item> &fields, uint flags); + bool with_sum_func() const { return m_with_sum_func; } + With_sum_func_cache* get_with_sum_func_cache() { return this; } table_map used_tables() const { return used_tables_cache; }; bool const_item() const { return const_item_cache; }; void update_used_tables() @@ -134,6 +145,11 @@ public: return Item_args::excl_dep_on_grouping_fields(sel); } + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) + { + return Item_args::excl_dep_on_in_subq_left_part(subq_pred); + } + bool check_vcol_func_processor(void *arg) {return FALSE; } Item *get_copy(THD *thd) { return get_item_copy<Item_row>(thd, this); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 51723a25dee..50fe1624d48 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -255,7 +255,7 @@ String *Item_func_sha2::val_str_ascii(String *str) Since we're subverting the usual String methods, we must make sure that the destination has space for the bytes we're about to write. */ - str->realloc((uint) digest_length*2 + 1); /* Each byte as two nybbles */ + str->alloc((uint) digest_length*2 + 1); /* Each byte as two nybbles */ /* Convert the large number to a string-hex representation. */ array_to_hex((char *) str->ptr(), digest_buf, (uint)digest_length); @@ -762,7 +762,7 @@ String *Item_func_des_encrypt::val_str(String *str) tail= 8 - (res_length % 8); // 1..8 marking extra length res_length+=tail; - if (tmp_arg.realloc(res_length)) + if (tmp_arg.alloc(res_length)) goto error; tmp_arg.length(0); tmp_arg.append(res->ptr(), res->length()); @@ -770,7 +770,6 @@ String *Item_func_des_encrypt::val_str(String *str) if (tmp_arg.append(append_str, tail) || str->alloc(res_length+1)) goto error; tmp_arg[res_length-1]=tail; // save extra length - str->realloc(res_length+1); str->length(res_length+1); str->set_charset(&my_charset_bin); (*str)[0]=(char) (128 | key_number); @@ -1017,7 +1016,7 @@ String *Item_func_concat_ws::val_str(String *str) { uint new_len = MY_MAX(tmp_value.alloced_length() * 2, concat_len); - if (tmp_value.realloc(new_len)) + if (tmp_value.alloc(new_len)) goto null; } } @@ -1072,8 +1071,7 @@ String *Item_func_reverse::val_str(String *str) /* An empty string is a special case as the string pointer may be null */ if (!res->length()) return make_empty_result(); - if (str->alloced_length() < res->length() && - str->realloc(res->length())) + if (str->alloc(res->length())) { null_value= 1; return 0; @@ -2659,12 +2657,10 @@ String *Item_func_format::val_str_ascii(String *str) if (args[0]->result_type() == DECIMAL_RESULT || args[0]->result_type() == INT_RESULT) { - my_decimal dec_val, rnd_dec, *res; - res= args[0]->val_decimal(&dec_val); - if ((null_value=args[0]->null_value)) + VDec res(args[0]); + if ((null_value= res.is_null())) return 0; /* purecov: inspected */ - my_decimal_round(E_DEC_FATAL_ERROR, res, dec, false, &rnd_dec); - my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str); + res.to_string_round(str, dec); str_length= str->length(); } else @@ -4180,7 +4176,7 @@ String *Item_func_compress::val_str(String *str) // Check new_size overflow: new_size <= res->length() if (((uint32) (new_size+5) <= res->length()) || - str->realloc((uint32) new_size + 4 + 1)) + str->alloc((uint32) new_size + 4 + 1)) { null_value= 1; return 0; @@ -4252,7 +4248,7 @@ String *Item_func_uncompress::val_str(String *str) max_allowed_packet)); goto err; } - if (str->realloc((uint32)new_size)) + if (str->alloc((uint32)new_size)) goto err; if ((err= uncompress((Byte*)str->ptr(), &new_size, @@ -4281,7 +4277,7 @@ String *Item_func_uuid::val_str(String *str) DBUG_ASSERT(fixed == 1); uchar guid[MY_UUID_SIZE]; - str->realloc(MY_UUID_STRING_LENGTH+1); + str->alloc(MY_UUID_STRING_LENGTH+1); str->length(MY_UUID_STRING_LENGTH); str->set_charset(system_charset_info); my_uuid(guid); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 29af0b43d9d..7c4ab93dc80 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -67,11 +67,6 @@ public: const Type_handler *type_handler() const { return string_type_handler(); } void left_right_max_length(); bool fix_fields(THD *thd, Item **ref); - void update_null_value() - { - StringBuffer<MAX_FIELD_WIDTH> tmp; - (void) val_str(&tmp); - } }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 1947a45186a..eef6755bc98 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -85,6 +85,9 @@ void Item_subselect::init(st_select_lex *select_lex, DBUG_ENTER("Item_subselect::init"); DBUG_PRINT("enter", ("select_lex: %p this: %p", select_lex, this)); + + select_lex->parent_lex->relink_hack(select_lex); + unit= select_lex->master_unit(); if (unit->item) @@ -123,13 +126,6 @@ void Item_subselect::init(st_select_lex *select_lex, else engine= new subselect_single_select_engine(select_lex, result, this); } - { - SELECT_LEX *upper= unit->outer_select(); - if (upper->parsing_place == IN_HAVING) - upper->subquery_in_having= 1; - /* The subquery is an expression cache candidate */ - upper->expr_cache_may_be_used[upper->parsing_place]= TRUE; - } DBUG_PRINT("info", ("engine: %p", engine)); DBUG_VOID_RETURN; } @@ -220,7 +216,8 @@ Item_subselect::~Item_subselect() if (own_engine) delete engine; else - engine->cleanup(); + if (engine) // can be empty in case of EOM + engine->cleanup(); engine= NULL; DBUG_VOID_RETURN; } @@ -244,6 +241,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) DBUG_ASSERT(unit->thd == thd); + { + SELECT_LEX *upper= unit->outer_select(); + if (upper->parsing_place == IN_HAVING) + upper->subquery_in_having= 1; + /* The subquery is an expression cache candidate */ + upper->expr_cache_may_be_used[upper->parsing_place]= TRUE; + } + status_var_increment(thd_param->status_var.feature_subquery); DBUG_ASSERT(fixed == 0); @@ -939,7 +944,7 @@ bool Item_subselect::const_item() const Item *Item_subselect::get_tmp_table_item(THD *thd_arg) { - if (!with_sum_func && !const_item()) + if (!Item_subselect::with_sum_func() && !const_item()) return new (thd->mem_root) Item_temptable_field(thd_arg, result_field); return copy_or_same(thd_arg); } @@ -1142,7 +1147,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) if (!select_lex->master_unit()->is_unit_op() && !select_lex->table_list.elements && select_lex->item_list.elements == 1 && - !select_lex->item_list.head()->with_sum_func && + !select_lex->item_list.head()->with_sum_func() && /* We cant change name of Item_field or Item_ref, because it will prevent it's correct resolving, but we should save name of @@ -1407,6 +1412,8 @@ Item_exists_subselect::Item_exists_subselect(THD *thd, emb_on_expr_nest(NULL), optimizer(0), exists_transformed(0) { DBUG_ENTER("Item_exists_subselect::Item_exists_subselect"); + + init(select_lex, new (thd->mem_root) select_exists_subselect(thd, this)); max_columns= UINT_MAX; null_value= FALSE; //can't be NULL @@ -1449,6 +1456,7 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp, { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); DBUG_PRINT("info", ("in_strategy: %u", (uint)in_strategy)); + left_expr_orig= left_expr= left_exp; /* prepare to possible disassembling the item in convert_subq_to_sj() */ if (left_exp->type() == Item::ROW_ITEM) @@ -2039,7 +2047,7 @@ bool Item_in_subselect::fix_having(Item *having, SELECT_LEX *select_lex) { bool fix_res= 0; DBUG_ASSERT(thd); - if (!having->fixed) + if (!having->is_fixed()) { select_lex->having_fix_field= 1; fix_res= having->fix_fields(thd, 0); @@ -2376,9 +2384,9 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join, Item *item_having_part2= 0; for (uint i= 0; i < cols_num; i++) { - DBUG_ASSERT((left_expr->fixed && + DBUG_ASSERT((left_expr->is_fixed() && - select_lex->ref_pointer_array[i]->fixed) || + select_lex->ref_pointer_array[i]->is_fixed()) || (select_lex->ref_pointer_array[i]->type() == REF_ITEM && ((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() == Item_ref::OUTER_REF)); @@ -2447,8 +2455,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join, for (uint i= 0; i < cols_num; i++) { Item *item, *item_isnull; - DBUG_ASSERT((left_expr->fixed && - select_lex->ref_pointer_array[i]->fixed) || + DBUG_ASSERT((left_expr->is_fixed() && + select_lex->ref_pointer_array[i]->is_fixed()) || (select_lex->ref_pointer_array[i]->type() == REF_ITEM && ((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() == Item_ref::OUTER_REF)); @@ -5802,14 +5810,14 @@ Ordered_key::cmp_keys_by_row_data(ha_rows a, ha_rows b) if (unlikely((error= tbl->file->ha_rnd_pos(tbl->record[0], rowid_a)))) { /* purecov: begin inspected */ - tbl->file->print_error(error, MYF(ME_FATALERROR)); // Sets fatal_error + tbl->file->print_error(error, MYF(ME_FATAL)); // Sets fatal_error return 0; /* purecov: end */ } if (unlikely((error= tbl->file->ha_rnd_pos(tbl->record[1], rowid_b)))) { /* purecov: begin inspected */ - tbl->file->print_error(error, MYF(ME_FATALERROR)); // Sets fatal_error + tbl->file->print_error(error, MYF(ME_FATAL)); // Sets fatal_error return 0; /* purecov: end */ } @@ -5891,7 +5899,7 @@ int Ordered_key::cmp_key_with_search_key(rownum_t row_num) if (unlikely((error= tbl->file->ha_rnd_pos(tbl->record[0], cur_rowid)))) { /* purecov: begin inspected */ - tbl->file->print_error(error, MYF(ME_FATALERROR)); // Sets fatal_error + tbl->file->print_error(error, MYF(ME_FATAL)); // Sets fatal_error return 0; /* purecov: end */ } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 363dbba4ddd..4980709b979 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -33,6 +33,7 @@ class subselect_hash_sj_engine; class Item_bool_func2; class Comp_creator; class With_element; +class Field_pair; typedef class st_select_lex SELECT_LEX; @@ -46,7 +47,8 @@ class Cached_item; /* base class for subselects */ class Item_subselect :public Item_result_field, - protected Used_tables_and_const_cache + protected Used_tables_and_const_cache, + protected With_sum_func_cache { bool value_assigned; /* value already assigned to subselect */ bool own_engine; /* the engine was not taken from other Item_subselect */ @@ -183,6 +185,8 @@ public: } bool fix_fields(THD *thd, Item **ref); bool with_subquery() const { DBUG_ASSERT(fixed); return true; } + bool with_sum_func() const { return m_with_sum_func; } + With_sum_func_cache* get_with_sum_func_cache() { return this; } bool mark_as_dependent(THD *thd, st_select_lex *select, Item *item); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void recalc_used_tables(st_select_lex *new_parent, bool after_pullout); @@ -395,7 +399,7 @@ public: } void no_rows_in_result(); - const Type_handler *type_handler() const { return &type_handler_longlong; } + const Type_handler *type_handler() const { return &type_handler_bool; } longlong val_int(); double val_real(); String *val_str(String*); @@ -570,6 +574,8 @@ public: */ bool is_registered_semijoin; + List<Field_pair> corresponding_fields; + /* Used to determine how this subselect item is represented in the item tree, in case there is a need to locate it there and replace with something else. @@ -621,7 +627,6 @@ public: double val_real(); String *val_str(String*); my_decimal *val_decimal(my_decimal *); - void update_null_value () { (void) val_bool(); } bool val_bool(); bool test_limit(st_select_lex_unit *unit); void print(String *str, enum_query_type query_type); @@ -741,6 +746,8 @@ public: return 0; }; + bool pushdown_cond_for_in_subquery(THD *thd, Item *cond); + friend class Item_ref_null_helper; friend class Item_is_not_null_test; friend class Item_in_optimizer; @@ -852,7 +859,6 @@ protected: bool set_row(List<Item> &item_list, Item_cache **row); }; - class subselect_single_select_engine: public subselect_engine { bool prepared; /* simple subselect is prepared */ @@ -886,9 +892,10 @@ public: friend class subselect_hash_sj_engine; friend class Item_in_subselect; - friend bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, - Item **join_where); - + friend bool execute_degenerate_jtbm_semi_join(THD *thd, + TABLE_LIST *tbl, + Item_in_subselect *subq_pred, + List<Item> &eq_list); }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 3163fb9ea2e..98a3f6116a6 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -404,7 +404,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref) for (sl= thd->lex->current_select; sl && sl != aggr_sel && sl->master_unit()->item; sl= sl->master_unit()->outer_select() ) - sl->master_unit()->item->with_sum_func= 1; + sl->master_unit()->item->get_with_sum_func_cache()->set_with_sum_func(); } thd->lex->current_select->mark_as_dependent(thd, aggr_sel, NULL); @@ -484,7 +484,6 @@ void Item_sum::mark_as_sum_func() cur_select->n_sum_items++; cur_select->with_sum_func= 1; const_item_cache= false; - with_sum_func= 1; with_field= 0; window_func_sum_expr_flag= false; } @@ -890,7 +889,7 @@ bool Aggregator_distinct::setup(THD *thd) item_sum->null_value= item_sum->maybe_null= 1; item_sum->quick_group= 0; - DBUG_ASSERT(item_sum->get_arg(0)->fixed); + DBUG_ASSERT(item_sum->get_arg(0)->is_fixed()); arg= item_sum->get_arg(0); if (arg->const_item()) @@ -1237,9 +1236,11 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table) if (args[0]->type() == Item::FIELD_ITEM) { Field *field= ((Item_field*) args[0])->field; - if ((field= create_tmp_field_from_field(table->in_use, field, &name, - table, NULL))) - field->flags&= ~NOT_NULL_FLAG; + if ((field= field->create_tmp_field(table->in_use->mem_root, table, true))) + { + DBUG_ASSERT((field->flags & NOT_NULL_FLAG) == 0); + field->field_name= name; + } DBUG_RETURN(field); } DBUG_RETURN(tmp_table_field_from_field_type(table)); @@ -1287,7 +1288,7 @@ Item_sum_sp::fix_fields(THD *thd, Item **ref) if (!m_sp) { my_missing_function_error(m_name->m_name, ErrConvDQName(m_name).ptr()); - context->process_error(thd); + process_error(thd); return TRUE; } @@ -1639,12 +1640,7 @@ longlong Item_sum_sum::val_int() if (aggr) aggr->endup(); if (result_type() == DECIMAL_RESULT) - { - longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, unsigned_flag, - &result); - return result; - } + return dec_buffs[curr_dec_buff].to_longlong(unsigned_flag); return val_int_from_real(); } @@ -1655,7 +1651,7 @@ double Item_sum_sum::val_real() if (aggr) aggr->endup(); if (result_type() == DECIMAL_RESULT) - my_decimal2double(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, &sum); + sum= dec_buffs[curr_dec_buff].to_double(); return sum; } @@ -1665,7 +1661,7 @@ String *Item_sum_sum::val_str(String *str) if (aggr) aggr->endup(); if (result_type() == DECIMAL_RESULT) - return val_string_from_decimal(str); + return VDec(this).to_string_round(str, decimals); return val_string_from_real(str); } @@ -2031,7 +2027,7 @@ String *Item_sum_avg::val_str(String *str) if (aggr) aggr->endup(); if (result_type() == DECIMAL_RESULT) - return val_string_from_decimal(str); + return VDec(this).to_string_round(str, decimals); return val_string_from_real(str); } @@ -2748,11 +2744,11 @@ void Item_sum_hybrid::reset_field() } case DECIMAL_RESULT: { - my_decimal value_buff, *arg_dec= arg0->val_decimal(&value_buff); + VDec arg_dec(arg0); if (maybe_null) { - if (arg0->null_value) + if (arg_dec.is_null()) result_field->set_null(); else result_field->set_notnull(); @@ -2761,9 +2757,7 @@ void Item_sum_hybrid::reset_field() We must store zero in the field as we will use the field value in add() */ - if (!arg_dec) // Null - arg_dec= &decimal_zero; - result_field->store_decimal(arg_dec); + result_field->store_decimal(arg_dec.ptr_or(&decimal_zero)); break; } case ROW_RESULT: @@ -2786,15 +2780,10 @@ void Item_sum_sum::reset_field() DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR); if (result_type() == DECIMAL_RESULT) { - my_decimal value, *arg_val; if (unlikely(direct_added)) - arg_val= &direct_sum_decimal; + result_field->store_decimal(&direct_sum_decimal); else - { - if (!(arg_val= args[0]->val_decimal(&value))) - arg_val= &decimal_zero; // Null - } - result_field->store_decimal(arg_val); + result_field->store_decimal(VDec(args[0]).ptr_or(&decimal_zero)); } else { @@ -2847,15 +2836,9 @@ void Item_sum_avg::reset_field() if (result_type() == DECIMAL_RESULT) { longlong tmp; - my_decimal value, *arg_dec= args[0]->val_decimal(&value); - if (args[0]->null_value) - { - arg_dec= &decimal_zero; - tmp= 0; - } - else - tmp= 1; - my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, res, f_precision, f_scale); + VDec value(args[0]); + tmp= value.is_null() ? 0 : 1; + value.to_binary(res, f_precision, f_scale); res+= dec_bin_size; int8store(res, tmp); } @@ -2922,9 +2905,8 @@ void Item_sum_sum::update_field() { if (!result_field->is_null()) { - my_decimal field_value; - my_decimal *field_val= result_field->val_decimal(&field_value); - my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, field_val); + my_decimal field_value(result_field); + my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, &field_value); result_field->store_decimal(dec_buffs); } else @@ -2991,15 +2973,14 @@ void Item_sum_avg::update_field() if (result_type() == DECIMAL_RESULT) { - my_decimal value, *arg_val= args[0]->val_decimal(&value); - if (!args[0]->null_value) + VDec tmp(args[0]); + if (!tmp.is_null()) { binary2my_decimal(E_DEC_FATAL_ERROR, res, dec_buffs + 1, f_precision, f_scale); field_count= sint8korr(res + dec_bin_size); - my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, dec_buffs + 1); - my_decimal2binary(E_DEC_FATAL_ERROR, dec_buffs, - res, f_precision, f_scale); + my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, tmp.ptr(), dec_buffs + 1); + dec_buffs->to_binary(res, f_precision, f_scale); res+= dec_bin_size; field_count++; int8store(res, field_count); @@ -3194,9 +3175,7 @@ my_decimal *Item_avg_field_decimal::val_decimal(my_decimal *dec_buf) if ((null_value= !count)) return 0; - my_decimal dec_count, dec_field; - binary2my_decimal(E_DEC_FATAL_ERROR, - field->ptr, &dec_field, f_precision, f_scale); + my_decimal dec_count, dec_field(field->ptr, f_precision, f_scale); int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count); my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_field, &dec_count, prec_increment); @@ -3310,24 +3289,6 @@ my_decimal *Item_sum_udf_float::val_decimal(my_decimal *dec) } -String *Item_sum_udf_decimal::val_str(String *str) -{ - return val_string_from_decimal(str); -} - - -double Item_sum_udf_decimal::val_real() -{ - return val_real_from_decimal(); -} - - -longlong Item_sum_udf_decimal::val_int() -{ - return val_int_from_decimal(); -} - - my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf) { my_decimal *res; @@ -4008,6 +3969,7 @@ bool Item_func_group_concat::setup(THD *thd) if (!ref_pointer_array) DBUG_RETURN(TRUE); memcpy(ref_pointer_array, args, arg_count * sizeof(Item*)); + DBUG_ASSERT(context); if (setup_order(thd, Ref_ptr_array(ref_pointer_array, n_elems), context->table_list, list, all_fields, *order)) DBUG_RETURN(TRUE); diff --git a/sql/item_sum.h b/sql/item_sum.h index b400ebd5f80..fe055673328 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -511,7 +511,12 @@ public: } virtual void make_unique() { force_copy_fields= TRUE; } Item *get_tmp_table_item(THD *thd); - Field *create_tmp_field(bool group, TABLE *table); + virtual Field *create_tmp_field(bool group, TABLE *table); + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + return create_tmp_field(param->group(), table); + } virtual bool collect_outer_ref_processor(void *param); bool init_sum_func_check(THD *thd); bool check_sum_func(THD *thd, Item **ref); @@ -578,6 +583,8 @@ public: void mark_as_window_func_sum_expr() { window_func_sum_expr_flag= true; } bool is_window_func_sum_expr() { return window_func_sum_expr_flag; } virtual void setup_caches(THD *thd) {}; + + bool with_sum_func() const { return true; } }; @@ -1384,9 +1391,13 @@ public: decimals= item->decimals; max_length= item->max_length; unsigned_flag= item->unsigned_flag; - fixed= true; } table_map used_tables() const { return (table_map) 1L; } + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + return create_tmp_field_ex_simple(table, src, param); + } void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); } bool check_vcol_func_processor(void *arg) { @@ -1439,9 +1450,18 @@ public: dec_bin_size(item->dec_bin_size) { } const Type_handler *type_handler() const { return &type_handler_newdecimal; } - double val_real() { return val_real_from_decimal(); } - longlong val_int() { return val_int_from_decimal(); } - String *val_str(String *str) { return val_string_from_decimal(str); } + double val_real() + { + return VDec(this).to_double(); + } + longlong val_int() + { + return VDec(this).to_longlong(unsigned_flag); + } + String *val_str(String *str) + { + return VDec(this).to_string_round(str, decimals); + } my_decimal *val_decimal(my_decimal *); Item *get_copy(THD *thd) { return get_item_copy<Item_avg_field_decimal>(thd, this); } @@ -1645,9 +1665,18 @@ public: Item_udf_sum(thd, udf_arg, list) {} Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item) :Item_udf_sum(thd, item) {} - String *val_str(String *); - double val_real(); - longlong val_int(); + String *val_str(String *str) + { + return VDec(this).to_string_round(str, decimals); + } + double val_real() + { + return VDec(this).to_double(); + } + longlong val_int() + { + return VDec(this).to_longlong(unsigned_flag); + } my_decimal *val_decimal(my_decimal *); const Type_handler *type_handler() const { return &type_handler_newdecimal; } bool fix_length_and_dec() { fix_num_length_and_dec(); return FALSE; } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d29181a3446..84db154566a 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -58,6 +58,29 @@ /** Day number for Dec 31st, 9999. */ #define MAX_DAY_NUMBER 3652424L + +Func_handler_date_add_interval_datetime_arg0_time + func_handler_date_add_interval_datetime_arg0_time; + +Func_handler_date_add_interval_datetime func_handler_date_add_interval_datetime; +Func_handler_date_add_interval_date func_handler_date_add_interval_date; +Func_handler_date_add_interval_time func_handler_date_add_interval_time; +Func_handler_date_add_interval_string func_handler_date_add_interval_string; + +Func_handler_add_time_datetime func_handler_add_time_datetime_add(1); +Func_handler_add_time_datetime func_handler_add_time_datetime_sub(-1); +Func_handler_add_time_time func_handler_add_time_time_add(1); +Func_handler_add_time_time func_handler_add_time_time_sub(-1); +Func_handler_add_time_string func_handler_add_time_string_add(1); +Func_handler_add_time_string func_handler_add_time_string_sub(-1); + +Func_handler_str_to_date_datetime_sec func_handler_str_to_date_datetime_sec; +Func_handler_str_to_date_datetime_usec func_handler_str_to_date_datetime_usec; +Func_handler_str_to_date_date func_handler_str_to_date_date; +Func_handler_str_to_date_time_sec func_handler_str_to_date_time_sec; +Func_handler_str_to_date_time_usec func_handler_str_to_date_time_usec; + + /* Date formats corresponding to compound %r and %T conversion specifiers @@ -427,10 +450,10 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, { if (!my_isspace(&my_charset_latin1,*val)) { + ErrConvString err(val_begin, length, &my_charset_bin); make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, - val_begin, length, - cached_timestamp_type, NullS); + &err, cached_timestamp_type, NullS); break; } } while (++val != val_end); @@ -1311,25 +1334,19 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval) bzero((char*) interval,sizeof(*interval)); if (int_type == INTERVAL_SECOND && args->decimals) { - my_decimal decimal_value, *val; - ulonglong second; - ulong second_part; - if (!(val= args->val_decimal(&decimal_value))) + VDec val(args); + if (val.is_null()) return true; - interval->neg= my_decimal2seconds(val, &second, &second_part); - if (second == LONGLONG_MAX) + Sec6 d(val.ptr()); + interval->neg= d.neg(); + if (d.sec() >= LONGLONG_MAX) { - THD *thd= current_thd; - ErrConvDecimal err(val); - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE, - ER_THD(thd, ER_TRUNCATED_WRONG_VALUE), "DECIMAL", - err.ptr()); + ErrConvDecimal err(val.ptr()); + current_thd->push_warning_truncated_wrong_value("seconds", err.ptr()); return true; } - - interval->second= second; - interval->second_part= second_part; + interval->second= d.sec(); + interval->second_part= d.usec(); return false; } else if ((int) int_type <= INTERVAL_MICROSECOND) @@ -1475,85 +1492,6 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval) } -String *Item_temporal_func::val_str(String *str) -{ - DBUG_ASSERT(fixed == 1); - return val_string_from_date(str); -} - - -bool Item_temporal_hybrid_func::fix_temporal_type(MYSQL_TIME *ltime) -{ - if (ltime->time_type < 0) /* MYSQL_TIMESTAMP_NONE, MYSQL_TIMESTAMP_ERROR */ - return false; - - if (ltime->time_type != MYSQL_TIMESTAMP_TIME) - goto date_or_datetime_value; - - /* Convert TIME to DATE or DATETIME */ - switch (field_type()) - { - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - { - MYSQL_TIME tmp; - if (time_to_datetime_with_warn(current_thd, ltime, &tmp, 0)) - return (null_value= true); - *ltime= tmp; - if (field_type() == MYSQL_TYPE_DATE) - datetime_to_date(ltime); - return false; - } - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_STRING: /* DATE_ADD, ADDTIME can return VARCHAR */ - return false; - default: - DBUG_ASSERT(0); - return (null_value= true); - } - -date_or_datetime_value: - /* Convert DATE or DATETIME to TIME, DATE, or DATETIME */ - switch (field_type()) - { - case MYSQL_TYPE_TIME: - datetime_to_time(ltime); - return false; - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - date_to_datetime(ltime); - return false; - case MYSQL_TYPE_DATE: - datetime_to_date(ltime); - return false; - case MYSQL_TYPE_STRING: /* DATE_ADD, ADDTIME can return VARCHAR */ - return false; - default: - DBUG_ASSERT(0); - return (null_value= true); - } - return false; -} - - -String *Item_temporal_hybrid_func::val_str_ascii(String *str) -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - - if (get_date(<ime, 0) || fix_temporal_type(<ime) || - (null_value= my_TIME_to_str(<ime, str, decimals))) - return (String *) 0; - - /* Check that the returned timestamp type matches to the function type */ - DBUG_ASSERT(field_type() == MYSQL_TYPE_STRING || - ltime.time_type == MYSQL_TIMESTAMP_NONE || - ltime.time_type == mysql_timestamp_type()); - return str; -} - - bool Item_func_from_days::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { longlong value=args[0]->val_int(); @@ -1699,7 +1637,7 @@ bool Item_func_now::fix_fields(THD *thd, Item **items) func_name(), TIME_SECOND_PART_DIGITS); return 1; } - return Item_temporal_func::fix_fields(thd, items); + return Item_datetimefunc::fix_fields(thd, items); } void Item_func_now::print(String *str, enum_query_type query_type) @@ -1726,7 +1664,7 @@ int Item_func_now_local::save_in_field(Field *field, bool no_conversions) return 0; } else - return Item_temporal_func::save_in_field(field, no_conversions); + return Item_datetimefunc::save_in_field(field, no_conversions); } @@ -1796,52 +1734,12 @@ bool Item_func_sysdate_local::get_date(MYSQL_TIME *res, bool Item_func_sec_to_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { DBUG_ASSERT(fixed == 1); - bool sign; - ulonglong sec; - ulong sec_part; - - bzero((char *)ltime, sizeof(*ltime)); - ltime->time_type= MYSQL_TIMESTAMP_TIME; - - sign= args[0]->get_seconds(&sec, &sec_part); - - if ((null_value= args[0]->null_value)) - return 1; - - ltime->neg= sign; - if (sec > TIME_MAX_VALUE_SECONDS) - goto overflow; - - DBUG_ASSERT(sec_part <= TIME_MAX_SECOND_PART); - - ltime->hour= (uint) (sec/3600); - ltime->minute= (uint) (sec % 3600) /60; - ltime->second= (uint) sec % 60; - ltime->second_part= sec_part; - - return 0; - -overflow: - /* use check_time_range() to set ltime to the max value depending on dec */ - int unused; - char buf[100]; - String tmp(buf, sizeof(buf), &my_charset_bin), *err= args[0]->val_str(&tmp); - - ltime->hour= TIME_MAX_HOUR+1; - check_time_range(ltime, decimals, &unused); - if (!err) - { - ErrConvInteger err2(sec, unsigned_flag); - make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, - &err2, MYSQL_TIMESTAMP_TIME, NullS); - } - else - { - ErrConvString err2(err); - make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, - &err2, MYSQL_TIMESTAMP_TIME, NullS); - } - return 0; + VSec6 sec(args[0], "seconds", LONGLONG_MAX); + if ((null_value= sec.is_null())) + return true; + if (sec.sec_to_time(ltime, decimals) && !sec.truncated()) + sec.make_truncated_warning(current_thd, "seconds"); + return false; } bool Item_func_date_format::fix_length_and_dec() @@ -2051,21 +1949,17 @@ bool Item_func_from_unixtime::fix_length_and_dec() bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date __attribute__((unused))) { - bool sign; - ulonglong sec; - ulong sec_part; - bzero((char *)ltime, sizeof(*ltime)); ltime->time_type= MYSQL_TIMESTAMP_TIME; - sign= args[0]->get_seconds(&sec, &sec_part); + VSec6 sec(args[0], "unixtime", TIMESTAMP_MAX_VALUE); + DBUG_ASSERT(sec.sec() <= TIMESTAMP_MAX_VALUE); - if (args[0]->null_value || sign || sec > TIMESTAMP_MAX_VALUE) + if (sec.is_null() || sec.truncated() || sec.neg()) return (null_value= 1); - tz->gmt_sec_to_TIME(ltime, (my_time_t)sec); - - ltime->second_part= sec_part; + tz->gmt_sec_to_TIME(ltime, (my_time_t) sec.sec()); + ltime->second_part= sec.usec(); return (null_value= 0); } @@ -2112,7 +2006,7 @@ bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime, void Item_func_convert_tz::cleanup() { from_tz_cached= to_tz_cached= 0; - Item_temporal_func::cleanup(); + Item_datetimefunc::cleanup(); } @@ -2143,81 +2037,44 @@ bool Item_date_add_interval::fix_length_and_dec() MYSQL_TIME or DATETIME argument) */ arg0_field_type= args[0]->field_type(); - uint interval_dec= 0; - if (int_type == INTERVAL_MICROSECOND || - (int_type >= INTERVAL_DAY_MICROSECOND && - int_type <= INTERVAL_SECOND_MICROSECOND)) - interval_dec= TIME_SECOND_PART_DIGITS; - else if (int_type == INTERVAL_SECOND && args[1]->decimals > 0) - interval_dec= MY_MIN(args[1]->decimals, TIME_SECOND_PART_DIGITS); if (arg0_field_type == MYSQL_TYPE_DATETIME || arg0_field_type == MYSQL_TYPE_TIMESTAMP) { - uint dec= MY_MAX(args[0]->datetime_precision(), interval_dec); - set_handler(&type_handler_datetime); - fix_attributes_datetime(dec); + set_func_handler(&func_handler_date_add_interval_datetime); } else if (arg0_field_type == MYSQL_TYPE_DATE) { if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH) - { - set_handler(&type_handler_newdate); - fix_attributes_date(); - } + set_func_handler(&func_handler_date_add_interval_date); else - { - set_handler(&type_handler_datetime2); - fix_attributes_datetime(interval_dec); - } + set_func_handler(&func_handler_date_add_interval_datetime); } else if (arg0_field_type == MYSQL_TYPE_TIME) { - uint dec= MY_MAX(args[0]->time_precision(), interval_dec); if (int_type >= INTERVAL_DAY && int_type != INTERVAL_YEAR_MONTH) - { - set_handler(&type_handler_time2); - fix_attributes_time(dec); - } + set_func_handler(&func_handler_date_add_interval_time); else - { - set_handler(&type_handler_datetime2); - fix_attributes_datetime(dec); - } + set_func_handler(&func_handler_date_add_interval_datetime_arg0_time); } else { - uint dec= MY_MAX(args[0]->datetime_precision(), interval_dec); - set_handler(&type_handler_string); - collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); - fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec); + set_func_handler(&func_handler_date_add_interval_string); } maybe_null= true; - return FALSE; + return m_func_handler->fix_length_and_dec(this); } -bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) +bool Func_handler_date_add_interval_datetime_arg0_time:: + get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const { - INTERVAL interval; - - if (args[0]->get_date(ltime, - field_type() == MYSQL_TYPE_TIME ? - TIME_TIME_ONLY : 0) || - get_interval_value(args[1], int_type, &interval)) - return (null_value=1); - - if (ltime->time_type != MYSQL_TIMESTAMP_TIME && - check_date_with_warn(ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE, - MYSQL_TIMESTAMP_ERROR)) - return (null_value=1); - - if (date_sub_interval) - interval.neg = !interval.neg; - - if (date_add_interval(ltime, int_type, interval)) - return (null_value=1); - return (null_value= 0); + THD *thd= current_thd; + // time_expr + INTERVAL {YEAR|QUARTER|MONTH|WEEK|YEAR_MONTH} + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_DATETIME_FUNCTION_OVERFLOW, + ER_THD(thd, ER_DATETIME_FUNCTION_OVERFLOW), "time"); + return (item->null_value= true); } @@ -2395,13 +2252,14 @@ bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const return 1; } -void Item_temporal_typecast::print(String *str, enum_query_type query_type) +void Item_func::print_cast_temporal(String *str, enum_query_type query_type) { char buf[32]; str->append(STRING_WITH_LEN("cast(")); args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as ")); - str->append(cast_type()); + const Name name= type_handler()->name(); + str->append(name.ptr(), name.length()); if (decimals && decimals != NOT_FIXED_DEC) { str->append('('); @@ -2670,17 +2528,14 @@ bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) bool Item_func_makedate::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { DBUG_ASSERT(fixed == 1); - long daynr= (long) args[1]->val_int(); - long year= (long) args[0]->val_int(); - long days; + long year, days, daynr= (long) args[1]->val_int(); - if (args[0]->null_value || args[1]->null_value || - year < 0 || year > 9999 || daynr <= 0) + VYear vyear(args[0]); + if (vyear.is_null() || args[1]->null_value || vyear.truncated() || daynr <= 0) goto err; - if (year < 100) + if ((year= (long) vyear.year()) < 100) year= year_2000_handling(year); - days= calc_daynr(year,1,1) + daynr - 1; if (get_date_from_daynr(days, <ime->year, <ime->month, <ime->day)) goto err; @@ -2719,101 +2574,24 @@ bool Item_func_add_time::fix_length_and_dec() arg0_field_type= args[0]->field_type(); if (arg0_field_type == MYSQL_TYPE_DATE || arg0_field_type == MYSQL_TYPE_DATETIME || - arg0_field_type == MYSQL_TYPE_TIMESTAMP || - is_date) + arg0_field_type == MYSQL_TYPE_TIMESTAMP) { - uint dec= MY_MAX(args[0]->datetime_precision(), args[1]->time_precision()); - set_handler(&type_handler_datetime2); - fix_attributes_datetime(dec); + set_func_handler(sign > 0 ? &func_handler_add_time_datetime_add : + &func_handler_add_time_datetime_sub); } else if (arg0_field_type == MYSQL_TYPE_TIME) { - uint dec= MY_MAX(args[0]->time_precision(), args[1]->time_precision()); - set_handler(&type_handler_time2); - fix_attributes_time(dec); + set_func_handler(sign > 0 ? &func_handler_add_time_time_add : + &func_handler_add_time_time_sub); } else { - uint dec= MY_MAX(args[0]->decimals, args[1]->decimals); - set_handler(&type_handler_string); - collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); - fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec); + set_func_handler(sign > 0 ? &func_handler_add_time_string_add : + &func_handler_add_time_string_sub); } - maybe_null= true; - return FALSE; -} - -/** - ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a - time/datetime value - - t: time_or_datetime_expression - a: time_expression - - Result: Time value or datetime value -*/ -bool Item_func_add_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME l_time1, l_time2; - bool is_time= 0; - long days, microseconds; - longlong seconds; - int l_sign= sign; - - if (Item_func_add_time::field_type() == MYSQL_TYPE_DATETIME) - { - // TIMESTAMP function OR the first argument is DATE/DATETIME/TIMESTAMP - if (get_arg0_date(&l_time1, 0) || - args[1]->get_time(&l_time2) || - l_time1.time_type == MYSQL_TIMESTAMP_TIME || - l_time2.time_type != MYSQL_TIMESTAMP_TIME) - return (null_value= 1); - } - else - { - // ADDTIME function AND the first argument is TIME - if (args[0]->get_time(&l_time1) || - args[1]->get_time(&l_time2) || - l_time2.time_type != MYSQL_TIMESTAMP_TIME) - return (null_value= 1); - is_time= (l_time1.time_type == MYSQL_TIMESTAMP_TIME); - } - if (l_time1.neg != l_time2.neg) - l_sign= -l_sign; - - bzero(ltime, sizeof(*ltime)); - - ltime->neg= calc_time_diff(&l_time1, &l_time2, -l_sign, - &seconds, µseconds); - - /* - If first argument was negative and diff between arguments - is non-zero we need to swap sign to get proper result. - */ - if (l_time1.neg && (seconds || microseconds)) - ltime->neg= 1-ltime->neg; // Swap sign of result - - if (!is_time && ltime->neg) - return (null_value= 1); - - days= (long) (seconds / SECONDS_IN_24H); - - calc_time_from_sec(ltime, (long)(seconds % SECONDS_IN_24H), microseconds); - - ltime->time_type= is_time ? MYSQL_TIMESTAMP_TIME : MYSQL_TIMESTAMP_DATETIME; - - if (!is_time) - { - if (get_date_from_daynr(days,<ime->year,<ime->month,<ime->day) || - !ltime->day) - return (null_value= 1); - return (null_value= 0); - } - - ltime->hour+= days*24; - return (null_value= adjust_time_range_with_warn(ltime, decimals)); + maybe_null= true; + return m_func_handler->fix_length_and_dec(this); } @@ -2863,12 +2641,11 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) bool overflow= 0; longlong hour= args[0]->val_int(); longlong minute= args[1]->val_int(); - ulonglong second; - ulong microsecond; - bool neg= args[2]->get_seconds(&second, µsecond); + VSec6 sec(args[2], "seconds", 59); - if (args[0]->null_value || args[1]->null_value || args[2]->null_value || - minute < 0 || minute > 59 || neg || second > 59) + DBUG_ASSERT(sec.sec() <= 59); + if (args[0]->null_value || args[1]->null_value || sec.is_null() || + minute < 0 || minute > 59 || sec.neg() || sec.truncated()) return (null_value= 1); bzero(ltime, sizeof(*ltime)); @@ -2889,8 +2666,8 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { ltime->hour= (uint) ((hour < 0 ? -hour : hour)); ltime->minute= (uint) minute; - ltime->second= (uint) second; - ltime->second_part= microsecond; + ltime->second= (uint) sec.sec(); + ltime->second_part= sec.usec(); } else { @@ -2899,10 +2676,10 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) ltime->second= TIME_MAX_SECOND; char buf[28]; char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10); - int len = (int)(ptr - buf) + sprintf(ptr, ":%02u:%02u", (uint)minute, (uint)second); - make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, - buf, len, MYSQL_TIMESTAMP_TIME, - NullS); + int len = (int)(ptr - buf) + sprintf(ptr, ":%02u:%02u", + (uint) minute, (uint) sec.sec()); + ErrConvString err(buf, len, &my_charset_bin); + current_thd->push_warning_truncated_wrong_value("time", err.ptr()); } return (null_value= 0); @@ -2929,8 +2706,8 @@ longlong Item_func_microsecond::val_int() longlong Item_func_timestamp_diff::val_int() { MYSQL_TIME ltime1, ltime2; - longlong seconds; - long microseconds; + ulonglong seconds; + ulong microseconds; long months= 0; int neg= 1; THD *thd= current_thd; @@ -3009,21 +2786,21 @@ longlong Item_func_timestamp_diff::val_int() case INTERVAL_MONTH: return months*neg; case INTERVAL_WEEK: - return seconds / SECONDS_IN_24H / 7L * neg; + return ((longlong) (seconds / SECONDS_IN_24H / 7L)) * neg; case INTERVAL_DAY: - return seconds / SECONDS_IN_24H * neg; + return ((longlong) (seconds / SECONDS_IN_24H)) * neg; case INTERVAL_HOUR: - return seconds/3600L*neg; + return ((longlong) (seconds / 3600L)) * neg; case INTERVAL_MINUTE: - return seconds/60L*neg; + return ((longlong) (seconds / 60L)) * neg; case INTERVAL_SECOND: - return seconds*neg; + return ((longlong) seconds) * neg; case INTERVAL_MICROSECOND: /* In MySQL difference between any two valid datetime values in microseconds fits into longlong. */ - return (seconds*1000000L+microseconds)*neg; + return ((longlong) ((ulonglong) seconds * 1000000L + microseconds)) * neg; default: break; } @@ -3153,15 +2930,10 @@ void Item_func_get_format::print(String *str, enum_query_type query_type) specifiers supported by extract_date_time() function. @return - One of date_time_format_types values: - - DATE_TIME_MICROSECOND - - DATE_TIME - - DATE_ONLY - - TIME_MICROSECOND - - TIME_ONLY + A function handler corresponding the given format */ -static date_time_format_types +static const Item_handled_func::Handler * get_date_time_result_type(const char *format, uint length) { const char *time_part_frms= "HISThiklrs"; @@ -3188,21 +2960,21 @@ get_date_time_result_type(const char *format, uint length) frac_second_used implies time_part_used, and thus we already have all types of date-time components and can end our search. */ - return DATE_TIME_MICROSECOND; + return &func_handler_str_to_date_datetime_usec; } } } /* We don't have all three types of date-time components */ if (frac_second_used) - return TIME_MICROSECOND; + return &func_handler_str_to_date_time_usec; if (time_part_used) { if (date_part_used) - return DATE_TIME; - return TIME_ONLY; + return &func_handler_str_to_date_datetime_sec; + return &func_handler_str_to_date_time_sec; } - return DATE_ONLY; + return &func_handler_str_to_date_date; } @@ -3222,56 +2994,27 @@ bool Item_func_str_to_date::fix_length_and_dec() internal_charset= &my_charset_utf8mb4_general_ci; maybe_null= true; - set_handler(&type_handler_datetime2); - fix_attributes_datetime(TIME_SECOND_PART_DIGITS); + set_func_handler(&func_handler_str_to_date_datetime_usec); if ((const_item= args[1]->const_item())) { - char format_buff[64]; - String format_str(format_buff, sizeof(format_buff), &my_charset_bin); + StringBuffer<64> format_str; String *format= args[1]->val_str(&format_str, &format_converter, internal_charset); - decimals= 0; if (!args[1]->null_value) - { - date_time_format_types cached_format_type= - get_date_time_result_type(format->ptr(), format->length()); - switch (cached_format_type) { - case DATE_ONLY: - set_handler(&type_handler_newdate); - fix_attributes_date(); - break; - case TIME_MICROSECOND: - set_handler(&type_handler_time2); - fix_attributes_time(TIME_SECOND_PART_DIGITS); - break; - case TIME_ONLY: - set_handler(&type_handler_time2); - fix_attributes_time(0); - break; - case DATE_TIME_MICROSECOND: - set_handler(&type_handler_datetime2); - fix_attributes_datetime(TIME_SECOND_PART_DIGITS); - break; - case DATE_TIME: - set_handler(&type_handler_datetime2); - fix_attributes_datetime(0); - break; - } - } + set_func_handler(get_date_time_result_type(format->ptr(), format->length())); } - cached_timestamp_type= mysql_timestamp_type(); - return FALSE; + return m_func_handler->fix_length_and_dec(this); } -bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) +bool Item_func_str_to_date::get_date_common(MYSQL_TIME *ltime, + ulonglong fuzzy_date, + timestamp_type tstype) { DATE_TIME_FORMAT date_time_format; - char val_buff[64], format_buff[64]; - String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val; - String format_str(format_buff, sizeof(format_buff), &my_charset_bin), - *format; + StringBuffer<64> val_string, format_str; + String *val, *format; val= args[0]->val_str(&val_string, &subject_converter, internal_charset); format= args[1]->val_str(&format_str, &format_converter, internal_charset); @@ -3281,19 +3024,9 @@ bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) date_time_format.format.str= (char*) format->ptr(); date_time_format.format.length= format->length(); if (extract_date_time(&date_time_format, val->ptr(), val->length(), - ltime, cached_timestamp_type, 0, "datetime", + ltime, tstype, 0, "datetime", fuzzy_date | sql_mode_for_dates(current_thd))) return (null_value=1); - if (cached_timestamp_type == MYSQL_TIMESTAMP_TIME && ltime->day) - { - /* - Day part for time type can be nonzero value and so - we should add hours from day part to hour part to - keep valid time value. - */ - ltime->hour+= ltime->day*24; - ltime->day= 0; - } return (null_value= 0); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 7aacdec85e0..f9709b8f72a 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -25,11 +25,6 @@ class MY_LOCALE; -enum date_time_format_types -{ - TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND -}; - bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval); @@ -586,66 +581,17 @@ public: }; -class Item_temporal_func: public Item_func -{ -public: - Item_temporal_func(THD *thd): Item_func(thd) {} - Item_temporal_func(THD *thd, Item *a): Item_func(thd, a) {} - Item_temporal_func(THD *thd, Item *a, Item *b): Item_func(thd, a, b) {} - Item_temporal_func(THD *thd, Item *a, Item *b, Item *c): Item_func(thd, a, b, c) {} - String *val_str(String *str); - longlong val_int() { return val_int_from_date(); } - double val_real() { return val_real_from_date(); } - 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); } -}; - - -/** - Abstract class for functions returning TIME, DATE, DATETIME or string values, - whose data type depends on parameters and is set at fix_fields time. -*/ -class Item_temporal_hybrid_func: public Item_hybrid_func -{ -protected: - String ascii_buf; // Conversion buffer -public: - Item_temporal_hybrid_func(THD *thd, Item *a, Item *b): - Item_hybrid_func(thd, a, b) {} - - longlong val_int() { return val_int_from_date(); } - double val_real() { return val_real_from_date(); } - bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date)= 0; - my_decimal *val_decimal(my_decimal *decimal_value) - { return val_decimal_from_date(decimal_value); } - - /** - Fix the returned timestamp to match field_type(), - which is important for val_str(). - */ - bool fix_temporal_type(MYSQL_TIME *ltime); - /** - Return string value in ASCII character set. - */ - String *val_str_ascii(String *str); - /** - Return string value in @@character_set_connection. - */ - String *val_str(String *str) - { - return val_str_from_val_str_ascii(str, &ascii_buf); - } -}; - - -class Item_datefunc :public Item_temporal_func +class Item_datefunc :public Item_func { public: - Item_datefunc(THD *thd): Item_temporal_func(thd) { } - Item_datefunc(THD *thd, Item *a): Item_temporal_func(thd, a) { } - Item_datefunc(THD *thd, Item *a, Item *b): Item_temporal_func(thd, a, b) { } + Item_datefunc(THD *thd): Item_func(thd) { } + Item_datefunc(THD *thd, Item *a): Item_func(thd, a) { } + Item_datefunc(THD *thd, Item *a, Item *b): Item_func(thd, a, b) { } const Type_handler *type_handler() const { return &type_handler_newdate; } + longlong val_int() { return Date(this).to_longlong(); } + double val_real() { return Date(this).to_double(); } + String *val_str(String *to) { return Date(this).to_string(to); } + my_decimal *val_decimal(my_decimal *to) { return Date(this).to_decimal(to); } bool fix_length_and_dec() { fix_attributes_date(); @@ -655,26 +601,34 @@ public: }; -class Item_timefunc :public Item_temporal_func +class Item_timefunc :public Item_func { public: - Item_timefunc(THD *thd): Item_temporal_func(thd) {} - Item_timefunc(THD *thd, Item *a): Item_temporal_func(thd, a) {} - Item_timefunc(THD *thd, Item *a, Item *b): Item_temporal_func(thd, a, b) {} - Item_timefunc(THD *thd, Item *a, Item *b, Item *c): - Item_temporal_func(thd, a, b ,c) {} + Item_timefunc(THD *thd): Item_func(thd) {} + Item_timefunc(THD *thd, Item *a): Item_func(thd, a) {} + Item_timefunc(THD *thd, Item *a, Item *b): Item_func(thd, a, b) {} + Item_timefunc(THD *thd, Item *a, Item *b, Item *c): Item_func(thd, a, b ,c) {} const Type_handler *type_handler() const { return &type_handler_time2; } + longlong val_int() { return Time(this).to_longlong(); } + double val_real() { return Time(this).to_double(); } + String *val_str(String *to) { return Time(this).to_string(to, decimals); } + my_decimal *val_decimal(my_decimal *to) { return Time(this).to_decimal(to); } }; -class Item_datetimefunc :public Item_temporal_func +class Item_datetimefunc :public Item_func { public: - Item_datetimefunc(THD *thd): Item_temporal_func(thd) {} - Item_datetimefunc(THD *thd, Item *a): Item_temporal_func(thd, a) {} + Item_datetimefunc(THD *thd): Item_func(thd) {} + Item_datetimefunc(THD *thd, Item *a): Item_func(thd, a) {} + Item_datetimefunc(THD *thd, Item *a, Item *b): Item_func(thd, a, b) {} Item_datetimefunc(THD *thd, Item *a, Item *b, Item *c): - Item_temporal_func(thd, a, b ,c) {} + Item_func(thd, a, b ,c) {} const Type_handler *type_handler() const { return &type_handler_datetime2; } + longlong val_int() { return Datetime(this).to_longlong(); } + double val_real() { return Datetime(this).to_double(); } + String *val_str(String *to) { return Datetime(this).to_string(to, decimals); } + my_decimal *val_decimal(my_decimal *to) { return Datetime(this).to_decimal(to); } }; @@ -988,18 +942,17 @@ public: }; -class Item_date_add_interval :public Item_temporal_hybrid_func +class Item_date_add_interval :public Item_handled_func { public: const interval_type int_type; // keep it public const bool date_sub_interval; // keep it public Item_date_add_interval(THD *thd, Item *a, Item *b, interval_type type_arg, bool neg_arg): - Item_temporal_hybrid_func(thd, a, b),int_type(type_arg), + Item_handled_func(thd, a, b), int_type(type_arg), date_sub_interval(neg_arg) {} const char *func_name() const { return "date_add_interval"; } bool fix_length_and_dec(); - bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); bool eq(const Item *item, bool binary_cmp) const; void print(String *str, enum_query_type query_type); enum precedence precedence() const { return ADDINTERVAL_PRECEDENCE; } @@ -1157,22 +1110,16 @@ public: }; -class Item_temporal_typecast: public Item_temporal_func -{ -public: - Item_temporal_typecast(THD *thd, Item *a): Item_temporal_func(thd, a) {} - virtual const char *cast_type() const = 0; - void print(String *str, enum_query_type query_type); -}; - -class Item_date_typecast :public Item_temporal_typecast +class Item_date_typecast :public Item_datefunc { public: - Item_date_typecast(THD *thd, Item *a): Item_temporal_typecast(thd, a) {} + Item_date_typecast(THD *thd, Item *a): Item_datefunc(thd, a) {} const char *func_name() const { return "cast_as_date"; } + void print(String *str, enum_query_type query_type) + { + print_cast_temporal(str, query_type); + } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); - const char *cast_type() const { return "date"; } - const Type_handler *type_handler() const { return &type_handler_newdate; } bool fix_length_and_dec() { return args[0]->type_handler()->Item_date_typecast_fix_length_and_dec(this); @@ -1182,15 +1129,17 @@ public: }; -class Item_time_typecast :public Item_temporal_typecast +class Item_time_typecast :public Item_timefunc { public: Item_time_typecast(THD *thd, Item *a, uint dec_arg): - Item_temporal_typecast(thd, a) { decimals= dec_arg; } + Item_timefunc(thd, a) { decimals= dec_arg; } const char *func_name() const { return "cast_as_time"; } + void print(String *str, enum_query_type query_type) + { + print_cast_temporal(str, query_type); + } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); - const char *cast_type() const { return "time"; } - const Type_handler *type_handler() const { return &type_handler_time2; } bool fix_length_and_dec() { return args[0]->type_handler()-> @@ -1201,14 +1150,16 @@ public: }; -class Item_datetime_typecast :public Item_temporal_typecast +class Item_datetime_typecast :public Item_datetimefunc { public: Item_datetime_typecast(THD *thd, Item *a, uint dec_arg): - Item_temporal_typecast(thd, a) { decimals= dec_arg; } + Item_datetimefunc(thd, a) { decimals= dec_arg; } const char *func_name() const { return "cast_as_datetime"; } - const char *cast_type() const { return "datetime"; } - const Type_handler *type_handler() const { return &type_handler_datetime2; } + void print(String *str, enum_query_type query_type) + { + print_cast_temporal(str, query_type); + } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); bool fix_length_and_dec() { @@ -1234,25 +1185,63 @@ public: }; -class Item_func_add_time :public Item_temporal_hybrid_func +class Item_func_timestamp :public Item_datetimefunc { - const bool is_date; - int sign; - + bool check_arguments() const + { + return args[0]->check_type_can_return_date(func_name()) || + args[1]->check_type_can_return_time(func_name()); + } public: - Item_func_add_time(THD *thd, Item *a, Item *b, bool type_arg, bool neg_arg): - Item_temporal_hybrid_func(thd, a, b), is_date(type_arg) - { sign= neg_arg ? -1 : 1; } - bool fix_length_and_dec(); - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); - const char *func_name() const + Item_func_timestamp(THD *thd, Item *a, Item *b) + :Item_datetimefunc(thd, a, b) + { } + const char *func_name() const { return "timestamp"; } + bool fix_length_and_dec() + { + uint dec= MY_MAX(args[0]->datetime_precision(), args[1]->time_precision()); + fix_attributes_datetime(dec); + maybe_null= true; + return false; + } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { - return is_date ? "timestamp" : sign > 0 ? "addtime" : "subtime"; + Datetime dt(current_thd, args[0], 0); + MYSQL_TIME ltime2; + return (null_value= (!dt.is_valid_datetime() || + args[1]->get_time(<ime2) || + Sec6_add(dt.get_mysql_time(), <ime2, 1). + to_datetime(ltime))); } Item *get_copy(THD *thd) + { return get_item_copy<Item_func_timestamp>(thd, this); } +}; + + +/** + ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a + time/datetime value + + t: time_or_datetime_expression + a: time_expression + + Result: Time value or datetime value +*/ + +class Item_func_add_time :public Item_handled_func +{ + int sign; +public: + Item_func_add_time(THD *thd, Item *a, Item *b, bool neg_arg) + :Item_handled_func(thd, a, b), sign(neg_arg ? -1 : 1) + { } + bool fix_length_and_dec(); + const char *func_name() const { return sign > 0 ? "addtime" : "subtime"; } + Item *get_copy(THD *thd) { return get_item_copy<Item_func_add_time>(thd, this); } }; + class Item_func_timediff :public Item_timefunc { bool check_arguments() const @@ -1369,19 +1358,18 @@ public: }; -class Item_func_str_to_date :public Item_temporal_hybrid_func +class Item_func_str_to_date :public Item_handled_func { - timestamp_type cached_timestamp_type; bool const_item; String subject_converter; String format_converter; CHARSET_INFO *internal_charset; public: Item_func_str_to_date(THD *thd, Item *a, Item *b): - Item_temporal_hybrid_func(thd, a, b), const_item(false), + Item_handled_func(thd, a, b), const_item(false), internal_charset(NULL) {} - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); + bool get_date_common(MYSQL_TIME *ltime, ulonglong fuzzy_date, timestamp_type); const char *func_name() const { return "str_to_date"; } bool fix_length_and_dec(); Item *get_copy(THD *thd) @@ -1401,4 +1389,329 @@ public: { return get_item_copy<Item_func_last_day>(thd, this); } }; + +/*****************************************************************************/ + +class Func_handler_date_add_interval +{ +protected: + static uint interval_dec(const Item *item, interval_type int_type) + { + if (int_type == INTERVAL_MICROSECOND || + (int_type >= INTERVAL_DAY_MICROSECOND && + int_type <= INTERVAL_SECOND_MICROSECOND)) + return TIME_SECOND_PART_DIGITS; + if (int_type == INTERVAL_SECOND && item->decimals > 0) + return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); + return 0; + } + interval_type int_type(const Item_handled_func *item) const + { + return static_cast<const Item_date_add_interval*>(item)->int_type; + } + bool sub(const Item_handled_func *item) const + { + return static_cast<const Item_date_add_interval*>(item)->date_sub_interval; + } + bool add(Item *item, interval_type type, bool sub, MYSQL_TIME *to) const + { + INTERVAL interval; + if (get_interval_value(item, type, &interval)) + return true; + if (sub) + interval.neg = !interval.neg; + return date_add_interval(to, type, interval); + } +}; + + +class Func_handler_date_add_interval_datetime: + public Item_handled_func::Handler_datetime, + public Func_handler_date_add_interval +{ +public: + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->datetime_precision(), + interval_dec(item->arguments()[1], int_type(item))); + item->fix_attributes_datetime(dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + Datetime dt(current_thd, item->arguments()[0], 0); + if (!dt.is_valid_datetime() || + dt.check_date_with_warn(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)) + return (item->null_value= true); + dt.copy_to_mysql_time(to); + return (item->null_value= add(item->arguments()[1], + int_type(item), sub(item), to)); + } +}; + + +class Func_handler_date_add_interval_datetime_arg0_time: + public Func_handler_date_add_interval_datetime +{ +public: + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const; +}; + + +class Func_handler_date_add_interval_date: + public Item_handled_func::Handler_date, + public Func_handler_date_add_interval +{ +public: + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + Date d(current_thd, item->arguments()[0], 0); + if (!d.is_valid_date() || + d.check_date_with_warn(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)) + return (item->null_value= true); + d.copy_to_mysql_time(to); + return (item->null_value= add(item->arguments()[1], + int_type(item), sub(item), to)); + } +}; + + +class Func_handler_date_add_interval_time: + public Item_handled_func::Handler_time, + public Func_handler_date_add_interval +{ +public: + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->time_precision(), + interval_dec(item->arguments()[1], int_type(item))); + item->fix_attributes_time(dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + Time t(item->arguments()[0]); + if (!t.is_valid_time()) + return (item->null_value= true); + t.copy_to_mysql_time(to); + return (item->null_value= add(item->arguments()[1], + int_type(item), sub(item), to)); + } +}; + + +class Func_handler_date_add_interval_string: + public Item_handled_func::Handler_temporal_string, + public Func_handler_date_add_interval +{ +public: + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->datetime_precision(), + interval_dec(item->arguments()[1], int_type(item))); + item->collation.set(item->default_charset(), + DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); + item->fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + if (item->arguments()[0]->get_date(to, 0) || + (to->time_type != MYSQL_TIMESTAMP_TIME && + check_date_with_warn(to, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE, + MYSQL_TIMESTAMP_ERROR))) + return (item->null_value= true); + return (item->null_value= add(item->arguments()[1], + int_type(item), sub(item), to)); + } +}; + + +class Func_handler_sign +{ +protected: + int m_sign; + Func_handler_sign(int sign) :m_sign(sign) { } +}; + + +class Func_handler_add_time_datetime: + public Item_handled_func::Handler_datetime, + public Func_handler_sign +{ +public: + Func_handler_add_time_datetime(int sign) + :Func_handler_sign(sign) + { } + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->datetime_precision(), + item->arguments()[1]->time_precision()); + item->fix_attributes_datetime(dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + DBUG_ASSERT(item->is_fixed()); + MYSQL_TIME l_time2; + Datetime dt(current_thd, item->arguments()[0], 0); + return (item->null_value= (!dt.is_valid_datetime() || + item->arguments()[1]->get_time(&l_time2) || + Sec6_add(dt.get_mysql_time(), &l_time2, m_sign). + to_datetime(to))); + } +}; + + +class Func_handler_add_time_time: + public Item_handled_func::Handler_time, + public Func_handler_sign +{ +public: + Func_handler_add_time_time(int sign) + :Func_handler_sign(sign) + { } + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->time_precision(), + item->arguments()[1]->time_precision()); + item->fix_attributes_time(dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + DBUG_ASSERT(item->is_fixed()); + MYSQL_TIME l_time2; + Time t(item->arguments()[0]); + return (item->null_value= (!t.is_valid_time() || + item->arguments()[1]->get_time(&l_time2) || + Sec6_add(t.get_mysql_time(), &l_time2, m_sign). + to_time(to, item->decimals))); + } +}; + + +class Func_handler_add_time_string: + public Item_handled_func::Handler_temporal_string, + public Func_handler_sign +{ +public: + Func_handler_add_time_string(int sign) + :Func_handler_sign(sign) + { } + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->decimals, + item->arguments()[1]->decimals); + item->collation.set(item->default_charset(), + DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); + item->fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + DBUG_ASSERT(item->is_fixed()); + // Detect a proper timestamp type based on the argument values + MYSQL_TIME l_time1, l_time2; + if (item->arguments()[0]->get_time(&l_time1) || + item->arguments()[1]->get_time(&l_time2)) + return (item->null_value= true); + Sec6_add add(&l_time1, &l_time2, m_sign); + return (item->null_value= (l_time1.time_type == MYSQL_TIMESTAMP_TIME ? + add.to_time(to, item->decimals) : + add.to_datetime(to))); + } +}; + + +class Func_handler_str_to_date_datetime_sec: + public Item_handled_func::Handler_datetime +{ +public: + bool fix_length_and_dec(Item_handled_func *item) const + { + item->fix_attributes_datetime(0); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + return static_cast<Item_func_str_to_date*>(item)-> + get_date_common(to, fuzzy, MYSQL_TIMESTAMP_DATETIME); + } +}; + + +class Func_handler_str_to_date_datetime_usec: + public Item_handled_func::Handler_datetime +{ +public: + bool fix_length_and_dec(Item_handled_func *item) const + { + item->fix_attributes_datetime(TIME_SECOND_PART_DIGITS); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + return static_cast<Item_func_str_to_date*>(item)-> + get_date_common(to, fuzzy, MYSQL_TIMESTAMP_DATETIME); + } +}; + + +class Func_handler_str_to_date_date: public Item_handled_func::Handler_date +{ +public: + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + return static_cast<Item_func_str_to_date*>(item)-> + get_date_common(to, fuzzy, MYSQL_TIMESTAMP_DATE); + } +}; + + +class Func_handler_str_to_date_time: public Item_handled_func::Handler_time +{ +public: + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + if (static_cast<Item_func_str_to_date*>(item)-> + get_date_common(to, fuzzy, MYSQL_TIMESTAMP_TIME)) + return true; + if (to->day) + { + /* + Day part for time type can be nonzero value and so + we should add hours from day part to hour part to + keep valid time value. + */ + to->hour+= to->day * 24; + to->day= 0; + } + return false; + } +}; + + +class Func_handler_str_to_date_time_sec: public Func_handler_str_to_date_time +{ +public: + bool fix_length_and_dec(Item_handled_func *item) const + { + item->fix_attributes_time(0); + return false; + } +}; + + +class Func_handler_str_to_date_time_usec: public Func_handler_str_to_date_time +{ +public: + bool fix_length_and_dec(Item_handled_func *item) const + { + item->fix_attributes_time(TIME_SECOND_PART_DIGITS); + return false; + } +}; + + #endif /* ITEM_TIMEFUNC_INCLUDED */ diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index 3ad0527384d..a17f9482ea0 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -120,7 +120,6 @@ Item_window_func::fix_fields(THD *thd, Item **ref) const_item_cache= false; with_window_func= true; - with_sum_func= false; if (fix_length_and_dec()) return TRUE; @@ -514,11 +513,11 @@ void Item_sum_hybrid_simple::reset_field() } case DECIMAL_RESULT: { - my_decimal value_buff, *arg_dec= args[0]->val_decimal(&value_buff); + VDec arg_dec(args[0]); if (maybe_null) { - if (args[0]->null_value) + if (arg_dec.is_null()) result_field->set_null(); else result_field->set_notnull(); @@ -527,9 +526,7 @@ void Item_sum_hybrid_simple::reset_field() We must store zero in the field as we will use the field value in add() */ - if (!arg_dec) // Null - arg_dec= &decimal_zero; - result_field->store_decimal(arg_dec); + result_field->store_decimal(arg_dec.ptr_or(&decimal_zero)); break; } case ROW_RESULT: diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 63734ecf9ac..146c5aa57fe 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -29,10 +29,8 @@ /* TODO: future development directions: - 1. add real constants for XPATH_NODESET_CMP and XPATH_NODESET - into enum Type in item.h. - 2. add nodeset_to_nodeset_comparator - 3. add lacking functions: + 1. add nodeset_to_nodeset_comparator + 2. add lacking functions: - name() - lang() - string() @@ -44,7 +42,7 @@ - substring-after() - normalize-space() - substring-before() - 4. add lacking axis: + 3. add lacking axis: - following-sibling - following, - preceding-sibling @@ -151,6 +149,9 @@ public: }; +static Type_handler_long_blob type_handler_xpath_nodeset; + + /* Common features of the functions returning a node set. */ @@ -181,16 +182,29 @@ public: void prepare(String *nodeset) { prepare_nodes(); - String *res= args[0]->val_nodeset(&tmp_value); + String *res= args[0]->val_raw(&tmp_value); fltbeg= (MY_XPATH_FLT*) res->ptr(); fltend= (MY_XPATH_FLT*) (res->ptr() + res->length()); nodeset->length(0); } - enum Type type() const { return XPATH_NODESET; } + const Type_handler *type_handler() const + { + return &type_handler_xpath_nodeset; + } + const Type_handler *fixed_type_handler() const + { + return &type_handler_xpath_nodeset; + } + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + DBUG_ASSERT(0); + return NULL; + } String *val_str(String *str) { prepare_nodes(); - String *res= val_nodeset(&tmp2_value); + String *res= val_raw(&tmp2_value); fltbeg= (MY_XPATH_FLT*) res->ptr(); fltend= (MY_XPATH_FLT*) (res->ptr() + res->length()); String active; @@ -247,7 +261,7 @@ public: Item_nodeset_func_rootelement(THD *thd, String *pxml): Item_nodeset_func(thd, pxml) {} const char *func_name() const { return "xpath_rootelement"; } - String *val_nodeset(String *nodeset); + String *val_raw(String *nodeset); Item *get_copy(THD *thd) { return get_item_copy<Item_nodeset_func_rootelement>(thd, this); } }; @@ -260,7 +274,7 @@ public: Item_nodeset_func_union(THD *thd, Item *a, Item *b, String *pxml): Item_nodeset_func(thd, a, b, pxml) {} const char *func_name() const { return "xpath_union"; } - String *val_nodeset(String *nodeset); + String *val_raw(String *nodeset); Item *get_copy(THD *thd) { return get_item_copy<Item_nodeset_func_union>(thd, this); } }; @@ -294,7 +308,7 @@ public: String *pxml): Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {} const char *func_name() const { return "xpath_selfbyname"; } - String *val_nodeset(String *nodeset); + String *val_raw(String *nodeset); Item *get_copy(THD *thd) { return get_item_copy<Item_nodeset_func_selfbyname>(thd, this); } }; @@ -308,7 +322,7 @@ public: String *pxml): Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {} const char *func_name() const { return "xpath_childbyname"; } - String *val_nodeset(String *nodeset); + String *val_raw(String *nodeset); Item *get_copy(THD *thd) { return get_item_copy<Item_nodeset_func_childbyname>(thd, this); } }; @@ -324,7 +338,7 @@ public: Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml), need_self(need_self_arg) {} const char *func_name() const { return "xpath_descendantbyname"; } - String *val_nodeset(String *nodeset); + String *val_raw(String *nodeset); Item *get_copy(THD *thd) { return get_item_copy<Item_nodeset_func_descendantbyname>(thd, this); } }; @@ -340,7 +354,7 @@ public: Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml), need_self(need_self_arg) {} const char *func_name() const { return "xpath_ancestorbyname"; } - String *val_nodeset(String *nodeset); + String *val_raw(String *nodeset); Item *get_copy(THD *thd) { return get_item_copy<Item_nodeset_func_ancestorbyname>(thd, this); } }; @@ -354,7 +368,7 @@ public: String *pxml): Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {} const char *func_name() const { return "xpath_parentbyname"; } - String *val_nodeset(String *nodeset); + String *val_raw(String *nodeset); Item *get_copy(THD *thd) { return get_item_copy<Item_nodeset_func_parentbyname>(thd, this); } }; @@ -368,7 +382,7 @@ public: uint l_arg, String *pxml): Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {} const char *func_name() const { return "xpath_attributebyname"; } - String *val_nodeset(String *nodeset); + String *val_raw(String *nodeset); Item *get_copy(THD *thd) { return get_item_copy<Item_nodeset_func_attributebyname>(thd, this); } }; @@ -385,7 +399,7 @@ public: Item_nodeset_func_predicate(THD *thd, Item *a, Item *b, String *pxml): Item_nodeset_func(thd, a, b, pxml) {} const char *func_name() const { return "xpath_predicate"; } - String *val_nodeset(String *nodeset); + String *val_raw(String *nodeset); Item *get_copy(THD *thd) { return get_item_copy<Item_nodeset_func_predicate>(thd, this); } }; @@ -398,7 +412,7 @@ public: Item_nodeset_func_elementbyindex(THD *thd, Item *a, Item *b, String *pxml): Item_nodeset_func(thd, a, b, pxml) { } const char *func_name() const { return "xpath_elementbyindex"; } - String *val_nodeset(String *nodeset); + String *val_raw(String *nodeset); Item *get_copy(THD *thd) { return get_item_copy<Item_nodeset_func_elementbyindex>(thd, this); } }; @@ -420,9 +434,9 @@ public: const char *func_name() const { return "xpath_cast_bool"; } longlong val_int() { - if (args[0]->type() == XPATH_NODESET) + if (args[0]->fixed_type_handler() == &type_handler_xpath_nodeset) { - String *flt= args[0]->val_nodeset(&tmp_value); + String *flt= args[0]->val_raw(&tmp_value); return flt->length() == sizeof(MY_XPATH_FLT) ? 1 : 0; } return args[0]->val_real() ? 1 : 0; @@ -455,7 +469,7 @@ public: String *string_cache; Item_nodeset_context_cache(THD *thd, String *str_arg, String *pxml): Item_nodeset_func(thd, pxml), string_cache(str_arg) { } - String *val_nodeset(String *res) + String *val_raw(String *res) { return string_cache; } bool fix_length_and_dec() { max_length= MAX_BLOB_WIDTH;; return FALSE; } Item *get_copy(THD *thd) @@ -474,7 +488,7 @@ public: bool fix_length_and_dec() { max_length=10; return FALSE; } longlong val_int() { - String *flt= args[0]->val_nodeset(&tmp_value); + String *flt= args[0]->val_raw(&tmp_value); if (flt->length() == sizeof(MY_XPATH_FLT)) return ((MY_XPATH_FLT*)flt->ptr())->pos + 1; return 0; @@ -496,7 +510,7 @@ public: longlong val_int() { uint predicate_supplied_context_size; - String *res= args[0]->val_nodeset(&tmp_value); + String *res= args[0]->val_raw(&tmp_value); if (res->length() == sizeof(MY_XPATH_FLT) && (predicate_supplied_context_size= ((MY_XPATH_FLT*)res->ptr())->size)) return predicate_supplied_context_size; @@ -519,7 +533,7 @@ public: double val_real() { double sum= 0; - String *res= args[0]->val_nodeset(&tmp_value); + String *res= args[0]->val_raw(&tmp_value); MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr(); MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length()); uint numnodes= pxml->length() / sizeof(MY_XML_NODE); @@ -587,19 +601,23 @@ public: Item_nodeset_to_const_comparator(THD *thd, Item *nodeset, Item *cmpfunc, String *p): Item_bool_func(thd, nodeset, cmpfunc), pxml(p) {} - enum Type type() const { return XPATH_NODESET_CMP; }; const char *func_name() const { return "xpath_nodeset_to_const_comparator"; } bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(func_name(), arg, VCOL_IMPOSSIBLE); } - + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + DBUG_ASSERT(0); + return NULL; + } longlong val_int() { Item_func *comp= (Item_func*)args[1]; Item_string_xml_non_const *fake= (Item_string_xml_non_const*)(comp->arguments()[0]); - String *res= args[0]->val_nodeset(&tmp_nodeset); + String *res= args[0]->val_raw(&tmp_nodeset); MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr(); MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length()); MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml->ptr(); @@ -630,7 +648,7 @@ public: }; -String *Item_nodeset_func_rootelement::val_nodeset(String *nodeset) +String *Item_nodeset_func_rootelement::val_raw(String *nodeset) { nodeset->length(0); ((XPathFilter*)nodeset)->append_element(0, 0); @@ -638,11 +656,11 @@ String *Item_nodeset_func_rootelement::val_nodeset(String *nodeset) } -String * Item_nodeset_func_union::val_nodeset(String *nodeset) +String * Item_nodeset_func_union::val_raw(String *nodeset) { uint num_nodes= pxml->length() / sizeof(MY_XML_NODE); - String set0, *s0= args[0]->val_nodeset(&set0); - String set1, *s1= args[1]->val_nodeset(&set1); + String set0, *s0= args[0]->val_raw(&set0); + String set1, *s1= args[1]->val_raw(&set1); String both_str; both_str.alloc(num_nodes); char *both= (char*) both_str.ptr(); @@ -669,7 +687,7 @@ String * Item_nodeset_func_union::val_nodeset(String *nodeset) } -String *Item_nodeset_func_selfbyname::val_nodeset(String *nodeset) +String *Item_nodeset_func_selfbyname::val_raw(String *nodeset) { prepare(nodeset); for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++) @@ -683,7 +701,7 @@ String *Item_nodeset_func_selfbyname::val_nodeset(String *nodeset) } -String *Item_nodeset_func_childbyname::val_nodeset(String *nodeset) +String *Item_nodeset_func_childbyname::val_raw(String *nodeset) { prepare(nodeset); for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++) @@ -704,7 +722,7 @@ String *Item_nodeset_func_childbyname::val_nodeset(String *nodeset) } -String *Item_nodeset_func_descendantbyname::val_nodeset(String *nodeset) +String *Item_nodeset_func_descendantbyname::val_raw(String *nodeset) { prepare(nodeset); for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++) @@ -726,7 +744,7 @@ String *Item_nodeset_func_descendantbyname::val_nodeset(String *nodeset) } -String *Item_nodeset_func_ancestorbyname::val_nodeset(String *nodeset) +String *Item_nodeset_func_ancestorbyname::val_raw(String *nodeset) { char *active; String active_str; @@ -768,7 +786,7 @@ String *Item_nodeset_func_ancestorbyname::val_nodeset(String *nodeset) } -String *Item_nodeset_func_parentbyname::val_nodeset(String *nodeset) +String *Item_nodeset_func_parentbyname::val_raw(String *nodeset) { char *active; String active_str; @@ -791,7 +809,7 @@ String *Item_nodeset_func_parentbyname::val_nodeset(String *nodeset) } -String *Item_nodeset_func_attributebyname::val_nodeset(String *nodeset) +String *Item_nodeset_func_attributebyname::val_raw(String *nodeset) { prepare(nodeset); for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++) @@ -812,7 +830,7 @@ String *Item_nodeset_func_attributebyname::val_nodeset(String *nodeset) } -String *Item_nodeset_func_predicate::val_nodeset(String *str) +String *Item_nodeset_func_predicate::val_raw(String *str) { Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0]; Item_func *comp_func= (Item_func*)args[1]; @@ -832,7 +850,7 @@ String *Item_nodeset_func_predicate::val_nodeset(String *str) } -String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset) +String *Item_nodeset_func_elementbyindex::val_raw(String *nodeset) { Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0]; prepare(nodeset); @@ -845,7 +863,9 @@ String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset) flt->pos, size); int index= (int) (args[1]->val_int()) - 1; - if (index >= 0 && (flt->pos == (uint) index || args[1]->is_bool_type())) + if (index >= 0 && + (flt->pos == (uint) index || + (args[1]->type_handler()->is_bool_type()))) ((XPathFilter*)nodeset)->append_element(flt->num, pos++); } return nodeset; @@ -858,7 +878,7 @@ String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset) */ static Item* nodeset2bool(MY_XPATH *xpath, Item *item) { - if (item->type() == Item::XPATH_NODESET) + if (item->fixed_type_handler() == &type_handler_xpath_nodeset) return new (xpath->thd->mem_root) Item_xpath_cast_bool(xpath->thd, item, xpath->pxml); return item; @@ -988,13 +1008,13 @@ static Item *create_comparator(MY_XPATH *xpath, int oper, MY_XPATH_LEX *context, Item *a, Item *b) { - if (a->type() != Item::XPATH_NODESET && - b->type() != Item::XPATH_NODESET) + if (a->fixed_type_handler() != &type_handler_xpath_nodeset && + b->fixed_type_handler() != &type_handler_xpath_nodeset) { return eq_func(xpath->thd, oper, a, b); // two scalar arguments } - else if (a->type() == Item::XPATH_NODESET && - b->type() == Item::XPATH_NODESET) + else if (a->fixed_type_handler() == &type_handler_xpath_nodeset && + b->fixed_type_handler() == &type_handler_xpath_nodeset) { uint len= (uint)(xpath->query.end - context->beg); set_if_smaller(len, 32); @@ -1019,7 +1039,7 @@ static Item *create_comparator(MY_XPATH *xpath, Item_string_xml_non_const(thd, "", 0, xpath->cs)); Item_nodeset_func *nodeset; Item *scalar, *comp; - if (a->type() == Item::XPATH_NODESET) + if (a->fixed_type_handler() == &type_handler_xpath_nodeset) { nodeset= (Item_nodeset_func*) a; scalar= b; @@ -1053,7 +1073,7 @@ static Item* nametestfunc(MY_XPATH *xpath, MEM_ROOT *mem_root= thd->mem_root; DBUG_ASSERT(arg != 0); - DBUG_ASSERT(arg->type() == Item::XPATH_NODESET); + DBUG_ASSERT(arg->fixed_type_handler() == &type_handler_xpath_nodeset); DBUG_ASSERT(beg != 0); DBUG_ASSERT(len > 0); @@ -1306,7 +1326,7 @@ static Item *create_func_substr(MY_XPATH *xpath, Item **args, uint nargs) static Item *create_func_count(MY_XPATH *xpath, Item **args, uint nargs) { - if (args[0]->type() != Item::XPATH_NODESET) + if (args[0]->fixed_type_handler() != &type_handler_xpath_nodeset) return 0; return new (xpath->thd->mem_root) Item_func_xpath_count(xpath->thd, args[0], xpath->pxml); } @@ -1314,7 +1334,7 @@ static Item *create_func_count(MY_XPATH *xpath, Item **args, uint nargs) static Item *create_func_sum(MY_XPATH *xpath, Item **args, uint nargs) { - if (args[0]->type() != Item::XPATH_NODESET) + if (args[0]->fixed_type_handler() != &type_handler_xpath_nodeset) return 0; return new (xpath->thd->mem_root) Item_func_xpath_sum(xpath->thd, args[0], xpath->pxml); @@ -1793,7 +1813,8 @@ my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(MY_XPATH *xpath) xpath->item= nodeset2bool(xpath, xpath->item); - if (xpath->item->is_bool_type()) + const Type_handler *fh; + if ((fh= xpath->item->fixed_type_handler()) && fh->is_bool_type()) { xpath->context= new (xpath->thd->mem_root) Item_nodeset_func_predicate(xpath->thd, prev_context, @@ -2047,11 +2068,11 @@ static int my_xpath_parse_UnionExpr(MY_XPATH *xpath) while (my_xpath_parse_term(xpath, MY_XPATH_LEX_VLINE)) { Item *prev= xpath->item; - if (prev->type() != Item::XPATH_NODESET) + if (prev->fixed_type_handler() != &type_handler_xpath_nodeset) return 0; if (!my_xpath_parse_PathExpr(xpath) - || xpath->item->type() != Item::XPATH_NODESET) + || xpath->item->fixed_type_handler() != &type_handler_xpath_nodeset) { xpath->error= 1; return 0; @@ -2089,7 +2110,7 @@ my_xpath_parse_FilterExpr_opt_slashes_RelativeLocationPath(MY_XPATH *xpath) if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH)) return 1; - if (xpath->item->type() != Item::XPATH_NODESET) + if (xpath->item->fixed_type_handler() != &type_handler_xpath_nodeset) { xpath->lasttok= xpath->prevtok; xpath->error= 1; @@ -3054,7 +3075,7 @@ String *Item_func_xml_update::val_str(String *str) null_value= 0; if (!nodeset_func || get_xml(&xml) || !(rep= args[2]->val_str(&tmp_value3)) || - !(nodeset= nodeset_func->val_nodeset(&tmp_value2))) + !(nodeset= nodeset_func->val_raw(&tmp_value2))) { null_value= 1; return 0; diff --git a/sql/log.cc b/sql/log.cc index 1ffa6f7588f..86137ad3543 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -866,10 +866,10 @@ bool Log_to_csv_event_handler:: Open_tables_backup open_tables_backup; CHARSET_INFO *client_cs= thd->variables.character_set_client; bool save_time_zone_used; - long query_time= (long) MY_MIN(query_utime/1000000, TIME_MAX_VALUE_SECONDS); - long lock_time= (long) MY_MIN(lock_utime/1000000, TIME_MAX_VALUE_SECONDS); - long query_time_micro= (long) (query_utime % 1000000); - long lock_time_micro= (long) (lock_utime % 1000000); + ulong query_time= (ulong) MY_MIN(query_utime/1000000, TIME_MAX_VALUE_SECONDS); + ulong lock_time= (ulong) MY_MIN(lock_utime/1000000, TIME_MAX_VALUE_SECONDS); + ulong query_time_micro= (ulong) (query_utime % 1000000); + ulong lock_time_micro= (ulong) (lock_utime % 1000000); DBUG_ENTER("Log_to_csv_event_handler::log_slow"); @@ -1162,6 +1162,10 @@ bool LOGGER::error_log_print(enum loglevel level, const char *format, { bool error= FALSE; Log_event_handler **current_handler; + THD *thd= current_thd; + + if (likely(thd)) + thd->error_printed_to_log= 1; /* currently we don't need locking here as there is no error_log table */ for (current_handler= error_log_handler_list ; *current_handler ;) @@ -2183,16 +2187,16 @@ void MYSQL_BIN_LOG::set_write_error(THD *thd, bool is_transactional) { if (is_transactional) { - my_message(ER_TRANS_CACHE_FULL, ER_THD(thd, ER_TRANS_CACHE_FULL), MYF(MY_WME)); + my_message(ER_TRANS_CACHE_FULL, ER_THD(thd, ER_TRANS_CACHE_FULL), MYF(0)); } else { - my_message(ER_STMT_CACHE_FULL, ER_THD(thd, ER_STMT_CACHE_FULL), MYF(MY_WME)); + my_message(ER_STMT_CACHE_FULL, ER_THD(thd, ER_STMT_CACHE_FULL), MYF(0)); } } else { - my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), name, errno); + my_error(ER_ERROR_ON_WRITE, MYF(0), name, errno); } DBUG_VOID_RETURN; @@ -2649,7 +2653,7 @@ bool MYSQL_LOG::open( #endif if ((file= mysql_file_open(log_file_key, log_file_name, open_flags, - MYF(MY_WME | ME_WAITTANG))) < 0) + MYF(MY_WME))) < 0) goto err; if (is_fifo) @@ -2791,7 +2795,7 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name, { THD *thd= current_thd; if (unlikely(thd)) - my_error(ER_NO_UNIQUE_LOGFILE, MYF(ME_FATALERROR), log_name); + my_error(ER_NO_UNIQUE_LOGFILE, MYF(ME_FATAL), log_name); sql_print_error(ER_DEFAULT(ER_NO_UNIQUE_LOGFILE), log_name); return 1; } @@ -4627,7 +4631,7 @@ int MYSQL_BIN_LOG::open_purge_index_file(bool destroy) if (!my_b_inited(&purge_index_file)) { if ((file= my_open(purge_index_file_name, O_RDWR | O_CREAT | O_BINARY, - MYF(MY_WME | ME_WAITTANG))) < 0 || + MYF(MY_WME))) < 0 || init_io_cache(&purge_index_file, file, IO_SIZE, (destroy ? WRITE_CACHE : READ_CACHE), 0, 0, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL))) @@ -5196,7 +5200,7 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock) close_on_error= TRUE; my_printf_error(ER_ERROR_ON_WRITE, ER_THD_OR_DEFAULT(current_thd, ER_CANT_OPEN_FILE), - MYF(ME_FATALERROR), name, errno); + MYF(ME_FATAL), name, errno); goto end; } bytes_written += r.data_written; @@ -5265,7 +5269,7 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock) /* handle reopening errors */ if (unlikely(error)) { - my_error(ER_CANT_OPEN_FILE, MYF(ME_FATALERROR), file_to_open, error); + my_error(ER_CANT_OPEN_FILE, MYF(ME_FATAL), file_to_open, error); close_on_error= TRUE; } @@ -7748,10 +7752,10 @@ MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry) switch (entry->error) { case ER_ERROR_ON_WRITE: - my_error(ER_ERROR_ON_WRITE, MYF(ME_NOREFRESH), name, entry->commit_errno); + my_error(ER_ERROR_ON_WRITE, MYF(ME_ERROR_LOG), name, entry->commit_errno); break; case ER_ERROR_ON_READ: - my_error(ER_ERROR_ON_READ, MYF(ME_NOREFRESH), + my_error(ER_ERROR_ON_READ, MYF(ME_ERROR_LOG), entry->error_cache->file_name, entry->commit_errno); break; default: @@ -7762,7 +7766,7 @@ MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry) */ my_printf_error(entry->error, "Error writing transaction to binary log: %d", - MYF(ME_NOREFRESH), entry->error); + MYF(ME_ERROR_LOG), entry->error); } /* @@ -7985,7 +7989,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) when the transaction has been safely committed in the engine. */ leader->cache_mngr->delayed_error= true; - my_error(ER_ERROR_ON_WRITE, MYF(ME_NOREFRESH), name, errno); + my_error(ER_ERROR_ON_WRITE, MYF(ME_ERROR_LOG), name, errno); check_purge= false; } /* In case of binlog rotate, update the correct current binlog offset. */ diff --git a/sql/log_event.cc b/sql/log_event.cc index c550adea26b..13690a8be60 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2732,9 +2732,7 @@ log_event_print_value(IO_CACHE *file, PRINT_EVENT_INFO *print_event_info, goto return_null; uint bin_size= my_decimal_get_binary_size(precision, decimals); - my_decimal dec; - binary2my_decimal(E_DEC_FATAL_ERROR, (uchar*) ptr, &dec, - precision, decimals); + my_decimal dec((const uchar *) ptr, precision, decimals); int length= DECIMAL_MAX_STR_LENGTH; char buff[DECIMAL_MAX_STR_LENGTH + 1]; decimal2string(&dec, buff, &length, 0, 0, 0); @@ -4390,7 +4388,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, size_t que have to use the transactional cache to ensure we don't calculate any checksum for the CREATE part. */ - trx_cache= (lex->select_lex.item_list.elements && + trx_cache= (lex->first_select_lex()->item_list.elements && thd->is_current_stmt_binlog_format_row()) || (thd->variables.option_bits & OPTION_GTID_BEGIN); use_cache= (lex->tmp_table() && @@ -7382,8 +7380,9 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi, ex.skip_lines = skip_lines; List<Item> field_list; - thd->lex->select_lex.context.resolve_in_table_list_only(&tables); - set_fields(tables.db.str, field_list, &thd->lex->select_lex.context); + thd->lex->first_select_lex()->context.resolve_in_table_list_only(&tables); + set_fields(tables.db.str, + field_list, &thd->lex->first_select_lex()->context); thd->variables.pseudo_thread_id= thread_id; if (net) { @@ -9037,11 +9036,8 @@ void User_var_log_event::pack_info(Protocol* protocol) String buf(buf_mem, sizeof(buf_mem), system_charset_info); char buf2[DECIMAL_MAX_STR_LENGTH+1]; String str(buf2, sizeof(buf2), &my_charset_bin); - my_decimal dec; buf.length(0); - binary2my_decimal(E_DEC_FATAL_ERROR, (uchar*) (val+2), &dec, val[0], - val[1]); - my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, 0, &str); + my_decimal((const uchar *) (val + 2), val[0], val[1]).to_string(&str); if (user_var_append_name_part(protocol->thd, &buf, name, name_len) || buf.append(buf2)) return; diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 338f78d8f08..de7018c53cb 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -20,6 +20,7 @@ #ifndef MYSQL_CLIENT #include "sql_class.h" // THD +#include "field.h" #endif #define DIG_BASE 1000000000 @@ -95,9 +96,8 @@ int decimal_operation_results(int result, const char *value, const char *type) @retval E_DEC_OOM */ -int my_decimal2string(uint mask, const my_decimal *d, - uint fixed_prec, uint fixed_dec, - char filler, String *str) +int my_decimal::to_string_native(String *str, uint fixed_prec, uint fixed_dec, + char filler, uint mask) const { /* Calculate the size of the string: For DECIMAL(a,b), fixed_prec==a @@ -113,11 +113,11 @@ int my_decimal2string(uint mask, const my_decimal *d, */ int length= (fixed_prec ? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1) - : my_decimal_string_length(d)); + : my_decimal_string_length(this)); int result; if (str->alloc(length)) return check_result(mask, E_DEC_OOM); - result= decimal2string((decimal_t*) d, (char*) str->ptr(), + result= decimal2string(this, (char*) str->ptr(), &length, (int)fixed_prec, fixed_dec, filler); str->length(length); @@ -156,8 +156,8 @@ str_set_decimal(uint mask, const my_decimal *val, { if (!(cs->state & MY_CS_NONASCII)) { - /* For ASCII-compatible character sets we can use my_decimal2string */ - my_decimal2string(mask, val, fixed_prec, fixed_dec, filler, str); + // For ASCII-compatible character sets we can use to_string_native() + val->to_string_native(str, fixed_prec, fixed_dec, filler, mask); str->set_charset(cs); return FALSE; } @@ -165,14 +165,13 @@ str_set_decimal(uint mask, const my_decimal *val, { /* For ASCII-incompatible character sets (like UCS2) we - call my_decimal2string() on a temporary buffer first, + call my_string_native() on a temporary buffer first, and then convert the result to the target character with help of str->copy(). */ uint errors; - char buf[DECIMAL_MAX_STR_LENGTH]; - String tmp(buf, sizeof(buf), &my_charset_latin1); - my_decimal2string(mask, val, fixed_prec, fixed_dec, filler, &tmp); + StringBuffer<DECIMAL_MAX_STR_LENGTH> tmp; + val->to_string_native(&tmp, fixed_prec, fixed_dec, filler, mask); return str->copy(tmp.ptr(), tmp.length(), &my_charset_latin1, cs, &errors); } } @@ -182,7 +181,7 @@ str_set_decimal(uint mask, const my_decimal *val, Convert from decimal to binary representation SYNOPSIS - my_decimal2binary() + to_binary() mask error processing mask d number for conversion bin pointer to buffer where to write result @@ -199,12 +198,11 @@ str_set_decimal(uint mask, const my_decimal *val, E_DEC_OVERFLOW */ -int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec, - int scale) +int my_decimal::to_binary(uchar *bin, int prec, int scale, uint mask) const { int err1= E_DEC_OK, err2; my_decimal rounded; - my_decimal2decimal(d, &rounded); + my_decimal2decimal(this, &rounded); rounded.frac= decimal_actual_fraction(&rounded); if (scale < rounded.frac) { @@ -368,6 +366,26 @@ int my_decimal2int(uint mask, const decimal_t *d, bool unsigned_flag, } +longlong my_decimal::to_longlong(bool unsigned_flag) const +{ + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, this, unsigned_flag, &result); + return result; +} + + +my_decimal::my_decimal(Field *field) +{ + init(); + DBUG_ASSERT(!field->is_null()); +#ifndef DBUG_OFF + my_decimal *dec= +#endif + field->val_decimal(this); + DBUG_ASSERT(dec == this); +} + + #ifndef DBUG_OFF /* routines for debugging print */ diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 22800c24338..d035641cfa6 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -39,6 +39,7 @@ C_MODE_START C_MODE_END class String; +class Field; typedef struct st_mysql_time MYSQL_TIME; /** @@ -63,6 +64,25 @@ inline int my_decimal_int_part(uint precision, uint decimals) } +#ifndef MYSQL_CLIENT +int decimal_operation_results(int result, const char *value, const char *type); +#else +inline int decimal_operation_results(int result, const char *value, + const char *type) +{ + return result; +} +#endif /*MYSQL_CLIENT*/ + + +inline int check_result(uint mask, int result) +{ + if (result & mask) + decimal_operation_results(result, "", "DECIMAL"); + return result; +} + + /** my_decimal class limits 'decimal_t' type to what we need in MySQL. @@ -125,6 +145,12 @@ public: { init(); } + my_decimal(const uchar *bin, int prec, int scale) + { + init(); + check_result(E_DEC_FATAL_ERROR, bin2decimal(bin, this, prec, scale)); + } + my_decimal(Field *field); ~my_decimal() { sanity_check(); @@ -141,7 +167,59 @@ public: bool sign() const { return decimal_t::sign; } void sign(bool s) { decimal_t::sign= s; } uint precision() const { return intg + frac; } + void set_zero() + { + /* + We need the up-cast here, since my_decimal has sign() member functions, + which conflicts with decimal_t::sign + (and decimal_make_zero is a macro, rather than a funcion). + */ + decimal_make_zero(static_cast<decimal_t*>(this)); + } + int cmp(const my_decimal *other) const + { + return decimal_cmp(this, other); + } +#ifndef MYSQL_CLIENT + bool to_bool() const + { + return !decimal_is_zero(this); + } + double to_double() const + { + double res; + decimal2double(this, &res); + return res; + } + longlong to_longlong(bool unsigned_flag) const; + // Convert to string returning decimal2string() error code + int to_string_native(String *to, uint prec, uint dec, char filler, + uint mask= E_DEC_FATAL_ERROR) const; + // Convert to string returning the String pointer + String *to_string(String *to, uint prec, uint dec, char filler) const + { + return to_string_native(to, prec, dec, filler) ? NULL : to; + } + String *to_string(String *to) const + { + return to_string(to, 0, 0, 0); + } + String *to_string_round(String *to, uint scale, my_decimal *round_buff) const + { + (void) round_to(round_buff, scale, HALF_UP); // QQ: check result? + return round_buff->to_string(to); + } + int round_to(my_decimal *to, uint scale, decimal_round_mode mode, + int mask= E_DEC_FATAL_ERROR) const + { + return check_result(mask, decimal_round(this, to, (int) scale, mode)); + } + bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, + const char *field_name); + int to_binary(uchar *bin, int prec, int scale, + uint mask= E_DEC_FATAL_ERROR) const; +#endif /** Swap two my_decimal values */ void swap(my_decimal &rhs) { @@ -164,16 +242,6 @@ bool str_set_decimal(uint mask, const my_decimal *val, uint fixed_prec, extern my_decimal decimal_zero; -#ifndef MYSQL_CLIENT -int decimal_operation_results(int result, const char *value, const char *type); -#else -inline int decimal_operation_results(int result, const char *value, - const char *type) -{ - return result; -} -#endif /*MYSQL_CLIENT*/ - inline void max_my_decimal(my_decimal *to, int precision, int frac) { @@ -187,13 +255,6 @@ inline void max_internal_decimal(my_decimal *to) max_my_decimal(to, DECIMAL_MAX_PRECISION, 0); } -inline int check_result(uint mask, int result) -{ - if (result & mask) - decimal_operation_results(result, "", "DECIMAL"); - return result; -} - inline int check_result_and_overflow(uint mask, int result, my_decimal *val) { if (check_result(mask, result) & E_DEC_OVERFLOW) @@ -271,10 +332,6 @@ void my_decimal2decimal(const my_decimal *from, my_decimal *to) } -int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec, - int scale); - - inline int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec, int scale) @@ -286,12 +343,7 @@ int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec, inline int my_decimal_set_zero(my_decimal *d) { - /* - We need the up-cast here, since my_decimal has sign() member functions, - which conflicts with decimal_t::sign - (and decimal_make_zero is a macro, rather than a funcion). - */ - decimal_make_zero(static_cast<decimal_t*>(d)); + d->set_zero(); return 0; } @@ -303,40 +355,12 @@ bool my_decimal_is_zero(const my_decimal *decimal_value) } -inline -int my_decimal_round(uint mask, const my_decimal *from, int scale, - bool truncate, my_decimal *to) -{ - return check_result(mask, decimal_round(from, to, scale, - (truncate ? TRUNCATE : HALF_UP))); -} - - -inline -int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to) -{ - return check_result(mask, decimal_round(from, to, 0, FLOOR)); -} - - -inline -int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to) -{ - return check_result(mask, decimal_round(from, to, 0, CEILING)); -} - - inline bool str_set_decimal(const my_decimal *val, String *str, CHARSET_INFO *cs) { return str_set_decimal(E_DEC_FATAL_ERROR, val, 0, 0, 0, str, cs); } -#ifndef MYSQL_CLIENT -class String; -int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec, - uint fixed_dec, char filler, String *str); -#endif bool my_decimal2seconds(const my_decimal *d, ulonglong *sec, ulong *microsec); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f2b00831d6f..acb7532f922 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -319,22 +319,15 @@ MY_TIMER_INFO sys_timer_info; /* static variables */ #ifdef HAVE_PSI_INTERFACE -#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) +#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) static PSI_thread_key key_thread_handle_con_namedpipes; static PSI_cond_key key_COND_handler_count; -#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */ - -#if defined(HAVE_SMEM) && !defined(EMBEDDED_LIBRARY) -static PSI_thread_key key_thread_handle_con_sharedmem; -#endif /* HAVE_SMEM && !EMBEDDED_LIBRARY */ - -#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) static PSI_thread_key key_thread_handle_con_sockets; -#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */ +#endif /* _WIN32 |&& !EMBEDDED_LIBRARY */ -#ifdef __WIN__ +#ifdef _WIN32 static PSI_thread_key key_thread_handle_shutdown; -#endif /* __WIN__ */ +#endif #ifdef HAVE_OPENSSL10 static PSI_rwlock_key key_rwlock_openssl; @@ -1098,9 +1091,9 @@ PSI_cond_key key_COND_ack_receiver; static PSI_cond_info all_server_conds[]= { -#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) +#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) { &key_COND_handler_count, "COND_handler_count", PSI_FLAG_GLOBAL}, -#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */ +#endif /* _WIN32 && !EMBEDDED_LIBRARY */ #ifdef HAVE_MMAP { &key_PAGE_cond, "PAGE::cond", 0}, { &key_COND_active, "TC_LOG_MMAP::COND_active", 0}, @@ -1161,21 +1154,11 @@ PSI_thread_key key_thread_ack_receiver; static PSI_thread_info all_server_threads[]= { -#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) +#if (defined (_WIN32) && !defined (EMBEDDED_LIBRARY)) { &key_thread_handle_con_namedpipes, "con_named_pipes", PSI_FLAG_GLOBAL}, -#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */ - -#if defined(HAVE_SMEM) && !defined(EMBEDDED_LIBRARY) - { &key_thread_handle_con_sharedmem, "con_shared_mem", PSI_FLAG_GLOBAL}, -#endif /* HAVE_SMEM && !EMBEDDED_LIBRARY */ - -#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) { &key_thread_handle_con_sockets, "con_sockets", PSI_FLAG_GLOBAL}, -#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */ - -#ifdef __WIN__ { &key_thread_handle_shutdown, "shutdown", PSI_FLAG_GLOBAL}, -#endif /* __WIN__ */ +#endif { &key_thread_bootstrap, "bootstrap", PSI_FLAG_GLOBAL}, { &key_thread_delayed_insert, "delayed_insert", 0}, @@ -1519,11 +1502,7 @@ int deny_severity = LOG_WARNING; ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE; Query_cache query_cache; #endif -#ifdef HAVE_SMEM -const char *shared_memory_base_name= default_shared_memory_base_name; -my_bool opt_enable_shared_memory; -HANDLE smem_event_connect_request= 0; -#endif + my_bool opt_use_ssl = 0; char *opt_ssl_ca= NULL, *opt_ssl_capath= NULL, *opt_ssl_cert= NULL, @@ -1585,9 +1564,6 @@ static bool read_init_file(char *file_name); #ifdef _WIN32 pthread_handler_t handle_connections_namedpipes(void *arg); #endif -#ifdef HAVE_SMEM -pthread_handler_t handle_connections_shared_memory(void *arg); -#endif pthread_handler_t handle_slave(void *arg); static void clean_up(bool print_message); static int test_if_case_insensitive(const char *dir_name); @@ -2011,21 +1987,6 @@ static void __cdecl kill_server(int sig_ptr) else sql_print_error(ER_DEFAULT(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */ -#ifdef HAVE_SMEM - /* - Send event to smem_event_connect_request for aborting - */ - if (opt_enable_shared_memory) - { - if (!SetEvent(smem_event_connect_request)) - { - DBUG_PRINT("error", - ("Got error: %ld from SetEvent of smem_event_connect_request", - GetLastError())); - } - } -#endif - /* Stop wsrep threads in case they are running. */ if (wsrep_running_threads > 0) { @@ -2786,9 +2747,10 @@ static void network_init(void) */ if (mysqld_unix_port[0] && !opt_bootstrap) { + size_t port_len; DBUG_PRINT("general",("UNIX Socket is %s",mysqld_unix_port)); - if (strlen(mysqld_unix_port) > (sizeof(UNIXaddr.sun_path) - 1)) + if ((port_len= strlen(mysqld_unix_port)) > sizeof(UNIXaddr.sun_path) - 1) { sql_print_error("The socket file path is too long (> %u): %s", (uint) sizeof(UNIXaddr.sun_path) - 1, mysqld_unix_port); @@ -2806,14 +2768,26 @@ static void network_init(void) bzero((char*) &UNIXaddr, sizeof(UNIXaddr)); UNIXaddr.sun_family = AF_UNIX; strmov(UNIXaddr.sun_path, mysqld_unix_port); - (void) unlink(mysqld_unix_port); +#if defined(__linux__) + /* Abstract socket */ + if (mysqld_unix_port[0] == '@') + { + UNIXaddr.sun_path[0]= '\0'; + port_len+= offsetof(struct sockaddr_un, sun_path); + } + else +#endif + { + (void) unlink(mysqld_unix_port); + port_len= sizeof(UNIXaddr); + } arg= 1; (void) mysql_socket_setsockopt(unix_sock,SOL_SOCKET,SO_REUSEADDR, (char*)&arg, sizeof(arg)); umask(0); if (mysql_socket_bind(unix_sock, reinterpret_cast<struct sockaddr *>(&UNIXaddr), - sizeof(UNIXaddr)) < 0) + port_len) < 0) { sql_perror("Can't start server : Bind on unix socket"); /* purecov: tested */ sql_print_error("Do you already have another mysqld server running on socket: %s ?",mysqld_unix_port); @@ -3647,7 +3621,7 @@ extern "C" void my_message_sql(uint error, const char *str, myf MyFlags); void my_message_sql(uint error, const char *str, myf MyFlags) { - THD *thd= current_thd; + THD *thd= MyFlags & ME_ERROR_LOG_ONLY ? NULL : current_thd; Sql_condition::enum_warning_level level; sql_print_message_func func; DBUG_ENTER("my_message_sql"); @@ -3656,13 +3630,15 @@ void my_message_sql(uint error, const char *str, myf MyFlags) DBUG_ASSERT(str != NULL); DBUG_ASSERT(error != 0); + DBUG_ASSERT((MyFlags & ~(ME_BELL | ME_ERROR_LOG | ME_ERROR_LOG_ONLY | + ME_NOTE | ME_WARNING | ME_FATAL)) == 0); - if (MyFlags & ME_JUST_INFO) + if (MyFlags & ME_NOTE) { level= Sql_condition::WARN_LEVEL_NOTE; func= sql_print_information; } - else if (MyFlags & ME_JUST_WARNING) + else if (MyFlags & ME_WARNING) { level= Sql_condition::WARN_LEVEL_WARN; func= sql_print_warning; @@ -3675,7 +3651,7 @@ void my_message_sql(uint error, const char *str, myf MyFlags) if (likely(thd)) { - if (unlikely(MyFlags & ME_FATALERROR)) + if (unlikely(MyFlags & ME_FATAL)) thd->is_fatal_error= 1; (void) thd->raise_condition(error, NULL, level, str); } @@ -3685,7 +3661,7 @@ void my_message_sql(uint error, const char *str, myf MyFlags) /* When simulating OOM, skip writing to error log to avoid mtr errors */ DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_VOID_RETURN;); - if (unlikely(!thd) || thd->log_all_errors || (MyFlags & ME_NOREFRESH)) + if (unlikely(!thd) || thd->log_all_errors || (MyFlags & ME_ERROR_LOG)) (*func)("%s: %s", my_progname_short, str); /* purecov: inspected */ DBUG_VOID_RETURN; } @@ -5613,7 +5589,7 @@ static int init_server_components() #ifndef EMBEDDED_LIBRARY - +#ifdef _WIN32 static void create_shutdown_thread() { #ifdef __WIN__ @@ -5631,19 +5607,14 @@ static void create_shutdown_thread() #endif /* __WIN__ */ } -#endif /* EMBEDDED_LIBRARY */ - -#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) static void handle_connections_methods() { pthread_t hThread; int error; DBUG_ENTER("handle_connections_methods"); - if (hPipe == INVALID_HANDLE_VALUE && - (!have_tcpip || opt_disable_networking) && - !opt_enable_shared_memory) + if (hPipe == INVALID_HANDLE_VALUE && opt_disable_networking) { - sql_print_error("TCP/IP, --shared-memory, or --named-pipe should be configured on NT OS"); + sql_print_error("TCP/IP, or --named-pipe should be configured on Windows"); unireg_abort(1); // Will not return } @@ -5674,20 +5645,6 @@ static void handle_connections_methods() handler_count--; } } -#ifdef HAVE_SMEM - if (opt_enable_shared_memory) - { - handler_count++; - if ((error= mysql_thread_create(key_thread_handle_con_sharedmem, - &hThread, &connection_attrib, - handle_connections_shared_memory, 0))) - { - sql_print_warning("Can't create thread to handle shared memory", - " (errno= %d)", error); - handler_count--; - } - } -#endif while (handler_count > 0) mysql_cond_wait(&COND_handler_count, &LOCK_start_thread); @@ -5703,10 +5660,11 @@ void decrement_handler_count() mysql_mutex_unlock(&LOCK_start_thread); my_thread_end(); } -#else +#else /* WIN32*/ +#define create_shutdown_thread() #define decrement_handler_count() -#endif /* defined(_WIN32) || defined(HAVE_SMEM) */ - +#endif +#endif /* EMBEDDED_LIBRARY */ #ifndef EMBEDDED_LIBRARY @@ -6178,11 +6136,11 @@ int mysqld_main(int argc, char **argv) /* Memory used when everything is setup */ start_memory_used= global_status_var.global_memory_used; -#if defined(_WIN32) || defined(HAVE_SMEM) +#ifdef _WIN32 handle_connections_methods(); #else handle_connections_sockets(); -#endif /* _WIN32 || HAVE_SMEM */ +#endif /* _WIN32 */ /* (void) pthread_attr_destroy(&connection_attrib); */ @@ -7014,250 +6972,6 @@ pthread_handler_t handle_connections_namedpipes(void *arg) } #endif /* _WIN32 */ - -#ifdef HAVE_SMEM - -/** - Thread of shared memory's service. - - @param arg Arguments of thread -*/ -pthread_handler_t handle_connections_shared_memory(void *arg) -{ - /* file-mapping object, use for create shared memory */ - HANDLE handle_connect_file_map= 0; - char *handle_connect_map= 0; // pointer on shared memory - HANDLE event_connect_answer= 0; - ulong smem_buffer_length= shared_memory_buffer_length + 4; - ulong connect_number= 1; - char *tmp= NULL; - char *suffix_pos; - char connect_number_char[22], *p; - const char *errmsg= 0; - SECURITY_ATTRIBUTES *sa_event= 0, *sa_mapping= 0; - my_thread_init(); - DBUG_ENTER("handle_connections_shared_memorys"); - DBUG_PRINT("general",("Waiting for allocated shared memory.")); - - /* - get enough space base-name + '_' + longest suffix we might ever send - */ - if (!(tmp= (char *)my_malloc(strlen(shared_memory_base_name) + 32L, - MYF(MY_FAE)))) - goto error; - - if (my_security_attr_create(&sa_event, &errmsg, - GENERIC_ALL, SYNCHRONIZE | EVENT_MODIFY_STATE)) - goto error; - - if (my_security_attr_create(&sa_mapping, &errmsg, - GENERIC_ALL, FILE_MAP_READ | FILE_MAP_WRITE)) - goto error; - - /* - The name of event and file-mapping events create agree next rule: - shared_memory_base_name+unique_part - Where: - shared_memory_base_name is unique value for each server - unique_part is unique value for each object (events and file-mapping) - */ - suffix_pos= strxmov(tmp,shared_memory_base_name,"_",NullS); - strmov(suffix_pos, "CONNECT_REQUEST"); - if ((smem_event_connect_request= CreateEvent(sa_event, - FALSE, FALSE, tmp)) == 0) - { - errmsg= "Could not create request event"; - goto error; - } - strmov(suffix_pos, "CONNECT_ANSWER"); - if ((event_connect_answer= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) - { - errmsg="Could not create answer event"; - goto error; - } - strmov(suffix_pos, "CONNECT_DATA"); - if ((handle_connect_file_map= - CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping, - PAGE_READWRITE, 0, sizeof(connect_number), tmp)) == 0) - { - errmsg= "Could not create file mapping"; - goto error; - } - if ((handle_connect_map= (char *)MapViewOfFile(handle_connect_file_map, - FILE_MAP_WRITE,0,0, - sizeof(DWORD))) == 0) - { - errmsg= "Could not create shared memory service"; - goto error; - } - - while (!abort_loop) - { - /* Wait a request from client */ - WaitForSingleObject(smem_event_connect_request,INFINITE); - - /* - it can be after shutdown command - */ - if (abort_loop) - goto error; - - HANDLE handle_client_file_map= 0; - char *handle_client_map= 0; - HANDLE event_client_wrote= 0; - HANDLE event_client_read= 0; // for transfer data server <-> client - HANDLE event_server_wrote= 0; - HANDLE event_server_read= 0; - HANDLE event_conn_closed= 0; - CONNECT *connect= 0; - - p= int10_to_str(connect_number, connect_number_char, 10); - /* - The name of event and file-mapping events create agree next rule: - shared_memory_base_name+unique_part+number_of_connection - Where: - shared_memory_base_name is uniquel value for each server - unique_part is unique value for each object (events and file-mapping) - number_of_connection is connection-number between server and client - */ - suffix_pos= strxmov(tmp,shared_memory_base_name,"_",connect_number_char, - "_",NullS); - strmov(suffix_pos, "DATA"); - if ((handle_client_file_map= - CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping, - PAGE_READWRITE, 0, smem_buffer_length, tmp)) == 0) - { - errmsg= "Could not create file mapping"; - goto errorconn; - } - if ((handle_client_map= (char*)MapViewOfFile(handle_client_file_map, - FILE_MAP_WRITE,0,0, - smem_buffer_length)) == 0) - { - errmsg= "Could not create memory map"; - goto errorconn; - } - strmov(suffix_pos, "CLIENT_WROTE"); - if ((event_client_wrote= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) - { - errmsg= "Could not create client write event"; - goto errorconn; - } - strmov(suffix_pos, "CLIENT_READ"); - if ((event_client_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) - { - errmsg= "Could not create client read event"; - goto errorconn; - } - strmov(suffix_pos, "SERVER_READ"); - if ((event_server_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) - { - errmsg= "Could not create server read event"; - goto errorconn; - } - strmov(suffix_pos, "SERVER_WROTE"); - if ((event_server_wrote= CreateEvent(sa_event, - FALSE, FALSE, tmp)) == 0) - { - errmsg= "Could not create server write event"; - goto errorconn; - } - strmov(suffix_pos, "CONNECTION_CLOSED"); - if ((event_conn_closed= CreateEvent(sa_event, - TRUE, FALSE, tmp)) == 0) - { - errmsg= "Could not create closed connection event"; - goto errorconn; - } - if (abort_loop) - goto errorconn; - - if (!(connect= new CONNECT)) - { - errmsg= "Could not create CONNECT object"; - goto errorconn; - } - - /* Send number of connection to client */ - int4store(handle_connect_map, connect_number); - if (!SetEvent(event_connect_answer)) - { - errmsg= "Could not send answer event"; - goto errorconn; - } - /* Set event that client should receive data */ - if (!SetEvent(event_client_read)) - { - errmsg= "Could not set client to read mode"; - goto errorconn; - } - if (!(connect->vio= vio_new_win32shared_memory(handle_client_file_map, - handle_client_map, - event_client_wrote, - event_client_read, - event_server_wrote, - event_server_read, - event_conn_closed))) - { - errmsg= "Could not create VIO object"; - goto errorconn; - } - connect->host= my_localhost; /* Host is unknown */ - create_new_thread(connect); - connect_number++; - continue; - -errorconn: - /* Could not form connection; Free used handlers/memort and retry */ - if (errmsg) - { - char buff[180]; - strxmov(buff, "Can't create shared memory connection: ", errmsg, ".", - NullS); - sql_perror(buff); - } - if (handle_client_file_map) - CloseHandle(handle_client_file_map); - if (handle_client_map) - UnmapViewOfFile(handle_client_map); - if (event_server_wrote) - CloseHandle(event_server_wrote); - if (event_server_read) - CloseHandle(event_server_read); - if (event_client_wrote) - CloseHandle(event_client_wrote); - if (event_client_read) - CloseHandle(event_client_read); - if (event_conn_closed) - CloseHandle(event_conn_closed); - - delete connect; - statistic_increment(aborted_connects,&LOCK_status); - statistic_increment(connection_errors_internal, &LOCK_status); - } - - /* End shared memory handling */ -error: - if (tmp) - my_free(tmp); - - if (errmsg) - { - char buff[180]; - strxmov(buff, "Can't create shared memory service: ", errmsg, ".", NullS); - sql_perror(buff); - } - my_security_attr_free(sa_event); - my_security_attr_free(sa_mapping); - if (handle_connect_map) UnmapViewOfFile(handle_connect_map); - if (handle_connect_file_map) CloseHandle(handle_connect_file_map); - if (event_connect_answer) CloseHandle(event_connect_answer); - if (smem_event_connect_request) CloseHandle(smem_event_connect_request); - DBUG_LEAVE; - decrement_handler_count(); - return 0; -} -#endif /* HAVE_SMEM */ #endif /* EMBEDDED_LIBRARY */ @@ -9061,9 +8775,6 @@ static int mysql_init_variables(void) ssl_acceptor_fd= 0; #endif /* ! EMBEDDED_LIBRARY */ #endif /* HAVE_OPENSSL */ -#ifdef HAVE_SMEM - shared_memory_base_name= default_shared_memory_base_name; -#endif #if defined(__WIN__) /* Allow Win32 users to move MySQL anywhere */ @@ -9806,10 +9517,10 @@ static int get_options(int *argc_ptr, char ***argv_ptr) errors. */ if (global_system_variables.log_warnings >= 10) - my_global_flags= MY_WME | ME_JUST_INFO; + my_global_flags= MY_WME | ME_NOTE; /* Log all errors not handled by thd->handle_error() to my_message_sql() */ if (global_system_variables.log_warnings >= 11) - my_global_flags|= ME_NOREFRESH; + my_global_flags|= ME_ERROR_LOG; if (my_assert_on_error) debug_assert_if_crashed_table= 1; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 0b29fcd2f11..7faae008dab 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1479,7 +1479,6 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler, { handler *save_file= file, *org_file; THD *thd= head->in_use; - MY_BITMAP * const save_vcol_set= head->vcol_set; MY_BITMAP * const save_read_set= head->read_set; MY_BITMAP * const save_write_set= head->write_set; DBUG_ENTER("QUICK_RANGE_SELECT::init_ror_merged_scan"); @@ -1537,14 +1536,14 @@ end: org_file= head->file; head->file= file; - head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap, &column_bitmap); + head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap); head->prepare_for_keyread(index, &column_bitmap); head->prepare_for_position(); head->file= org_file; /* Restore head->read_set (and write_set) to what they had before the call */ - head->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set); + head->column_bitmaps_set(save_read_set, save_write_set); if (reset()) { @@ -1559,7 +1558,7 @@ end: DBUG_RETURN(0); failure: - head->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set); + head->column_bitmaps_set(save_read_set, save_write_set); delete file; file= save_file; DBUG_RETURN(1); @@ -1893,6 +1892,118 @@ SEL_ARG::SEL_ARG(Field *field_,uint8 part_, left=right= &null_element; } + +/* + A number of helper classes: + SEL_ARG_LE, SEL_ARG_LT, SEL_ARG_GT, SEL_ARG_GE, + to share the code between: + Field::stored_field_make_mm_leaf() + Field::stored_field_make_mm_leaf_exact() +*/ +class SEL_ARG_LE: public SEL_ARG +{ +public: + SEL_ARG_LE(const uchar *key, Field *field) + :SEL_ARG(field, key, key) + { + if (!field->real_maybe_null()) + min_flag= NO_MIN_RANGE; // From start + else + { + min_value= is_null_string; + min_flag= NEAR_MIN; // > NULL + } + } +}; + + +class SEL_ARG_LT: public SEL_ARG_LE +{ +public: + /* + Use this constructor if value->save_in_field() went precisely, + without any data rounding or truncation. + */ + SEL_ARG_LT(const uchar *key, Field *field) + :SEL_ARG_LE(key, field) + { max_flag= NEAR_MAX; } + /* + Use this constructor if value->save_in_field() returned success, + but we don't know if rounding or truncation happened + (as some Field::store() do not report minor data changes). + */ + SEL_ARG_LT(THD *thd, const uchar *key, Field *field, Item *value) + :SEL_ARG_LE(key, field) + { + if (stored_field_cmp_to_item(thd, field, value) == 0) + max_flag= NEAR_MAX; + } +}; + + +class SEL_ARG_GT: public SEL_ARG +{ +public: + /* + Use this constructor if value->save_in_field() went precisely, + without any data rounding or truncation. + */ + SEL_ARG_GT(const uchar *key, const KEY_PART *key_part, Field *field) + :SEL_ARG(field, key, key) + { + // Don't use open ranges for partial key_segments + if (!(key_part->flag & HA_PART_KEY_SEG)) + min_flag= NEAR_MIN; + max_flag= NO_MAX_RANGE; + } + /* + Use this constructor if value->save_in_field() returned success, + but we don't know if rounding or truncation happened + (as some Field::store() do not report minor data changes). + */ + SEL_ARG_GT(THD *thd, const uchar *key, + const KEY_PART *key_part, Field *field, Item *value) + :SEL_ARG(field, key, key) + { + // Don't use open ranges for partial key_segments + if ((!(key_part->flag & HA_PART_KEY_SEG)) && + (stored_field_cmp_to_item(thd, field, value) <= 0)) + min_flag= NEAR_MIN; + max_flag= NO_MAX_RANGE; + } +}; + + +class SEL_ARG_GE: public SEL_ARG +{ +public: + /* + Use this constructor if value->save_in_field() went precisely, + without any data rounding or truncation. + */ + SEL_ARG_GE(const uchar *key, Field *field) + :SEL_ARG(field, key, key) + { + max_flag= NO_MAX_RANGE; + } + /* + Use this constructor if value->save_in_field() returned success, + but we don't know if rounding or truncation happened + (as some Field::store() do not report minor data changes). + */ + SEL_ARG_GE(THD *thd, const uchar *key, + const KEY_PART *key_part, Field *field, Item *value) + :SEL_ARG(field, key, key) + { + // Don't use open ranges for partial key_segments + if ((!(key_part->flag & HA_PART_KEY_SEG)) && + (stored_field_cmp_to_item(thd, field, value) < 0)) + min_flag= NEAR_MIN; + max_flag= NO_MAX_RANGE; + } +}; + + SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, SEL_ARG **next_arg) { @@ -4544,7 +4655,7 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records) if (max_cost != DBL_MAX && (busy_blocks+index_reads_cost) >= n_blocks) return 1; */ - JOIN *join= param->thd->lex->select_lex.join; + JOIN *join= param->thd->lex->first_select_lex()->join; if (!join || join->table_count == 1) { /* No join, assume reading is done in one 'sweep' */ @@ -8015,52 +8126,112 @@ Item_func_like::get_mm_leaf(RANGE_OPT_PARAM *param, SEL_ARG * Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param, Field *field, KEY_PART *key_part, - Item_func::Functype type, Item *value) + Item_func::Functype functype, Item *value) { - uint maybe_null=(uint) field->real_maybe_null(); - SEL_ARG *tree= 0; - MEM_ROOT *alloc= param->mem_root; - uchar *str; - int err; DBUG_ENTER("Item_bool_func::get_mm_leaf"); - DBUG_ASSERT(value); // IS NULL and IS NOT NULL are handled separately - if (key_part->image_type != Field::itRAW) DBUG_RETURN(0); // e.g. SPATIAL index + DBUG_RETURN(field->get_mm_leaf(param, key_part, this, + functype_to_scalar_comparison_op(functype), + value)); +} - if (param->using_real_indexes && - !field->optimize_range(param->real_keynr[key_part->key], - key_part->part) && - type != EQ_FUNC && - type != EQUAL_FUNC) - goto end; // Can't optimize this - if (!field->can_optimize_range(this, value, - type == EQUAL_FUNC || type == EQ_FUNC)) - goto end; +bool Field::can_optimize_scalar_range(const RANGE_OPT_PARAM *param, + const KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, + const Item *value) const +{ + bool is_eq_func= op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL; + if ((param->using_real_indexes && + !optimize_range(param->real_keynr[key_part->key], + key_part->part) && !is_eq_func) || + !can_optimize_range(cond, value, is_eq_func)) + return false; + return true; +} + + +uchar *Field::make_key_image(MEM_ROOT *mem_root, const KEY_PART *key_part) +{ + DBUG_ENTER("Field::make_key_image"); + uint maybe_null= (uint) real_maybe_null(); + uchar *str; + if (!(str= (uchar*) alloc_root(mem_root, key_part->store_length + 1))) + DBUG_RETURN(0); + if (maybe_null) + *str= (uchar) is_real_null(); // Set to 1 if null + get_key_image(str + maybe_null, key_part->length, key_part->image_type); + DBUG_RETURN(str); +} + + +SEL_ARG *Field::stored_field_make_mm_leaf_truncated(RANGE_OPT_PARAM *param, + scalar_comparison_op op, + Item *value) +{ + DBUG_ENTER("Field::stored_field_make_mm_leaf_truncated"); + if ((op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL) && + value->result_type() == item_cmp_type(result_type(), + value->result_type())) + DBUG_RETURN(new (param->mem_root) SEL_ARG_IMPOSSIBLE(this)); + /* + TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE + for the cases like int_field > 999999999999999999999999 as well. + */ + DBUG_RETURN(0); +} + - err= value->save_in_field_no_warnings(field, 1); +SEL_ARG *Field_num::get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value) +{ + DBUG_ENTER("Field_num::get_mm_leaf"); + if (!can_optimize_scalar_range(prm, key_part, cond, op, value)) + DBUG_RETURN(0); + int err= value->save_in_field_no_warnings(this, 1); + if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0) + DBUG_RETURN(&null_element); + if (err > 0 && cmp_type() != value->result_type()) + DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value)); + DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value)); +} + + +SEL_ARG *Field_temporal::get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value) +{ + DBUG_ENTER("Field_temporal::get_mm_leaf"); + if (!can_optimize_scalar_range(prm, key_part, cond, op, value)) + DBUG_RETURN(0); + int err= value->save_in_field_no_warnings(this, 1); + if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0) + DBUG_RETURN(&null_element); if (err > 0) - { - if (field->type_handler() == &type_handler_enum || - field->type_handler() == &type_handler_set) - { - if (type == EQ_FUNC || type == EQUAL_FUNC) - tree= new (alloc) SEL_ARG_IMPOSSIBLE(field); - goto end; - } + DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value)); + DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value)); +} - if (err == 2 && field->cmp_type() == STRING_RESULT) - { - if (type == EQ_FUNC || type == EQUAL_FUNC) - tree= new (alloc) SEL_ARG_IMPOSSIBLE(field); - else - tree= NULL; /* Cannot infer anything */ - goto end; - } - if (err == 3 && field->type() == FIELD_TYPE_DATE) +SEL_ARG *Field_date_common::get_mm_leaf(RANGE_OPT_PARAM *prm, + KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, + Item *value) +{ + DBUG_ENTER("Field_date_common::get_mm_leaf"); + if (!can_optimize_scalar_range(prm, key_part, cond, op, value)) + DBUG_RETURN(0); + int err= value->save_in_field_no_warnings(this, 1); + if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0) + DBUG_RETURN(&null_element); + if (err > 0) + { + if (err == 3) { /* We were saving DATETIME into a DATE column, the conversion went ok @@ -8080,76 +8251,86 @@ Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param, be done together with other types at the end of this function (grep for stored_field_cmp_to_item) */ - if (type == EQ_FUNC || type == EQUAL_FUNC) - { - tree= new (alloc) SEL_ARG_IMPOSSIBLE(field); - goto end; - } - // Continue with processing non-equality ranges - } - else if (field->cmp_type() != value->result_type()) - { - if ((type == EQ_FUNC || type == EQUAL_FUNC) && - value->result_type() == item_cmp_type(field->result_type(), - value->result_type())) - { - tree= new (alloc) SEL_ARG_IMPOSSIBLE(field); - goto end; - } - else - { - /* - TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE - for the cases like int_field > 999999999999999999999999 as well. - */ - tree= 0; - goto end; - } - } - - /* - guaranteed at this point: err > 0; field and const of same type - If an integer got bounded (e.g. to within 0..255 / -128..127) - for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN) - */ - else if (err == 1 && field->result_type() == INT_RESULT) - { - if (type == LT_FUNC && (value->val_int() > 0)) - type= LE_FUNC; - else if (type == GT_FUNC && - (field->type() != FIELD_TYPE_BIT) && - !((Field_num*)field)->unsigned_flag && - !((Item_int*)value)->unsigned_flag && - (value->val_int() < 0)) - type= GE_FUNC; + if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL) + DBUG_RETURN(new (prm->mem_root) SEL_ARG_IMPOSSIBLE(this)); + DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value)); } + DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value)); } - else if (err < 0) + DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value)); +} + + +SEL_ARG *Field_str::get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value) +{ + DBUG_ENTER("Field_str::get_mm_leaf"); + if (!can_optimize_scalar_range(prm, key_part, cond, op, value)) + DBUG_RETURN(0); + int err= value->save_in_field_no_warnings(this, 1); + if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0) + DBUG_RETURN(&null_element); + if (err > 0) { - /* This happens when we try to insert a NULL field in a not null column */ - tree= &null_element; // cmp with NULL is never TRUE - goto end; + if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL) + DBUG_RETURN(new (prm->mem_root) SEL_ARG_IMPOSSIBLE(this)); + DBUG_RETURN(NULL); /* Cannot infer anything */ } + DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value)); +} - /* - Any sargable predicate except "<=>" involving NULL as a constant is always - FALSE - */ - if (type != EQUAL_FUNC && field->is_real_null()) + +SEL_ARG *Field::get_mm_leaf_int(RANGE_OPT_PARAM *prm, KEY_PART *key_part, + const Item_bool_func *cond, + scalar_comparison_op op, Item *value, + bool unsigned_field) +{ + DBUG_ENTER("Field::get_mm_leaf_int"); + if (!can_optimize_scalar_range(prm, key_part, cond, op, value)) + DBUG_RETURN(0); + int err= value->save_in_field_no_warnings(this, 1); + if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0) + DBUG_RETURN(&null_element); + if (err > 0) { - tree= &null_element; - goto end; + if (value->result_type() != INT_RESULT) + DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value)); + else + DBUG_RETURN(stored_field_make_mm_leaf_bounded_int(prm, key_part, + op, value, + unsigned_field)); } - - str= (uchar*) alloc_root(alloc, key_part->store_length+1); - if (!str) - goto end; - if (maybe_null) - *str= (uchar) field->is_real_null(); // Set to 1 if null - field->get_key_image(str+maybe_null, key_part->length, - key_part->image_type); - if (!(tree= new (alloc) SEL_ARG(field, str, str))) - goto end; // out of memory + if (value->result_type() != INT_RESULT) + DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value)); + DBUG_RETURN(stored_field_make_mm_leaf_exact(prm, key_part, op, value)); +} + + +/* + This method is called when: + - value->save_in_field_no_warnings() returned err > 0 + - and both field and "value" are of integer data types + If an integer got bounded (e.g. to within 0..255 / -128..127) + for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN) +*/ + +SEL_ARG *Field::stored_field_make_mm_leaf_bounded_int(RANGE_OPT_PARAM *param, + KEY_PART *key_part, + scalar_comparison_op op, + Item *value, + bool unsigned_field) +{ + DBUG_ENTER("Field::stored_field_make_mm_leaf_bounded_int"); + if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL) // e.g. tinyint = 200 + DBUG_RETURN(new (param->mem_root) SEL_ARG_IMPOSSIBLE(this)); + longlong item_val= value->val_int(); + + if (op == SCALAR_CMP_LT && item_val > 0) + op= SCALAR_CMP_LE; // e.g. rewrite (tinyint < 200) to (tinyint <= 127) + else if (op == SCALAR_CMP_GT && !unsigned_field && + !value->unsigned_flag && item_val < 0) + op= SCALAR_CMP_GE; // e.g. rewrite (tinyint > -200) to (tinyint >= -128) /* Check if we are comparing an UNSIGNED integer with a negative constant. @@ -8162,66 +8343,74 @@ Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param, negative integers (which otherwise fails because at query execution time negative integers are cast to unsigned if compared with unsigned). */ - if (field->result_type() == INT_RESULT && - value->result_type() == INT_RESULT && - ((field->type() == FIELD_TYPE_BIT || - ((Field_num *) field)->unsigned_flag) && - !((Item_int*) value)->unsigned_flag)) + if (unsigned_field && !value->unsigned_flag && item_val < 0) { - longlong item_val= value->val_int(); - if (item_val < 0) - { - if (type == LT_FUNC || type == LE_FUNC) - { - tree->type= SEL_ARG::IMPOSSIBLE; - goto end; - } - if (type == GT_FUNC || type == GE_FUNC) - { - tree= 0; - goto end; - } - } + if (op == SCALAR_CMP_LT || op == SCALAR_CMP_LE) // e.g. uint < -1 + DBUG_RETURN(new (param->mem_root) SEL_ARG_IMPOSSIBLE(this)); + if (op == SCALAR_CMP_GT || op == SCALAR_CMP_GE) // e.g. uint > -1 + DBUG_RETURN(0); } + DBUG_RETURN(stored_field_make_mm_leaf_exact(param, key_part, op, value)); +} - switch (type) { - case LT_FUNC: - if (stored_field_cmp_to_item(param->thd, field, value) == 0) - tree->max_flag=NEAR_MAX; - /* fall through */ - case LE_FUNC: - if (!maybe_null) - tree->min_flag=NO_MIN_RANGE; /* From start */ - else - { // > NULL - tree->min_value=is_null_string; - tree->min_flag=NEAR_MIN; - } - break; - case GT_FUNC: - /* Don't use open ranges for partial key_segments */ - if ((!(key_part->flag & HA_PART_KEY_SEG)) && - (stored_field_cmp_to_item(param->thd, field, value) <= 0)) - tree->min_flag=NEAR_MIN; - tree->max_flag= NO_MAX_RANGE; - break; - case GE_FUNC: - /* Don't use open ranges for partial key_segments */ - if ((!(key_part->flag & HA_PART_KEY_SEG)) && - (stored_field_cmp_to_item(param->thd, field, value) < 0)) - tree->min_flag= NEAR_MIN; - tree->max_flag=NO_MAX_RANGE; - break; - case EQ_FUNC: - case EQUAL_FUNC: - break; - default: - DBUG_ASSERT(0); + +SEL_ARG *Field::stored_field_make_mm_leaf(RANGE_OPT_PARAM *param, + KEY_PART *key_part, + scalar_comparison_op op, + Item *value) +{ + DBUG_ENTER("Field::stored_field_make_mm_leaf"); + THD *thd= param->thd; + MEM_ROOT *mem_root= param->mem_root; + uchar *str; + if (!(str= make_key_image(param->mem_root, key_part))) + DBUG_RETURN(0); + + switch (op) { + case SCALAR_CMP_LE: + DBUG_RETURN(new (mem_root) SEL_ARG_LE(str, this)); + case SCALAR_CMP_LT: + DBUG_RETURN(new (mem_root) SEL_ARG_LT(thd, str, this, value)); + case SCALAR_CMP_GT: + DBUG_RETURN(new (mem_root) SEL_ARG_GT(thd, str, key_part, this, value)); + case SCALAR_CMP_GE: + DBUG_RETURN(new (mem_root) SEL_ARG_GE(thd, str, key_part, this, value)); + case SCALAR_CMP_EQ: + case SCALAR_CMP_EQUAL: + DBUG_RETURN(new (mem_root) SEL_ARG(this, str, str)); break; } + DBUG_ASSERT(0); + DBUG_RETURN(NULL); +} -end: - DBUG_RETURN(tree); + +SEL_ARG *Field::stored_field_make_mm_leaf_exact(RANGE_OPT_PARAM *param, + KEY_PART *key_part, + scalar_comparison_op op, + Item *value) +{ + DBUG_ENTER("Field::stored_field_make_mm_leaf_exact"); + uchar *str; + if (!(str= make_key_image(param->mem_root, key_part))) + DBUG_RETURN(0); + + switch (op) { + case SCALAR_CMP_LE: + DBUG_RETURN(new (param->mem_root) SEL_ARG_LE(str, this)); + case SCALAR_CMP_LT: + DBUG_RETURN(new (param->mem_root) SEL_ARG_LT(str, this)); + case SCALAR_CMP_GT: + DBUG_RETURN(new (param->mem_root) SEL_ARG_GT(str, key_part, this)); + case SCALAR_CMP_GE: + DBUG_RETURN(new (param->mem_root) SEL_ARG_GE(str, this)); + case SCALAR_CMP_EQ: + case SCALAR_CMP_EQUAL: + DBUG_RETURN(new (param->mem_root) SEL_ARG(this, str, str)); + break; + } + DBUG_ASSERT(0); + DBUG_RETURN(NULL); } @@ -11351,7 +11540,6 @@ int QUICK_RANGE_SELECT::reset() HANDLER_BUFFER empty_buf; MY_BITMAP * const save_read_set= head->read_set; MY_BITMAP * const save_write_set= head->write_set; - MY_BITMAP * const save_vcol_set= head->vcol_set; DBUG_ENTER("QUICK_RANGE_SELECT::reset"); last_range= NULL; cur_range= (QUICK_RANGE**) ranges.buffer; @@ -11365,8 +11553,7 @@ int QUICK_RANGE_SELECT::reset() } if (in_ror_merged_scan) - head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap, - &column_bitmap); + head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap); if (file->inited == handler::NONE) { @@ -11412,8 +11599,7 @@ int QUICK_RANGE_SELECT::reset() err: /* Restore bitmaps set on entry */ if (in_ror_merged_scan) - head->column_bitmaps_set_no_signal(save_read_set, save_write_set, - save_vcol_set); + head->column_bitmaps_set_no_signal(save_read_set, save_write_set); DBUG_RETURN(error); } @@ -11444,16 +11630,13 @@ int QUICK_RANGE_SELECT::get_next() MY_BITMAP * const save_read_set= head->read_set; MY_BITMAP * const save_write_set= head->write_set; - MY_BITMAP * const save_vcol_set= head->vcol_set; /* We don't need to signal the bitmap change as the bitmap is always the same for this head->file */ - head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap, - &column_bitmap); + head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap); result= file->multi_range_read_next(&dummy); - head->column_bitmaps_set_no_signal(save_read_set, save_write_set, - save_vcol_set); + head->column_bitmaps_set_no_signal(save_read_set, save_write_set); DBUG_RETURN(result); } @@ -13028,7 +13211,8 @@ check_group_min_max_predicates(Item *cond, Item_field *min_max_arg_item, if (args[0] && args[1]) // this is a binary function or BETWEEN { - DBUG_ASSERT(pred->is_bool_type()); + DBUG_ASSERT(pred->fixed_type_handler()); + DBUG_ASSERT(pred->fixed_type_handler()->is_bool_type()); Item_bool_func *bool_func= (Item_bool_func*) pred; Field *field= min_max_arg_item->field; if (!args[2]) // this is a binary function diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 13c0ce0c157..d1877c6c245 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -519,6 +519,7 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs, if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0 !child_select->is_part_of_union() && // 1 parent_unit->first_select()->leaf_tables.elements && // 2 + child_select->outer_select() && child_select->outer_select()->leaf_tables.elements && // 2A subquery_types_allow_materialization(in_subs) && (in_subs->is_top_level_item() || //3 @@ -826,7 +827,7 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs) { DBUG_ENTER("subquery_types_allow_materialization"); - DBUG_ASSERT(in_subs->left_expr->fixed); + DBUG_ASSERT(in_subs->left_expr->is_fixed()); List_iterator<Item> it(in_subs->unit->first_select()->item_list); uint elements= in_subs->unit->first_select()->item_list.elements; @@ -902,7 +903,7 @@ bool make_in_exists_conversion(THD *thd, JOIN *join, Item_in_subselect *item) /* We're going to finalize IN->EXISTS conversion. Normally, IN->EXISTS conversion takes place inside the - Item_subselect::fix_fields() call, where item_subselect->fixed==FALSE (as + Item_subselect::fix_fields() call, where item_subselect->is_fixed()==FALSE (as fix_fields() haven't finished yet) and item_subselect->changed==FALSE (as the conversion haven't been finalized) @@ -929,7 +930,7 @@ bool make_in_exists_conversion(THD *thd, JOIN *join, Item_in_subselect *item) item->fixed= 1; Item *substitute= item->substitution; - bool do_fix_fields= !item->substitution->fixed; + bool do_fix_fields= !item->substitution->is_fixed(); /* The Item_subselect has already been wrapped with Item_in_optimizer, so we should search for item->optimizer, not 'item'. @@ -1265,7 +1266,7 @@ bool convert_join_subqueries_to_semijoins(JOIN *join) in_subq->fixed= 1; Item *substitute= in_subq->substitution; - bool do_fix_fields= !in_subq->substitution->fixed; + bool do_fix_fields= !in_subq->substitution->is_fixed(); Item **tree= (in_subq->emb_on_expr_nest == NO_JOIN_NEST)? &join->conds : &(in_subq->emb_on_expr_nest->on_expr); Item *replace_me= in_subq->original_item(); @@ -1800,7 +1801,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) subq_lex->ref_pointer_array[i]); if (!item_eq) DBUG_RETURN(TRUE); - DBUG_ASSERT(subq_pred->left_expr->element_index(i)->fixed); + DBUG_ASSERT(subq_pred->left_expr->element_index(i)->is_fixed()); if (subq_pred->left_expr_orig->element_index(i) != subq_pred->left_expr->element_index(i)) thd->change_item_tree(item_eq->arguments(), @@ -5509,31 +5510,454 @@ int select_value_catcher::send_data(List<Item> &items) } -/* - Setup JTBM join tabs for execution +/** + @brief + Conjugate conditions after optimize_cond() call + + @param thd the thread handle + @param cond the condition where to attach new conditions + @param cond_eq IN/OUT the multiple equalities of cond + @param new_conds IN/OUT the list of conditions needed to add + @param cond_value the returned value of the condition + + @details + The method creates new condition through conjunction of cond and + the conditions from new_conds list. + The method is called after optimize_cond() for cond. The result + of the conjunction should be the same as if it was done before the + the optimize_cond() call. + + @retval NULL if an error occurs + @retval otherwise the created condition +*/ + +Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond, + COND_EQUAL **cond_eq, + List<Item> &new_conds, + Item::cond_result *cond_value) +{ + COND_EQUAL new_cond_equal; + Item *item; + Item_equal *equality; + bool is_simplified_cond= false; + List_iterator<Item> li(new_conds); + List_iterator_fast<Item_equal> it(new_cond_equal.current_level); + + /* + Creates multiple equalities new_cond_equal from new_conds list + equalities. If multiple equality can't be created or the condition + from new_conds list isn't an equality the method leaves it in new_conds + list. + + The equality can't be converted into the multiple equality if it + is a knowingly false or true equality. + For example, (3 = 1) equality. + */ + while ((item=li++)) + { + if (item->type() == Item::FUNC_ITEM && + ((Item_func *) item)->functype() == Item_func::EQ_FUNC && + check_simple_equality(thd, + Item::Context(Item::ANY_SUBST, + ((Item_func_equal *)item)->compare_type_handler(), + ((Item_func_equal *)item)->compare_collation()), + ((Item_func *)item)->arguments()[0]->real_item(), + ((Item_func *)item)->arguments()[1]->real_item(), + &new_cond_equal)) + li.remove(); + } + + it.rewind(); + if (cond && cond->type() == Item::COND_ITEM && + ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) + { + /* + cond is an AND-condition. + The method conjugates the AND-condition cond, created multiple + equalities new_cond_equal and remain conditions from new_conds. + + First, the method disjoins multiple equalities of cond and + merges new_cond_equal multiple equalities with these equalities. + It checks if after the merge the multiple equalities are knowingly + true or false equalities. + It attaches to cond the conditions from new_conds list and the result + of the merge of multiple equalities. The multiple equalities are + attached only to the upper level of AND-condition cond. So they + should be pushed down to the inner levels of cond AND-condition + if needed. It is done by propagate_new_equalities(). + */ + COND_EQUAL *cond_equal= &((Item_cond_and *) cond)->m_cond_equal; + List<Item_equal> *cond_equalities= &cond_equal->current_level; + List<Item> *and_args= ((Item_cond_and *)cond)->argument_list(); + and_args->disjoin((List<Item> *) cond_equalities); + and_args->append(&new_conds); + + while ((equality= it++)) + { + equality->upper_levels= 0; + equality->merge_into_list(thd, cond_equalities, false, false); + } + List_iterator_fast<Item_equal> ei(*cond_equalities); + while ((equality= ei++)) + { + if (equality->const_item() && !equality->val_int()) + is_simplified_cond= true; + equality->fixed= 0; + if (equality->fix_fields(thd, NULL)) + return NULL; + } + + and_args->append((List<Item> *) cond_equalities); + *cond_eq= &((Item_cond_and *) cond)->m_cond_equal; + + propagate_new_equalities(thd, cond, cond_equalities, + cond_equal->upper_levels, + &is_simplified_cond); + cond= cond->propagate_equal_fields(thd, + Item::Context_boolean(), + cond_equal); + } + else + { + /* + cond isn't AND-condition or is NULL. + There can be several cases: + + 1. cond is a multiple equality. + In this case cond is merged with the multiple equalities of + new_cond_equal. + The new condition is created with the conjunction of new_conds + list conditions and the result of merge of multiple equalities. + 2. cond is NULL + The new condition is created from the conditions of new_conds + list and multiple equalities from new_cond_equal. + 3. Otherwise + In this case the new condition is created from cond, remain conditions + from new_conds list and created multiple equalities from + new_cond_equal. + */ + List<Item> new_conds_list; + /* Flag is set to true if cond is a multiple equality */ + bool is_mult_eq= (cond && cond->type() == Item::FUNC_ITEM && + ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC); + + if (cond && !is_mult_eq && + new_conds_list.push_back(cond, thd->mem_root)) + return NULL; + + if (new_conds.elements > 0) + { + li.rewind(); + while ((item=li++)) + { + if (item->fix_fields_if_needed(thd, NULL)) + return NULL; + if (item->const_item() && !item->val_int()) + is_simplified_cond= true; + } + + if (new_conds.elements > 1) + new_conds_list.append(&new_conds); + else + { + li.rewind(); + item= li++; + if (new_conds_list.push_back(item, thd->mem_root)) + return NULL; + } + } + + if (new_cond_equal.current_level.elements > 0) + { + if (is_mult_eq) + { + Item_equal *eq_cond= (Item_equal *)cond; + eq_cond->upper_levels= 0; + eq_cond->merge_into_list(thd, &new_cond_equal.current_level, + false, false); + + while ((equality= it++)) + { + if (equality->const_item() && !equality->val_int()) + is_simplified_cond= true; + } + + if (new_cond_equal.current_level.elements + + new_conds_list.elements == 1) + { + it.rewind(); + equality= it++; + equality->fixed= 0; + if (equality->fix_fields(thd, NULL)) + return NULL; + } + (*cond_eq)->copy(new_cond_equal); + } + new_conds_list.append((List<Item> *)&new_cond_equal.current_level); + } + + if (new_conds_list.elements > 1) + { + Item_cond_and *and_cond= + new (thd->mem_root) Item_cond_and(thd, new_conds_list); + + and_cond->m_cond_equal.copy(new_cond_equal); + cond= (Item *)and_cond; + *cond_eq= &((Item_cond_and *)cond)->m_cond_equal; + } + else + { + List_iterator_fast<Item> iter(new_conds_list); + cond= iter++; + } + + if (cond->fix_fields_if_needed(thd, NULL)) + return NULL; + + if (new_cond_equal.current_level.elements > 0) + cond= cond->propagate_equal_fields(thd, + Item::Context_boolean(), + &new_cond_equal); + } + + /* + If it was found that some of the created condition parts are knowingly + true or false equalities the method calls removes_eq_cond() to remove them + from cond and set the cond_value to the appropriate value. + */ + if (is_simplified_cond) + cond= cond->remove_eq_conds(thd, cond_value, true); + return cond; +} + + +/** + @brief Materialize a degenerate jtbm semi join + + @param thd thread handler + @param tbl table list for the target jtbm semi join table + @param subq_pred IN subquery predicate with the degenerate jtbm semi join + @param eq_list IN/OUT the list where to add produced equalities + + @details + The method materializes the degenerate jtbm semi join for the + subquery from the IN subquery predicate subq_pred taking table + as the target for materialization. + Any degenerate table is guaranteed to produce 0 or 1 record. + Examples of both cases: + + select * from ot where col in (select ... from it where 2>3) + select * from ot where col in (select MY_MIN(it.key) from it) + + in this case, there is no necessity to create a temp.table for + materialization. + We now just need to + 1. Check whether 1 or 0 records are produced, setup this as a + constant join tab. + 2. Create a dummy temporary table, because all of the join + optimization code relies on TABLE object being present. + + In the case when materialization produces one row the function + additionally creates equalities between the expressions from the + left part of the IN subquery predicate and the corresponding + columns of the produced row. These equalities are added to the + list eq_list. They are supposed to be conjuncted with the condition + of the WHERE clause. + + @retval TRUE if an error occurs + @retval FALSE otherwise */ -bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, - Item **join_where) +bool execute_degenerate_jtbm_semi_join(THD *thd, + TABLE_LIST *tbl, + Item_in_subselect *subq_pred, + List<Item> &eq_list) +{ + DBUG_ENTER("execute_degenerate_jtbm_semi_join"); + select_value_catcher *new_sink; + + DBUG_ASSERT(subq_pred->engine->engine_type() == + subselect_engine::SINGLE_SELECT_ENGINE); + subselect_single_select_engine *engine= + (subselect_single_select_engine*)subq_pred->engine; + if (!(new_sink= new (thd->mem_root) select_value_catcher(thd, subq_pred))) + DBUG_RETURN(TRUE); + if (new_sink->setup(&engine->select_lex->join->fields_list) || + engine->select_lex->join->change_result(new_sink, NULL) || + engine->exec()) + { + DBUG_RETURN(TRUE); + } + subq_pred->is_jtbm_const_tab= TRUE; + + if (new_sink->assigned) + { + /* + Subselect produced one row, which is saved in new_sink->row. + Save "left_expr[i] == row[i]" equalities into the eq_list. + */ + subq_pred->jtbm_const_row_found= TRUE; + + Item *eq_cond; + for (uint i= 0; i < subq_pred->left_expr->cols(); i++) + { + eq_cond= + new (thd->mem_root) Item_func_eq(thd, + subq_pred->left_expr->element_index(i), + new_sink->row[i]); + if (!eq_cond || eq_cond->fix_fields(thd, NULL) || + eq_list.push_back(eq_cond, thd->mem_root)) + DBUG_RETURN(TRUE); + } + } + else + { + /* Subselect produced no rows. Just set the flag */ + subq_pred->jtbm_const_row_found= FALSE; + } + + TABLE *dummy_table; + if (!(dummy_table= create_dummy_tmp_table(thd))) + DBUG_RETURN(TRUE); + tbl->table= dummy_table; + tbl->table->pos_in_table_list= tbl; + /* + Note: the table created above may be freed by: + 1. JOIN_TAB::cleanup(), when the parent join is a regular join. + 2. cleanup_empty_jtbm_semi_joins(), when the parent join is a + degenerate join (e.g. one with "Impossible where"). + */ + setup_table_map(tbl->table, tbl, tbl->jtbm_table_no); + DBUG_RETURN(FALSE); +} + + +/** + @brief + Execute degenerate jtbm semi joins before optimize_cond() for parent + + @param join the parent join for jtbm semi joins + @param join_list the list of tables where jtbm semi joins are processed + @param eq_list IN/OUT the list where to add equalities produced after + materialization of single-row degenerate jtbm semi joins + + @details + The method traverses join_list trying to find any degenerate jtbm semi + joins for subqueries of IN predicates. For each degenerate jtbm + semi join execute_degenerate_jtbm_semi_join() is called. As a result + of this call new equalities that substitute for single-row materialized + jtbm semi join are added to eq_list. + + In the case when a table is nested in another table 'nested_join' the + method is recursively called for the join_list of the 'nested_join' trying + to find in the list any degenerate jtbm semi joins. Currently a jtbm semi + join may occur in a mergeable semi join nest. + + @retval TRUE if an error occurs + @retval FALSE otherwise +*/ + +bool setup_degenerate_jtbm_semi_joins(JOIN *join, + List<TABLE_LIST> *join_list, + List<Item> &eq_list) +{ + TABLE_LIST *table; + NESTED_JOIN *nested_join; + List_iterator<TABLE_LIST> li(*join_list); + THD *thd= join->thd; + DBUG_ENTER("setup_degenerate_jtbm_semi_joins"); + + while ((table= li++)) + { + Item_in_subselect *subq_pred; + + if ((subq_pred= table->jtbm_subselect)) + { + JOIN *subq_join= subq_pred->unit->first_select()->join; + + if (!subq_join->tables_list || !subq_join->table_count) + { + if (execute_degenerate_jtbm_semi_join(thd, + table, + subq_pred, + eq_list)) + DBUG_RETURN(TRUE); + join->is_orig_degenerated= true; + } + } + if ((nested_join= table->nested_join)) + { + if (setup_degenerate_jtbm_semi_joins(join, + &nested_join->join_list, + eq_list)) + DBUG_RETURN(TRUE); + } + } + DBUG_RETURN(FALSE); +} + + +/** + @brief + Optimize jtbm semi joins for materialization + + @param join the parent join for jtbm semi joins + @param join_list the list of TABLE_LIST objects where jtbm semi join + can occur + @param eq_list IN/OUT the list where to add produced equalities + + @details + This method is called by the optimizer after the call of + optimize_cond() for parent select. + The method traverses join_list trying to find any jtbm semi joins for + subqueries from IN predicates and optimizes them. + After the optimization some of jtbm semi joins may become degenerate. + For example the subquery 'SELECT MAX(b) FROM t2' from the query + + SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2); + + will become degenerate if there is an index on t2.b. + If a subquery becomes degenerate it is handled by the function + execute_degenerate_jtbm_semi_join(). + + Otherwise the method creates a temporary table in which the subquery + of the jtbm semi join will be materialied. + + The function saves the equalities between all pairs of the expressions + from the left part of the IN subquery predicate and the corresponding + columns of the subquery from the predicate in eq_list appending them + to the list. The equalities of eq_list will be later conjucted with the + condition of the WHERE clause. + + In the case when a table is nested in another table 'nested_join' the + method is recursively called for the join_list of the 'nested_join' trying + to find in the list any degenerate jtbm semi joins. Currently a jtbm semi + join may occur in a mergeable semi join nest. + + @retval TRUE if an error occurs + @retval FALSE otherwise +*/ + +bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, + List<Item> &eq_list) { TABLE_LIST *table; NESTED_JOIN *nested_join; List_iterator<TABLE_LIST> li(*join_list); THD *thd= join->thd; DBUG_ENTER("setup_jtbm_semi_joins"); - + while ((table= li++)) { - Item_in_subselect *item; + Item_in_subselect *subq_pred; - if ((item= table->jtbm_subselect)) + if ((subq_pred= table->jtbm_subselect)) { - Item_in_subselect *subq_pred= item; double rows; double read_time; /* - Perform optimization of the subquery, so that we know estmated + Perform optimization of the subquery, so that we know estimated - cost of materialization process - how many records will be in the materialized temp.table */ @@ -5546,102 +5970,37 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, if (!subq_join->tables_list || !subq_join->table_count) { - /* - A special case; subquery's join is degenerate, and it either produces - 0 or 1 record. Examples of both cases: - - select * from ot where col in (select ... from it where 2>3) - select * from ot where col in (select MY_MIN(it.key) from it) - - in this case, the subquery predicate has not been setup for - materialization. In particular, there is no materialized temp.table. - We'll now need to - 1. Check whether 1 or 0 records are produced, setup this as a - constant join tab. - 2. Create a dummy temporary table, because all of the join - optimization code relies on TABLE object being present (here we - follow a bad tradition started by derived tables) - */ - DBUG_ASSERT(subq_pred->engine->engine_type() == - subselect_engine::SINGLE_SELECT_ENGINE); - subselect_single_select_engine *engine= - (subselect_single_select_engine*)subq_pred->engine; - select_value_catcher *new_sink; - if (!(new_sink= - new (thd->mem_root) select_value_catcher(thd, subq_pred))) - DBUG_RETURN(TRUE); - if (new_sink->setup(&engine->select_lex->join->fields_list) || - engine->select_lex->join->change_result(new_sink, NULL) || - engine->exec()) - { + if (!join->is_orig_degenerated && + execute_degenerate_jtbm_semi_join(thd, table, subq_pred, + eq_list)) DBUG_RETURN(TRUE); - } - subq_pred->is_jtbm_const_tab= TRUE; - - if (new_sink->assigned) - { - subq_pred->jtbm_const_row_found= TRUE; - /* - Subselect produced one row, which is saved in new_sink->row. - Inject "left_expr[i] == row[i] equalities into parent's WHERE. - */ - Item *eq_cond; - for (uint i= 0; i < subq_pred->left_expr->cols(); i++) - { - eq_cond= new (thd->mem_root) - Item_func_eq(thd, subq_pred->left_expr->element_index(i), - new_sink->row[i]); - if (!eq_cond) - DBUG_RETURN(1); - - if (!((*join_where)= and_items(thd, *join_where, eq_cond)) || - (*join_where)->fix_fields(thd, join_where)) - DBUG_RETURN(1); - } - } - else - { - /* Subselect produced no rows. Just set the flag, */ - subq_pred->jtbm_const_row_found= FALSE; - } - - /* Set up a dummy TABLE*, optimizer code needs JOIN_TABs to have TABLE */ - TABLE *dummy_table; - if (!(dummy_table= create_dummy_tmp_table(thd))) - DBUG_RETURN(1); - table->table= dummy_table; - table->table->pos_in_table_list= table; - /* - Note: the table created above may be freed by: - 1. JOIN_TAB::cleanup(), when the parent join is a regular join. - 2. cleanup_empty_jtbm_semi_joins(), when the parent join is a - degenerate join (e.g. one with "Impossible where"). - */ - setup_table_map(table->table, table, table->jtbm_table_no); } else { DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION)); subq_pred->is_jtbm_const_tab= FALSE; subselect_hash_sj_engine *hash_sj_engine= - ((subselect_hash_sj_engine*)item->engine); + ((subselect_hash_sj_engine*)subq_pred->engine); table->table= hash_sj_engine->tmp_table; table->table->pos_in_table_list= table; setup_table_map(table->table, table, table->jtbm_table_no); - Item *sj_conds= hash_sj_engine->semi_join_conds; - - (*join_where)= and_items(thd, *join_where, sj_conds); - (*join_where)->fix_fields_if_needed(thd, join_where); + List_iterator<Item> li(*hash_sj_engine->semi_join_conds->argument_list()); + Item *item; + while ((item=li++)) + { + item->update_used_tables(); + if (eq_list.push_back(item, thd->mem_root)) + DBUG_RETURN(TRUE); + } } table->table->maybe_null= MY_TEST(join->mixed_implicit_grouping); } - if ((nested_join= table->nested_join)) { - if (setup_jtbm_semi_joins(join, &nested_join->join_list, join_where)) + if (setup_jtbm_semi_joins(join, &nested_join->join_list, eq_list)) DBUG_RETURN(TRUE); } } @@ -5749,8 +6108,8 @@ bool JOIN::choose_subquery_plan(table_map join_tables) /* A strategy must be chosen earlier. */ DBUG_ASSERT(in_subs->has_strategy()); DBUG_ASSERT(in_to_exists_where || in_to_exists_having); - DBUG_ASSERT(!in_to_exists_where || in_to_exists_where->fixed); - DBUG_ASSERT(!in_to_exists_having || in_to_exists_having->fixed); + DBUG_ASSERT(!in_to_exists_where || in_to_exists_where->is_fixed()); + DBUG_ASSERT(!in_to_exists_having || in_to_exists_having->is_fixed()); /* The original QEP of the subquery. */ Join_plan_state save_qep(table_count); @@ -6037,3 +6396,418 @@ bool JOIN::choose_tableless_subquery_plan() exec_const_cond= zero_result_cause ? 0 : conds; return FALSE; } + + +/* + Check if the item exists in the fields list of the left part of + the IN subquery predicate subq_pred and returns its corresponding + item from the select of the right part of subq_pred. +*/ +Item *Item::get_corresponding_field_in_insubq(Item_in_subselect *subq_pred) +{ + DBUG_ASSERT(type() == Item::FIELD_ITEM || + (type() == Item::REF_ITEM && + ((Item_ref *) this)->ref_type() == Item_ref::VIEW_REF)); + + List_iterator<Field_pair> it(subq_pred->corresponding_fields); + Field_pair *ret; + Item_field *field_item= (Item_field *) (real_item()); + while ((ret= it++)) + { + if (field_item->field == ret->field) + return ret->corresponding_item; + } + return NULL; +} + + +bool Item_field::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) +{ + if (((Item *)this)->get_corresponding_field_in_insubq(subq_pred)) + return true; + if (item_equal) + { + Item_equal_fields_iterator it(*item_equal); + Item *equal_item; + while ((equal_item= it++)) + { + if (equal_item->const_item()) + continue; + if (equal_item->get_corresponding_field_in_insubq(subq_pred)) + return true; + } + } + return false; +} + + +bool Item_direct_view_ref::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) +{ + if (item_equal) + { + DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM); + if (((Item *)this)->get_corresponding_field_in_insubq(subq_pred)) + return true; + } + return (*ref)->excl_dep_on_in_subq_left_part(subq_pred); +} + + +bool Item_equal::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) +{ + Item *left_item = get_const(); + Item_equal_fields_iterator it(*this); + Item *item; + if (!left_item) + { + while ((item=it++)) + { + if (item->excl_dep_on_in_subq_left_part(subq_pred)) + { + left_item= item; + break; + } + } + } + if (!left_item) + return false; + while ((item=it++)) + { + if (item->excl_dep_on_in_subq_left_part(subq_pred)) + return true; + } + return false; +} + + +/** + @brief + Get corresponding item from the select of the right part of IN subquery + + @param thd the thread handle + @param item the item from the left part of subq_pred for which + corresponding item should be found + @param subq_pred the IN subquery predicate + + @details + This method looks through the fields of the select of the right part of + the IN subquery predicate subq_pred trying to find the corresponding + item 'new_item' for item. If item has equal items it looks through + the fields of the select of the right part of subq_pred for each equal + item trying to find the corresponding item. + The method assumes that the given item is either a field item or + a reference to a field item. + + @retval <item*> reference to the corresponding item + @retval NULL if item was not found +*/ + +static +Item *get_corresponding_item(THD *thd, Item *item, + Item_in_subselect *subq_pred) +{ + DBUG_ASSERT(item->type() == Item::FIELD_ITEM || + (item->type() == Item::REF_ITEM && + ((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF)); + + Item *corresonding_item; + Item_equal *item_equal= item->get_item_equal(); + + if (item_equal) + { + Item_equal_fields_iterator it(*item_equal); + Item *equal_item; + while ((equal_item= it++)) + { + corresonding_item= + equal_item->get_corresponding_field_in_insubq(subq_pred); + if (corresonding_item) + return corresonding_item; + } + return NULL; + } + else + return item->get_corresponding_field_in_insubq(subq_pred); +} + + +Item *Item_field::in_subq_field_transformer_for_where(THD *thd, uchar *arg) +{ + Item_in_subselect *subq_pred= (Item_in_subselect *)arg; + Item *producing_item= get_corresponding_item(thd, this, subq_pred); + if (producing_item) + return producing_item->build_clone(thd); + return this; +} + + +Item *Item_direct_view_ref::in_subq_field_transformer_for_where(THD *thd, + uchar *arg) +{ + if (item_equal) + { + Item_in_subselect *subq_pred= (Item_in_subselect *)arg; + Item *producing_item= get_corresponding_item(thd, this, subq_pred); + DBUG_ASSERT (producing_item != NULL); + return producing_item->build_clone(thd); + } + return this; +} + + +/** + @brief + Transforms item so it can be pushed into the IN subquery HAVING clause + + @param thd the thread handle + @param in_item the item for which pushable item should be created + @param subq_pred the IN subquery predicate + + @details + This method finds for in_item that is a field from the left part of the + IN subquery predicate subq_pred its corresponding item from the right part + of subq_pred. + If corresponding item is found, a shell for this item is created. + This shell can be pushed into the HAVING part of subq_pred select. + + @retval <item*> reference to the created corresponding item shell for in_item + @retval NULL if mistake occurs +*/ + +static Item* +get_corresponding_item_for_in_subq_having(THD *thd, Item *in_item, + Item_in_subselect *subq_pred) +{ + Item *new_item= get_corresponding_item(thd, in_item, subq_pred); + + if (new_item) + { + Item_ref *ref= + new (thd->mem_root) Item_ref(thd, + &subq_pred->unit->first_select()->context, + NullS, NullS, + &new_item->name); + if (!ref) + DBUG_ASSERT(0); + return ref; + } + return new_item; +} + + +Item *Item_field::in_subq_field_transformer_for_having(THD *thd, uchar *arg) +{ + return get_corresponding_item_for_in_subq_having(thd, this, + (Item_in_subselect *)arg); +} + + +Item *Item_direct_view_ref::in_subq_field_transformer_for_having(THD *thd, + uchar *arg) +{ + if (!item_equal) + return this; + else + { + Item *new_item= get_corresponding_item_for_in_subq_having(thd, this, + (Item_in_subselect *)arg); + if (!new_item) + return this; + return new_item; + } +} + + +/** + @brief + Find fields that are used in the GROUP BY of the select + + @param thd the thread handle + @param sel the select of the IN subquery predicate + @param fields fields of the left part of the IN subquery predicate + @param grouping_list GROUP BY clause + + @details + This method traverses fields which are used in the GROUP BY of + sel and saves them with their corresponding items from fields. +*/ + +bool grouping_fields_in_the_in_subq_left_part(THD *thd, + st_select_lex *sel, + List<Field_pair> *fields, + ORDER *grouping_list) +{ + DBUG_ENTER("grouping_fields_in_the_in_subq_left_part"); + sel->grouping_tmp_fields.empty(); + List_iterator<Field_pair> it(*fields); + Field_pair *item; + while ((item= it++)) + { + for (ORDER *ord= grouping_list; ord; ord= ord->next) + { + if ((*ord->item)->eq(item->corresponding_item, 0)) + { + if (sel->grouping_tmp_fields.push_back(item, thd->mem_root)) + DBUG_RETURN(TRUE); + } + } + } + DBUG_RETURN(FALSE); +} + + +/** + @brief + Extract condition that can be pushed into select of this IN subquery + + @param thd the thread handle + @param cond current condition + + @details + This function builds the most restrictive condition depending only on + the list of fields of the left part of this IN subquery predicate + (directly or indirectly through equality) that can be extracted from the + given condition cond and pushes it into this IN subquery. + + Example of the transformation: + + SELECT * FROM t1 + WHERE a>3 AND b>10 AND + (a,b) IN (SELECT x,MAX(y) FROM t2 GROUP BY x); + + => + + SELECT * FROM t1 + WHERE a>3 AND b>10 AND + (a,b) IN (SELECT x,max(y) + FROM t2 + WHERE x>3 + GROUP BY x + HAVING MAX(y)>10); + + + In details: + 1. Check what pushable formula can be extracted from cond + 2. Build a clone PC of the formula that can be extracted + (the clone is built only if the extracted formula is a AND subformula + of cond or conjunction of such subformulas) + 3. If there is no HAVING clause prepare PC to be conjuncted with + WHERE clause of this subquery. Otherwise do 4-7. + 4. Check what formula PC_where can be extracted from PC to be pushed + into the WHERE clause of the subquery + 5. Build PC_where and if PC_where is a conjunct(s) of PC remove it from PC + getting PC_having + 6. Prepare PC_where to be conjuncted with the WHERE clause of + the IN subquery + 7. Prepare PC_having to be conjuncted with the HAVING clause of + the IN subquery + + @note + This method is similar to pushdown_cond_for_derived() + + @retval TRUE if an error occurs + @retval FALSE otherwise +*/ + +bool Item_in_subselect::pushdown_cond_for_in_subquery(THD *thd, Item *cond) +{ + DBUG_ENTER("Item_in_subselect::pushdown_cond_for_in_subquery"); + Item *remaining_cond= NULL; + + if (!cond) + DBUG_RETURN(FALSE); + + st_select_lex *sel = unit->first_select(); + + if (is_jtbm_const_tab) + DBUG_RETURN(FALSE); + + if (!sel->cond_pushdown_is_allowed()) + DBUG_RETURN(FALSE); + + /* + Create a list of Field_pair items for this IN subquery. + It consists of the pairs of fields from the left part of this IN subquery + predicate 'left_part' and the respective fields from the select of the + right part of the IN subquery 'sel' (the field from left_part with the + corresponding field from the sel projection list). + Attach this list to the IN subquery. + */ + corresponding_fields.empty(); + List_iterator_fast<Item> it(sel->join->fields_list); + Item *item; + for (uint i= 0; i < left_expr->cols(); i++) + { + item= it++; + Item *elem= left_expr->element_index(i); + + if (elem->real_item()->type() != Item::FIELD_ITEM) + continue; + + if (corresponding_fields.push_back( + new Field_pair(((Item_field *)(elem->real_item()))->field, + item))) + DBUG_RETURN(TRUE); + } + + /* 1. Check what pushable formula can be extracted from cond */ + Item *extracted_cond; + cond->check_pushable_cond(&Item::pushable_cond_checker_for_subquery, + (uchar *)this); + /* 2. Build a clone PC of the formula that can be extracted */ + extracted_cond= + cond->build_pushable_cond(thd, + &Item::pushable_equality_checker_for_subquery, + (uchar *)this); + /* Nothing to push */ + if (!extracted_cond) + { + DBUG_RETURN(FALSE); + } + + /* Collect fields that are used in the GROUP BY of sel */ + st_select_lex *save_curr_select= thd->lex->current_select; + if (sel->have_window_funcs()) + { + if (sel->group_list.first || sel->join->implicit_grouping) + goto exit; + ORDER *common_partition_fields= + sel->find_common_window_func_partition_fields(thd); + if (!common_partition_fields) + goto exit; + + if (grouping_fields_in_the_in_subq_left_part(thd, sel, &corresponding_fields, + common_partition_fields)) + DBUG_RETURN(TRUE); + } + else if (grouping_fields_in_the_in_subq_left_part(thd, sel, + &corresponding_fields, + sel->group_list.first)) + DBUG_RETURN(TRUE); + + /* Do 4-6 */ + sel->pushdown_cond_into_where_clause(thd, extracted_cond, + &remaining_cond, + &Item::in_subq_field_transformer_for_where, + (uchar *) this); + if (!remaining_cond) + goto exit; + /* + 7. Prepare PC_having to be conjuncted with the HAVING clause of + the IN subquery + */ + remaining_cond= + remaining_cond->transform(thd, + &Item::in_subq_field_transformer_for_having, + (uchar *)this); + if (!remaining_cond) + goto exit; + + remaining_cond->walk(&Item::cleanup_excluding_const_fields_processor, + 0, 0); + sel->cond_pushed_into_having= remaining_cond; + +exit: + thd->lex->current_select= save_curr_select; + DBUG_RETURN(FALSE); +} diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index 9cb19e0cc6c..031118288b9 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -26,8 +26,15 @@ int check_and_do_in_subquery_rewrites(JOIN *join); bool convert_join_subqueries_to_semijoins(JOIN *join); int pull_out_semijoin_tables(JOIN *join); bool optimize_semijoin_nests(JOIN *join, table_map all_table_map); -bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, - Item **join_where); +Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond, + COND_EQUAL **cond_eq, + List<Item> &new_conds, + Item::cond_result *cond_value); +bool setup_degenerate_jtbm_semi_joins(JOIN *join, + List<TABLE_LIST> *join_list, + List<Item> &eq_list); +bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, + List<Item> &eq_list); void cleanup_empty_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list); // used by Loose_scan_opt diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 82946709166..ecede5903a2 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -318,7 +318,7 @@ int opt_sum_query(THD *thd, error= tl->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); if (unlikely(error)) { - tl->table->file->print_error(error, MYF(ME_FATALERROR)); + tl->table->file->print_error(error, MYF(ME_FATAL)); DBUG_RETURN(error); } count*= tl->table->file->stats.records; diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc index ef9b07cca47..74d1e775c43 100644 --- a/sql/opt_table_elimination.cc +++ b/sql/opt_table_elimination.cc @@ -617,12 +617,12 @@ void eliminate_tables(JOIN *join) we should also take into account tables mentioned in "val". */ if (join->thd->lex->sql_command == SQLCOM_INSERT_SELECT && - join->select_lex == &thd->lex->select_lex) + join->select_lex == thd->lex->first_select_lex()) { List_iterator<Item> val_it(thd->lex->value_list); while ((item= val_it++)) { - DBUG_ASSERT(item->fixed); + DBUG_ASSERT(item->is_fixed()); used_tables |= item->used_tables(); } } @@ -640,7 +640,7 @@ void eliminate_tables(JOIN *join) used_tables |= (*(cur_list->item))->used_tables(); } - if (join->select_lex == &thd->lex->select_lex) + if (join->select_lex == thd->lex->first_select_lex()) { /* Multi-table UPDATE: don't eliminate tables referred from SET statement */ diff --git a/sql/procedure.h b/sql/procedure.h index 1ece31223ad..8826b397fb2 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -44,6 +44,16 @@ public: this->name.length= strlen(name_par); } enum Type type() const { return Item::PROC_ITEM; } + Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + /* + We can get to here when using a CURSOR for a query with PROCEDURE: + DECLARE c CURSOR FOR SELECT * FROM t1 PROCEDURE analyse(); + OPEN c; + */ + return create_tmp_field_ex_simple(table, src, param); + } virtual void set(double nr)=0; virtual void set(const char *str,uint length,CHARSET_INFO *cs)=0; virtual void set(longlong nr)=0; diff --git a/sql/protocol.cc b/sql/protocol.cc index c4c243ea166..7eee9283989 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1195,9 +1195,8 @@ bool Protocol_text::store_decimal(const my_decimal *d) field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); field_pos++; #endif - char buff[DECIMAL_MAX_STR_LENGTH]; - String str(buff, sizeof(buff), &my_charset_bin); - (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str); + StringBuffer<DECIMAL_MAX_STR_LENGTH> str; + (void) d->to_string(&str); return net_store_data((uchar*) str.ptr(), str.length()); } @@ -1446,9 +1445,8 @@ bool Protocol_binary::store_decimal(const my_decimal *d) field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); field_pos++; #endif - char buff[DECIMAL_MAX_STR_LENGTH]; - String str(buff, sizeof(buff), &my_charset_bin); - (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str); + StringBuffer<DECIMAL_MAX_STR_LENGTH> str; + (void) d->to_string(&str); return store(str.ptr(), str.length(), str.charset()); } diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 6f659aa12ad..897d4394525 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -1091,7 +1091,7 @@ bool Master_info_index::init_all_master_info() if ((index_file_nr= my_open(index_file_name, O_RDWR | O_CREAT | O_BINARY , - MYF(MY_WME | ME_NOREFRESH))) < 0 || + MYF(MY_WME | ME_ERROR_LOG))) < 0 || my_sync(index_file_nr, MYF(MY_WME)) || init_io_cache(&index_file, index_file_nr, IO_SIZE, READ_CACHE, @@ -1307,7 +1307,7 @@ Master_info *get_master_info(const LEX_CSTRING *connection_name, if (warning != Sql_condition::WARN_LEVEL_NOTE) my_error(WARN_NO_MASTER_INFO, MYF(warning == Sql_condition::WARN_LEVEL_WARN ? - ME_JUST_WARNING : 0), + ME_WARNING : 0), (int) connection_name->length, connection_name->str); mysql_mutex_unlock(&LOCK_active_mi); DBUG_RETURN(0); @@ -1377,7 +1377,7 @@ Master_info_index::get_master_info(const LEX_CSTRING *connection_name, if (!mi && warning != Sql_condition::WARN_LEVEL_NOTE) { my_error(WARN_NO_MASTER_INFO, - MYF(warning == Sql_condition::WARN_LEVEL_WARN ? ME_JUST_WARNING : + MYF(warning == Sql_condition::WARN_LEVEL_WARN ? ME_WARNING : 0), (int) connection_name->length, connection_name->str); diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index db579a63ce0..94c1f08e4e3 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -497,7 +497,9 @@ int prepare_record(TABLE *const table, const uint skip, const bool check) DBUG_RETURN(0); } /** - Fills @c table->record[0] with computed values of extra persistent column which are present on slave but not on master. + Fills @c table->record[0] with computed values of extra persistent column + which are present on slave but not on master. + @param table Table whose record[0] buffer is prepared. @param master_cols No of columns on master @returns 0 on success @@ -514,10 +516,8 @@ int fill_extra_persistent_columns(TABLE *table, int master_cols) vfield= *vfield_ptr; if (vfield->field_index >= master_cols && vfield->stored_in_db()) { - /*Set bitmap for writing*/ - bitmap_set_bit(table->vcol_set, vfield->field_index); + bitmap_set_bit(table->write_set, vfield->field_index); error= vfield->vcol_info->expr->save_in_field(vfield,0); - bitmap_clear_bit(table->vcol_set, vfield->field_index); } } return error; diff --git a/sql/set_var.cc b/sql/set_var.cc index 8ab892068b3..de9bda3d067 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -742,7 +742,7 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free) err: if (free) - free_underlaid_joins(thd, &thd->lex->select_lex); + free_underlaid_joins(thd, thd->lex->first_select_lex()); DBUG_RETURN(error); } diff --git a/sql/sp.cc b/sql/sp.cc index af86737ebb9..723f30ec85d 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1468,7 +1468,7 @@ log: log_query.ptr(), log_query.length(), FALSE, FALSE, FALSE, 0)) { - my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), "binary log", -1); + my_error(ER_ERROR_ON_WRITE, MYF(0), "binary log", -1); goto done; } thd->variables.sql_mode= 0; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index c1c938dd9e7..c86edc47bf9 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -71,33 +71,6 @@ static void reset_start_time_for_sp(THD *thd) } -Item::Type -sp_map_item_type(const Type_handler *handler) -{ - if (handler == &type_handler_row) - return Item::ROW_ITEM; - enum_field_types type= real_type_to_type(handler->real_field_type()); - - switch (type) { - case MYSQL_TYPE_BIT: - case MYSQL_TYPE_TINY: - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_LONG: - case MYSQL_TYPE_LONGLONG: - case MYSQL_TYPE_INT24: - return Item::INT_ITEM; - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - return Item::DECIMAL_ITEM; - case MYSQL_TYPE_FLOAT: - case MYSQL_TYPE_DOUBLE: - return Item::REAL_ITEM; - default: - return Item::STRING_ITEM; - } -} - - bool Item_splocal::append_for_log(THD *thd, String *str) { if (fix_fields_if_needed(thd, NULL)) @@ -318,7 +291,7 @@ sp_get_flags_for_command(LEX *lex) - EXPLAIN DELETE ... - ANALYZE DELETE ... */ - if (lex->select_lex.item_list.is_empty() && + if (lex->first_select_lex()->item_list.is_empty() && !lex->describe && !lex->analyze_stmt) flags= 0; else @@ -1922,7 +1895,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, for (arg_no= 0; arg_no < argcount; arg_no++) { /* Arguments must be fixed in Item_func_sp::fix_fields */ - DBUG_ASSERT(argp[arg_no]->fixed); + DBUG_ASSERT(argp[arg_no]->is_fixed()); if ((err_status= (*func_ctx)->set_parameter(thd, arg_no, &(argp[arg_no])))) goto err_with_cleanup; @@ -2292,6 +2265,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) if (!err_status) { err_status= execute(thd, TRUE); + DBUG_PRINT("info", ("execute returned %d", (int) err_status)); } if (save_log_general) @@ -4576,7 +4550,7 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp) thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item)) { /* If this also failed, we have to abort. */ - my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL)); } } else diff --git a/sql/sp_head.h b/sql/sp_head.h index cf934603cf0..8db6ecac9e7 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -39,9 +39,6 @@ @{ */ -Item::Type -sp_map_item_type(const Type_handler *handler); - uint sp_get_flags_for_command(LEX *lex); @@ -592,7 +589,8 @@ public: if (!oldlex) DBUG_RETURN(false); // Nothing to restore LEX *sublex= thd->lex; - if (thd->restore_from_local_lex_to_old_lex(oldlex))// This restores thd->lex + // This restores thd->lex and thd->stmt_lex + if (thd->restore_from_local_lex_to_old_lex(oldlex)) DBUG_RETURN(true); if (!sublex->sp_lex_in_use) { diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 24777abe1c3..a31631e33ef 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -228,9 +228,10 @@ bool Qualified_column_ident::resolve_type_ref(THD *thd, Column_definition *def) // Make %TYPE variables see temporary tables that shadow permanent tables thd->temporary_tables= open_tables_state_backup.temporary_tables; - if ((table_list= lex.select_lex.add_table_to_list(thd, this, NULL, 0, - TL_READ_NO_INSERT, - MDL_SHARED_READ)) && + if ((table_list= + lex.first_select_lex()->add_table_to_list(thd, this, NULL, 0, + TL_READ_NO_INSERT, + MDL_SHARED_READ)) && !check_table_access(thd, SELECT_ACL, table_list, TRUE, UINT_MAX, FALSE) && !open_tables_only_view_structure(thd, table_list, thd->mdl_context.has_locks())) @@ -286,9 +287,10 @@ bool Table_ident::resolve_table_rowtype_ref(THD *thd, // Make %ROWTYPE variables see temporary tables that shadow permanent tables thd->temporary_tables= open_tables_state_backup.temporary_tables; - if ((table_list= lex.select_lex.add_table_to_list(thd, this, NULL, 0, - TL_READ_NO_INSERT, - MDL_SHARED_READ)) && + if ((table_list= + lex.first_select_lex()->add_table_to_list(thd, this, NULL, 0, + TL_READ_NO_INSERT, + MDL_SHARED_READ)) && !check_table_access(thd, SELECT_ACL, table_list, TRUE, UINT_MAX, FALSE) && !open_tables_only_view_structure(thd, table_list, thd->mdl_context.has_locks())) diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 21bb086f013..9f92af61eec 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -306,7 +306,7 @@ static bool open_only_one_table(THD* thd, TABLE_LIST* table, bool is_view_operator_func) { LEX *lex= thd->lex; - SELECT_LEX *select= &lex->select_lex; + SELECT_LEX *select= lex->first_select_lex(); TABLE_LIST *save_next_global, *save_next_local; bool open_error; save_next_global= table->next_global; @@ -1301,7 +1301,7 @@ bool mysql_preload_keys(THD* thd, TABLE_LIST* tables) bool Sql_cmd_analyze_table::execute(THD *thd) { LEX *m_lex= thd->lex; - TABLE_LIST *first_table= m_lex->select_lex.table_list.first; + TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first; bool res= TRUE; thr_lock_type lock_type = TL_READ_NO_INSERT; DBUG_ENTER("Sql_cmd_analyze_table::execute"); @@ -1321,7 +1321,7 @@ bool Sql_cmd_analyze_table::execute(THD *thd) */ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - m_lex->select_lex.table_list.first= first_table; + m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; error: @@ -1332,7 +1332,7 @@ error: bool Sql_cmd_check_table::execute(THD *thd) { LEX *m_lex= thd->lex; - TABLE_LIST *first_table= m_lex->select_lex.table_list.first; + TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first; thr_lock_type lock_type = TL_READ_NO_INSERT; bool res= TRUE; DBUG_ENTER("Sql_cmd_check_table::execute"); @@ -1345,7 +1345,7 @@ bool Sql_cmd_check_table::execute(THD *thd) lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0, &handler::ha_check, &view_check); - m_lex->select_lex.table_list.first= first_table; + m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; error: @@ -1356,7 +1356,7 @@ error: bool Sql_cmd_optimize_table::execute(THD *thd) { LEX *m_lex= thd->lex; - TABLE_LIST *first_table= m_lex->select_lex.table_list.first; + TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first; bool res= TRUE; DBUG_ENTER("Sql_cmd_optimize_table::execute"); @@ -1378,7 +1378,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd) */ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - m_lex->select_lex.table_list.first= first_table; + m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; error: @@ -1389,7 +1389,7 @@ error: bool Sql_cmd_repair_table::execute(THD *thd) { LEX *m_lex= thd->lex; - TABLE_LIST *first_table= m_lex->select_lex.table_list.first; + TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first; bool res= TRUE; DBUG_ENTER("Sql_cmd_repair_table::execute"); @@ -1413,7 +1413,7 @@ bool Sql_cmd_repair_table::execute(THD *thd) */ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - m_lex->select_lex.table_list.first= first_table; + m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; error: diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index a96b0a5a32b..700b4699430 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -356,7 +356,7 @@ bool Sql_cmd_alter_table::execute(THD *thd) { LEX *lex= thd->lex; /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); /* first table of first SELECT_LEX */ TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first; /* @@ -506,7 +506,7 @@ error: bool Sql_cmd_discard_import_tablespace::execute(THD *thd) { /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); /* first table of first SELECT_LEX */ TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first; diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 6626a054052..a7cfaca0d0e 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -68,6 +68,25 @@ int compare_decimal2(int* len, const char *s, const char *t) } +static bool +prepare_param(THD *thd, Item **item, const char *proc_name, uint pos) +{ + if ((*item)->fix_fields_if_needed(thd, item)) + { + DBUG_PRINT("info", ("fix_fields() for the parameter %u failed", pos)); + return true; + } + if ((*item)->type_handler()->result_type() != INT_RESULT || + !(*item)->basic_const_item() || + (*item)->val_real() < 0) + { + my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name); + return true; + } + return false; +} + + Procedure * proc_analyse_init(THD *thd, ORDER *param, select_result *result, List<Item> &field_list) @@ -88,17 +107,8 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, else if (param->next) { // first parameter - if ((*param->item)->fix_fields_if_needed(thd, param->item)) - { - DBUG_PRINT("info", ("fix_fields() for the first parameter failed")); - goto err; - } - if ((*param->item)->type() != Item::INT_ITEM || - (*param->item)->val_real() < 0) - { - my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name); + if (prepare_param(thd, param->item, proc_name, 0)) goto err; - } pc->max_tree_elements = (uint) (*param->item)->val_int(); param = param->next; if (param->next) // no third parameter possible @@ -107,25 +117,12 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, goto err; } // second parameter - if ((*param->item)->fix_fields_if_needed(thd, param->item)) - { - DBUG_PRINT("info", ("fix_fields() for the second parameter failed")); - goto err; - } - if ((*param->item)->type() != Item::INT_ITEM || - (*param->item)->val_real() < 0) - { - my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name); + if (prepare_param(thd, param->item, proc_name, 1)) goto err; - } pc->max_treemem = (uint) (*param->item)->val_int(); } - else if ((*param->item)->type() != Item::INT_ITEM || - (*param->item)->val_real() < 0) - { - my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name); + else if (prepare_param(thd, param->item, proc_name, 0)) goto err; - } // if only one parameter was given, it will be the value of max_tree_elements else { @@ -481,30 +478,28 @@ void field_real::add() void field_decimal::add() { /*TODO - remove rounding stuff after decimal_div returns proper frac */ - my_decimal dec_buf, *dec= item->val_decimal(&dec_buf); - my_decimal rounded; + VDec vdec(item); uint length; TREE_ELEMENT *element; - if (item->null_value) + if (vdec.is_null()) { nulls++; return; } - my_decimal_round(E_DEC_FATAL_ERROR, dec, item->decimals, FALSE,&rounded); - dec= &rounded; + my_decimal dec; + vdec.round_to(&dec, item->decimals, HALF_UP); - length= my_decimal_string_length(dec); + length= my_decimal_string_length(&dec); - if (decimal_is_zero(dec)) + if (decimal_is_zero(&dec)) empty++; if (room_in_tree) { uchar buf[DECIMAL_MAX_FIELD_SIZE]; - my_decimal2binary(E_DEC_FATAL_ERROR, dec, buf, - item->max_length, item->decimals); + dec.to_binary(buf, item->max_length, item->decimals); if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg))) { room_in_tree = 0; // Remove tree, out of RAM ? @@ -524,18 +519,18 @@ void field_decimal::add() if (!found) { found = 1; - min_arg = max_arg = sum[0] = *dec; - my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, dec, dec); + min_arg = max_arg = sum[0] = dec; + my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, &dec, &dec); cur_sum= 0; min_length = max_length = length; } - else if (!decimal_is_zero(dec)) + else if (!decimal_is_zero(&dec)) { int next_cur_sum= cur_sum ^ 1; my_decimal sqr_buf; - my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, dec); - my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec); + my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, &dec); + my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, &dec, &dec); my_decimal_add(E_DEC_FATAL_ERROR, sum_sqr+next_cur_sum, sum_sqr+cur_sum, &sqr_buf); cur_sum= next_cur_sum; @@ -543,13 +538,13 @@ void field_decimal::add() min_length = length; if (length > max_length) max_length = length; - if (my_decimal_cmp(dec, &min_arg) < 0) + if (dec.cmp(&min_arg) < 0) { - min_arg= *dec; + min_arg= dec; } - if (my_decimal_cmp(dec, &max_arg) > 0) + if (dec.cmp(&max_arg) > 0) { - max_arg= *dec; + max_arg= dec; } } } @@ -1003,7 +998,7 @@ void field_decimal::get_opt_type(String *answer, uint length; my_decimal_set_zero(&zero); - my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0); + my_bool is_unsigned= (zero.cmp(&min_arg) >= 0); length= sprintf(buff, "DECIMAL(%d, %d)", (int) (max_length - (item->decimals ? 1 : 0)), @@ -1016,14 +1011,14 @@ void field_decimal::get_opt_type(String *answer, String *field_decimal::get_min_arg(String *str) { - my_decimal2string(E_DEC_FATAL_ERROR, &min_arg, 0, 0, '0', str); + min_arg.to_string_native(str, 0, 0, '0'); return str; } String *field_decimal::get_max_arg(String *str) { - my_decimal2string(E_DEC_FATAL_ERROR, &max_arg, 0, 0, '0', str); + max_arg.to_string_native(str, 0, 0, '0'); return str; } @@ -1041,10 +1036,10 @@ String *field_decimal::avg(String *s, ha_rows rows) int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num); my_decimal_div(E_DEC_FATAL_ERROR, &avg_val, sum+cur_sum, &num, prec_increment); /* TODO remove this after decimal_div returns proper frac */ - my_decimal_round(E_DEC_FATAL_ERROR, &avg_val, + avg_val.round_to(&rounded_avg, MY_MIN(sum[cur_sum].frac + prec_increment, DECIMAL_MAX_SCALE), - FALSE,&rounded_avg); - my_decimal2string(E_DEC_FATAL_ERROR, &rounded_avg, 0, 0, '0', s); + HALF_UP); + rounded_avg.to_string_native(s, 0, 0, '0'); return s; } @@ -1057,7 +1052,6 @@ String *field_decimal::std(String *s, ha_rows rows) return s; } my_decimal num, tmp, sum2, sum2d; - double std_sqr; int prec_increment= current_thd->variables.div_precincrement; int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num); @@ -1065,7 +1059,7 @@ String *field_decimal::std(String *s, ha_rows rows) my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment); my_decimal_sub(E_DEC_FATAL_ERROR, &sum2, sum_sqr+cur_sum, &tmp); my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment); - my_decimal2double(E_DEC_FATAL_ERROR, &tmp, &std_sqr); + double std_sqr= tmp.to_double(); s->set_real(((double) std_sqr <= 0.0 ? 0.0 : sqrt(std_sqr)), MY_MIN(item->decimals + prec_increment, NOT_FIXED_DEC), my_thd_charset); @@ -1117,12 +1111,9 @@ int collect_decimal(uchar *element, element_count count, info->str->append(','); else info->found = 1; - my_decimal dec; - binary2my_decimal(E_DEC_FATAL_ERROR, element, &dec, - info->item->max_length, info->item->decimals); - + my_decimal dec(element, info->item->max_length, info->item->decimals); info->str->append('\''); - my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, '0', &s); + dec.to_string_native(&s, 0, 0, '0'); info->str->append(s); info->str->append('\''); return 0; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 15cfba80340..7327484469a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -597,6 +597,7 @@ bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection) static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table) { + DBUG_ENTER("mark_used_tables_as_free_for_reuse"); for (; table ; table= table->next) { DBUG_ASSERT(table->pos_in_locked_tables == NULL || @@ -607,6 +608,7 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table) table->file->ha_reset(); } } + DBUG_VOID_RETURN; } @@ -5424,43 +5426,27 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table) DBUG_ENTER("update_field_dependencies"); if (should_mark_column(thd->column_usage)) { - MY_BITMAP *bitmap; - /* We always want to register the used keys, as the column bitmap may have been set for all fields (for example for view). */ - table->covering_keys.intersect(field->part_of_key); - if (field->vcol_info) - table->mark_virtual_col(field); - if (thd->column_usage == MARK_COLUMNS_READ) - bitmap= table->read_set; + { + if (table->mark_column_with_deps(field)) + DBUG_VOID_RETURN; // Field was already marked + } else - bitmap= table->write_set; - - /* - The test-and-set mechanism in the bitmap is not reliable during - multi-UPDATE statements under MARK_COLUMNS_READ mode - (thd->column_usage == MARK_COLUMNS_READ), as this bitmap contains - only those columns that are used in the SET clause. I.e they are being - set here. See multi_update::prepare() - */ - if (bitmap_fast_test_and_set(bitmap, field->field_index)) { - if (thd->column_usage == MARK_COLUMNS_WRITE) + if (bitmap_fast_test_and_set(table->write_set, field->field_index)) { DBUG_PRINT("warning", ("Found duplicated field")); thd->dup_field= field; + DBUG_VOID_RETURN; } - else - { - DBUG_PRINT("note", ("Field found before")); - } - DBUG_VOID_RETURN; } + table->used_fields++; } if (table->get_fields_in_item_tree) @@ -7378,7 +7364,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, Item_window_func::split_sum_func. */ if (sum_func_list && - ((item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) || + ((item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) || item->with_window_func)) { item->split_sum_func(thd, ref_pointer_array, *sum_func_list, @@ -7486,7 +7472,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, TABLE_LIST *first_select_table= (select_insert ? tables->next_local: 0); - SELECT_LEX *select_lex= select_insert ? &thd->lex->select_lex : + SELECT_LEX *select_lex= select_insert ? thd->lex->first_select_lex() : thd->lex->current_select; if (select_lex->first_cond_optimization) { @@ -7514,7 +7500,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, { /* new counting for SELECT of INSERT ... SELECT command */ first_select_table= 0; - thd->lex->select_lex.insert_tables= tablenr; + thd->lex->first_select_lex()->insert_tables= tablenr; tablenr= 0; } if(table_list->jtbm_subselect) @@ -7881,18 +7867,9 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, if ((field= field_iterator.field())) { - /* Mark fields as used to allow storage engine to optimze access */ - bitmap_set_bit(field->table->read_set, field->field_index); - /* - Mark virtual fields for write and others that the virtual fields - depend on for read. - */ - if (field->vcol_info) - field->table->mark_virtual_col(field); + field->table->mark_column_with_deps(field); if (table) - { table->covering_keys.intersect(field->part_of_key); - } if (tables->is_natural_join) { TABLE *field_table; @@ -8070,7 +8047,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves, from subquery of VIEW, because tables of subquery belongs to VIEW (see condition before prepare_check_option() call) */ - bool it_is_update= (select_lex == &thd->lex->select_lex) && + bool it_is_update= (select_lex == thd->lex->first_select_lex()) && thd->lex->which_check_option_applicable(); bool save_is_item_list_lookup= select_lex->is_item_list_lookup; TABLE_LIST *derived= select_lex->master_unit()->derived; @@ -8086,7 +8063,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves, for (table= tables; table; table= table->next_local) { - if (select_lex == &thd->lex->select_lex && + if (select_lex == thd->lex->first_select_lex() && select_lex->first_cond_optimization && table->merged_for_insert && table->prepare_where(thd, conds, FALSE)) @@ -8693,7 +8670,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) Item_func_match *ifm; while ((ifm=li++)) - if (unlikely(!ifm->fixed)) + if (unlikely(!ifm->is_fixed())) /* it mean that clause where was FT function was removed, so we have to remove the function from the list. @@ -8795,6 +8772,13 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, void close_system_tables(THD *thd, Open_tables_backup *backup) { + /* + Inform the transaction handler that we are closing the + system tables and we don't need the read view anymore. + */ + for (TABLE *table= thd->open_tables ; table ; table= table->next) + table->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE); + close_thread_tables(thd); thd->restore_backup_open_tables_state(backup); } @@ -8928,7 +8912,7 @@ void unfix_fields(List<Item> &fields) List_iterator<Item> li(fields); Item *item; while ((item= li++)) - item->fixed= 0; + item->unfix_fields(); } diff --git a/sql/sql_base.h b/sql/sql_base.h index be93566be09..59c849086e6 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -367,10 +367,12 @@ inline bool setup_fields_with_no_wrap(THD *thd, Ref_ptr_array ref_pointer_array, bool allow_sum_func) { bool res; - thd->lex->select_lex.no_wrap_view_item= TRUE; + SELECT_LEX *first= thd->lex->first_select_lex(); + DBUG_ASSERT(thd->lex->current_select == first); + first->no_wrap_view_item= TRUE; res= setup_fields(thd, ref_pointer_array, item, column_usage, sum_func_list, NULL, allow_sum_func); - thd->lex->select_lex.no_wrap_view_item= FALSE; + first->no_wrap_view_item= FALSE; return res; } diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 00270fb6f32..1fa3cca7c27 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -173,7 +173,7 @@ void mysql_client_binlog_statement(THD* thd) */ if (!(rli && buf)) { - my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), 1); /* needed 1 bytes */ + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 1); /* needed 1 bytes */ goto end; } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index aa4c77d0939..44211fca506 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -480,8 +480,7 @@ static void make_base_query(String *new_query, /* We do not support UCS2, UTF16, UTF32 as a client character set */ DBUG_ASSERT(current_thd->variables.character_set_client->mbminlen == 1); - new_query->length(0); // Don't copy anything from old buffer - if (new_query->realloc(query_length + additional_length)) + if (new_query->alloc(query_length + additional_length)) { /* We could not allocate the query. Use original query for @@ -4147,13 +4146,13 @@ Query_cache::is_cacheable(THD *thd, LEX *lex, if (thd->lex->safe_to_cache_query && (thd->variables.query_cache_type == 1 || - (thd->variables.query_cache_type == 2 && (lex->select_lex.options & - OPTION_TO_QUERY_CACHE))) && + (thd->variables.query_cache_type == 2 && + (lex->first_select_lex()->options & OPTION_TO_QUERY_CACHE))) && qc_is_able_to_intercept_result(thd)) { DBUG_PRINT("qcache", ("options: %lx %lx type: %u", (long) OPTION_TO_QUERY_CACHE, - (long) lex->select_lex.options, + (long) lex->first_select_lex()->options, (int) thd->variables.query_cache_type)); if (!(table_count= process_and_count_tables(thd, tables_used, @@ -4174,7 +4173,7 @@ Query_cache::is_cacheable(THD *thd, LEX *lex, ("not interesting query: %d or not cacheable, options %lx %lx type: %u net->vio present: %u", (int) lex->sql_command, (long) OPTION_TO_QUERY_CACHE, - (long) lex->select_lex.options, + (long) lex->first_select_lex()->options, (int) thd->variables.query_cache_type, (uint) MY_TEST(qc_is_able_to_intercept_result(thd)))); DBUG_RETURN(0); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index fc96aa96278..0bbfdba88c7 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1406,7 +1406,7 @@ bool THD::set_db(const LEX_CSTRING *new_db) const char *tmp= NULL; if (new_db->str) { - if (!(tmp= my_strndup(new_db->str, new_db->length, MYF(MY_WME | ME_FATALERROR)))) + if (!(tmp= my_strndup(new_db->str, new_db->length, MYF(MY_WME | ME_FATAL)))) result= 1; } @@ -2565,7 +2565,7 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, size_t key_length) key_length + 1); if (!new_table) { - my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_FATALERROR), + my_error(EE_OUTOFMEMORY, MYF(ME_FATAL), ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1); set_killed(KILL_CONNECTION); return 0; @@ -3220,9 +3220,9 @@ int select_export::send_data(List<Item> &items) ((uint64) res->length() / res->charset()->mbminlen + 1) * write_cs->mbmaxlen + 1; set_if_smaller(estimated_bytes, UINT_MAX32); - if (cvt_str.realloc((uint32) estimated_bytes)) + if (cvt_str.alloc((uint32) estimated_bytes)) { - my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), (uint32) estimated_bytes); + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), (uint32) estimated_bytes); goto err; } @@ -3480,7 +3480,7 @@ int select_singlerow_subselect::send_data(List<Item> &items) if (it->assigned()) { my_message(ER_SUBQUERY_NO_1_ROW, ER_THD(thd, ER_SUBQUERY_NO_1_ROW), - MYF(current_thd->lex->ignore ? ME_JUST_WARNING : 0)); + MYF(current_thd->lex->ignore ? ME_WARNING : 0)); DBUG_RETURN(1); } if (unit->offset_limit_cnt) @@ -3587,18 +3587,15 @@ bool select_max_min_finder_subselect::cmp_int() bool select_max_min_finder_subselect::cmp_decimal() { Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0); - my_decimal cval, *cvalue= cache->val_decimal(&cval); - my_decimal mval, *mvalue= maxmin->val_decimal(&mval); + VDec cvalue(cache), mvalue(maxmin); /* Ignore NULLs for ANY and keep them for ALL subqueries */ - if (cache->null_value) - return (is_all && !maxmin->null_value) || (!is_all && maxmin->null_value); - if (maxmin->null_value) + if (cvalue.is_null()) + return (is_all && !mvalue.is_null()) || (!is_all && mvalue.is_null()); + if (mvalue.is_null()) return !is_all; - if (fmax) - return (my_decimal_cmp(cvalue, mvalue) > 0) ; - return (my_decimal_cmp(cvalue,mvalue) < 0); + return fmax ? cvalue.cmp(mvalue) > 0 : cvalue.cmp(mvalue) < 0; } bool select_max_min_finder_subselect::cmp_str() diff --git a/sql/sql_class.h b/sql/sql_class.h index 00a5c41f708..30622fde577 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -718,6 +718,7 @@ typedef struct system_variables ulong session_track_transaction_info; my_bool session_track_schema; my_bool session_track_state_change; + my_bool tcp_nodelay; ulong threadpool_priority; @@ -3123,6 +3124,9 @@ public: it returned an error on master, and this is OK on the slave. */ bool is_slave_error; + /* True if we have printed something to the error log for this statement */ + bool error_printed_to_log; + /* True when a transaction is queued up for binlog group commit. Used so that if another transaction needs to wait for a row lock held by @@ -4372,6 +4376,69 @@ private: return raised; } +private: + void push_warning_truncated_priv(Sql_condition::enum_warning_level level, + uint sql_errno, + const char *type_str, const char *val) + { + DBUG_ASSERT(sql_errno == ER_TRUNCATED_WRONG_VALUE || + sql_errno == ER_WRONG_VALUE); + char buff[MYSQL_ERRMSG_SIZE]; + CHARSET_INFO *cs= &my_charset_latin1; + cs->cset->snprintf(cs, buff, sizeof(buff), + ER_THD(this, sql_errno), type_str, val); + /* + Note: the format string can vary between ER_TRUNCATED_WRONG_VALUE + and ER_WRONG_VALUE, but the code passed to push_warning() is + always ER_TRUNCATED_WRONG_VALUE. This is intentional. + */ + push_warning(this, level, ER_TRUNCATED_WRONG_VALUE, buff); + } +public: + void push_warning_truncated_wrong_value(Sql_condition::enum_warning_level level, + const char *type_str, const char *val) + { + return push_warning_truncated_priv(level, ER_TRUNCATED_WRONG_VALUE, + type_str, val); + } + void push_warning_wrong_value(Sql_condition::enum_warning_level level, + const char *type_str, const char *val) + { + return push_warning_truncated_priv(level, ER_WRONG_VALUE, type_str, val); + } + void push_warning_truncated_wrong_value(const char *type_str, const char *val) + { + return push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_WARN, + type_str, val); + } + void push_warning_truncated_value_for_field(Sql_condition::enum_warning_level + level, const char *type_str, + const char *val, const char *name) + { + DBUG_ASSERT(name); + char buff[MYSQL_ERRMSG_SIZE]; + CHARSET_INFO *cs= &my_charset_latin1; + cs->cset->snprintf(cs, buff, sizeof(buff), + ER_THD(this, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), + type_str, val, name, + (ulong) get_stmt_da()->current_row_for_warning()); + push_warning(this, level, ER_TRUNCATED_WRONG_VALUE, buff); + + } + void push_warning_wrong_or_truncated_value(Sql_condition::enum_warning_level level, + bool totally_useless_value, + const char *type_str, + const char *val, + const char *field_name) + { + if (field_name) + push_warning_truncated_value_for_field(level, type_str, val, field_name); + else if (totally_useless_value) + push_warning_wrong_value(level, type_str, val); + else + push_warning_truncated_wrong_value(level, type_str, val); + } + public: /** Overloaded to guard query/query_length fields */ virtual void set_statement(Statement *stmt); @@ -6318,7 +6385,8 @@ public: inline bool add_item_to_list(THD *thd, Item *item) { - return thd->lex->current_select->add_item_to_list(thd, item); + bool res= thd->lex->current_select->add_item_to_list(thd, item); + return res; } inline bool add_value_to_list(THD *thd, Item *value) diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index 97bbf8f73bd..a518f991892 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -55,6 +55,14 @@ bool With_clause::add_with_element(With_element *elem) } +void st_select_lex_unit::set_with_clause(With_clause *with_cl) +{ + with_clause= with_cl; + if (with_clause) + with_clause->set_owner(this); +} + + /** @brief Check dependencies between tables defined in a list of with clauses @@ -682,7 +690,7 @@ void With_element::move_anchors_ahead() { st_select_lex *next_sl; st_select_lex *new_pos= spec->first_select(); - new_pos->linkage= UNION_TYPE; + new_pos->set_linkage(UNION_TYPE); for (st_select_lex *sl= new_pos; sl; sl= next_sl) { next_sl= sl->next_select(); @@ -691,9 +699,9 @@ void With_element::move_anchors_ahead() sl->move_node(new_pos); if (new_pos == spec->first_select()) { - enum sub_select_type type= new_pos->linkage; - new_pos->linkage= sl->linkage; - sl->linkage= type; + enum sub_select_type type= new_pos->get_linkage(); + new_pos->set_linkage(sl->get_linkage()); + sl->set_linkage(type); new_pos->with_all_modifier= sl->with_all_modifier; sl->with_all_modifier= false; } @@ -764,7 +772,7 @@ bool With_element::set_unparsed_spec(THD *thd, char *spec_start, char *spec_end) if (!unparsed_spec.str) { - my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), static_cast<int>(unparsed_spec.length)); return true; } @@ -834,9 +842,8 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd, goto err; lex_start(thd); lex->stmt_lex= old_lex; - with_select= &lex->select_lex; - with_select->select_number= ++thd->lex->stmt_lex->current_select_number; parse_status= parse_sql(thd, &parser_state, 0); + with_select= lex->first_select_lex(); if (parse_status) goto err; @@ -987,7 +994,7 @@ bool With_element::prepare_unreferenced(THD *thd) rename_columns_of_derived_unit(thd, spec) || check_duplicate_names(thd, first_sl->item_list, 1))) rc= true; - + thd->lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED; return rc; } @@ -1098,7 +1105,8 @@ bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem) if(!(derived= with_elem->clone_parsed_spec(thd, this))) return true; } - derived->first_select()->linkage= DERIVED_TABLE_TYPE; + derived->first_select()->set_linkage(DERIVED_TABLE_TYPE); + select_lex->add_statistics(derived); with_elem->inc_references(); return false; } diff --git a/sql/sql_cte.h b/sql/sql_cte.h index 16b473f0665..4a194b2a38f 100644 --- a/sql/sql_cte.h +++ b/sql/sql_cte.h @@ -279,8 +279,7 @@ private: */ With_clause *next_with_clause; /* Set to true if dependencies between with elements have been checked */ - bool dependencies_are_checked; - + bool dependencies_are_checked; /* The bitmap of all recursive with elements whose specifications are not complied with restrictions imposed by the SQL standards @@ -304,9 +303,8 @@ public: bool with_recursive; With_clause(bool recursive_fl, With_clause *emb_with_clause) - : owner(NULL), - embedding_with_clause(emb_with_clause), next_with_clause(NULL), - dependencies_are_checked(false), unrestricted(0), + : owner(NULL), embedding_with_clause(emb_with_clause), + next_with_clause(NULL), dependencies_are_checked(false), unrestricted(0), with_prepared_anchor(0), cleaned(0), stabilized(0), with_recursive(recursive_fl) { } @@ -320,8 +318,12 @@ public: last_next= &this->next_with_clause; } + st_select_lex_unit *get_owner() { return owner; } + void set_owner(st_select_lex_unit *unit) { owner= unit; } + void attach_to(st_select_lex *select_lex); + With_clause *pop() { return embedding_with_clause; } bool check_dependencies(); @@ -354,7 +356,6 @@ bool With_element::is_unrestricted() } inline - bool With_element::is_with_prepared_anchor() { return owner->with_prepared_anchor & get_elem_map(); @@ -436,11 +437,14 @@ void With_element::prepare_for_next_iteration() inline -void st_select_lex_unit::set_with_clause(With_clause *with_cl) -{ - with_clause= with_cl; - if (with_clause) - with_clause->set_owner(this); +void With_clause::attach_to(st_select_lex *select_lex) +{ + for (With_element *with_elem= with_list.first; + with_elem; + with_elem= with_elem->next) + { + select_lex->register_unit(with_elem->spec, NULL); + } } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index a040ba9eb93..326f2a64bbe 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -290,7 +290,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, bool has_triggers; ORDER *order= (ORDER *) ((order_list && order_list->elements) ? order_list->first : NULL); - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); killed_state killed_status= NOT_KILLED; THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE; bool binlog_is_row; @@ -352,7 +352,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DBUG_RETURN(TRUE); } table->map=1; - query_plan.select_lex= &thd->lex->select_lex; + query_plan.select_lex= thd->lex->first_select_lex(); query_plan.table= table; query_plan.updating_a_view= MY_TEST(table_list->view); @@ -384,7 +384,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, setup_order(thd, select_lex->ref_pointer_array, &tables, fields, all_fields, order)) { - free_underlaid_joins(thd, &thd->lex->select_lex); + free_underlaid_joins(thd, thd->lex->first_select_lex()); DBUG_RETURN(TRUE); } } @@ -770,7 +770,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, else { table->file->print_error(error, - MYF(thd->lex->ignore ? ME_JUST_WARNING : 0)); + MYF(thd->lex->ignore ? ME_WARNING : 0)); if (thd->is_error()) { error= 1; @@ -931,14 +931,16 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, bool *delete_while_scanning) { Item *fake_conds= 0; - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); DBUG_ENTER("mysql_prepare_delete"); List<Item> all_fields; *delete_while_scanning= true; thd->lex->allow_sum_func= 0; - if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, + if (setup_tables_and_check_access(thd, + &thd->lex->first_select_lex()->context, + &thd->lex->first_select_lex()-> + top_join_list, table_list, select_lex->leaf_tables, FALSE, DELETE_ACL, SELECT_ACL, TRUE)) @@ -1021,21 +1023,23 @@ int mysql_multi_delete_prepare(THD *thd) lex->query_tables also point on local list of DELETE SELECT_LEX */ - if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, + if (setup_tables_and_check_access(thd, + &thd->lex->first_select_lex()->context, + &thd->lex->first_select_lex()-> + top_join_list, lex->query_tables, - lex->select_lex.leaf_tables, FALSE, - DELETE_ACL, SELECT_ACL, FALSE)) + lex->first_select_lex()->leaf_tables, + FALSE, DELETE_ACL, SELECT_ACL, FALSE)) DBUG_RETURN(TRUE); - if (lex->select_lex.handle_derived(thd->lex, DT_MERGE)) + if (lex->first_select_lex()->handle_derived(thd->lex, DT_MERGE)) DBUG_RETURN(TRUE); /* Multi-delete can't be constructed over-union => we always have single SELECT on top and have to check underlying SELECTs of it */ - lex->select_lex.exclude_from_table_unique_test= TRUE; + lex->first_select_lex()->exclude_from_table_unique_test= TRUE; /* Fix tables-to-be-deleted-from list to point at opened tables */ for (target_tbl= (TABLE_LIST*) aux_tables; target_tbl; @@ -1077,8 +1081,8 @@ int mysql_multi_delete_prepare(THD *thd) Reset the exclude flag to false so it doesn't interfare with further calls to unique_table */ - lex->select_lex.exclude_from_table_unique_test= FALSE; - + lex->first_select_lex()->exclude_from_table_unique_test= FALSE; + if (lex->save_prep_leaf_tables()) DBUG_RETURN(TRUE); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 6a2e956fbf3..d65969d2160 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -99,7 +99,8 @@ mysql_handle_derived(LEX *lex, uint phases) processed normally. */ if (phases == DT_MERGE_FOR_INSERT && - cursor && cursor->top_table()->select_lex != &lex->select_lex) + cursor && (cursor->top_table()->select_lex != + lex->first_select_lex())) continue; for (; cursor && !res; @@ -1239,25 +1240,61 @@ bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived) /** @brief - Extract the condition depended on derived table/view and pushed it there + Extract condition that can be pushed into a derived table/view - @param thd The thread handle - @param cond The condition from which to extract the pushed condition - @param derived The reference to the derived table/view + @param thd the thread handle + @param cond current condition + @param derived the reference to the derived table/view @details - This functiom builds the most restrictive condition depending only on - the derived table/view that can be extracted from the condition cond. - The built condition is pushed into the having clauses of the - selects contained in the query specifying the derived table/view. - The function also checks for each select whether any condition depending - only on grouping fields can be extracted from the pushed condition. - If so, it pushes the condition over grouping fields into the where - clause of the select. - - @retval - true if an error is reported - false otherwise + This function builds the most restrictive condition depending only on + the derived table/view (directly or indirectly through equality) that + can be extracted from the given condition cond and pushes it into the + derived table/view. + + Example of the transformation: + + SELECT * + FROM t1, + ( + SELECT x,MAX(y) AS max_y + FROM t2 + GROUP BY x + ) AS d_tab + WHERE d_tab.x>1 AND d_tab.max_y<30; + + => + + SELECT * + FROM t1, + ( + SELECT x,z,MAX(y) AS max_y + FROM t2 + WHERE x>1 + HAVING max_y<30 + GROUP BY x + ) AS d_tab + WHERE d_tab.x>1 AND d_tab.max_y<30; + + In details: + 1. Check what pushable formula can be extracted from cond + 2. Build a clone PC of the formula that can be extracted + (the clone is built only if the extracted formula is a AND subformula + of cond or conjunction of such subformulas) + Do for every select specifying derived table/view: + 3. If there is no HAVING clause prepare PC to be conjuncted with + WHERE clause of the select. Otherwise do 4-7. + 4. Check what formula PC_where can be extracted from PC to be pushed + into the WHERE clause of the select + 5. Build PC_where and if PC_where is a conjunct(s) of PC remove it from PC + getting PC_having + 6. Prepare PC_where to be conjuncted with the WHERE clause of the select + 7. Prepare PC_having to be conjuncted with the HAVING clause of the select + @note + This method is similar to pushdown_cond_for_in_subquery() + + @retval TRUE if an error occurs + @retval FALSE otherwise */ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) @@ -1297,63 +1334,25 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) if (!some_select_allows_cond_pushdown) DBUG_RETURN(false); - /* - Build the most restrictive condition extractable from 'cond' - that can be pushed into the derived table 'derived'. - All subexpressions of this condition are cloned from the - subexpressions of 'cond'. - This condition has to be fixed yet. - */ + /* 1. Check what pushable formula can be extracted from cond */ Item *extracted_cond; - derived->check_pushable_cond_for_table(cond); - extracted_cond= derived->build_pushable_cond_for_table(thd, cond); + cond->check_pushable_cond(&Item::pushable_cond_checker_for_derived, + (uchar *)(&derived->table->map)); + /* 2. Build a clone PC of the formula that can be extracted */ + extracted_cond= + cond->build_pushable_cond(thd, + &Item::pushable_equality_checker_for_derived, + ((uchar *)&derived->table->map)); if (!extracted_cond) { /* Nothing can be pushed into the derived table */ DBUG_RETURN(false); } - /* Push extracted_cond into every select of the unit specifying 'derived' */ + st_select_lex *save_curr_select= thd->lex->current_select; for (; sl; sl= sl->next_select()) { Item *extracted_cond_copy; - if (!sl->cond_pushdown_is_allowed()) - continue; - thd->lex->current_select= sl; - if (sl->have_window_funcs()) - { - if (sl->join->group_list || sl->join->implicit_grouping) - continue; - ORDER *common_partition_fields= - sl->find_common_window_func_partition_fields(thd); - if (!common_partition_fields) - continue; - extracted_cond_copy= !sl->next_select() ? - extracted_cond : - extracted_cond->build_clone(thd); - if (!extracted_cond_copy) - continue; - - Item *cond_over_partition_fields;; - sl->collect_grouping_fields(thd, common_partition_fields); - sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy, - derived); - cond_over_partition_fields= - sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true); - if (cond_over_partition_fields) - cond_over_partition_fields= cond_over_partition_fields->transform(thd, - &Item::derived_grouping_field_transformer_for_where, - (uchar*) sl); - if (cond_over_partition_fields) - { - cond_over_partition_fields->walk( - &Item::cleanup_excluding_const_fields_processor, 0, 0); - sl->cond_pushed_into_where= cond_over_partition_fields; - } - - continue; - } - /* For each select of the unit except the last one create a clone of extracted_cond @@ -1364,73 +1363,44 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) if (!extracted_cond_copy) continue; - if (!sl->join->group_list && !sl->with_sum_func) - { - /* extracted_cond_copy is pushed into where of sl */ - extracted_cond_copy= extracted_cond_copy->transform(thd, - &Item::derived_field_transformer_for_where, - (uchar*) sl); - if (extracted_cond_copy) - { - extracted_cond_copy->walk( - &Item::cleanup_excluding_const_fields_processor, 0, 0); - sl->cond_pushed_into_where= extracted_cond_copy; - } - - continue; - } - - /* - Figure out what can be extracted from the pushed condition - that could be pushed into the where clause of sl - */ - Item *cond_over_grouping_fields; - sl->collect_grouping_fields(thd, sl->join->group_list); - sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy, - derived); - cond_over_grouping_fields= - sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true); - - /* - Transform the references to the 'derived' columns from the condition - pushed into the where clause of sl to make them usable in the new context - */ - if (cond_over_grouping_fields) - cond_over_grouping_fields= cond_over_grouping_fields->transform(thd, - &Item::derived_grouping_field_transformer_for_where, - (uchar*) sl); - - if (cond_over_grouping_fields) + /* Collect fields that are used in the GROUP BY of sl */ + if (sl->have_window_funcs()) { - /* - In extracted_cond_copy remove top conjuncts that - has been pushed into the where clause of sl - */ - extracted_cond_copy= remove_pushed_top_conjuncts(thd, extracted_cond_copy); - - cond_over_grouping_fields->walk( - &Item::cleanup_excluding_const_fields_processor, 0, 0); - sl->cond_pushed_into_where= cond_over_grouping_fields; - - if (!extracted_cond_copy) + if (sl->group_list.first || sl->join->implicit_grouping) + continue; + ORDER *common_partition_fields= + sl->find_common_window_func_partition_fields(thd); + if (!common_partition_fields) continue; + sl->collect_grouping_fields(thd, common_partition_fields); } + else + sl->collect_grouping_fields(thd, sl->group_list.first); + + Item *remaining_cond= NULL; + /* Do 4-6 */ + sl->pushdown_cond_into_where_clause(thd, extracted_cond_copy, + &remaining_cond, + &Item::derived_field_transformer_for_where, + (uchar *) sl); + if (!remaining_cond) + continue; /* - Transform the references to the 'derived' columns from the condition - pushed into the having clause of sl to make them usable in the new context + 7. Prepare PC_having to be conjuncted with the HAVING clause of + the select */ - extracted_cond_copy= extracted_cond_copy->transform(thd, - &Item::derived_field_transformer_for_having, - (uchar*) sl); - if (!extracted_cond_copy) + remaining_cond= + remaining_cond->transform(thd, + &Item::derived_field_transformer_for_having, + (uchar *) sl); + if (!remaining_cond) continue; - extracted_cond_copy->walk(&Item::cleanup_excluding_const_fields_processor, - 0, 0); - sl->cond_pushed_into_having= extracted_cond_copy; + remaining_cond->walk(&Item::cleanup_excluding_const_fields_processor, + 0, 0); + sl->cond_pushed_into_having= remaining_cond; } thd->lex->current_select= save_curr_select; DBUG_RETURN(false); } - diff --git a/sql/sql_do.cc b/sql/sql_do.cc index 2a4e43ab78a..1652b313909 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -33,7 +33,7 @@ bool mysql_do(THD *thd, List<Item> &values) DBUG_RETURN(TRUE); while ((value = li++)) (void) value->is_null(); - free_underlaid_joins(thd, &thd->lex->select_lex); + free_underlaid_joins(thd, thd->lex->first_select_lex()); if (unlikely(thd->is_error())) { diff --git a/sql/sql_error.cc b/sql/sql_error.cc index d6f5b99eef6..8d639f9271d 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -781,7 +781,7 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show) List<Item> field_list; MEM_ROOT *mem_root= thd->mem_root; const Sql_condition *err; - SELECT_LEX *sel= &thd->lex->select_lex; + SELECT_LEX *sel= thd->lex->first_select_lex(); SELECT_LEX_UNIT *unit= &thd->lex->unit; ulonglong idx= 0; Protocol *protocol=thd->protocol; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 69ea04a170c..72df8367dc7 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -433,8 +433,6 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) /* Always read all columns */ table->read_set= &table->s->all_set; - if (table->vcol_set) - table->vcol_set= &table->s->all_set; /* Restore the state. */ thd->set_open_tables(backup_open_tables); diff --git a/sql/sql_help.cc b/sql/sql_help.cc index aa9f3fedd6d..95bc6ade366 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -87,7 +87,7 @@ enum enum_used_fields static bool init_fields(THD *thd, TABLE_LIST *tables, struct st_find_field *find_fields, uint count) { - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; DBUG_ENTER("init_fields"); context->resolve_in_table_list_only(tables); for (; count-- ; find_fields++) @@ -719,10 +719,11 @@ static bool mysqld_help_internal(THD *thd, const char *mask) Init tables and fields to be usable from items tables do not contain VIEWs => we can pass 0 as conds */ - thd->lex->select_lex.context.table_list= - thd->lex->select_lex.context.first_name_resolution_table= &tables[0]; - if (setup_tables(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, + thd->lex->first_select_lex()->context.table_list= + thd->lex->first_select_lex()->context.first_name_resolution_table= + &tables[0]; + if (setup_tables(thd, &thd->lex->first_select_lex()->context, + &thd->lex->first_select_lex()->top_join_list, tables, leaves, FALSE, FALSE)) goto error; memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields)); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 52a465f7613..51acf10a98a 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -241,7 +241,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } else { // Part field list - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); Name_resolution_context *context= &select_lex->context; Name_resolution_context_state ctx_state; int res; @@ -273,7 +273,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, /* Restore the current context. */ ctx_state.restore_state(context, table_list); - thd->lex->select_lex.no_wrap_view_item= FALSE; + thd->lex->first_select_lex()->no_wrap_view_item= FALSE; if (res) DBUG_RETURN(-1); @@ -657,7 +657,7 @@ static void save_insert_query_plan(THD* thd, TABLE_LIST *table_list) bool skip= MY_TEST(table_list->view); /* Save subquery children */ - for (SELECT_LEX_UNIT *unit= thd->lex->select_lex.first_inner_unit(); + for (SELECT_LEX_UNIT *unit= thd->lex->first_select_lex()->first_inner_unit(); unit; unit= unit->next_unit()) { @@ -777,7 +777,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, /* mysql_prepare_insert sets table_list->table if it was not set */ table= table_list->table; - context= &thd->lex->select_lex.context; + context= &thd->lex->first_select_lex()->context; /* These three asserts test the hypothesis that the resetting of the name resolution context below is not necessary at all since the list of local @@ -1070,7 +1070,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, } while (bulk_parameters_iterations(thd)); values_loop_end: - free_underlaid_joins(thd, &thd->lex->select_lex); + free_underlaid_joins(thd, thd->lex->first_select_lex()); joins_freed= TRUE; /* @@ -1259,7 +1259,7 @@ abort: table->file->ha_release_auto_increment(); if (!joins_freed) - free_underlaid_joins(thd, &thd->lex->select_lex); + free_underlaid_joins(thd, thd->lex->first_select_lex()); thd->abort_on_warning= 0; DBUG_RETURN(retval); } @@ -1289,7 +1289,7 @@ abort: static bool check_view_insertability(THD * thd, TABLE_LIST *view) { - uint num= view->view->select_lex.item_list.elements; + uint num= view->view->first_select_lex()->item_list.elements; TABLE *table= view->table; Field_translator *trans_start= view->field_translation, *trans_end= trans_start + num; @@ -1389,10 +1389,12 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, than INSERT. */ - if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, + if (setup_tables_and_check_access(thd, + &thd->lex->first_select_lex()->context, + &thd->lex->first_select_lex()-> + top_join_list, table_list, - thd->lex->select_lex.leaf_tables, + thd->lex->first_select_lex()->leaf_tables, select_insert, INSERT_ACL, SELECT_ACL, TRUE)) DBUG_RETURN(TRUE); @@ -1400,7 +1402,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, if (insert_into_view && !fields.elements) { thd->lex->empty_field_list_on_rset= 1; - if (!thd->lex->select_lex.leaf_tables.head()->table || + if (!thd->lex->first_select_lex()->leaf_tables.head()->table || table_list->is_multitable()) { my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0), @@ -1474,7 +1476,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, enum_duplicates duplic, COND **where, bool select_insert) { - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); Name_resolution_context *context= &select_lex->context; Name_resolution_context_state ctx_state; bool insert_into_view= (table_list->view != 0); @@ -1719,7 +1721,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) */ if (info->ignore) { - table->file->print_error(error, MYF(ME_JUST_WARNING)); + table->file->print_error(error, MYF(ME_WARNING)); goto ok_or_after_trg_err; /* Ignoring a not fatal error, return 0 */ } goto err; @@ -1844,7 +1846,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) { if (!(thd->variables.old_behavior & OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE)) - table->file->print_error(error, MYF(ME_JUST_WARNING)); + table->file->print_error(error, MYF(ME_WARNING)); goto ok_or_after_trg_err; } goto err; @@ -2025,7 +2027,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) goto err; if (!(thd->variables.old_behavior & OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE)) - table->file->print_error(error, MYF(ME_JUST_WARNING)); + table->file->print_error(error, MYF(ME_WARNING)); table->file->restore_auto_increment(prev_insert_id); goto ok_or_after_trg_err; } @@ -2359,7 +2361,7 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request, di->thd.set_db(&table_list->db); di->thd.set_query(my_strndup(table_list->table_name.str, table_list->table_name.length, - MYF(MY_WME | ME_FATALERROR)), + MYF(MY_WME | ME_FATAL)), table_list->table_name.length, system_charset_info); if (di->thd.db.str == NULL || di->thd.query() == NULL) { @@ -2391,7 +2393,7 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request, mysql_mutex_unlock(&di->mutex); di->unlock(); delete di; - my_error(ER_CANT_CREATE_THREAD, MYF(ME_FATALERROR), error); + my_error(ER_CANT_CREATE_THREAD, MYF(ME_FATAL), error); goto end_create; } @@ -2604,10 +2606,6 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) share->default_fields) { bool error_reported= FALSE; - if (unlikely(!(copy->def_vcol_set= - (MY_BITMAP*) alloc_root(client_thd->mem_root, - sizeof(MY_BITMAP))))) - goto error; if (unlikely(parse_vcol_defs(client_thd, client_thd->mem_root, copy, &error_reported))) goto error; @@ -2626,15 +2624,6 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) copy->def_write_set.bitmap= ((my_bitmap_map*) (bitmap + share->column_bitmap_size)); bitmaps_used= 2; - if (share->virtual_fields) - { - my_bitmap_init(copy->def_vcol_set, - (my_bitmap_map*) (bitmap + - bitmaps_used*share->column_bitmap_size), - share->fields, FALSE); - bitmaps_used++; - copy->vcol_set= copy->def_vcol_set; - } if (share->default_fields || share->default_expressions) { my_bitmap_init(©->has_value_set, @@ -3260,7 +3249,7 @@ bool Delayed_insert::handle_inserts(void) or if another thread is removing the current table definition from the table cache. */ - my_error(ER_DELAYED_CANT_CHANGE_LOCK, MYF(ME_FATALERROR | ME_NOREFRESH), + my_error(ER_DELAYED_CANT_CHANGE_LOCK, MYF(ME_FATAL | ME_ERROR_LOG), table->s->table_name.str); goto err; } @@ -3433,7 +3422,7 @@ bool Delayed_insert::handle_inserts(void) { /* This is not known to happen. */ my_error(ER_DELAYED_CANT_CHANGE_LOCK, - MYF(ME_FATALERROR | ME_NOREFRESH), + MYF(ME_FATAL | ME_ERROR_LOG), table->s->table_name.str); goto err; } @@ -3529,7 +3518,7 @@ bool Delayed_insert::handle_inserts(void) bool mysql_insert_select_prepare(THD *thd) { LEX *lex= thd->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); DBUG_ENTER("mysql_insert_select_prepare"); @@ -3618,7 +3607,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) select, LEX::current_select should point to the first select while we are fixing fields from insert list. */ - lex->current_select= &lex->select_lex; + lex->current_select= lex->first_select_lex(); res= (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, NULL, 0) || @@ -3635,7 +3624,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) if (info.handle_duplicates == DUP_UPDATE && !res) { - Name_resolution_context *context= &lex->select_lex.context; + Name_resolution_context *context= &lex->first_select_lex()->context; Name_resolution_context_state ctx_state; /* Save the state of the current name resolution context. */ @@ -3645,7 +3634,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) table_list->next_local= 0; context->resolve_in_table_list_only(table_list); - lex->select_lex.no_wrap_view_item= TRUE; + lex->first_select_lex()->no_wrap_view_item= TRUE; res= res || check_update_fields(thd, context->table_list, *info.update_fields, *info.update_values, @@ -3656,15 +3645,15 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) */ true, &map); - lex->select_lex.no_wrap_view_item= FALSE; + lex->first_select_lex()->no_wrap_view_item= FALSE; /* When we are not using GROUP BY and there are no ungrouped aggregate functions we can refer to other tables in the ON DUPLICATE KEY part. We use next_name_resolution_table descructively, so check it first (views?) */ DBUG_ASSERT (!table_list->next_name_resolution_table); - if (lex->select_lex.group_list.elements == 0 && - !lex->select_lex.with_sum_func) + if (lex->first_select_lex()->group_list.elements == 0 && + !lex->first_select_lex()->with_sum_func) /* We must make a single context out of the two separate name resolution contexts : the INSERT table and the tables in the SELECT part of INSERT ... SELECT. @@ -4080,9 +4069,9 @@ void select_insert::abort_result_set() { Field *Item::create_field_for_create_select(TABLE *table) { - Field *def_field, *tmp_field; - return ::create_tmp_field(table->in_use, table, this, type(), - (Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0); + static Tmp_field_param param(false, false, false, false); + Tmp_field_src src; + return create_tmp_field_ex(table, &src, ¶m); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 1b1031d440b..bff6dfb0e05 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -174,7 +174,7 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex) { TABLE_LIST *table_list; Table_ident *table_ident; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); Name_resolution_context *context= &select_lex->context; /* We will call the parser to create a part_info struct based on the @@ -635,6 +635,30 @@ void Lex_input_stream::reduce_digest_token(uint token_left, uint token_right) } } +/** + lex starting operations for builtin select collected together +*/ + +void SELECT_LEX::lex_start(LEX *plex) +{ + SELECT_LEX_UNIT *unit= &plex->unit; + /* 'parent_lex' is used in init_query() so it must be before it. */ + parent_lex= plex; + init_query(); + master= unit; + prev= &unit->slave; + link_next= slave= next= 0; + link_prev= (st_select_lex_node**)&(plex->all_selects_list); + DBUG_ASSERT(!group_list_ptrs); + select_number= 1; + in_sum_expr=0; + ftfunc_list_alloc.empty(); + ftfunc_list= &ftfunc_list_alloc; + group_list.empty(); + order_list.empty(); + gorder_list.empty(); +} + void lex_start(THD *thd) { DBUG_ENTER("lex_start"); @@ -659,17 +683,18 @@ void LEX::start(THD *thd_arg) DBUG_ASSERT(!explain); + builtin_select.lex_start(this); + lex_options= 0; context_stack.empty(); + //empty select_stack + select_stack_top= 0; unit.init_query(); - current_select_number= 1; - select_lex.linkage= UNSPECIFIED_TYPE; - /* 'parent_lex' is used in init_query() so it must be before it. */ - select_lex.parent_lex= this; - select_lex.init_query(); + current_select_number= 0; curr_with_clause= 0; with_clauses_list= 0; with_clauses_list_last_next= &with_clauses_list; create_view= NULL; + field_list.empty(); value_list.empty(); update_list.empty(); set_var_list.empty(); @@ -683,17 +708,8 @@ void LEX::start(THD *thd_arg) auxiliary_table_list.empty(); unit.next= unit.master= unit.link_next= unit.return_to= 0; unit.prev= unit.link_prev= 0; - unit.slave= current_select= all_selects_list= &select_lex; - select_lex.master= &unit; - select_lex.prev= &unit.slave; - select_lex.link_next= select_lex.slave= select_lex.next= 0; - select_lex.link_prev= (st_select_lex_node**)&(all_selects_list); - select_lex.options= 0; - select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; - select_lex.init_order(); - select_lex.group_list.empty(); - if (select_lex.group_list_ptrs) - select_lex.group_list_ptrs->clear(); + unit.slave= current_select= all_selects_list= &builtin_select; + sql_cache= LEX::SQL_CACHE_UNSPECIFIED; describe= 0; analyze_stmt= 0; explain_json= false; @@ -703,14 +719,7 @@ void LEX::start(THD *thd_arg) safe_to_cache_query= 1; parsing_options.reset(); empty_field_list_on_rset= 0; - select_lex.select_number= 1; part_info= 0; - select_lex.in_sum_expr=0; - select_lex.ftfunc_list_alloc.empty(); - select_lex.ftfunc_list= &select_lex.ftfunc_list_alloc; - select_lex.group_list.empty(); - select_lex.order_list.empty(); - select_lex.gorder_list.empty(); m_sql_cmd= NULL; duplicates= DUP_ERROR; ignore= 0; @@ -722,6 +731,8 @@ void LEX::start(THD *thd_arg) query_tables= 0; reset_query_tables_list(FALSE); expr_allows_subselect= TRUE; + selects_allow_into= FALSE; + selects_allow_procedure= FALSE; use_only_table_context= FALSE; parse_vcol_expr= FALSE; check_exists= FALSE; @@ -731,8 +742,8 @@ void LEX::start(THD *thd_arg) name= null_clex_str; event_parse_data= NULL; profile_options= PROFILE_NONE; - nest_level=0 ; - select_lex.nest_level_base= &unit; + nest_level= 0; + builtin_select.nest_level_base= &unit; allow_sum_func= 0; in_sum_func= NULL; @@ -756,6 +767,13 @@ void LEX::start(THD *thd_arg) vers_conditions.empty(); is_lex_started= TRUE; + + next_is_main= FALSE; + next_is_down= FALSE; + + wild= 0; + exchange= 0; + DBUG_VOID_RETURN; } @@ -1272,7 +1290,8 @@ int ORAlex(YYSTYPE *yylval, THD *thd) int Lex_input_stream::lex_token(YYSTYPE *yylval, THD *thd) { int token; - + const int left_paren= (int) '('; + if (lookahead_token >= 0) { /* @@ -1289,6 +1308,8 @@ int Lex_input_stream::lex_token(YYSTYPE *yylval, THD *thd) token= lex_one_token(yylval, thd); add_digest_token(token, yylval); + SELECT_LEX *curr_sel= thd->lex->current_select; + switch(token) { case WITH: /* @@ -1337,8 +1358,16 @@ int Lex_input_stream::lex_token(YYSTYPE *yylval, THD *thd) } break; case VALUES: - if (thd->lex->current_select->parsing_place == IN_UPDATE_ON_DUP_KEY || - thd->lex->current_select->parsing_place == IN_PART_FUNC) + if (curr_sel && + (curr_sel->parsing_place == BEFORE_OPT_LIST || + curr_sel->parsing_place == AFTER_LIST)) + { + curr_sel->parsing_place= NO_MATTER; + break; + } + if (curr_sel && + (curr_sel->parsing_place == IN_UPDATE_ON_DUP_KEY || + curr_sel->parsing_place == IN_PART_FUNC)) return VALUE_SYM; token= lex_one_token(yylval, thd); add_digest_token(token, yylval); @@ -1352,6 +1381,43 @@ int Lex_input_stream::lex_token(YYSTYPE *yylval, THD *thd) lookahead_token= token; return VALUES; } + case VALUE_SYM: + if (curr_sel && + (curr_sel->parsing_place == BEFORE_OPT_LIST || + curr_sel->parsing_place == AFTER_LIST)) + { + curr_sel->parsing_place= NO_MATTER; + return VALUES; + } + break; + case PARTITION_SYM: + case SELECT_SYM: + case UNION_SYM: + if (curr_sel && + (curr_sel->parsing_place == BEFORE_OPT_LIST || + curr_sel->parsing_place == AFTER_LIST)) + { + curr_sel->parsing_place= NO_MATTER; + } + break; + case left_paren: + if (!curr_sel || + curr_sel->parsing_place != BEFORE_OPT_LIST) + return token; + token= lex_one_token(yylval, thd); + add_digest_token(token, yylval); + lookahead_yylval= yylval; + yylval= NULL; + lookahead_token= token; + curr_sel->parsing_place= NO_MATTER; + if (token == LIKE) + return LEFT_PAREN_LIKE; + if (token == WITH) + return LEFT_PAREN_WITH; + if (token != left_paren && token != SELECT_SYM) + return LEFT_PAREN_ALT; + else + return left_paren; break; default: break; @@ -1688,7 +1754,7 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd) return(TEXT_STRING); } case MY_LEX_COMMENT: // Comment - lex->select_lex.options|= OPTION_FOUND_COMMENT; + lex->lex_options|= OPTION_LEX_FOUND_COMMENT; while ((c= yyGet()) != '\n' && c) ; yyUnget(); // Safety against eof state= MY_LEX_START; // Try again @@ -1699,7 +1765,7 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd) state= MY_LEX_CHAR; // Probable division break; } - lex->select_lex.options|= OPTION_FOUND_COMMENT; + lex->lex_options|= OPTION_LEX_FOUND_COMMENT; /* Reject '/' '*', since we might need to turn off the echo */ yyUnget(); @@ -2207,8 +2273,8 @@ void trim_whitespace(CHARSET_INFO *cs, LEX_CSTRING *str, size_t * prefix_length) void st_select_lex_node::init_query_common() { options= 0; - sql_cache= SQL_CACHE_UNSPECIFIED; - linkage= UNSPECIFIED_TYPE; + set_linkage(UNSPECIFIED_TYPE); + distinct= TRUE; no_table_names_allowed= 0; uncacheable= 0; } @@ -2216,7 +2282,7 @@ void st_select_lex_node::init_query_common() void st_select_lex_unit::init_query() { init_query_common(); - linkage= GLOBAL_OPTIONS_TYPE; + set_linkage(GLOBAL_OPTIONS_TYPE); select_limit_cnt= HA_POS_ERROR; offset_limit_cnt= 0; union_distinct= 0; @@ -2258,16 +2324,6 @@ void st_select_lex::init_query() having_fix_field_for_pushed_cond= 0; context.select_lex= this; context.init(); - /* - Add the name resolution context of the current (sub)query to the - stack of contexts for the whole query. - TODO: - push_context may return an error if there is no memory for a new - element in the stack, however this method has no return value, - thus push_context should be moved to a place where query - initialization is checked for failure. - */ - parent_lex->push_context(&context, parent_lex->thd->mem_root); cond_count= between_count= with_wild= 0; max_equal_elems= 0; ref_pointer_array.reset(); @@ -2313,16 +2369,14 @@ void st_select_lex::init_select() table_join_options= 0; in_sum_expr= with_wild= 0; options= 0; - sql_cache= SQL_CACHE_UNSPECIFIED; ftfunc_list_alloc.empty(); inner_sum_func_list= 0; ftfunc_list= &ftfunc_list_alloc; - order_list.elements= 0; - order_list.first= 0; - order_list.next= &order_list.first; + order_list.empty(); /* Set limit and offset to default values */ select_limit= 0; /* denotes the default limit = HA_POS_ERROR */ offset_limit= 0; /* denotes the default offset = 0 */ + is_set_query_expr_tail= false; with_sum_func= 0; with_all_modifier= 0; is_correlated= 0; @@ -2384,6 +2438,23 @@ void st_select_lex_node::add_slave(st_select_lex_node *slave_arg) } } +void st_select_lex_node::link_chain_down(st_select_lex_node *first) +{ + st_select_lex_node *last_node; + st_select_lex_node *node= first; + do + { + last_node= node; + node->master= this; + node= node->next; + } while (node); + if ((last_node->next= slave)) + { + slave->prev= &last_node->next; + } + first->prev= &slave; + slave= first; +} /* include on level down (but do not link) @@ -2433,7 +2504,7 @@ void st_select_lex_node::fast_exclude() // Remove slave structure for (; slave; slave= slave->next) slave->fast_exclude(); - + } @@ -2907,8 +2978,7 @@ void st_select_lex::print_order(String *str, else { /* replace numeric reference with equivalent for ORDER constant */ - if (order->item[0]->type() == Item::INT_ITEM && - order->item[0]->basic_const_item()) + if (order->item[0]->is_order_clause_position()) { /* make it expression instead of integer constant */ str->append(STRING_WITH_LEN("''")); @@ -3103,6 +3173,7 @@ LEX::LEX() gtid_domain_static_buffer, initial_gtid_domain_buffer_size, initial_gtid_domain_buffer_size, 0); + unit.slave= &builtin_select; } @@ -3129,12 +3200,12 @@ bool LEX::can_be_merged() // TODO: do not forget implement case when select_lex.table_list.elements==0 /* find non VIEW subqueries/unions */ - bool selects_allow_merge= (select_lex.next_select() == 0 && - !(select_lex.uncacheable & + bool selects_allow_merge= (first_select_lex()->next_select() == 0 && + !(first_select_lex()->uncacheable & UNCACHEABLE_RAND)); if (selects_allow_merge) { - for (SELECT_LEX_UNIT *tmp_unit= select_lex.first_inner_unit(); + for (SELECT_LEX_UNIT *tmp_unit= first_select_lex()->first_inner_unit(); tmp_unit; tmp_unit= tmp_unit->next_unit()) { @@ -3151,12 +3222,12 @@ bool LEX::can_be_merged() } return (selects_allow_merge && - select_lex.group_list.elements == 0 && - select_lex.having == 0 && - select_lex.with_sum_func == 0 && - select_lex.table_list.elements >= 1 && - !(select_lex.options & SELECT_DISTINCT) && - select_lex.select_limit == 0); + first_select_lex()->group_list.elements == 0 && + first_select_lex()->having == 0 && + first_select_lex()->with_sum_func == 0 && + first_select_lex()->table_list.elements >= 1 && + !(first_select_lex()->options & SELECT_DISTINCT) && + first_select_lex()->select_limit == 0); } @@ -3509,7 +3580,7 @@ void LEX::set_trg_event_type_for_tables() Do not iterate over sub-selects, only the tables in the outermost SELECT_LEX can be modified, if any. */ - TABLE_LIST *tables= select_lex.get_table_list(); + TABLE_LIST *tables= first_select_lex()->get_table_list(); while (tables) { @@ -3565,12 +3636,13 @@ TABLE_LIST *LEX::unlink_first_table(bool *link_to_local) /* and from local list if it is not empty */ - if ((*link_to_local= MY_TEST(select_lex.table_list.first))) + if ((*link_to_local= MY_TEST(first_select_lex()->table_list.first))) { - select_lex.context.table_list= - select_lex.context.first_name_resolution_table= first->next_local; - select_lex.table_list.first= first->next_local; - select_lex.table_list.elements--; //safety + first_select_lex()->context.table_list= + first_select_lex()->context.first_name_resolution_table= + first->next_local; + first_select_lex()->table_list.first= first->next_local; + first_select_lex()->table_list.elements--; //safety first->next_local= 0; /* Ensure that the global list has the same first table as the local @@ -3601,7 +3673,7 @@ TABLE_LIST *LEX::unlink_first_table(bool *link_to_local) void LEX::first_lists_tables_same() { - TABLE_LIST *first_table= select_lex.table_list.first; + TABLE_LIST *first_table= first_select_lex()->table_list.first; if (query_tables != first_table && first_table != 0) { TABLE_LIST *next; @@ -3626,6 +3698,23 @@ void LEX::first_lists_tables_same() } } +void LEX::fix_first_select_number() +{ + SELECT_LEX *first= first_select_lex(); + if (first && first->select_number != 1) + { + uint num= first->select_number; + for (SELECT_LEX *sel= all_selects_list; + sel; + sel= sel->next_select_in_list()) + { + if (sel->select_number < num) + sel->select_number++; + } + first->select_number= 1; + } +} + /* Link table back that was unlinked with unlink_first_table() @@ -3651,10 +3740,10 @@ void LEX::link_first_table_back(TABLE_LIST *first, if (link_to_local) { - first->next_local= select_lex.table_list.first; - select_lex.context.table_list= first; - select_lex.table_list.first= first; - select_lex.table_list.elements++; //safety + first->next_local= first_select_lex()->table_list.first; + first_select_lex()->context.table_list= first; + first_select_lex()->table_list.first= first; + first_select_lex()->table_list.elements++; //safety } } } @@ -3683,19 +3772,19 @@ void LEX::cleanup_after_one_table_open() NOTE: all units will be connected to thd->lex->select_lex, because we have not UNION on most upper level. */ - if (all_selects_list != &select_lex) + if (all_selects_list != first_select_lex()) { derived_tables= 0; - select_lex.exclude_from_table_unique_test= false; + first_select_lex()->exclude_from_table_unique_test= false; /* cleunup underlying units (units of VIEW) */ - for (SELECT_LEX_UNIT *un= select_lex.first_inner_unit(); + for (SELECT_LEX_UNIT *un= first_select_lex()->first_inner_unit(); un; un= un->next_unit()) un->cleanup(); /* reduce all selects list to default state */ - all_selects_list= &select_lex; + all_selects_list= first_select_lex(); /* remove underlying units (units of VIEW) subtree */ - select_lex.cut_subtree(); + first_select_lex()->cut_subtree(); } } @@ -4350,7 +4439,7 @@ void SELECT_LEX::update_used_tables() tab->covering_keys= tab->s->keys_for_keyread; tab->covering_keys.intersect(tab->keys_in_use_for_query); /* - View/derived was merged. Need to recalculate read_set/vcol_set + View/derived was merged. Need to recalculate read_set bitmaps here. For example: CREATE VIEW v1 AS SELECT f1,f2,f3 FROM t1; SELECT f1 FROM v1; @@ -4359,8 +4448,6 @@ void SELECT_LEX::update_used_tables() be in the read_set. */ bitmap_clear_all(tab->read_set); - if (tab->vcol_set) - bitmap_clear_all(tab->vcol_set); break; } } @@ -4561,7 +4648,7 @@ void st_select_lex::set_explain_type(bool on_the_fly) using_materialization= TRUE; } - if (&master_unit()->thd->lex->select_lex == this) + if (master_unit()->thd->lex->first_select_lex() == this) { type= is_primary ? "PRIMARY" : "SIMPLE"; } @@ -4756,8 +4843,8 @@ bool LEX::save_prep_leaf_tables() Query_arena *arena= thd->stmt_arena, backup; arena= thd->activate_stmt_arena_if_needed(&backup); //It is used for DETETE/UPDATE so top level has only one SELECT - DBUG_ASSERT(select_lex.next_select() == NULL); - bool res= select_lex.save_prep_leaf_tables(thd); + DBUG_ASSERT(first_select_lex()->next_select() == NULL); + bool res= first_select_lex()->save_prep_leaf_tables(thd); if (arena) thd->restore_active_arena(arena, &backup); @@ -5088,8 +5175,13 @@ bool LEX::is_partition_management() const SELECT_LEX *LEX::exclude_last_select() { - DBUG_ENTER("SELECT_LEX::exclude_last_select"); - SELECT_LEX *exclude= current_select; + return exclude_not_first_select(current_select); +} + +SELECT_LEX *LEX::exclude_not_first_select(SELECT_LEX *exclude) +{ + DBUG_ENTER("LEX::exclude_not_first_select"); + DBUG_PRINT("enter", ("exclude %p #%u", exclude, exclude->select_number)); SELECT_LEX_UNIT *unit= exclude->master_unit(); SELECT_LEX *sl; DBUG_ASSERT(unit->first_select() != exclude); @@ -5100,89 +5192,255 @@ SELECT_LEX *LEX::exclude_last_select() DBUG_PRINT("info", ("excl: %p unit: %p prev: %p", exclude, unit, sl)); if (!sl) DBUG_RETURN(NULL); - DBUG_ASSERT(exclude->next_select() == NULL); - exclude->exclude_from_tree(); + DBUG_ASSERT(&sl->next == exclude->prev); + + exclude->prev= NULL; + current_select= sl; DBUG_RETURN(exclude); } -/** - Put given (new) SELECT_LEX level below after currect (last) SELECT +SELECT_LEX_UNIT *LEX::alloc_unit() +{ + SELECT_LEX_UNIT *unit; + DBUG_ENTER("LEX::alloc_unit"); + if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT())) + DBUG_RETURN(NULL); + + unit->init_query(); + /* TODO: reentrant problem */ + unit->thd= thd; + unit->link_next= 0; + unit->link_prev= 0; + /* TODO: remove return_to */ + unit->return_to= NULL; + DBUG_RETURN(unit); +} - LAST SELECT -> DUMMY SELECT - | - V - NEW UNIT - | - V - NEW SELECT - SELECT (*LAST*) ... FROM (SELECT (*NEW*) ... ) +SELECT_LEX *LEX::alloc_select(bool select) +{ + SELECT_LEX *select_lex; + DBUG_ENTER("LEX::alloc_select"); + if (!(select_lex= new (thd->mem_root) SELECT_LEX())) + DBUG_RETURN(NULL); + DBUG_PRINT("info", ("Allocate select: %p #%u statement lex: %p", + select_lex, thd->lex->stmt_lex->current_select_number, + thd->lex->stmt_lex)); + /* + TODO: move following init to constructor when we get rid of builtin + select + */ + select_lex->select_number= ++thd->lex->stmt_lex->current_select_number; + select_lex->parent_lex= this; /* Used in init_query. */ + select_lex->init_query(); + if (select) + select_lex->init_select(); + select_lex->nest_level_base= &this->unit; + select_lex->include_global((st_select_lex_node**)&all_selects_list); + select_lex->context.resolve_in_select_list= TRUE; + DBUG_RETURN(select_lex); +} - @param nselect Select to put one level below +SELECT_LEX_UNIT * +LEX::create_unit(SELECT_LEX *first_sel) +{ + SELECT_LEX_UNIT *unit; + DBUG_ENTER("LEX::create_unit"); - @retval TRUE Error - @retval FALSE OK -*/ + if (!(unit= alloc_unit())) + DBUG_RETURN(NULL); -bool LEX::add_unit_in_brackets(SELECT_LEX *nselect) + unit->register_select_chain(first_sel); + if (first_sel->next_select()) + { + unit->reset_distinct(); + DBUG_ASSERT(!unit->fake_select_lex); + if (unit->add_fake_select_lex(thd)) + DBUG_RETURN(NULL); + } + DBUG_RETURN(unit); +} + +SELECT_LEX_UNIT * +SELECT_LEX::attach_selects_chain(SELECT_LEX *first_sel, + Name_resolution_context *context) { - DBUG_ENTER("LEX::add_unit_in_brackets"); - bool distinct= nselect->master_unit()->union_distinct == nselect; - bool rc= add_select_to_union_list(distinct, nselect->linkage, 0); - if (rc) - DBUG_RETURN(TRUE); - SELECT_LEX* dummy_select= current_select; - dummy_select->automatic_brackets= TRUE; - dummy_select->linkage= nselect->linkage; + SELECT_LEX_UNIT *unit; + DBUG_ENTER("SELECT_LEX::attach_select_chain"); + + if (!(unit= parent_lex->alloc_unit())) + DBUG_RETURN(NULL); + + unit->register_select_chain(first_sel); + register_unit(unit, context); + if (first_sel->next_select()) + { + unit->reset_distinct(); + DBUG_ASSERT(!unit->fake_select_lex); + if (unit->add_fake_select_lex(parent_lex->thd)) + DBUG_RETURN(NULL); + } + + DBUG_RETURN(unit); +} + +SELECT_LEX * +LEX::wrap_unit_into_derived(SELECT_LEX_UNIT *unit) +{ + SELECT_LEX *wrapping_sel; + Table_ident *ti; + DBUG_ENTER("LEX::wrap_unit_into_derived"); + + if (!(wrapping_sel= alloc_select(TRUE))) + DBUG_RETURN(NULL); + Name_resolution_context *context= &wrapping_sel->context; + context->init(); + wrapping_sel->automatic_brackets= FALSE; + + wrapping_sel->register_unit(unit, context); /* stuff dummy SELECT * FROM (...) */ + + if (push_select(wrapping_sel)) // for Items & TABLE_LIST + DBUG_RETURN(NULL); + + /* add SELECT list*/ + { + Item *item= new (thd->mem_root) + Item_field(thd, context, NULL, NULL, &star_clex_str); + if (item == NULL) + goto err; + if (add_item_to_list(thd, item)) + goto err; + (wrapping_sel->with_wild)++; + } + + unit->first_select()->set_linkage(DERIVED_TABLE_TYPE); + + ti= new (thd->mem_root) Table_ident(unit); + if (ti == NULL) + goto err; + { + TABLE_LIST *table_list; + LEX_CSTRING alias; + if (wrapping_sel->make_unique_derived_name(thd, &alias)) + goto err; + + if (!(table_list= wrapping_sel->add_table_to_list(thd, ti, &alias, + 0, TL_READ, + MDL_SHARED_READ))) + goto err; + + context->resolve_in_table_list_only(table_list); + wrapping_sel->add_joined_table(table_list); + } + + pop_select(); + + derived_tables|= DERIVED_SUBQUERY; + + DBUG_RETURN(wrapping_sel); + +err: + pop_select(); + DBUG_RETURN(NULL); +} + +SELECT_LEX *LEX::wrap_select_chain_into_derived(SELECT_LEX *sel) +{ + SELECT_LEX *dummy_select; + SELECT_LEX_UNIT *unit; + Table_ident *ti; + DBUG_ENTER("LEX::wrap_select_chain_into_derived"); + + if (!(dummy_select= alloc_select(TRUE))) + DBUG_RETURN(NULL); Name_resolution_context *context= &dummy_select->context; - context->init(); + dummy_select->automatic_brackets= FALSE; + + if (!(unit= dummy_select->attach_selects_chain(sel, context))) + DBUG_RETURN(NULL); + + /* stuff dummy SELECT * FROM (...) */ + + if (push_select(dummy_select)) // for Items & TABLE_LIST + DBUG_RETURN(NULL); /* add SELECT list*/ - Item *item= new (thd->mem_root) - Item_field(thd, context, NULL, NULL, &star_clex_str); - if (unlikely(item == NULL)) - DBUG_RETURN(TRUE); - if (unlikely(add_item_to_list(thd, item))) - DBUG_RETURN(TRUE); - (dummy_select->with_wild)++; + { + Item *item= new (thd->mem_root) + Item_field(thd, context, NULL, NULL, &star_clex_str); + if (item == NULL) + goto err; + if (add_item_to_list(thd, item)) + goto err; + (dummy_select->with_wild)++; + } - rc= mysql_new_select(this, 1, nselect); - nselect->linkage= DERIVED_TABLE_TYPE; - DBUG_ASSERT(nselect->outer_select() == dummy_select); + sel->set_linkage(DERIVED_TABLE_TYPE); - current_select= dummy_select; - current_select->nest_level--; + ti= new (thd->mem_root) Table_ident(unit); + if (ti == NULL) + goto err; + { + TABLE_LIST *table_list; + LEX_CSTRING alias; + if (dummy_select->make_unique_derived_name(thd, &alias)) + goto err; - SELECT_LEX_UNIT *unit= nselect->master_unit(); - Table_ident *ti= new (thd->mem_root) Table_ident(unit); - if (unlikely(ti == NULL)) - DBUG_RETURN(TRUE); - char buff[10]; - LEX_CSTRING alias; - alias.length= my_snprintf(buff, sizeof(buff), - "__%u", dummy_select->select_number); - alias.str= thd->strmake(buff, alias.length); - if (unlikely(!alias.str)) - DBUG_RETURN(TRUE); + if (!(table_list= dummy_select->add_table_to_list(thd, ti, &alias, + 0, TL_READ, + MDL_SHARED_READ))) + goto err; - TABLE_LIST *table_list; - if (unlikely(!(table_list= - dummy_select->add_table_to_list(thd, ti, &alias, - 0, TL_READ, - MDL_SHARED_READ)))) - DBUG_RETURN(TRUE); - context->resolve_in_table_list_only(table_list); - dummy_select->add_joined_table(table_list); + context->resolve_in_table_list_only(table_list); + dummy_select->add_joined_table(table_list); + } + + pop_select(); derived_tables|= DERIVED_SUBQUERY; - current_select= nselect; - current_select->nest_level++; - DBUG_RETURN(rc); + DBUG_RETURN(dummy_select); + +err: + pop_select(); + DBUG_RETURN(NULL); +} + +bool LEX::push_context(Name_resolution_context *context) +{ + DBUG_ENTER("LEX::push_context"); + DBUG_PRINT("info", ("Context: %p Select: %p (%d)", + context, context->select_lex, + (context->select_lex ? + context->select_lex->select_number: + 0))); + bool res= context_stack.push_front(context, thd->mem_root); + DBUG_RETURN(res); +} + + +SELECT_LEX *LEX::create_priority_nest(SELECT_LEX *first_in_nest) +{ + DBUG_ENTER("LEX::create_priority_nest"); + DBUG_ASSERT(first_in_nest->first_nested); + enum sub_select_type wr_unit_type= first_in_nest->get_linkage(); + bool wr_distinct= first_in_nest->distinct; + SELECT_LEX *attach_to= first_in_nest->first_nested; + attach_to->cut_next(); + SELECT_LEX *wrapper= wrap_select_chain_into_derived(first_in_nest); + if (wrapper) + { + first_in_nest->first_nested= NULL; + wrapper->set_linkage_and_distinct(wr_unit_type, wr_distinct); + wrapper->first_nested= attach_to->first_nested; + wrapper->set_master_unit(attach_to->master_unit()); + attach_to->link_neighbour(wrapper); + } + DBUG_RETURN(wrapper); } @@ -5197,7 +5455,7 @@ bool LEX::add_unit_in_brackets(SELECT_LEX *nselect) void LEX::check_automatic_up(enum sub_select_type type) { if (type != INTERSECT_TYPE && - current_select->linkage == INTERSECT_TYPE && + current_select->get_linkage() == INTERSECT_TYPE && current_select->outer_select() && current_select->outer_select()->automatic_brackets) { @@ -5647,10 +5905,17 @@ bool LEX::sp_for_loop_implicit_cursor_statement(THD *thd, bounds->m_index->sp_lex_in_use= true; sphead->reset_lex(thd, bounds->m_index); DBUG_ASSERT(thd->lex != this); - if (unlikely(!(item= - new (thd->mem_root) Item_field(thd, - thd->lex->current_context(), - NullS, NullS, &name)))) + /* + We pass NULL as Name_resolution_context here. + It's OK, fix_fields() will not be called for this Item_field created. + Item_field is only needed for LEX::sp_for_loop_cursor_declarations() + and is used to transfer the loop index variable name, "rec" in this example: + FOR rec IN (SELECT * FROM t1) + DO + SELECT rec.a, rec.b; + END FOR; + */ + if (!(item= new (thd->mem_root) Item_field(thd, NULL, NullS, NullS, &name))) return true; bounds->m_index->set_item_and_free_list(item, NULL); if (thd->lex->sphead->restore_lex(thd)) @@ -5757,10 +6022,22 @@ bool LEX::sp_for_loop_intrange_declarations(THD *thd, Lex_for_loop_st *loop, const LEX_CSTRING *index, const Lex_for_loop_bounds_st &bounds) { - if (unlikely(!(loop->m_index= - bounds.m_index-> - sp_add_for_loop_variable(thd, index, - bounds.m_index->get_item())))) + Item *item; + if ((item= bounds.m_index->get_item())->type() == Item::FIELD_ITEM) + { + // We're here is the lower bound is unknown identifier + my_error(ER_SP_UNDECLARED_VAR, MYF(0), item->full_name()); + return true; + } + if ((item= bounds.m_upper_bound->get_item())->type() == Item::FIELD_ITEM) + { + // We're here is the upper bound is unknown identifier + my_error(ER_SP_UNDECLARED_VAR, MYF(0), item->full_name()); + return true; + } + if (!(loop->m_index= + bounds.m_index->sp_add_for_loop_variable(thd, index, + bounds.m_index->get_item()))) return true; if (unlikely(!(loop->m_upper_bound= bounds.m_upper_bound-> @@ -6673,7 +6950,6 @@ Item_param *LEX::add_placeholder(THD *thd, const LEX_CSTRING *name, my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); return NULL; } - Query_fragment pos(thd, sphead, start, end); Item_param *item= new (thd->mem_root) Item_param(thd, name, pos.pos(), pos.length()); @@ -6704,6 +6980,38 @@ bool LEX::add_resignal_statement(THD *thd, const sp_condition_value *v) } +/* + Make an Item when an identifier is found in the FOR loop bounds: + FOR rec IN cursor + FOR var IN var1 .. xxx + FOR var IN row1.field1 .. xxx + When we parse the first expression after the "IN" keyword, + we don't know yet if it's a cursor name, or a scalar SP variable name, + or a field of a ROW SP variable. Here we create Item_field to remember + the fully qualified name. Later sp_for_loop_cursor_declarations() + detects how to treat this name properly. +*/ +Item *LEX::create_item_for_loop_bound(THD *thd, + const LEX_CSTRING *a, + const LEX_CSTRING *b, + const LEX_CSTRING *c) +{ + /* + Pass NULL as the name resolution context. + This is OK, fix_fields() won't be called for this Item_field. + */ + return new (thd->mem_root) Item_field(thd, NULL, a->str, b->str, c); +} + + +bool LEX::check_expr_allows_fields_or_error(THD *thd, const char *name) const +{ + if (select_stack_top > 0) + return false; // OK, fields are allowed + my_error(ER_BAD_FIELD_ERROR, MYF(0), name, thd->where); + return true; // Error, fields are not allowed +} + Item *LEX::create_item_ident_nospvar(THD *thd, const Lex_ident_sys_st *a, const Lex_ident_sys_st *b) @@ -6726,12 +7034,11 @@ Item *LEX::create_item_ident_nospvar(THD *thd, my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), a->str, thd->where); return NULL; } - if ((current_select->parsing_place != IN_HAVING) || - (current_select->get_in_sum_expr() > 0)) - return new (thd->mem_root) Item_field(thd, current_context(), - NullS, a->str, b); - return new (thd->mem_root) Item_ref(thd, current_context(), - NullS, a->str, b); + + if (current_select->parsing_place == FOR_LOOP_BOUND) + return create_item_for_loop_bound(thd, &null_clex_str, a, b); + + return create_item_ident_field(thd, NullS, a->str, b); } @@ -6943,12 +7250,11 @@ Item *LEX::create_item_ident(THD *thd, my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), b->str, thd->where); return NULL; } - if (current_select->parsing_place != IN_HAVING || - current_select->get_in_sum_expr() > 0) - return new (thd->mem_root) Item_field(thd, current_context(), - schema, b->str, c); - return new (thd->mem_root) Item_ref(thd, current_context(), - schema, b->str, c); + + if (current_select->parsing_place == FOR_LOOP_BOUND) + return create_item_for_loop_bound(thd, &null_clex_str, b, c); + + return create_item_ident_field(thd, schema, b->str, c); } @@ -6981,11 +7287,9 @@ Item *LEX::create_item_limit(THD *thd, const Lex_ident_cli_st *ca) #endif safe_to_cache_query= 0; - if (unlikely(item->type() != Item::INT_ITEM)) - { - my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0)); + if (!item->is_valid_limit_clause_variable_with_error()) return NULL; - } + item->limit_clause_param= true; return item; } @@ -7015,11 +7319,8 @@ Item *LEX::create_item_limit(THD *thd, if (unlikely(!(item= create_item_spvar_row_field(thd, rh, &sa, &sb, spv, ca->pos(), cb->end())))) return NULL; - if (unlikely(item->type() != Item::INT_ITEM)) - { - my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0)); + if (!item->is_valid_limit_clause_variable_with_error()) return NULL; - } item->limit_clause_param= true; return item; } @@ -7039,15 +7340,20 @@ bool LEX::set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val) } -Item *LEX::create_item_ident_nosp(THD *thd, Lex_ident_sys_st *name) +Item *LEX::create_item_ident_field(THD *thd, const char *db, + const char *table, + const Lex_ident_sys_st *name) { + if (check_expr_allows_fields_or_error(thd, name->str)) + return NULL; + if (current_select->parsing_place != IN_HAVING || current_select->get_in_sum_expr() > 0) return new (thd->mem_root) Item_field(thd, current_context(), - NullS, NullS, name); + db, table, name); return new (thd->mem_root) Item_ref(thd, current_context(), - NullS, NullS, name); + db, table, name); } @@ -7097,6 +7403,11 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name, if (lex_string_eq(name, STRING_WITH_LEN("SQLERRM"))) return new (thd->mem_root) Item_func_sqlerrm(thd); } + + if (current_select->parsing_place == FOR_LOOP_BOUND) + return create_item_for_loop_bound(thd, &null_clex_str, &null_clex_str, + name); + return create_item_ident_nosp(thd, name); } @@ -7390,8 +7701,8 @@ void st_select_lex::collect_grouping_fields(THD *thd, { if ((*ord->item)->eq((Item*)item, 0)) { - Grouping_tmp_field *grouping_tmp_field= - new Grouping_tmp_field(master_unit()->derived->table->field[i], item); + Field_pair *grouping_tmp_field= + new Field_pair(master_unit()->derived->table->field[i], item); grouping_tmp_fields.push_back(grouping_tmp_field); } } @@ -7422,8 +7733,7 @@ void st_select_lex::collect_grouping_fields(THD *thd, */ void -st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond, - TABLE_LIST *derived) +st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond) { cond->clear_extraction_flag(); if (cond->type() == Item::COND_ITEM) @@ -7436,7 +7746,7 @@ st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond, Item *item; while ((item=li++)) { - check_cond_extraction_for_grouping_fields(item, derived); + check_cond_extraction_for_grouping_fields(item); if (item->get_extraction_flag() != NO_EXTRACTION_FL) { count++; @@ -7485,7 +7795,7 @@ st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond, to figure out whether a subformula depends only on these fields or not. @note The built condition C is always implied by the condition cond - (cond => C). The method tries to build the most restictive such + (cond => C). The method tries to build the least restictive such condition (i.e. for any other condition C' such that cond => C' we have C => C'). @note @@ -7561,6 +7871,140 @@ Item *st_select_lex::build_cond_for_grouping_fields(THD *thd, Item *cond, } +bool st_select_lex::set_nest_level(int new_nest_level) +{ + DBUG_ENTER("st_select_lex::set_nest_level"); + DBUG_PRINT("enter", ("select #%d %p nest level: %d", + select_number, this, new_nest_level)); + if (new_nest_level > (int) MAX_SELECT_NESTING) + { + my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0)); + DBUG_RETURN(TRUE); + } + nest_level= new_nest_level; + new_nest_level++; + for (SELECT_LEX_UNIT *u= first_inner_unit(); u; u= u->next_unit()) + { + if (u->set_nest_level(new_nest_level)) + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} + +bool st_select_lex_unit::set_nest_level(int new_nest_level) +{ + DBUG_ENTER("st_select_lex_unit::set_nest_level"); + for(SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + if (sl->set_nest_level(new_nest_level)) + DBUG_RETURN(TRUE); + } + if (fake_select_lex && + fake_select_lex->set_nest_level(new_nest_level)) + DBUG_RETURN(TRUE); + DBUG_RETURN(FALSE); +} + + +bool st_select_lex::check_parameters(SELECT_LEX *main_select) +{ + DBUG_ENTER("st_select_lex::check_parameters"); + DBUG_PRINT("enter", ("select #%d %p nest level: %d", + select_number, this, nest_level)); + + + if ((options & OPTION_PROCEDURE_CLAUSE) && + (!parent_lex->selects_allow_procedure || + next_select() != NULL || + this != master_unit()->first_select() || + nest_level != 0)) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "PROCEDURE"); + DBUG_RETURN(TRUE); + } + + if ((options & SELECT_HIGH_PRIORITY) && this != main_select) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "HIGH_PRIORITY"); + DBUG_RETURN(TRUE); + } + if ((options & OPTION_BUFFER_RESULT) && this != main_select) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_BUFFER_RESULT"); + DBUG_RETURN(TRUE); + } + if ((options & OPTION_FOUND_ROWS) && this != main_select) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CALC_FOUND_ROWS"); + DBUG_RETURN(TRUE); + } + if (options & OPTION_NO_QUERY_CACHE) + { + /* + Allow this flag only on the first top-level SELECT statement, if + SQL_CACHE wasn't specified. + */ + if (this != main_select) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE"); + DBUG_RETURN(TRUE); + } + if (parent_lex->sql_cache == LEX::SQL_CACHE) + { + my_error(ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE"); + DBUG_RETURN(TRUE); + } + parent_lex->safe_to_cache_query=0; + parent_lex->sql_cache= LEX::SQL_NO_CACHE; + } + if (options & OPTION_TO_QUERY_CACHE) + { + /* + Allow this flag only on the first top-level SELECT statement, if + SQL_NO_CACHE wasn't specified. + */ + if (this != main_select) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE"); + DBUG_RETURN(TRUE); + } + if (parent_lex->sql_cache == LEX::SQL_NO_CACHE) + { + my_error(ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE"); + DBUG_RETURN(TRUE); + } + parent_lex->safe_to_cache_query=1; + parent_lex->sql_cache= LEX::SQL_CACHE; + } + + for (SELECT_LEX_UNIT *u= first_inner_unit(); u; u= u->next_unit()) + { + if (u->check_parameters(main_select)) + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} + + +bool st_select_lex_unit::check_parameters(SELECT_LEX *main_select) +{ + for(SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + if (sl->check_parameters(main_select)) + return TRUE; + } + return fake_select_lex && fake_select_lex->check_parameters(main_select); +} + + +bool LEX::check_main_unit_semantics() +{ + if (unit.set_nest_level(0) || + unit.check_parameters(first_select_lex())) + return TRUE; + return FALSE; +} + int set_statement_var_if_exists(THD *thd, const char *var_name, size_t var_name_length, ulonglong value) { @@ -7615,10 +8059,10 @@ bool LEX::create_or_alter_view_finalize(THD *thd, Table_ident *table_ident) { sql_command= SQLCOM_CREATE_VIEW; /* first table in list is target VIEW name */ - if (unlikely(!select_lex.add_table_to_list(thd, table_ident, NULL, + if (!first_select_lex()->add_table_to_list(thd, table_ident, NULL, TL_OPTION_UPDATING, TL_IGNORE, - MDL_EXCLUSIVE))) + MDL_EXCLUSIVE)) return true; query_tables->open_strategy= TABLE_LIST::OPEN_STUB; return false; @@ -7911,6 +8355,130 @@ Item *Lex_trim_st::make_item_func_trim(THD *thd) const } +/** + @brief + Extract from given item a condition pushable into WHERE clause + + @param thd the thread handle + @param cond the item to extract a condition to be pushed + into WHERE + @param remaining_cond the condition that will remain of cond after + the pushdown of its parts into the WHERE clause + @param transformer the transformer callback function to be + applied to the condition so it can be pushed + down into the WHERE clause of this select + @param arg parameter to be passed to the transformer + + @details + This method checks if cond entirely or its parts can be + pushed into the WHERE clause of this select and prepares it for pushing. + + First it checks wherever this select doesn't have any aggregation function + in its projection and GROUP BY clause. If so cond can be entirely + pushed into the WHERE clause of this select but before its fields should + be transformed with transformer_for_where to make it pushable. + + Otherwise the method checks wherever any condition depending only on + grouping fields can be extracted from cond. If there is any it prepares it + for pushing using grouping_field_transformer_for_where and if it happens to + be a conjunct of cond it removes it from cond. It saves the result of + removal in remaining_cond. + The extracted condition is saved in cond_pushed_into_where of this select. + + @note + When looking for pushable condition the method considers only the grouping + fields from the list grouping_tmp_fields whose elements are of the type + Field_pair. This list must be prepared before the call of the + function. + + @note + This method is called for pushdown conditions into materialized + derived tables/views optimization. + Item::derived_field_transformer_for_where is passed as the actual + callback function. + Also it is called for pushdown conditions into materialized IN subqueries. + Item::in_subq_field_transformer_for_where is passed as the actual + callback function. +*/ + +void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond, + Item **remaining_cond, + Item_transformer transformer, + uchar *arg) +{ + if (!cond_pushdown_is_allowed()) + return; + thd->lex->current_select= this; + if (have_window_funcs()) + { + Item *cond_over_partition_fields; + check_cond_extraction_for_grouping_fields(cond); + cond_over_partition_fields= + build_cond_for_grouping_fields(thd, cond, true); + if (cond_over_partition_fields) + cond_over_partition_fields= cond_over_partition_fields->transform(thd, + &Item::grouping_field_transformer_for_where, + (uchar*) this); + if (cond_over_partition_fields) + { + cond_over_partition_fields->walk( + &Item::cleanup_excluding_const_fields_processor, 0, 0); + cond_pushed_into_where= cond_over_partition_fields; + } + + return; + } + + if (!join->group_list && !with_sum_func) + { + cond= + cond->transform(thd, transformer, arg); + if (cond) + { + cond->walk( + &Item::cleanup_excluding_const_fields_processor, 0, 0); + cond_pushed_into_where= cond; + } + + return; + } + + /* + Figure out what can be extracted from cond + that could be pushed into the WHERE clause of this select + */ + Item *cond_over_grouping_fields; + check_cond_extraction_for_grouping_fields(cond); + cond_over_grouping_fields= + build_cond_for_grouping_fields(thd, cond, true); + + /* + Transform the references to the columns from the cond + pushed into the WHERE clause of this select to make them usable in + the new context + */ + if (cond_over_grouping_fields) + cond_over_grouping_fields= cond_over_grouping_fields->transform(thd, + &Item::grouping_field_transformer_for_where, + (uchar*) this); + + if (cond_over_grouping_fields) + { + + /* + In cond remove top conjuncts that has been pushed into the WHERE + clause of this select + */ + cond= remove_pushed_top_conjuncts(thd, cond); + + cond_over_grouping_fields->walk( + &Item::cleanup_excluding_const_fields_processor, 0, 0); + cond_pushed_into_where= cond_over_grouping_fields; + } + + *remaining_cond= cond; +} + Item *LEX::make_item_func_call_generic(THD *thd, Lex_ident_cli_st *cdb, Lex_ident_cli_st *cname, List<Item> *args) { @@ -8177,9 +8745,716 @@ bool LEX::tvc_finalize_derived() thd->parse_error(); return true; } - if (current_select->linkage == GLOBAL_OPTIONS_TYPE || + if (current_select->get_linkage() == GLOBAL_OPTIONS_TYPE || unlikely(mysql_new_select(this, 1, NULL))) return true; - current_select->linkage= DERIVED_TABLE_TYPE; + current_select->set_linkage(DERIVED_TABLE_TYPE); return tvc_finalize(); } + + +void st_select_lex_unit::reset_distinct() +{ + union_distinct= NULL; + for(SELECT_LEX *sl= first_select()->next_select(); + sl; + sl= sl->next_select()) + { + if (sl->distinct) + { + union_distinct= sl; + } + } +} + + +void st_select_lex_unit::fix_distinct(st_select_lex_unit *new_unit) +{ + if (union_distinct) + { + if (this != union_distinct->master_unit()) + { + DBUG_ASSERT(new_unit == union_distinct->master_unit()); + new_unit->union_distinct= union_distinct; + reset_distinct(); + } + else + new_unit->reset_distinct(); + } +} + + +void st_select_lex_unit::register_select_chain(SELECT_LEX *first_sel) +{ + DBUG_ASSERT(first_sel != 0); + slave= first_sel; + first_sel->prev= &slave; + for(SELECT_LEX *sel=first_sel; sel; sel= sel->next_select()) + { + sel->master= (st_select_lex_node *)this; + uncacheable|= sel->uncacheable; + } +} + + +void st_select_lex::register_unit(SELECT_LEX_UNIT *unit, + Name_resolution_context *outer_context) +{ + if ((unit->next= slave)) + slave->prev= &unit->next; + unit->prev= &slave; + slave= unit; + unit->master= this; + uncacheable|= unit->uncacheable; + + for(SELECT_LEX *sel= unit->first_select();sel; sel= sel->next_select()) + { + sel->context.outer_context= outer_context; + } +} + + +void st_select_lex::add_statistics(SELECT_LEX_UNIT *unit) +{ + for (; + unit; + unit= unit->next_unit()) + for(SELECT_LEX *child= unit->first_select(); + child; + child= child->next_select()) + { + /* + A subselect can add fields to an outer select. + Reserve space for them. + */ + select_n_where_fields+= child->select_n_where_fields; + /* + Aggregate functions in having clause may add fields + to an outer select. Count them also. + */ + select_n_having_items+= child->select_n_having_items; + } +} + + +bool LEX::main_select_push() +{ + DBUG_ENTER("LEX::main_select_push"); + current_select_number= 1; + builtin_select.select_number= 1; + if (push_select(&builtin_select)) + DBUG_RETURN(TRUE); + DBUG_RETURN(FALSE); +} + +void Lex_select_lock::set_to(SELECT_LEX *sel) +{ + if (defined_lock) + { + if (sel->master_unit() && + sel == sel->master_unit()->fake_select_lex) + sel->master_unit()->set_lock_to_the_last_select(*this); + else + { + sel->parent_lex->safe_to_cache_query= 0; + if (update_lock) + { + sel->lock_type= TL_WRITE; + sel->set_lock_for_tables(TL_WRITE); + } + else + { + sel->lock_type= TL_READ_WITH_SHARED_LOCKS; + sel->set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS); + } + } + } +} + +bool Lex_order_limit_lock::set_to(SELECT_LEX *sel) +{ + /*TODO: lock */ + //if (lock.defined_lock && sel == sel->master_unit()->fake_select_lex) + // return TRUE; + if (lock.defined_timeout) + { + THD *thd= sel->parent_lex->thd; + if (set_statement_var_if_exists(thd, + C_STRING_WITH_LEN("lock_wait_timeout"), + lock.timeout) || + set_statement_var_if_exists(thd, + C_STRING_WITH_LEN("innodb_lock_wait_timeout"), + lock.timeout)) + return TRUE; + } + lock.set_to(sel); + sel->explicit_limit= limit.explicit_limit; + sel->select_limit= limit.select_limit; + sel->offset_limit= limit.offset_limit; + if (order_list) + { + if (sel->get_linkage() != GLOBAL_OPTIONS_TYPE && + sel->olap != UNSPECIFIED_OLAP_TYPE && + (sel->get_linkage() != UNION_TYPE || sel->braces)) + { + my_error(ER_WRONG_USAGE, MYF(0), + "CUBE/ROLLUP", "ORDER BY"); + return TRUE; + } + sel->order_list= *(order_list); + } + sel->is_set_query_expr_tail= true; + return FALSE; +} + + +static void change_item_list_context(List<Item> *list, + Name_resolution_context *context) +{ + List_iterator_fast<Item> it (*list); + Item *item; + while((item= it++)) + { + item->walk(&Item::change_context_processor, FALSE, (void *)context); + } +} + + +bool LEX::insert_select_hack(SELECT_LEX *sel) +{ + DBUG_ENTER("LEX::insert_select_hack"); + + DBUG_ASSERT(first_select_lex() == &builtin_select); + DBUG_ASSERT(sel != NULL); + + DBUG_ASSERT(builtin_select.first_inner_unit() == NULL); + + if (builtin_select.link_prev) + { + if ((*builtin_select.link_prev= builtin_select.link_next)) + ((st_select_lex *)builtin_select.link_next)->link_prev= + builtin_select.link_prev; + builtin_select.link_prev= NULL; // indicator of removal + } + + set_main_unit(sel->master_unit()); + + DBUG_ASSERT(builtin_select.table_list.elements == 1); + TABLE_LIST *insert_table= builtin_select.table_list.first; + + if (!(insert_table->next_local= sel->table_list.first)) + { + sel->table_list.next= &insert_table->next_local; + } + sel->table_list.first= insert_table; + sel->table_list.elements++; + insert_table->select_lex= sel; + + sel->context.first_name_resolution_table= insert_table; + builtin_select.context= sel->context; + change_item_list_context(&field_list, &sel->context); + + if (sel->tvc && !sel->next_select() && + (sql_command == SQLCOM_INSERT_SELECT || + sql_command == SQLCOM_REPLACE_SELECT)) + { + DBUG_PRINT("info", ("'Usual' INSERT detected")); + many_values= sel->tvc->lists_of_values; + sel->options= sel->tvc->select_options; + sel->tvc= NULL; + if (sql_command == SQLCOM_INSERT_SELECT) + sql_command= SQLCOM_INSERT; + else + sql_command= SQLCOM_REPLACE; + } + + + for (SELECT_LEX *sel= all_selects_list; + sel; + sel= sel->next_select_in_list()) + { + if (sel->select_number != 1) + sel->select_number--; + }; + + DBUG_RETURN(FALSE); +} + + +/* + Create an Item_singlerow_subselect for a query expression. +*/ +Item *LEX::create_item_query_expression(THD *thd, + const char *tok_start, + st_select_lex_unit *unit) +{ + if (!expr_allows_subselect || sql_command == SQLCOM_PURGE) + { + thd->parse_error(ER_SYNTAX_ERROR, tok_start); + return NULL; + } + + // Add the subtree of subquery to the current SELECT_LEX + SELECT_LEX *curr_sel= select_stack_head(); + DBUG_ASSERT(current_select == curr_sel); + if (!curr_sel) + curr_sel= &builtin_select; + curr_sel->register_unit(unit, &curr_sel->context); + curr_sel->add_statistics(unit); + + return new (thd->mem_root) + Item_singlerow_subselect(thd, unit->first_select()); +} + + +/** + Process unit parsed in brackets +*/ + +bool LEX::parsed_unit_in_brackets(SELECT_LEX_UNIT *unit) +{ + SELECT_LEX *first_in_nest= unit->pre_last_parse->next_select()->first_nested; + if (first_in_nest->first_nested != first_in_nest) + { + /* There is a priority jump starting from first_in_nest */ + if (create_priority_nest(first_in_nest) == NULL) + return true; + } + push_select(unit->fake_select_lex); + return false; +} + + +/** + Process tail of unit parsed in brackets +*/ +SELECT_LEX *LEX::parsed_unit_in_brackets_tail(SELECT_LEX_UNIT *unit, + Lex_order_limit_lock * l) +{ + pop_select(); + if (l) + { + (l)->set_to(unit->fake_select_lex); + } + return unit->first_select(); +} + + +/** + Process select parsed in brackets +*/ + +SELECT_LEX *LEX::parsed_select(SELECT_LEX *sel, Lex_order_limit_lock * l) +{ + pop_select(); + if (l) + { + if (sel->next_select()) + { + SELECT_LEX_UNIT *unit= sel->master_unit(); + if (!unit) + unit= create_unit(sel); + if (!unit) + return NULL; + if (!unit->fake_select_lex->is_set_query_expr_tail) + l->set_to(unit->fake_select_lex); + else + { + sel= wrap_unit_into_derived(unit); + if (!sel) + return NULL; + l->set_to(sel); + } + } + else if (!sel->is_set_query_expr_tail) + { + l->set_to(sel); + } + else + { + SELECT_LEX_UNIT *unit= create_unit(sel); + if (!unit) + return NULL; + sel= wrap_unit_into_derived(unit); + if (!sel) + return NULL; + l->set_to(sel); + } + } + return sel; +} + + +/** + Process select parsed in brackets +*/ + +SELECT_LEX *LEX::parsed_select_in_brackets(SELECT_LEX *sel, + Lex_order_limit_lock * l) +{ + sel->braces= TRUE; + return parsed_select(sel, l); +} + + +SELECT_LEX_UNIT *LEX::parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2, + enum sub_select_type unit_type, + bool distinct) +{ + SELECT_LEX_UNIT *res; + SELECT_LEX *sel1; + SELECT_LEX *sel2; + if (!s1->next_select()) + sel1= s1; + else + { + sel1= wrap_unit_into_derived(s1->master_unit()); + if (!sel1) + return NULL; + } + if (!s2->next_select()) + sel2= s2; + else + { + sel2= wrap_unit_into_derived(s2->master_unit()); + if (!sel2) + return NULL; + } + sel1->link_neighbour(sel2); + sel2->set_linkage_and_distinct(unit_type, distinct); + sel2->first_nested= sel1->first_nested= sel1; + res= create_unit(sel1); + if (res == NULL) + return NULL; + res->pre_last_parse= sel1; + return res; +} + + +SELECT_LEX_UNIT *LEX::parsed_select_expr_cont(SELECT_LEX_UNIT *unit, + SELECT_LEX *s2, + enum sub_select_type unit_type, + bool distinct, bool oracle) +{ + SELECT_LEX *sel1; + if (!s2->next_select()) + sel1= s2; + else + { + sel1= wrap_unit_into_derived(s2->master_unit()); + if (!sel1) + return NULL; + } + SELECT_LEX *last= unit->pre_last_parse->next_select(); + + int cmp= oracle? 0 : cmp_unit_op(unit_type, last->get_linkage()); + if (cmp == 0) + { + sel1->first_nested= last->first_nested; + } + else if (cmp > 0) + { + last->first_nested= unit->pre_last_parse; + sel1->first_nested= last; + } + else /* cmp < 0 */ + { + SELECT_LEX *first_in_nest= last->first_nested; + if (first_in_nest->first_nested != first_in_nest) + { + /* There is a priority jump starting from first_in_nest */ + if ((last= create_priority_nest(first_in_nest)) == NULL) + return NULL; + } + sel1->first_nested= last->first_nested; + } + last->link_neighbour(sel1); + sel1->set_master_unit(unit); + sel1->set_linkage_and_distinct(unit_type, distinct); + unit->pre_last_parse= last; + return unit; +} + +/** + Process parsed select in body +*/ + +SELECT_LEX_UNIT *LEX::parsed_body_select(SELECT_LEX *sel, + Lex_order_limit_lock * l) +{ + if (!(sel= parsed_select(sel, l))) + return NULL; + + SELECT_LEX_UNIT *res= create_unit(sel); + return res; +} + +/** + Process parsed unit in body +*/ + +bool LEX::parsed_body_unit(SELECT_LEX_UNIT *unit) +{ + SELECT_LEX *first_in_nest= + unit->pre_last_parse->next_select()->first_nested; + if (first_in_nest->first_nested != first_in_nest) + { + /* There is a priority jump starting from first_in_nest */ + if (create_priority_nest(first_in_nest) == NULL) + return true; + } + push_select(unit->fake_select_lex); + return false; +} + +/** + Process parsed tail of unit in body + + TODO: make processing for double tail case +*/ + +SELECT_LEX_UNIT *LEX::parsed_body_unit_tail(SELECT_LEX_UNIT *unit, + Lex_order_limit_lock * l) +{ + pop_select(); + if (l) + { + (l)->set_to(unit->fake_select_lex); + } + return unit; +} + +/** + Process subselect parsing +*/ + +SELECT_LEX *LEX::parsed_subselect(SELECT_LEX_UNIT *unit, char *place) +{ + if (!expr_allows_subselect || + sql_command == (int)SQLCOM_PURGE) + { + thd->parse_error(ER_SYNTAX_ERROR, place); + return NULL; + } + + // Add the subtree of subquery to the current SELECT_LEX + SELECT_LEX *curr_sel= select_stack_head(); + DBUG_ASSERT(current_select == curr_sel); + if (curr_sel) + { + curr_sel->register_unit(unit, &curr_sel->context); + curr_sel->add_statistics(unit); + } + + return unit->first_select(); +} + + +/** + Process INSERT-like select +*/ + +bool LEX::parsed_insert_select(SELECT_LEX *first_select) +{ + if (sql_command == SQLCOM_INSERT || + sql_command == SQLCOM_REPLACE) + { + if (sql_command == SQLCOM_INSERT) + sql_command= SQLCOM_INSERT_SELECT; + else + sql_command= SQLCOM_REPLACE_SELECT; + } + insert_select_hack(first_select); + if (check_main_unit_semantics()) + return true; + + // fix "main" select + SELECT_LEX *blt= pop_select(); + DBUG_ASSERT(blt == &builtin_select); + push_select(first_select); + return false; +} + + +bool LEX::parsed_TVC_start() +{ + SELECT_LEX *sel; + many_values.empty(); + insert_list= 0; + if (!(sel= alloc_select(TRUE)) || + push_select(sel)) + return true; + sel->init_select(); + sel->braces= FALSE; // just initialisation + return false; +} + + +SELECT_LEX *LEX::parsed_TVC_end() +{ + + SELECT_LEX *res= pop_select(); // above TVC select + if (!(res->tvc= + new (thd->mem_root) table_value_constr(many_values, + res, + res->options))) + return NULL; + many_values.empty(); + return res; +} + + +TABLE_LIST *LEX::parsed_derived_select(SELECT_LEX *sel, int for_system_time, + LEX_CSTRING *alias) +{ + TABLE_LIST *res; + derived_tables|= DERIVED_SUBQUERY; + sel->set_linkage(DERIVED_TABLE_TYPE); + sel->braces= FALSE; + // Add the subtree of subquery to the current SELECT_LEX + SELECT_LEX *curr_sel= select_stack_head(); + DBUG_ASSERT(current_select == curr_sel); + SELECT_LEX_UNIT *unit= sel->master_unit(); + if (!unit) + { + unit= create_unit(sel); + if (!unit) + return NULL; + } + curr_sel->register_unit(unit, &curr_sel->context); + curr_sel->add_statistics(unit); + + Table_ident *ti= new (thd->mem_root) Table_ident(unit); + if (ti == NULL) + return NULL; + if (!(res= curr_sel->add_table_to_list(thd, ti, alias, 0, + TL_READ, MDL_SHARED_READ))) + return NULL; + if (for_system_time) + { + res->vers_conditions= vers_conditions; + } + return res; +} + +TABLE_LIST *LEX::parsed_derived_unit(SELECT_LEX_UNIT *unit, + int for_system_time, + LEX_CSTRING *alias) +{ + TABLE_LIST *res; + derived_tables|= DERIVED_SUBQUERY; + unit->first_select()->set_linkage(DERIVED_TABLE_TYPE); + + // Add the subtree of subquery to the current SELECT_LEX + SELECT_LEX *curr_sel= select_stack_head(); + DBUG_ASSERT(current_select == curr_sel); + curr_sel->register_unit(unit, &curr_sel->context); + curr_sel->add_statistics(unit); + + Table_ident *ti= new (thd->mem_root) Table_ident(unit); + if (ti == NULL) + return NULL; + if (!(res= curr_sel->add_table_to_list(thd, ti, alias, 0, + TL_READ, MDL_SHARED_READ))) + return NULL; + if (for_system_time) + { + res->vers_conditions= vers_conditions; + } + return res; +} + +bool LEX::parsed_create_view(SELECT_LEX_UNIT *unit, int check) +{ + SQL_I_List<TABLE_LIST> *save= &first_select_lex()->table_list; + set_main_unit(unit); + if (check_main_unit_semantics()) + return true; + first_select_lex()->table_list.push_front(save); + current_select= first_select_lex(); + size_t len= thd->m_parser_state->m_lip.get_cpp_ptr() - + create_view->select.str; + void *create_view_select= thd->memdup(create_view->select.str, len); + create_view->select.length= len; + create_view->select.str= (char *) create_view_select; + size_t not_used; + trim_whitespace(thd->charset(), + &create_view->select, ¬_used); + create_view->check= check; + parsing_options.allows_variable= TRUE; + return false; +} + +bool LEX::select_finalize(st_select_lex_unit *expr) +{ + sql_command= SQLCOM_SELECT; + selects_allow_into= TRUE; + selects_allow_procedure= TRUE; + set_main_unit(expr); + return check_main_unit_semantics(); +} + + +/* + "IN" and "EXISTS" subselect can appear in two statement types: + + 1. Statements that can have table columns, such as SELECT, DELETE, UPDATE + 2. Statements that cannot have table columns, e.g: + RETURN ((1) IN (SELECT * FROM t1)) + IF ((1) IN (SELECT * FROM t1)) + + Statements of the first type call master_select_push() in the beginning. + In such case everything is properly linked. + + Statements of the second type do not call mastr_select_push(). + Here we catch the second case and relink thd->lex->builtin_select and + select_lex to properly point to each other. + + QQ: Shouldn't subselects of other type also call relink_hack()? + QQ: Can we do it at constructor time instead? +*/ + +void LEX::relink_hack(st_select_lex *select_lex) +{ + if (!select_stack_top) // Statements of the second type + { + if (!select_lex->get_master()->get_master()) + ((st_select_lex *) select_lex->get_master())-> + set_master(&builtin_select); + if (!builtin_select.get_slave()) + builtin_select.set_slave(select_lex->get_master()); + } +} + + + +bool SELECT_LEX_UNIT::set_lock_to_the_last_select(Lex_select_lock l) +{ + if (l.defined_lock) + { + SELECT_LEX *sel= first_select(); + while (sel->next_select()) + sel= sel->next_select(); + if (sel->braces) + { + my_error(ER_WRONG_USAGE, MYF(0), "lock options", + "End SELECT expression"); + return TRUE; + } + l.set_to(sel); + } + return FALSE; +} + +/** + Generate unique name for generated derived table for this SELECT +*/ + +bool SELECT_LEX::make_unique_derived_name(THD *thd, LEX_CSTRING *alias) +{ + // uint32 digits + two underscores + trailing '\0' + char buff[MAX_INT_WIDTH + 2 + 1]; + alias->length= my_snprintf(buff, sizeof(buff), "__%u", select_number); + alias->str= thd->strmake(buff, alias->length); + return !alias->str; +} diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 49e10421911..24788158d26 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -162,6 +162,23 @@ public: }; +/** + ORDER BY ... LIMIT parameters; +*/ +class Lex_order_limit_lock: public Sql_alloc +{ +public: + SQL_I_List<st_order> *order_list; /* ORDER clause */ + Lex_select_lock lock; + Lex_select_limit limit; + + Lex_order_limit_lock() :order_list(NULL) + {} + + bool set_to(st_select_lex *sel); +}; + + enum sub_select_type { UNSPECIFIED_TYPE, @@ -169,6 +186,14 @@ enum sub_select_type UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, GLOBAL_OPTIONS_TYPE, DERIVED_TABLE_TYPE, OLAP_TYPE }; + +inline int cmp_unit_op(enum sub_select_type op1, enum sub_select_type op2) +{ + DBUG_ASSERT(op1 >= UNION_TYPE && op1 <= EXCEPT_TYPE); + DBUG_ASSERT(op2 >= UNION_TYPE && op2 <= EXCEPT_TYPE); + return (op1 == INTERSECT_TYPE ? 1 : 0) - (op2 == INTERSECT_TYPE ? 1 : 0); +} + enum unit_common_op {OP_MIX, OP_UNION, OP_INTERSECT, OP_EXCEPT}; enum enum_view_suid @@ -287,7 +312,8 @@ struct LEX_TYPE This is not within #ifdef because we want "EXPLAIN PARTITIONS ..." to produce additional "partitions" column even if partitioning is not compiled in. */ -#define DESCRIBE_PARTITIONS 4 +#define DESCRIBE_PARTITIONS 4 +#define DESCRIBE_EXTENDED2 8 #ifdef MYSQL_SERVER @@ -526,7 +552,7 @@ public: unit is container of either - One SELECT - UNION of selects - select_lex and unit are both inherited form select_lex_node + select_lex and unit are both inherited form st_select_lex_node neighbors are two select_lex or units on the same level All select describing structures linked with following pointers: @@ -651,13 +677,6 @@ public: ulonglong options; /* - In sql_cache we store SQL_CACHE flag as specified by user to be - able to restore SELECT statement from internal structures. - */ - enum e_sql_cache { SQL_CACHE_UNSPECIFIED, SQL_NO_CACHE, SQL_CACHE }; - e_sql_cache sql_cache; - - /* result of this query can't be cached, bit field, can be : UNCACHEABLE_DEPENDENT_GENERATED UNCACHEABLE_DEPENDENT_INJECTED @@ -667,11 +686,15 @@ public: UNCACHEABLE_PREPARE */ uint8 uncacheable; +private: enum sub_select_type linkage; +public: bool is_linkage_set() const { return linkage == UNION_TYPE || linkage == INTERSECT_TYPE || linkage == EXCEPT_TYPE; } + enum sub_select_type get_linkage() { return linkage; } + bool distinct; bool no_table_names_allowed; /* used for global order by */ static void *operator new(size_t size, MEM_ROOT *mem_root) throw () @@ -689,13 +712,33 @@ public: } inline st_select_lex_node* get_master() { return master; } + inline st_select_lex_node* get_slave() { return slave; } void include_down(st_select_lex_node *upper); void add_slave(st_select_lex_node *slave_arg); void include_neighbour(st_select_lex_node *before); + void link_chain_down(st_select_lex_node *first); + void link_neighbour(st_select_lex_node *neighbour) + { + DBUG_ASSERT(next == NULL); + DBUG_ASSERT(neighbour != NULL); + next= neighbour; + neighbour->prev= &next; + } + void cut_next() { next= NULL; } void include_standalone(st_select_lex_node *sel, st_select_lex_node **ref); void include_global(st_select_lex_node **plink); void exclude(); void exclude_from_tree(); + void exclude_from_global() + { + if (!link_prev) + return; + if (((*link_prev)= link_next)) + link_next->link_prev= link_prev; + link_next= NULL; + link_prev= NULL; + } + void set_slave(st_select_lex_node *slave_arg) { slave= slave_arg; } void move_node(st_select_lex_node *where_to_move) @@ -711,6 +754,22 @@ public: st_select_lex_node *insert_chain_before(st_select_lex_node **ptr_pos_to_insert, st_select_lex_node *end_chain_node); void move_as_slave(st_select_lex_node *new_master); + void set_linkage(enum sub_select_type l) + { + DBUG_ENTER("st_select_lex_node::set_linkage"); + DBUG_PRINT("info", ("node: %p linkage: %d->%d", this, linkage, l)); + linkage= l; + DBUG_VOID_RETURN; + } + /* + This method created for reiniting LEX in mysql_admin_table() and can be + used only if you are going remove all SELECT_LEX & units except belonger + to LEX (LEX::unit & LEX::select, for other purposes there are + SELECT_LEX_UNIT::exclude_level & SELECT_LEX_UNIT::exclude_tree. + + It is also used in parsing to detach builtin select. + */ + void cut_subtree() { slave= 0; } friend class st_select_lex_unit; friend bool mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *sel); friend bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, @@ -720,6 +779,8 @@ public: friend bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *orig_table_list); friend bool TABLE_LIST::init_derived(THD *thd, bool init_view); + + friend class st_select_lex; private: void fast_exclude(); }; @@ -765,9 +826,9 @@ public: { } - TABLE *table; /* temporary table using for appending UNION results */ select_result *result; + st_select_lex *pre_last_parse; bool prepared, // prepare phase already performed for UNION (unit) optimized, // optimize phase already performed for UNION (unit) optimized_2, @@ -854,7 +915,7 @@ public: { return reinterpret_cast<st_select_lex*>(slave); } - inline void set_with_clause(With_clause *with_cl); + void set_with_clause(With_clause *with_cl); st_select_lex_unit* next_unit() { return reinterpret_cast<st_select_lex_unit*>(next); @@ -897,6 +958,18 @@ public: int save_union_explain(Explain_query *output); int save_union_explain_part2(Explain_query *output); unit_common_op common_op(); + + void reset_distinct(); + void fix_distinct(st_select_lex_unit *new_unit); + + void register_select_chain(SELECT_LEX *first_sel); + + bool set_nest_level(int new_nest_level); + bool check_parameters(SELECT_LEX *main_select); + + bool set_lock_to_the_last_select(Lex_select_lock l); + + friend class st_select_lex; }; typedef class st_select_lex_unit SELECT_LEX_UNIT; @@ -904,25 +977,42 @@ typedef Bounds_checked_array<Item*> Ref_ptr_array; /* - Structure which consists of the field and the item which - produces this field. + Structure which consists of the field and the item that + corresponds to this field. */ - -class Grouping_tmp_field :public Sql_alloc +class Field_pair :public Sql_alloc { public: - Field *tmp_field; - Item *producing_item; - Grouping_tmp_field(Field *fld, Item *item) - :tmp_field(fld), producing_item(item) {} + Field *field; + Item *corresponding_item; + Field_pair(Field *fld, Item *item) + :field(fld), corresponding_item(item) {} }; + /* SELECT_LEX - store information of parsed SELECT statment */ class st_select_lex: public st_select_lex_node { public: + /* + Currently the field first_nested is used only by parser. + It containa either a reference to the first select + of the nest of selects to which 'this' belongs to, or + in the case of priority jump it contains a reference to + the select to which the priority nest has to be attached to. + If there is no priority jump then the first select of the + nest contains the reference to itself in first_nested. + Example: + select1 union select2 intersect select + Here we have a priority jump at select2. + So select2->first_nested points to select1, + while select3->first_nested points to select2 and + select1->first_nested points to select1. + */ + st_select_lex *first_nested; + Name_resolution_context context; LEX_CSTRING db; Item *where, *having; /* WHERE & HAVING clauses */ @@ -1018,6 +1108,7 @@ public: SQL_I_List<ORDER> order_list; /* ORDER clause */ SQL_I_List<ORDER> gorder_list; Item *select_limit, *offset_limit; /* LIMIT clause parameters */ + bool is_set_query_expr_tail; /// Array of pointers to top elements of all_fields list Ref_ptr_array ref_pointer_array; @@ -1140,7 +1231,8 @@ public: nesting_map name_visibility_map; table_map with_dep; - List<Grouping_tmp_field> grouping_tmp_fields; + /* the structure to store fields that are used in the GROUP BY of this select */ + List<Field_pair> grouping_tmp_fields; /* it is for correct printing SELECT options */ thr_lock_type lock_type; @@ -1158,6 +1250,14 @@ public: void init_query(); void init_select(); st_select_lex_unit* master_unit() { return (st_select_lex_unit*) master; } + inline void set_master_unit(st_select_lex_unit *master_unit) + { + master= (st_select_lex_node *)master_unit; + } + void set_master(st_select_lex *master_arg) + { + master= master_arg; + } st_select_lex_unit* first_inner_unit() { return (st_select_lex_unit*) slave; @@ -1209,12 +1309,6 @@ public: List<Item>* get_item_list(); ulong get_table_join_options(); void set_lock_for_tables(thr_lock_type lock_type); - inline void init_order() - { - order_list.elements= 0; - order_list.first= 0; - order_list.next= &order_list.first; - } /* This method created for reiniting LEX in mysql_admin_table() and can be used only if you are going remove all SELECT_LEX & units except belonger @@ -1345,9 +1439,8 @@ public: With_element *find_table_def_in_with_clauses(TABLE_LIST *table); bool check_unrestricted_recursive(bool only_standard_compliant); bool check_subqueries_with_recursive_references(); - void collect_grouping_fields(THD *thd, ORDER *grouping_list); - void check_cond_extraction_for_grouping_fields(Item *cond, - TABLE_LIST *derived); + void collect_grouping_fields(THD *thd, ORDER *grouping_list); + void check_cond_extraction_for_grouping_fields(Item *cond); Item *build_cond_for_grouping_fields(THD *thd, Item *cond, bool no_to_clones); @@ -1373,6 +1466,11 @@ public: bool cond_pushdown_is_allowed() const { return !olap && !explicit_limit && !tvc; } + void pushdown_cond_into_where_clause(THD *thd, Item *extracted_cond, + Item **remaining_cond, + Item_transformer transformer, + uchar *arg); + private: bool m_non_agg_field_used; bool m_agg_func_used; @@ -1390,6 +1488,35 @@ public: DBUG_ASSERT(this != sel); select_n_where_fields+= sel->select_n_where_fields; } + inline void set_linkage_and_distinct(enum sub_select_type l, bool d) + { + DBUG_ENTER("SELECT_LEX::set_linkage_and_distinct"); + DBUG_PRINT("info", ("select: %p distinct %d", this, d)); + set_linkage(l); + DBUG_ASSERT(l == UNION_TYPE || + l == INTERSECT_TYPE || + l == EXCEPT_TYPE); + if (d && master_unit() && master_unit()->union_distinct != this) + master_unit()->union_distinct= this; + distinct= d; + with_all_modifier= !distinct; + DBUG_VOID_RETURN; + } + bool set_nest_level(int new_nest_level); + bool check_parameters(SELECT_LEX *main_select); + void mark_select() + { + DBUG_ENTER("st_select_lex::mark_select()"); + DBUG_PRINT("info", ("Select #%d", select_number)); + DBUG_VOID_RETURN; + } + void register_unit(SELECT_LEX_UNIT *unit, + Name_resolution_context *outer_context); + SELECT_LEX_UNIT *attach_selects_chain(SELECT_LEX *sel, + Name_resolution_context *context); + void add_statistics(SELECT_LEX_UNIT *unit); + bool make_unique_derived_name(THD *thd, LEX_CSTRING *alias); + void lex_start(LEX *plex); }; typedef class st_select_lex SELECT_LEX; @@ -2789,8 +2916,13 @@ class Query_arena_memroot; struct LEX: public Query_tables_list { SELECT_LEX_UNIT unit; /* most upper unit */ - SELECT_LEX select_lex; /* first SELECT_LEX */ + inline SELECT_LEX *first_select_lex() {return unit.first_select();} + +private: + SELECT_LEX builtin_select; /* current SELECT_LEX in parsing */ + +public: SELECT_LEX *current_select; /* list of all SELECT_LEX */ SELECT_LEX *all_selects_list; @@ -2887,6 +3019,12 @@ private: bool sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop); bool sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop); + /* + Check if Item_field and Item_ref are allowed in the current statement. + @retval false OK (fields are allowed) + @retval true ERROR (fields are not allowed). Error is raised. + */ + bool check_expr_allows_fields_or_error(THD *thd, const char *name) const; public: void parse_error(uint err_number= ER_SYNTAX_ERROR); inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;} @@ -2914,6 +3052,8 @@ public: required a local context, the parser pops the top-most context. */ List<Name_resolution_context> context_stack; + SELECT_LEX *select_stack[MAX_SELECT_NESTING + 1]; + uint select_stack_top; SQL_I_List<ORDER> proc_list; SQL_I_List<TABLE_LIST> auxiliary_table_list, save_list; @@ -2953,6 +3093,8 @@ public: syntax error back. */ bool expr_allows_subselect; + bool selects_allow_into; + bool selects_allow_procedure; /* A special command "PARSE_VCOL_EXPR" is defined for the parser to translate a defining expression of a virtual column into an @@ -3007,7 +3149,17 @@ public: enum enum_yes_no_unknown tx_chain, tx_release; bool safe_to_cache_query; bool subqueries, ignore; + bool next_is_main; // use "main" SELECT_LEX for nrxt allocation; + bool next_is_down; // use "main" SELECT_LEX for nrxt allocation; st_parsing_options parsing_options; + uint8 lex_options; // see OPTION_LEX_* + /* + In sql_cache we store SQL_CACHE flag as specified by user to be + able to restore SELECT statement from internal structures. + */ + enum e_sql_cache { SQL_CACHE_UNSPECIFIED, SQL_NO_CACHE, SQL_CACHE }; + e_sql_cache sql_cache; + Alter_info alter_info; /* For CREATE TABLE statement last element of table list which is not @@ -3206,20 +3358,24 @@ public: SELECT_LEX *sl; SELECT_LEX_UNIT *un; for (sl= current_select, un= sl->master_unit(); - un != &unit; - sl= sl->outer_select(), un= sl->master_unit()) + un && un != &unit; + sl= sl->outer_select(), un= (sl ? sl->master_unit() : NULL)) { - sl->uncacheable|= cause; - un->uncacheable|= cause; + sl->uncacheable|= cause; + un->uncacheable|= cause; } - select_lex.uncacheable|= cause; + if (sl) + sl->uncacheable|= cause; } + if (first_select_lex()) + first_select_lex()->uncacheable|= cause; } void set_trg_event_type_for_tables(); TABLE_LIST *unlink_first_table(bool *link_to_local); void link_first_table_back(TABLE_LIST *first, bool link_to_local); void first_lists_tables_same(); + void fix_first_select_number(); bool can_be_merged(); bool can_use_merged(); @@ -3257,14 +3413,83 @@ public: void cleanup_after_one_table_open(); - bool push_context(Name_resolution_context *context, MEM_ROOT *mem_root) + bool push_context(Name_resolution_context *context); + + void pop_context() { - return context_stack.push_front(context, mem_root); + DBUG_ENTER("LEX::pop_context"); + Name_resolution_context *context= context_stack.pop(); + DBUG_PRINT("info", ("Pop context %p Select: %p (%d)", + context, context->select_lex, + (context->select_lex ? + context->select_lex->select_number: + 0))); + DBUG_VOID_RETURN; } - void pop_context() + SELECT_LEX *select_stack_head() + { + if (likely(select_stack_top)) + return select_stack[select_stack_top - 1]; + return NULL; + } + + bool push_select(SELECT_LEX *select_lex) + { + DBUG_ENTER("LEX::push_select"); + DBUG_PRINT("info", ("Top Select was %p (%d) depth: %u pushed: %p (%d)", + select_stack_head(), + select_stack_top, + (select_stack_top ? + select_stack_head()->select_number : + 0), + select_lex, select_lex->select_number)); + if (unlikely(select_stack_top > MAX_SELECT_NESTING)) + { + my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0)); + DBUG_RETURN(TRUE); + } + if (push_context(&select_lex->context)) + DBUG_RETURN(TRUE); + select_stack[select_stack_top++]= select_lex; + current_select= select_lex; + DBUG_RETURN(FALSE); + } + + SELECT_LEX *pop_select() + { + DBUG_ENTER("LEX::pop_select"); + SELECT_LEX *select_lex; + if (likely(select_stack_top)) + select_lex= select_stack[--select_stack_top]; + else + select_lex= 0; + DBUG_PRINT("info", ("Top Select is %p (%d) depth: %u poped: %p (%d)", + select_stack_head(), + select_stack_top, + (select_stack_top ? + select_stack_head()->select_number : + 0), + select_lex, + (select_lex ? select_lex->select_number : 0))); + DBUG_ASSERT(select_lex); + + pop_context(); + + if (unlikely(!select_stack_top)) + { + current_select= NULL; + DBUG_PRINT("info", ("Top Select is empty")); + } + else + current_select= select_stack[select_stack_top - 1]; + + DBUG_RETURN(select_lex); + } + + SELECT_LEX *current_select_or_default() { - context_stack.pop(); + return current_select ? current_select : &builtin_select; } bool copy_db_to(LEX_CSTRING *to); @@ -3273,6 +3498,7 @@ public: { return context_stack.head(); } + /* Restore the LEX and THD in case of a parse error. */ @@ -3301,9 +3527,8 @@ public: on its top. So select_lex (as the first added) will be at the tail of the list. */ - if (&select_lex == all_selects_list && !sroutines.records) + if (first_select_lex() == all_selects_list && !sroutines.records) { - DBUG_ASSERT(!all_selects_list->next_select_in_list()); return TRUE; } return FALSE; @@ -3342,9 +3567,6 @@ public: int case_stmt_action_expr(Item* expr); int case_stmt_action_when(Item *when, bool simple); int case_stmt_action_then(); - bool add_select_to_union_list(bool is_union_distinct, - enum sub_select_type type, - bool is_top_level); bool setup_select_in_parentheses(); bool set_trigger_new_row(const LEX_CSTRING *name, Item *val); bool set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2, @@ -3469,7 +3691,12 @@ public: return create_item_qualified_asterisk(thd, &a, &b); } - Item *create_item_ident_nosp(THD *thd, Lex_ident_sys_st *name); + Item *create_item_ident_field(THD *thd, const char *db, const char *table, + const Lex_ident_sys_st *name); + Item *create_item_ident_nosp(THD *thd, Lex_ident_sys_st *name) + { + return create_item_ident_field(thd, NullS, NullS, name); + } Item *create_item_ident_sp(THD *thd, Lex_ident_sys_st *name, const char *start, const char *end); Item *create_item_ident(THD *thd, Lex_ident_cli_st *cname) @@ -3607,6 +3834,10 @@ public: const Lex_ident_cli_st *var_name, const Lex_ident_cli_st *field_name); + Item *create_item_query_expression(THD *thd, + const char *tok_start, + st_select_lex_unit *unit); + Item *make_item_func_replace(THD *thd, Item *org, Item *find, Item *replace); Item *make_item_func_substr(THD *thd, Item *a, Item *b, Item *c); Item *make_item_func_substr(THD *thd, Item *a, Item *b); @@ -3801,6 +4032,17 @@ public: sp_for_loop_intrange_finalize(thd, loop); } bool sp_for_loop_outer_block_finalize(THD *thd, const Lex_for_loop_st &loop); + + /* + Make an Item when an identifier is found in the FOR loop bounds: + FOR rec IN cursor + FOR rec IN var1 .. var2 + FOR rec IN row1.field1 .. xxx + */ + Item *create_item_for_loop_bound(THD *thd, + const LEX_CSTRING *a, + const LEX_CSTRING *b, + const LEX_CSTRING *c); /* End of FOR LOOP methods */ bool add_signal_statement(THD *thd, const class sp_condition_value *value); @@ -3923,7 +4165,7 @@ public: bool if_exists() const { return create_info.if_exists(); } SELECT_LEX *exclude_last_select(); - bool add_unit_in_brackets(SELECT_LEX *nselect); + SELECT_LEX *exclude_not_first_select(SELECT_LEX *exclude); void check_automatic_up(enum sub_select_type type); bool create_or_alter_view_finalize(THD *thd, Table_ident *table_ident); bool add_alter_view(THD *thd, uint16 algorithm, enum_view_suid suid, @@ -3931,7 +4173,6 @@ public: bool add_create_view(THD *thd, DDL_options_st ddl, uint16 algorithm, enum_view_suid suid, Table_ident *table_ident); - bool add_grant_command(THD *thd, enum_sql_command sql_command_arg, stored_procedure_type type_arg); @@ -3950,7 +4191,7 @@ public: */ bool check_simple_select(const LEX_CSTRING *option) { - if (current_select != &select_lex) + if (current_select != &builtin_select) { char command[80]; strmake(command, option->str, MY_MIN(option->length, sizeof(command)-1)); @@ -3968,6 +4209,63 @@ public: } bool tvc_finalize(); bool tvc_finalize_derived(); + + bool make_select_in_brackets(SELECT_LEX* dummy_select, + SELECT_LEX *nselect, bool automatic); + + SELECT_LEX_UNIT *alloc_unit(); + SELECT_LEX *alloc_select(bool is_select); + SELECT_LEX_UNIT *create_unit(SELECT_LEX*); + SELECT_LEX *wrap_unit_into_derived(SELECT_LEX_UNIT *unit); + SELECT_LEX *wrap_select_chain_into_derived(SELECT_LEX *sel); + bool main_select_push(); + bool insert_select_hack(SELECT_LEX *sel); + SELECT_LEX *create_priority_nest(SELECT_LEX *first_in_nest); + + void set_main_unit(st_select_lex_unit *u) + { + unit.options= u->options; + unit.uncacheable= u->uncacheable; + unit.register_select_chain(u->first_select()); + unit.first_select()->options|= builtin_select.options; + unit.fake_select_lex= u->fake_select_lex; + unit.union_distinct= u->union_distinct; + unit.set_with_clause(u->with_clause); + builtin_select.exclude_from_global(); + } + bool check_main_unit_semantics(); + + // reaction on different parsed parts (bodies are in sql_yacc.yy) + bool parsed_unit_in_brackets(SELECT_LEX_UNIT *unit); + SELECT_LEX *parsed_select(SELECT_LEX *sel, Lex_order_limit_lock * l); + SELECT_LEX *parsed_unit_in_brackets_tail(SELECT_LEX_UNIT *unit, + Lex_order_limit_lock * l); + SELECT_LEX *parsed_select_in_brackets(SELECT_LEX *sel, + Lex_order_limit_lock * l); + SELECT_LEX_UNIT *parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2, + enum sub_select_type unit_type, + bool distinct); + SELECT_LEX_UNIT *parsed_select_expr_cont(SELECT_LEX_UNIT *unit, + SELECT_LEX *s2, + enum sub_select_type unit_type, + bool distinct, bool oracle); + SELECT_LEX_UNIT *parsed_body_select(SELECT_LEX *sel, + Lex_order_limit_lock * l); + bool parsed_body_unit(SELECT_LEX_UNIT *unit); + SELECT_LEX_UNIT *parsed_body_unit_tail(SELECT_LEX_UNIT *unit, + Lex_order_limit_lock * l); + SELECT_LEX *parsed_subselect(SELECT_LEX_UNIT *unit, char *place); + bool parsed_insert_select(SELECT_LEX *firs_select); + bool parsed_TVC_start(); + SELECT_LEX *parsed_TVC_end(); + TABLE_LIST *parsed_derived_select(SELECT_LEX *sel, int for_system_time, + LEX_CSTRING *alias); + TABLE_LIST *parsed_derived_unit(SELECT_LEX_UNIT *unit, + int for_system_time, + LEX_CSTRING *alias); + bool parsed_create_view(SELECT_LEX_UNIT *unit, int check); + bool select_finalize(st_select_lex_unit *expr); + void relink_hack(st_select_lex *select_lex); }; diff --git a/sql/sql_list.h b/sql/sql_list.h index 39a1c3375e0..27827b42be5 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -611,7 +611,7 @@ struct ilink struct ilink **prev,*next; static void *operator new(size_t size) throw () { - return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE | ME_FATALERROR)); + return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE | ME_FATAL)); } static void operator delete(void* ptr_arg, size_t) { diff --git a/sql/sql_load.cc b/sql/sql_load.cc index ddb5029c78a..dd6e723c953 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -390,10 +390,13 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, if (mysql_handle_single_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT) || mysql_handle_single_derived(thd->lex, table_list, DT_PREPARE)) DBUG_RETURN(TRUE); - if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, + if (setup_tables_and_check_access(thd, + &thd->lex->first_select_lex()->context, + &thd->lex->first_select_lex()-> + top_join_list, table_list, - thd->lex->select_lex.leaf_tables, FALSE, + thd->lex->first_select_lex()->leaf_tables, + FALSE, INSERT_ACL | UPDATE_ACL, INSERT_ACL | UPDATE_ACL, FALSE)) DBUG_RETURN(-1); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c68e91bbef3..201cb4f1dbe 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2008,10 +2008,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, Init TABLE_LIST members necessary when the undelrying table is view. */ - table_list.select_lex= &(thd->lex->select_lex); + table_list.select_lex= thd->lex->first_select_lex(); thd->lex-> - select_lex.table_list.link_in_list(&table_list, - &table_list.next_local); + first_select_lex()->table_list.link_in_list(&table_list, + &table_list.next_local); thd->lex->add_to_query_tables(&table_list); if (is_infoschema_db(&table_list.db)) @@ -2575,23 +2575,24 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, DBUG_RETURN(1); #else { - if (lex->select_lex.db.str == NULL && - lex->copy_db_to(&lex->select_lex.db)) + if (lex->first_select_lex()->db.str == NULL && + lex->copy_db_to(&lex->first_select_lex()->db)) { DBUG_RETURN(1); } schema_select_lex= new (thd->mem_root) SELECT_LEX(); schema_select_lex->table_list.first= NULL; if (lower_case_table_names == 1) - lex->select_lex.db.str= thd->strdup(lex->select_lex.db.str); - schema_select_lex->db= lex->select_lex.db; + lex->first_select_lex()->db.str= + thd->strdup(lex->first_select_lex()->db.str); + schema_select_lex->db= lex->first_select_lex()->db; /* check_db_name() may change db.str if lower_case_table_names == 1, but that's ok as the db is allocted above in this case. */ - if (check_db_name((LEX_STRING*) &lex->select_lex.db)) + if (check_db_name((LEX_STRING*) &lex->first_select_lex()->db)) { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->select_lex.db.str); + my_error(ER_WRONG_DB_NAME, MYF(0), lex->first_select_lex()->db.str); DBUG_RETURN(1); } break; @@ -2630,7 +2631,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, default: break; } - + if (schema_select_lex) + schema_select_lex->set_master_unit(&lex->unit); SELECT_LEX *select_lex= lex->current_select; if (make_schema_select(thd, select_lex, get_schema_table(schema_table_idx))) DBUG_RETURN(1); @@ -3227,7 +3229,7 @@ mysql_execute_command(THD *thd) int up_result= 0; LEX *lex= thd->lex; /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); /* first table of first SELECT_LEX */ TABLE_LIST *first_table= select_lex->table_list.first; /* list of all tables in query */ @@ -3266,6 +3268,7 @@ mysql_execute_command(THD *thd) DBUG_ASSERT(first_table == all_tables && first_table != 0); */ lex->first_lists_tables_same(); + lex->fix_first_select_number(); /* should be assigned after making first tables same */ all_tables= lex->query_tables; /* set context for commands which do not use setup_tables */ @@ -7521,7 +7524,7 @@ bool check_stack_overrun(THD *thd, long margin, if (ebuff) { my_snprintf(ebuff, MYSQL_ERRMSG_SIZE, ER_THD(thd, ER_STACK_OVERRUN_NEED_MORE), stack_used, my_thread_stack_size, margin); - my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR)); + my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATAL)); delete [] ebuff; } return 1; @@ -7591,16 +7594,21 @@ void THD::reset_for_next_command(bool do_clear_error) DBUG_ASSERT(!in_sub_stmt); if (likely(do_clear_error)) + { clear_error(1); - + /* + The following variable can't be reset in clear_error() as + clear_error() is called during auto_repair of table + */ + error_printed_to_log= 0; + } free_list= 0; /* We also assign stmt_lex in lex_start(), but during bootstrap this code is executed first. */ DBUG_ASSERT(lex == &main_lex); - main_lex.stmt_lex= &main_lex; main_lex.current_select_number= 1; - DBUG_PRINT("info", ("Lex and stmt_lex: %p", &main_lex)); + main_lex.stmt_lex= &main_lex; main_lex.current_select_number= 0; /* Those two lines below are theoretically unneeded as THD::cleanup_after_query() should take care of this already. @@ -7686,11 +7694,7 @@ mysql_init_select(LEX *lex) SELECT_LEX *select_lex= lex->current_select; select_lex->init_select(); lex->wild= 0; - if (select_lex == &lex->select_lex) - { - DBUG_ASSERT(lex->result == 0); - lex->exchange= 0; - } + lex->exchange= 0; } @@ -7711,6 +7715,7 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) { THD *thd= lex->thd; bool new_select= select_lex == NULL; + int old_nest_level= lex->current_select->nest_level; DBUG_ENTER("mysql_new_select"); if (new_select) @@ -7722,27 +7727,19 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) select_lex->init_query(); select_lex->init_select(); } - lex->nest_level++; - if (lex->nest_level > (int) MAX_SELECT_NESTING) - { - my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0)); - DBUG_RETURN(1); - } - select_lex->nest_level= lex->nest_level; select_lex->nest_level_base= &thd->lex->unit; if (move_down) { + lex->nest_level++; + if (select_lex->set_nest_level(old_nest_level + 1)) + DBUG_RETURN(1); SELECT_LEX_UNIT *unit; lex->subqueries= TRUE; /* first select_lex of subselect or derived table */ - if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT())) + if (!(unit= lex->alloc_unit())) DBUG_RETURN(1); - unit->init_query(); - unit->thd= thd; unit->include_down(lex->current_select); - unit->link_next= 0; - unit->link_prev= 0; unit->return_to= lex->current_select; select_lex->include_down(unit); /* @@ -7776,15 +7773,13 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) "SELECT ... PROCEDURE ANALYSE()"); DBUG_RETURN(TRUE); } - // SELECT 1 FROM t1 ORDER BY 1 UNION SELECT 1 FROM t1 -- not possible - DBUG_ASSERT(!lex->current_select->order_list.first || - lex->current_select->braces); - // SELECT 1 FROM t1 LIMIT 1 UNION SELECT 1 FROM t1; -- not possible - DBUG_ASSERT(!lex->current_select->explicit_limit || - lex->current_select->braces); + SELECT_LEX_NODE *save_slave= select_lex->slave; select_lex->include_neighbour(lex->current_select); - SELECT_LEX_UNIT *unit= select_lex->master_unit(); + select_lex->slave= save_slave; + SELECT_LEX_UNIT *unit= select_lex->master_unit(); + if (select_lex->set_nest_level(old_nest_level)) + DBUG_RETURN(1); if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd)) DBUG_RETURN(1); select_lex->context.outer_context= @@ -7840,9 +7835,10 @@ void mysql_init_multi_delete(LEX *lex) { lex->sql_command= SQLCOM_DELETE_MULTI; mysql_init_select(lex); - lex->select_lex.select_limit= 0; + lex->first_select_lex()->select_limit= 0; lex->unit.select_limit_cnt= HA_POS_ERROR; - lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list); + lex->first_select_lex()->table_list. + save_and_clear(&lex->auxiliary_table_list); lex->query_tables= 0; lex->query_tables_last= &lex->query_tables; } @@ -8156,7 +8152,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length) thd->reset_for_next_command(); if (!parse_sql(thd, & parser_state, NULL, true) && - all_tables_not_ok(thd, lex->select_lex.table_list.first)) + all_tables_not_ok(thd, lex->first_select_lex()->table_list.first)) error= 1; /* Ignore question */ thd->end_statement(); } @@ -8238,6 +8234,10 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, LEX_CSTRING alias_str; LEX *lex= thd->lex; DBUG_ENTER("add_table_to_list"); + DBUG_PRINT("enter", ("Table '%s' (%p) Select %p (%u)", + (alias ? alias->str : table->table.str), + table, + this, select_number)); if (unlikely(!table)) DBUG_RETURN(0); // End of memory @@ -8331,7 +8331,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->schema_table_name= ptr->table_name; ptr->schema_table= schema_table; } - ptr->select_lex= lex->current_select; + ptr->select_lex= this; /* We can't cache internal temporary tables between prepares as the table may be deleted before next exection. @@ -8438,8 +8438,6 @@ bool st_select_lex::init_nested_join(THD *thd) nested_join= ptr->nested_join= ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST)))); - if (unlikely(join_list->push_front(ptr, thd->mem_root))) - DBUG_RETURN(1); ptr->embedding= embedding; ptr->join_list= join_list; ptr->alias.str="(nested_join)"; @@ -8547,7 +8545,6 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) ptr->join_using_fields= prev_join_using; } } - join_list->push_front(ptr, thd->mem_root); nested_join->used_tables= nested_join->not_null_tables= (table_map) 0; DBUG_RETURN(ptr); } @@ -8739,7 +8736,7 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type) bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg) { SELECT_LEX *first_sl= first_select(); - DBUG_ENTER("add_fake_select_lex"); + DBUG_ENTER("st_select_lex_unit::add_fake_select_lex"); DBUG_ASSERT(!fake_select_lex); if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX())) @@ -8749,16 +8746,19 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg) fake_select_lex->select_number= INT_MAX; fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */ fake_select_lex->make_empty_select(); - fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE; + fake_select_lex->set_linkage(GLOBAL_OPTIONS_TYPE); fake_select_lex->select_limit= 0; + fake_select_lex->no_table_names_allowed= 1; + fake_select_lex->context.outer_context=first_sl->context.outer_context; /* allow item list resolving in fake select for ORDER BY */ fake_select_lex->context.resolve_in_select_list= TRUE; fake_select_lex->context.select_lex= fake_select_lex; fake_select_lex->nest_level_base= first_select()->nest_level_base; - fake_select_lex->nest_level=first_select()->nest_level; + if (fake_select_lex->set_nest_level(first_select()->nest_level)) + DBUG_RETURN(1); if (!is_unit_op()) { @@ -8771,7 +8771,7 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg) fake_select_lex->no_table_names_allowed= 1; thd_arg->lex->current_select= fake_select_lex; } - thd_arg->lex->pop_context(); + //thd_arg->lex->pop_context("add fake"); DBUG_RETURN(0); } @@ -8807,7 +8807,7 @@ push_new_name_resolution_context(THD *thd, left_op->first_leaf_for_name_resolution(); on_context->last_name_resolution_table= right_op->last_leaf_for_name_resolution(); - return thd->lex->push_context(on_context, thd->mem_root); + return thd->lex->push_context(on_context); } @@ -9236,7 +9236,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) { TABLE_LIST *table; LEX *lex= thd->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); DBUG_ENTER("multi_update_precheck"); if (select_lex->item_list.elements != lex->value_list.elements) @@ -9272,7 +9272,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) /* Is there tables of subqueries? */ - if (&lex->select_lex != lex->all_selects_list) + if (lex->first_select_lex() != lex->all_selects_list) { DBUG_PRINT("info",("Checking sub query list")); for (table= tables; table; table= table->next_global) @@ -9306,7 +9306,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) { - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last; DBUG_ENTER("multi_delete_precheck"); @@ -9423,7 +9423,7 @@ static TABLE_LIST *multi_delete_table_match(LEX *lex, TABLE_LIST *tbl, bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) { - TABLE_LIST *tables= lex->select_lex.table_list.first; + TABLE_LIST *tables= lex->first_select_lex()->table_list.first; TABLE_LIST *target_tbl; DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables"); @@ -9465,7 +9465,8 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) bool update_precheck(THD *thd, TABLE_LIST *tables) { DBUG_ENTER("update_precheck"); - if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements) + if (thd->lex->first_select_lex()->item_list.elements != + thd->lex->value_list.elements) { my_message(ER_WRONG_VALUE_COUNT, ER_THD(thd, ER_WRONG_VALUE_COUNT), MYF(0)); DBUG_RETURN(TRUE); @@ -9556,7 +9557,7 @@ void create_table_set_open_action_and_adjust_tables(LEX *lex) else create_table->open_type= OT_BASE_ONLY; - if (!lex->select_lex.item_list.elements) + if (!lex->first_select_lex()->item_list.elements) { /* Avoid opening and locking target table for ordinary CREATE TABLE @@ -9587,7 +9588,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table) { LEX *lex= thd->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); ulong want_priv; bool error= TRUE; // Error message is given DBUG_ENTER("create_table_precheck"); @@ -9729,8 +9730,9 @@ Item *negate_expression(THD *thd, Item *expr) { /* it is NOT(NOT( ... )) */ Item *arg= ((Item_func *) expr)->arguments()[0]; + const Type_handler *fh= arg->fixed_type_handler(); enum_parsing_place place= thd->lex->current_select->parsing_place; - if (arg->is_bool_type() || place == IN_WHERE || place == IN_HAVING) + if ((fh && fh->is_bool_type()) || place == IN_WHERE || place == IN_HAVING) return arg; /* if it is not boolean function then we have to emulate value of @@ -10098,6 +10100,9 @@ bool parse_sql(THD *thd, Parser_state *parser_state, ((thd->variables.sql_mode & MODE_ORACLE) ? ORAparse(thd) : MYSQLparse(thd)) != 0; + DBUG_ASSERT(opt_bootstrap || mysql_parse_status || + thd->lex->select_stack_top == 0); + thd->lex->current_select= thd->lex->first_select_lex(); /* Check that if MYSQLparse() failed either thd->is_error() is set, or an diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ffe632d5409..3133b94fa5b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -525,15 +525,10 @@ static bool create_full_part_field_array(THD *thd, TABLE *table, full_part_field_array may be NULL if storage engine supports native partitioning. */ - table->vcol_set= table->read_set= &part_info->full_part_field_set; + table->read_set= &part_info->full_part_field_set; if ((ptr= part_info->full_part_field_array)) for (; *ptr; ptr++) - { - if ((*ptr)->vcol_info) - table->mark_virtual_col(*ptr); - else - bitmap_fast_test_and_set(table->read_set, (*ptr)->field_index); - } + table->mark_column_with_deps(*ptr); table->default_column_bitmaps(); end: @@ -835,7 +830,8 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, goto end; table->get_fields_in_item_tree= true; - func_expr->walk(&Item::change_context_processor, 0, &lex.select_lex.context); + func_expr->walk(&Item::change_context_processor, 0, + &lex.first_select_lex()->context); thd->where= "partition function"; /* In execution we must avoid the use of thd->change_item_tree since @@ -2644,7 +2640,7 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info, default: DBUG_ASSERT(0); /* We really shouldn't get here, no use in continuing from here */ - my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL)); DBUG_RETURN(NULL); } if (part_info->part_type == VERSIONING_PARTITION) @@ -5991,7 +5987,7 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->pack_frm_data, lpt->pack_frm_len)))) { - file->print_error(error, MYF(error != ER_OUTOFMEMORY ? 0 : ME_FATALERROR)); + file->print_error(error, MYF(error != ER_OUTOFMEMORY ? 0 : ME_FATAL)); } if (mysql_trans_commit_alter_copy_data(thd)) diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index 99fe09d5afe..2cc3f247e95 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -51,7 +51,7 @@ bool Sql_cmd_alter_table_exchange_partition::execute(THD *thd) /* Moved from mysql_execute_command */ LEX *lex= thd->lex; /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); /* first table of first SELECT_LEX */ TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first; /* @@ -743,7 +743,7 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd) int error; ha_partition *partition; ulong timeout= thd->variables.lock_wait_timeout; - TABLE_LIST *first_table= thd->lex->select_lex.table_list.first; + TABLE_LIST *first_table= thd->lex->first_select_lex()->table_list.first; Alter_info *alter_info= &thd->lex->alter_info; uint table_counter, i; List<String> partition_names_list; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 2ffecbab617..b0b0c815fa1 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1342,7 +1342,7 @@ static int mysql_test_update(Prepared_statement *stmt, THD *thd= stmt->thd; uint table_count= 0; TABLE_LIST *update_source_table; - SELECT_LEX *select= &stmt->lex->select_lex; + SELECT_LEX *select= stmt->lex->first_select_lex(); #ifndef NO_EMBEDDED_ACCESS_CHECKS uint want_privilege; #endif @@ -1398,10 +1398,10 @@ static int mysql_test_update(Prepared_statement *stmt, table_list->table->grant.want_privilege= want_privilege; table_list->register_want_access(want_privilege); #endif - thd->lex->select_lex.no_wrap_view_item= TRUE; + thd->lex->first_select_lex()->no_wrap_view_item= TRUE; res= setup_fields(thd, Ref_ptr_array(), select->item_list, MARK_COLUMNS_READ, 0, NULL, 0); - thd->lex->select_lex.no_wrap_view_item= FALSE; + thd->lex->first_select_lex()->no_wrap_view_item= FALSE; if (res) goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1466,10 +1466,10 @@ static bool mysql_test_delete(Prepared_statement *stmt, goto error; } - DBUG_RETURN(mysql_prepare_delete(thd, table_list, - lex->select_lex.with_wild, - lex->select_lex.item_list, - &lex->select_lex.where, + DBUG_RETURN(mysql_prepare_delete(thd, table_list, + lex->first_select_lex()->with_wild, + lex->first_select_lex()->item_list, + &lex->first_select_lex()->where, &delete_while_scanning)); error: DBUG_RETURN(TRUE); @@ -1501,7 +1501,7 @@ static int mysql_test_select(Prepared_statement *stmt, SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("mysql_test_select"); - lex->select_lex.context.resolve_in_select_list= TRUE; + lex->first_select_lex()->context.resolve_in_select_list= TRUE; ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL; if (tables) @@ -1514,7 +1514,7 @@ static int mysql_test_select(Prepared_statement *stmt, if (!lex->result && !(lex->result= new (stmt->mem_root) select_send(thd))) { - my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), static_cast<int>(sizeof(select_send))); goto error; } @@ -1535,7 +1535,7 @@ static int mysql_test_select(Prepared_statement *stmt, if (!lex->describe && !thd->lex->analyze_stmt && !stmt->is_sql_prepare()) { /* Make copy of item list, as change_columns may change it */ - List<Item> fields(lex->select_lex.item_list); + List<Item> fields(lex->first_select_lex()->item_list); /* Change columns if a procedure like analyse() */ if (unit->last_procedure && unit->last_procedure->change_columns(thd, fields)) @@ -1693,7 +1693,7 @@ static bool select_like_stmt_test(Prepared_statement *stmt, THD *thd= stmt->thd; LEX *lex= stmt->lex; - lex->select_lex.context.resolve_in_select_list= TRUE; + lex->first_select_lex()->context.resolve_in_select_list= TRUE; if (specific_prepare && (*specific_prepare)(thd)) DBUG_RETURN(TRUE); @@ -1761,7 +1761,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt) DBUG_ENTER("mysql_test_create_table"); THD *thd= stmt->thd; LEX *lex= stmt->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); bool res= FALSE; bool link_to_local; TABLE_LIST *create_table= lex->query_tables; @@ -2081,11 +2081,11 @@ static bool mysql_test_multidelete(Prepared_statement *stmt, { THD *thd= stmt->thd; - thd->lex->current_select= &thd->lex->select_lex; + thd->lex->current_select= thd->lex->first_select_lex(); if (add_item_to_list(thd, new (thd->mem_root) Item_null(thd))) { - my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), 0); + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 0); goto error; } @@ -2120,13 +2120,14 @@ error: static int mysql_insert_select_prepare_tester(THD *thd) { - SELECT_LEX *first_select= &thd->lex->select_lex; + SELECT_LEX *first_select= thd->lex->first_select_lex(); TABLE_LIST *second_table= first_select->table_list.first->next_local; /* Skip first table, which is the table we are inserting in */ first_select->table_list.first= second_table; - thd->lex->select_lex.context.table_list= - thd->lex->select_lex.context.first_name_resolution_table= second_table; + thd->lex->first_select_lex()->context.table_list= + thd->lex->first_select_lex()->context.first_name_resolution_table= + second_table; return mysql_insert_select_prepare(thd); } @@ -2161,7 +2162,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt, return 1; /* store it, because mysql_insert_select_prepare_tester change it */ - first_local_table= lex->select_lex.table_list.first; + first_local_table= lex->first_select_lex()->table_list.first; DBUG_ASSERT(first_local_table != 0); res= @@ -2169,7 +2170,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt, &mysql_insert_select_prepare_tester, OPTION_SETUP_TABLES_DONE); /* revert changes made by mysql_insert_select_prepare_tester */ - lex->select_lex.table_list.first= first_local_table; + lex->first_select_lex()->table_list.first= first_local_table; return res; } @@ -2195,7 +2196,7 @@ static int mysql_test_handler_read(Prepared_statement *stmt, SQL_HANDLER *ha_table; DBUG_ENTER("mysql_test_handler_read"); - lex->select_lex.context.resolve_in_select_list= TRUE; + lex->first_select_lex()->context.resolve_in_select_list= TRUE; /* We don't have to test for permissions as this is already done during @@ -2205,7 +2206,7 @@ static int mysql_test_handler_read(Prepared_statement *stmt, lex->ident.str, lex->insert_list, lex->ha_rkey_mode, - lex->select_lex.where))) + lex->first_select_lex()->where))) DBUG_RETURN(1); if (!stmt->is_sql_prepare()) @@ -2244,7 +2245,7 @@ static bool check_prepared_statement(Prepared_statement *stmt) { THD *thd= stmt->thd; LEX *lex= stmt->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); TABLE_LIST *tables; enum enum_sql_command sql_command= lex->sql_command; int res= 0; @@ -2253,10 +2254,11 @@ static bool check_prepared_statement(Prepared_statement *stmt) sql_command, stmt->param_count)); lex->first_lists_tables_same(); + lex->fix_first_select_number(); tables= lex->query_tables; /* set context for commands which do not use setup_tables */ - lex->select_lex.context.resolve_in_table_list_only(select_lex-> + lex->first_select_lex()->context.resolve_in_table_list_only(select_lex-> get_table_list()); /* Reset warning count for each query that uses tables */ @@ -3021,7 +3023,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) { tables->reinit_before_use(thd); } - lex->current_select= &lex->select_lex; + lex->current_select= lex->first_select_lex(); if (lex->result) @@ -4559,8 +4561,8 @@ bool Prepared_statement::validate_metadata(Prepared_statement *copy) if (is_sql_prepare() || lex->describe) return FALSE; - if (lex->select_lex.item_list.elements != - copy->lex->select_lex.item_list.elements) + if (lex->first_select_lex()->item_list.elements != + copy->lex->first_select_lex()->item_list.elements) { /** Column counts mismatch, update the client */ thd->server_status|= SERVER_STATUS_METADATA_CHANGED; @@ -4717,7 +4719,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) alloc_query(thd, (char*) expanded_query->ptr(), expanded_query->length())) { - my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), expanded_query->length()); + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), expanded_query->length()); goto error; } /* @@ -5297,16 +5299,8 @@ bool Protocol_local::store_longlong(longlong value, bool unsigned_flag) bool Protocol_local::store_decimal(const my_decimal *value) { - char buf[DECIMAL_MAX_STR_LENGTH]; - String str(buf, sizeof (buf), &my_charset_bin); - int rc; - - rc= my_decimal2string(E_DEC_FATAL_ERROR, value, 0, 0, 0, &str); - - if (rc) - return TRUE; - - return store_column(str.ptr(), str.length()); + StringBuffer<DECIMAL_MAX_STR_LENGTH> str; + return value->to_string(&str) ? store_column(str.ptr(), str.length()) : true; } diff --git a/sql/sql_priv.h b/sql/sql_priv.h index e48b6195bb7..fa12b645041 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -183,7 +183,11 @@ #define OPTION_ALLOW_BATCH (1ULL << 36) // THD, intern (slave) #define OPTION_SKIP_REPLICATION (1ULL << 37) // THD, user #define OPTION_RPL_SKIP_PARALLEL (1ULL << 38) -#define OPTION_FOUND_COMMENT (1ULL << 39) // SELECT, intern, parser +#define OPTION_NO_QUERY_CACHE (1ULL << 39) // SELECT, user +#define OPTION_PROCEDURE_CLAUSE (1ULL << 40) // Internal usage + + +#define OPTION_LEX_FOUND_COMMENT (1ULL << 0) // intern, parser /* The rest of the file is included in the server only */ #ifndef MYSQL_CLIENT @@ -228,6 +232,7 @@ #define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 29) #define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED (1ULL << 30) #define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 31) +#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY (1ULL << 32) #define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \ OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \ @@ -254,7 +259,8 @@ OPTIMIZER_SWITCH_EXISTS_TO_IN | \ OPTIMIZER_SWITCH_ORDERBY_EQ_PROP | \ OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED | \ - OPTIMIZER_SWITCH_SPLIT_MATERIALIZED) + OPTIMIZER_SWITCH_SPLIT_MATERIALIZED | \ + OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY) /* Replication uses 8 bytes to store SQL_MODE in the binary log. The day you @@ -356,6 +362,9 @@ enum enum_parsing_place IN_ORDER_BY, IN_UPDATE_ON_DUP_KEY, IN_PART_FUNC, + BEFORE_OPT_LIST, + AFTER_LIST, + FOR_LOOP_BOUND, PARSING_PLACE_SIZE /* always should be the last */ }; diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 13f03fed5f3..6ca21aebb37 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -110,7 +110,7 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table) }; ST_FIELD_INFO *field_info; - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; int i; for (i= 0; schema_table->fields_info[i].field_name != NULL; i++) @@ -402,7 +402,7 @@ bool PROFILING::show_profiles() QUERY_PROFILE *prof; List<Item> field_list; MEM_ROOT *mem_root= thd->mem_root; - SELECT_LEX *sel= &thd->lex->select_lex; + SELECT_LEX *sel= thd->lex->first_select_lex(); SELECT_LEX_UNIT *unit= &thd->lex->unit; ha_rows idx= 0; Protocol *protocol= thd->protocol; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 4c0035b9c48..2ee175293de 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -3841,8 +3841,7 @@ int reset_master(THD* thd, rpl_gtid *init_state, uint32 init_state_len, if (!mysql_bin_log.is_open()) { my_message(ER_FLUSH_MASTER_BINLOG_CLOSED, - ER_THD(thd, ER_FLUSH_MASTER_BINLOG_CLOSED), - MYF(ME_BELL+ME_WAITTANG)); + ER_THD(thd, ER_FLUSH_MASTER_BINLOG_CLOSED), MYF(0)); return 1; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7ff29bb081c..3b927510c80 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -351,7 +351,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, ulong setup_tables_done_option) { bool res; - SELECT_LEX *select_lex = &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); DBUG_ENTER("handle_select"); MYSQL_SELECT_START(thd->query()); @@ -1048,7 +1048,7 @@ JOIN::prepare(TABLE_LIST *tables_init, while ((select_el= select_it++)) { - if (select_el->with_sum_func) + if (select_el->with_sum_func()) found_sum_func_elem= true; if (select_el->with_field) found_field_elem= true; @@ -1216,14 +1216,14 @@ JOIN::prepare(TABLE_LIST *tables_init, item->max_length))) real_order= TRUE; - if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) + if (item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) item->split_sum_func(thd, ref_ptrs, all_fields, 0); } if (!real_order) order= NULL; } - if (having && having->with_sum_func) + if (having && having->with_sum_func()) having->split_sum_func2(thd, ref_ptrs, all_fields, &having, SPLIT_SUM_SKIP_REGISTERED); if (select_lex->inner_sum_func_list) @@ -1393,6 +1393,7 @@ err: bool JOIN::build_explain() { + DBUG_ENTER("JOIN::build_explain"); create_explain_query_if_not_exists(thd->lex, thd->mem_root); have_query_plan= QEP_AVAILABLE; @@ -1410,8 +1411,7 @@ bool JOIN::build_explain() thd->mem_root= old_mem_root; DBUG_ASSERT(thd->free_list == old_free_list); // no Items were created if (res) - return 1; - + DBUG_RETURN(1); uint select_nr= select_lex->select_number; JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt(); for (uint i= 0; i < aggr_tables; i++, curr_tab++) @@ -1429,7 +1429,7 @@ bool JOIN::build_explain() get_using_temporary_read_tracker(); } } - return 0; + DBUG_RETURN(0); } @@ -1594,7 +1594,7 @@ JOIN::optimize_inner() { /* Item_cond_and can't be fixed after creation, so we do not check - conds->fixed + conds->is_fixed() */ conds->fix_fields(thd, &conds); conds->change_ref_to_fields(thd, tables_list); @@ -1638,7 +1638,7 @@ JOIN::optimize_inner() if (arena) thd->restore_active_arena(arena, &backup); } - + if (optimize_constant_subqueries()) DBUG_RETURN(1); @@ -1649,9 +1649,28 @@ JOIN::optimize_inner() (void) having->walk(&Item::cleanup_is_expensive_cache_processor, 0, (void *) 0); - if (setup_jtbm_semi_joins(this, join_list, &conds)) + List<Item> eq_list; + + if (setup_degenerate_jtbm_semi_joins(this, join_list, eq_list)) DBUG_RETURN(1); + if (eq_list.elements != 0) + { + Item *new_cond; + + if (eq_list.elements == 1) + new_cond= eq_list.pop(); + else + new_cond= new (thd->mem_root) Item_cond_and(thd, eq_list); + + if (new_cond && + ((new_cond->fix_fields(thd, &new_cond) || + !(conds= and_items(thd, conds, new_cond)) || + conds->fix_fields(thd, &conds)))) + DBUG_RETURN(TRUE); + } + eq_list.empty(); + if (select_lex->cond_pushed_into_where) { conds= and_conds(thd, conds, select_lex->cond_pushed_into_where); @@ -1682,6 +1701,31 @@ JOIN::optimize_inner() DBUG_RETURN(1); } + if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY)) + { + TABLE_LIST *tbl; + List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables); + while ((tbl= li++)) + if (tbl->jtbm_subselect) + { + if (tbl->jtbm_subselect->pushdown_cond_for_in_subquery(thd, conds)) + DBUG_RETURN(1); + } + } + + if (setup_jtbm_semi_joins(this, join_list, eq_list)) + DBUG_RETURN(1); + + if (eq_list.elements != 0) + { + conds= and_new_conditions_to_optimized_cond(thd, conds, &cond_equal, + eq_list, &cond_value); + + if (!conds && + cond_value != Item::COND_FALSE && cond_value != Item::COND_TRUE) + DBUG_RETURN(TRUE); + } + if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED)) { TABLE_LIST *tbl; @@ -1998,7 +2042,7 @@ int JOIN::optimize_stage2() if (!conds && outer_join) { /* Handle the case where we have an OUTER JOIN without a WHERE */ - conds= new (thd->mem_root) Item_int(thd, (longlong) 1,1); // Always true + conds= new (thd->mem_root) Item_bool(thd, true); // Always true } if (impossible_where) @@ -2137,7 +2181,7 @@ int JOIN::optimize_stage2() if (conds && const_table_map != found_const_table_map && (select_options & SELECT_DESCRIBE)) { - conds=new (thd->mem_root) Item_int(thd, (longlong) 0, 1); // Always false + conds=new (thd->mem_root) Item_bool(thd, false); // Always false } /* Cache constant expressions in WHERE, HAVING, ON clauses. */ @@ -2420,13 +2464,13 @@ int JOIN::optimize_stage2() elements may be lost during further having condition transformation in JOIN::exec. */ - if (having && const_table_map && !having->with_sum_func) + if (having && const_table_map && !having->with_sum_func()) { having->update_used_tables(); having= having->remove_eq_conds(thd, &select_lex->having_value, true); if (select_lex->having_value == Item::COND_FALSE) { - having= new (thd->mem_root) Item_int(thd, (longlong) 0,1); + having= new (thd->mem_root) Item_bool(thd, false); zero_result_cause= "Impossible HAVING noticed after reading const tables"; error= 0; select_lex->mark_const_derived(zero_result_cause); @@ -3760,6 +3804,15 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite, bool need_tmp_table, bool need_order, bool distinct) { + DBUG_ENTER("JOIN::save_explain_data"); + DBUG_PRINT("enter", ("Save explain Select_lex: %u (%p) parent lex: %p stmt_lex: %p present select: %u (%p)", + select_lex->select_number, select_lex, + select_lex->parent_lex, thd->lex->stmt_lex, + (output->get_select(select_lex->select_number) ? + select_lex->select_number : 0), + (output->get_select(select_lex->select_number) ? + output->get_select(select_lex->select_number) + ->select_lex : NULL))); /* If there is SELECT in this statement with the same number it must be the same SELECT @@ -3786,8 +3839,9 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite, /* It's a degenerate join */ message= zero_result_cause ? zero_result_cause : "No tables used"; } - return save_explain_data_intern(thd->lex->explain, need_tmp_table, need_order, - distinct, message); + bool rc= save_explain_data_intern(thd->lex->explain, need_tmp_table, + need_order, distinct, message); + DBUG_RETURN(rc); } /* @@ -3809,11 +3863,11 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite, { if (!(join_tab[i].filesort->tracker= new Filesort_tracker(thd->lex->analyze_stmt))) - return 1; + DBUG_RETURN(1); } } } - return 0; + DBUG_RETURN(0); } @@ -4170,10 +4224,10 @@ mysql_select(THD *thd, is it single SELECT in derived table, called in derived table creation */ - if (select_lex->linkage != DERIVED_TABLE_TYPE || + if (select_lex->get_linkage() != DERIVED_TABLE_TYPE || (select_options & SELECT_DESCRIBE)) { - if (select_lex->linkage != GLOBAL_OPTIONS_TYPE) + if (select_lex->get_linkage() != GLOBAL_OPTIONS_TYPE) { /* Original join tabs might be overwritten at first @@ -4787,7 +4841,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, if (join->cond_value == Item::COND_FALSE) { join->impossible_where= true; - conds= new (join->thd->mem_root) Item_int(join->thd, (longlong) 0, 1); + conds= new (join->thd->mem_root) Item_bool(join->thd, false); } join->cond_equal= NULL; @@ -10534,7 +10588,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) below to check if we should use 'quick' instead. */ DBUG_PRINT("info", ("Item_int")); - tmp= new (thd->mem_root) Item_int(thd, (longlong) 1, 1); // Always true + tmp= new (thd->mem_root) Item_bool(thd, true); // Always true } } @@ -10662,7 +10716,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) Yet attributes of the just built condition are not needed. Thus we call sel->cond->quick_fix_field for safety. */ - if (sel->cond && !sel->cond->fixed) + if (sel->cond && !sel->cond->is_fixed()) sel->cond->quick_fix_field(); if (sel->test_quick_select(thd, tab->keys, @@ -12663,7 +12717,8 @@ void JOIN::join_free() !(select_options & SELECT_NO_UNLOCK) && !select_lex->subquery_in_having && (select_lex == (thd->lex->unit.fake_select_lex ? - thd->lex->unit.fake_select_lex : &thd->lex->select_lex))) + thd->lex->unit.fake_select_lex : + thd->lex->first_select_lex()))) { /* TODO: unlock tables even if the join isn't top level select in the @@ -12955,7 +13010,7 @@ static void update_depend_map_for_order(JOIN *join, ORDER *order) order->used= 0; // Not item_sum(), RAND() and no reference to table outside of sub select if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT)) - && !order->item[0]->with_sum_func && + && !order->item[0]->with_sum_func() && join->join_tab) { for (JOIN_TAB **tab=join->map2table; @@ -13046,7 +13101,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, for (order=first_order; order ; order=order->next) { table_map order_tables=order->item[0]->used_tables(); - if (order->item[0]->with_sum_func || + if (order->item[0]->with_sum_func() || /* If the outer table of an outer join is const (either by itself or after applying WHERE condition), grouping on a field from such a @@ -13222,7 +13277,7 @@ ORDER *simple_remove_const(ORDER *order, COND *where) ORDER *first= NULL, *prev= NULL; for (; order; order= order->next) { - DBUG_ASSERT(!order->item[0]->with_sum_func); // should never happen + DBUG_ASSERT(!order->item[0]->with_sum_func()); // should never happen if (!const_expression_in_where(where, order->item[0])) { if (!first) @@ -13471,9 +13526,9 @@ finish: FALSE otherwise */ -static bool check_simple_equality(THD *thd, const Item::Context &ctx, - Item *left_item, Item *right_item, - COND_EQUAL *cond_equal) +bool check_simple_equality(THD *thd, const Item::Context &ctx, + Item *left_item, Item *right_item, + COND_EQUAL *cond_equal) { Item *orig_left_item= left_item; Item *orig_right_item= right_item; @@ -13926,7 +13981,7 @@ COND *Item_cond_and::build_equal_items(THD *thd, if (!cond_args->elements && !cond_equal.current_level.elements && !eq_list.elements) - return new (thd->mem_root) Item_int(thd, (longlong) 1, 1); + return new (thd->mem_root) Item_bool(thd, true); List_iterator_fast<Item_equal> it(cond_equal.current_level); while ((item_equal= it++)) @@ -14033,7 +14088,7 @@ COND *Item_func_eq::build_equal_items(THD *thd, Item_equal *item_equal; int n= cond_equal.current_level.elements + eq_list.elements; if (n == 0) - return new (thd->mem_root) Item_int(thd, (longlong) 1, 1); + return new (thd->mem_root) Item_bool(thd, true); else if (n == 1) { if ((item_equal= cond_equal.current_level.pop())) @@ -14424,7 +14479,7 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels, List<Item> eq_list; Item_func_eq *eq_item= 0; if (((Item *) item_equal)->const_item() && !item_equal->val_int()) - return new (thd->mem_root) Item_int(thd, (longlong) 0, 1); + return new (thd->mem_root) Item_bool(thd, false); Item *item_const= item_equal->get_const(); Item_equal_fields_iterator it(*item_equal); Item *head; @@ -14432,7 +14487,7 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels, Item *current_sjm_head= NULL; DBUG_ASSERT(!cond || - cond->type() == Item::INT_ITEM || + cond->is_bool_literal() || (cond->type() == Item::FUNC_ITEM && ((Item_func *) cond)->functype() == Item_func::EQ_FUNC) || (cond->type() == Item::COND_ITEM && @@ -14553,13 +14608,13 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels, cond AND eq_1 AND eq_2 AND eq_3 AND ... - 'cond' is a parameter for this function, which may be NULL, an Item_int(1), + 'cond' is a parameter for this function, which may be NULL, an Item_bool(1), or an Item_func_eq or an Item_cond_and. We want to return a well-formed condition: no nested Item_cond_and objects, or Item_cond_and with a single child: - if 'cond' is an Item_cond_and, we add eq_i as its tail - - if 'cond' is Item_int(1), we return eq_i + - if 'cond' is Item_bool(1), we return eq_i - otherwise, we create our own Item_cond_and and put 'cond' at the front of it. - if we have only one condition to return, we don't create an Item_cond_and @@ -14571,10 +14626,10 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels, switch (eq_list.elements) { case 0: - res= cond ? cond : new (thd->mem_root) Item_int(thd, (longlong) 1, 1); + res= cond ? cond : new (thd->mem_root) Item_bool(thd, true); break; case 1: - if (!cond || cond->type() == Item::INT_ITEM) + if (!cond || cond->is_bool_literal()) res= eq_item; break; default: @@ -14716,7 +14771,7 @@ static COND* substitute_for_best_equal_field(THD *thd, JOIN_TAB *context_tab, eq_cond= 0; break; } - else if (eq_cond->type() == Item::INT_ITEM && !eq_cond->val_bool()) + else if (eq_cond->is_bool_literal() && !eq_cond->val_bool()) { /* This occurs when eliminate_item_equal() founds that cond is @@ -14741,7 +14796,7 @@ static COND* substitute_for_best_equal_field(THD *thd, JOIN_TAB *context_tab, else { /* Do not add an equality condition if it's always true */ - if (eq_cond->type() != Item::INT_ITEM && + if (!eq_cond->is_bool_literal() && cond_list->push_front(eq_cond, thd->mem_root)) eq_cond= 0; } @@ -15255,7 +15310,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top, conds= and_conds(join->thd, conds, table->on_expr); conds->top_level_item(); /* conds is always a new item as both cond and on_expr existed */ - DBUG_ASSERT(!conds->fixed); + DBUG_ASSERT(!conds->is_fixed()); conds->fix_fields(join->thd, &conds); } else @@ -16323,9 +16378,8 @@ Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value, { Field *field= ((Item_field*) real_item)->field; - if (((field->type() == MYSQL_TYPE_DATE) || - (field->type() == MYSQL_TYPE_DATETIME)) && - (field->flags & NOT_NULL_FLAG)) + if ((field->flags & NOT_NULL_FLAG) && + field->type_handler()->cond_notnull_field_isnull_to_field_eq_zero()) { /* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */ /* @@ -16341,7 +16395,7 @@ Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value, */ - Item *item0= new(thd->mem_root) Item_int(thd, (longlong) 0, 1); + Item *item0= new(thd->mem_root) Item_bool(thd, false); Item *eq_cond= new(thd->mem_root) Item_func_eq(thd, args[0], item0); if (!eq_cond) return this; @@ -16411,7 +16465,7 @@ Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value, cond= new_cond; /* Item_func_eq can't be fixed after creation so we do not check - cond->fixed, also it do not need tables so we use 0 as second + cond->is_fixed(), also it do not need tables so we use 0 as second argument. */ cond->fix_fields(thd, &cond); @@ -16571,60 +16625,6 @@ const_expression_in_where(COND *cond, Item *comp_item, Field *comp_field, Create internal temporary table ****************************************************************************/ -/** - Create field for temporary table from given field. - - @param thd Thread handler - @param org_field field from which new field will be created - @param name New field name - @param table Temporary table - @param item !=NULL if item->result_field should point to new field. - This is relevant for how fill_record() is going to work: - If item != NULL then fill_record() will update - the record in the original table. - If item == NULL then fill_record() will update - the temporary table - - @retval - NULL on error - @retval - new_created field -*/ - -Field *create_tmp_field_from_field(THD *thd, Field *org_field, - LEX_CSTRING *name, TABLE *table, - Item_field *item) -{ - Field *new_field; - - new_field= org_field->make_new_field(thd->mem_root, table, - table == org_field->table); - if (new_field) - { - new_field->init(table); - new_field->orig_table= org_field->orig_table; - if (item) - item->result_field= new_field; - else - new_field->field_name= *name; - new_field->flags|= org_field->flags & NO_DEFAULT_VALUE_FLAG; - if (org_field->maybe_null() || (item && item->maybe_null)) - new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join - if (org_field->type() == MYSQL_TYPE_VAR_STRING || - org_field->type() == MYSQL_TYPE_VARCHAR) - table->s->db_create_options|= HA_OPTION_PACK_RECORD; - else if (org_field->type() == FIELD_TYPE_DOUBLE) - ((Field_double *) new_field)->not_fixed= TRUE; - new_field->vcol_info= 0; - new_field->cond_selectivity= 1.0; - new_field->next_equal_field= NULL; - new_field->option_list= NULL; - new_field->option_struct= NULL; - } - return new_field; -} - - Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length) { const Type_handler *h= &type_handler_long; @@ -16634,6 +16634,22 @@ Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length) *this, table); } +Field *Item::tmp_table_field_from_field_type_maybe_null(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param, + bool is_explicit_null) +{ + DBUG_ASSERT(!param->make_copy_field()); + DBUG_ASSERT(!is_result_field()); + Field *result; + if ((result= tmp_table_field_from_field_type(table))) + { + if (result && is_explicit_null) + result->is_created_from_null_item= true; + } + return result; +} + Field *Item_sum::create_tmp_field(bool group, TABLE *table) { @@ -16665,57 +16681,6 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table) } -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. - - @param thd Thread handler - @param item Item to create a field for - @param table Temporary table - @param copy_func If set and item is a function, store copy of - item in this array - @param modify_item 1 if item->result_field should point to new - item. This is relevent for how fill_record() - is going to work: - If modify_item is 1 then fill_record() will - update the record in the original table. - If modify_item is 0 then fill_record() will - update the temporary table - - @retval - 0 on error - @retval - new_created field -*/ - -static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, - Item ***copy_func, bool modify_item) -{ - Field *UNINIT_VAR(new_field); - DBUG_ASSERT(thd == table->in_use); - 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; -} - - /** Create field for information schema table. @@ -16753,19 +16718,182 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table) /** + Create a temporary field for Item_field (or its descendant), + either direct or referenced by an Item_ref. +*/ +Field * +Item_field::create_tmp_field_from_item_field(TABLE *new_table, + Item_ref *orig_item, + const Tmp_field_param *param) +{ + DBUG_ASSERT(!is_result_field()); + Field *result; + /* + If item have to be able to store NULLs but underlaid field can't do it, + create_tmp_field_from_field() can't be used for tmp field creation. + */ + if (((maybe_null && in_rollup) || + (new_table->in_use->create_tmp_table_for_derived && /* for mat. view/dt */ + orig_item && orig_item->maybe_null)) && + !field->maybe_null()) + { + /* + The item the ref points to may have maybe_null flag set while + the ref doesn't have it. This may happen for outer fields + when the outer query decided at some point after name resolution phase + that this field might be null. Take this into account here. + */ + Record_addr rec(orig_item ? orig_item->maybe_null : maybe_null); + const Type_handler *handler= type_handler()-> + type_handler_for_tmp_table(this); + result= handler->make_and_init_table_field(orig_item ? &orig_item->name : &name, + rec, *this, new_table); + } + else if (param->table_cant_handle_bit_fields() && + field->type() == MYSQL_TYPE_BIT) + { + const Type_handler *handler= type_handler_long_or_longlong(); + result= handler->make_and_init_table_field(&name, + Record_addr(maybe_null), + *this, new_table); + } + else + { + LEX_CSTRING *tmp= orig_item ? &orig_item->name : &name; + bool tmp_maybe_null= param->modify_item() ? maybe_null : + field->maybe_null(); + result= field->create_tmp_field(new_table->in_use->mem_root, new_table, + tmp_maybe_null); + if (result) + result->field_name= *tmp; + } + if (result && param->modify_item()) + result_field= result; + return result; +} + + +Field *Item_field::create_tmp_field_ex(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) +{ + DBUG_ASSERT(!is_result_field()); + Field *result; + src->set_field(field); + if (!(result= create_tmp_field_from_item_field(table, NULL, param))) + return NULL; + /* + Fields that are used as arguments to the DEFAULT() function already have + their data pointers set to the default value during name resolution. See + Item_default_value::fix_fields. + */ + if (type() != Item::DEFAULT_VALUE_ITEM && field->eq_def(result)) + src->set_default_field(field); + return result; +} + + +Field *Item_ref::create_tmp_field_ex(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) +{ + Item *item= real_item(); + DBUG_ASSERT(is_result_field()); + if (item->type() == Item::FIELD_ITEM) + { + Field *result; + Item_field *field= (Item_field*) item; + Tmp_field_param prm2(*param); + prm2.set_modify_item(false); + src->set_field(field->field); + if (!(result= field->create_tmp_field_from_item_field(table, this, &prm2))) + return NULL; + if (param->modify_item()) + result_field= result; + return result; + } + return Item_result_field::create_tmp_field_ex(table, src, param); +} + + +void Item_result_field::get_tmp_field_src(Tmp_field_src *src, + const Tmp_field_param *param) +{ + if (param->make_copy_field()) + { + DBUG_ASSERT(result_field); + src->set_field(result_field); + } + else + { + src->set_item_result_field(this); // Save for copy_funcs + } +} + + +Field *Item_result_field::create_tmp_field_ex(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) +{ + /* + Possible Item types: + - Item_cache_wrapper (only for CREATE..SELECT ?) + - Item_func + - Item_subselect + */ + DBUG_ASSERT(is_result_field()); + DBUG_ASSERT(type() != NULL_ITEM); + get_tmp_field_src(src, param); + Field *result; + if ((result= tmp_table_field_from_field_type(table)) && param->modify_item()) + result_field= result; + return result; +} + + +Field *Item_func_user_var::create_tmp_field_ex(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) +{ + DBUG_ASSERT(is_result_field()); + DBUG_ASSERT(type() != NULL_ITEM); + get_tmp_field_src(src, param); + Field *result; + if ((result= create_table_field_from_handler(table)) && param->modify_item()) + result_field= result; + return result; +} + + +Field *Item_func_sp::create_tmp_field_ex(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) +{ + Field *result; + get_tmp_field_src(src, param); + if ((result= sp_result_field->create_tmp_field(table->in_use->mem_root, + table))) + { + result->field_name= name; + if (param->modify_item()) + result_field= result; + } + return result; +} + +/** Create field for temporary table. - @param thd Thread handler - @param table Temporary table - @param item Item to create a field for - @param type Type of item (normally item->type) - @param copy_func If set and item is a function, store copy of item + @param table Temporary table + @param item Item to create a field for + @param type Type of item (normally item->type) + @param copy_func If set and item is a function, store copy of item in this array @param from_field if field will be created using other field as example, pointer example field will be written here - @param default_field If field has a default value field, store it here - @param group 1 if we are going to do a relative group by on result - @param modify_item 1 if item->result_field should point to new item. + @param default_field If field has a default value field, store it here + @param group 1 if we are going to do a relative group by on result + @param modify_item 1 if item->result_field should point to new item. This is relevent for how fill_record() is going to work: If modify_item is 1 then fill_record() will update @@ -16774,175 +16902,28 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table) the temporary table @retval - 0 on error + 0 on error @retval new_created field + Create a temporary field for Item_field (or its descendant), + either direct or referenced by an Item_ref. */ - -Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, +Field *create_tmp_field(TABLE *table, Item *item, Item ***copy_func, Field **from_field, Field **default_field, bool group, bool modify_item, bool table_cant_handle_bit_fields, bool make_copy_field) { - Field *result; - 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) - { - orig_item= item; - item= item->real_item(); - type= Item::FIELD_ITEM; - } - - switch (type) { - case Item::TYPE_HOLDER: - case Item::SUM_FUNC_ITEM: - { - result= item->create_tmp_field(group, table); - if (!result) - my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); - return result; - } - case Item::FIELD_ITEM: - case Item::DEFAULT_VALUE_ITEM: - case Item::INSERT_VALUE_ITEM: - case Item::TRIGGER_FIELD_ITEM: - { - Item_field *field= (Item_field*) item; - bool orig_modify= modify_item; - if (orig_type == Item::REF_ITEM) - modify_item= 0; - /* - If item have to be able to store NULLs but underlaid field can't do it, - create_tmp_field_from_field() can't be used for tmp field creation. - */ - if (((field->maybe_null && field->in_rollup) || - (thd->create_tmp_table_for_derived && /* for mat. view/dt */ - orig_item && orig_item->maybe_null)) && - !field->field->maybe_null()) - { - bool save_maybe_null= FALSE; - /* - The item the ref points to may have maybe_null flag set while - the ref doesn't have it. This may happen for outer fields - when the outer query decided at some point after name resolution phase - that this field might be null. Take this into account here. - */ - if (orig_item) - { - save_maybe_null= item->maybe_null; - item->maybe_null= orig_item->maybe_null; - } - result= create_tmp_field_from_item(thd, item, table, NULL, - modify_item); - *from_field= field->field; - if (result && modify_item) - field->result_field= result; - if (orig_item) - { - item->maybe_null= save_maybe_null; - result->field_name= orig_item->name; - } - } - 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; - 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; - } - else - { - LEX_CSTRING *tmp= orig_item ? &orig_item->name : &item->name; - result= create_tmp_field_from_field(thd, (*from_field= field->field), - tmp, table, - modify_item ? field : - NULL); - } - - if (orig_type == Item::REF_ITEM && orig_modify) - ((Item_ref*)orig_item)->set_result_field(result); - /* - Fields that are used as arguments to the DEFAULT() function already have - their data pointers set to the default value during name resolution. See - Item_default_value::fix_fields. - */ - if (orig_type != Item::DEFAULT_VALUE_ITEM && field->field->eq_def(result)) - *default_field= field->field; - return result; - } - /* Fall through */ - case Item::FUNC_ITEM: - if (((Item_func *) item)->functype() == Item_func::FUNC_SP) - { - Item_func_sp *item_func_sp= (Item_func_sp *) item; - Field *sp_result_field= item_func_sp->get_sp_result_field(); - - if (make_copy_field) - { - DBUG_ASSERT(item_func_sp->result_field); - *from_field= item_func_sp->result_field; - } - else - { - *((*copy_func)++)= item; - } - Field *result_field= - create_tmp_field_from_field(thd, - sp_result_field, - &item_func_sp->name, - table, - NULL); - - if (modify_item) - item->set_result_field(result_field); - - return result_field; - } - - /* Fall through */ - case Item::COND_ITEM: - case Item::FIELD_AVG_ITEM: - case Item::FIELD_STD_ITEM: - case Item::SUBSELECT_ITEM: - /* The following can only happen with 'CREATE TABLE ... SELECT' */ - case Item::PROC_ITEM: - case Item::INT_ITEM: - case Item::REAL_ITEM: - case Item::DECIMAL_ITEM: - case Item::STRING_ITEM: - case Item::DATE_ITEM: - case Item::REF_ITEM: - case Item::NULL_ITEM: - case Item::VARBIN_ITEM: - case Item::CACHE_ITEM: - case Item::WINDOW_FUNC_ITEM: // psergey-winfunc: - case Item::EXPR_CACHE_ITEM: - case Item::PARAM_ITEM: - if (make_copy_field) - { - DBUG_ASSERT(((Item_result_field*)item)->result_field); - *from_field= ((Item_result_field*)item)->result_field; - } - return create_tmp_field_from_item(thd, item, table, - (make_copy_field ? 0 : copy_func), - modify_item); - default: // Dosen't have to be stored - return 0; - } + Tmp_field_src src; + Tmp_field_param prm(group, modify_item, table_cant_handle_bit_fields, + make_copy_field); + Field *result= item->create_tmp_field_ex(table, &src, &prm); + *from_field= src.field(); + *default_field= src.default_field(); + if (src.item_result_field()) + *((*copy_func)++)= src.item_result_field(); + return result; } /* @@ -16958,7 +16939,7 @@ setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps, uint field_count) { uint bitmap_size= bitmap_buffer_size(field_count); - DBUG_ASSERT(table->s->virtual_fields == 0 && table->def_vcol_set == 0); + DBUG_ASSERT(table->s->virtual_fields == 0); my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count, FALSE); @@ -17223,7 +17204,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, } if (not_all_columns) { - if (item->with_sum_func && type != Item::SUM_FUNC_ITEM) + if (item->with_sum_func() && type != Item::SUM_FUNC_ITEM) { if (item->used_tables() & OUTER_REF_TABLE_BIT) item->update_used_tables(); @@ -17253,7 +17234,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, { Item *tmp_item; Field *new_field= - create_tmp_field(thd, table, arg, arg->type(), ©_func, + create_tmp_field(table, arg, ©_func, tmp_from_field, &default_field[fieldnr], group != 0,not_all_columns, distinct, false); @@ -17303,7 +17284,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, else { /* - The last parameter to create_tmp_field() is a bit tricky: + The last parameter to create_tmp_field_ex() is a bit tricky: We need to set it to 0 in union, to get fill_record() to modify the temporary table. @@ -17317,7 +17298,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, */ Field *new_field= (param->schema_table) ? item->create_field_for_schema(thd, table) : - create_tmp_field(thd, table, item, type, ©_func, + create_tmp_field(table, item, ©_func, tmp_from_field, &default_field[fieldnr], group != 0, !force_copy_fields && @@ -17331,8 +17312,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, */ item->marker == 4 || param->bit_fields_as_long, force_copy_fields); - - if (unlikely(!new_field)) + if (!new_field) { if (unlikely(thd->is_fatal_error)) goto err; // Got OOM @@ -17913,12 +17893,10 @@ bool Virtual_tmp_table::add(List<Spvar_definition> &field_list) while ((cdef= it++)) { Field *tmp; - if (!(tmp= cdef->make_field(s, in_use->mem_root, 0, - (uchar*) (f_maybe_null(cdef->pack_flag) ? "" : 0), - f_maybe_null(cdef->pack_flag) ? 1 : 0, - &cdef->field_name))) + Record_addr addr(f_maybe_null(cdef->pack_flag)); + if (!(tmp= cdef->make_field(s, in_use->mem_root, &addr, &cdef->field_name))) DBUG_RETURN(true); - add(tmp); + add(tmp); } DBUG_RETURN(false); } @@ -18038,7 +18016,7 @@ bool Virtual_tmp_table::sp_set_all_fields_from_item_list(THD *thd, bool Virtual_tmp_table::sp_set_all_fields_from_item(THD *thd, Item *value) { - DBUG_ASSERT(value->fixed); + DBUG_ASSERT(value->is_fixed()); DBUG_ASSERT(value->cols() == s->fields); for (uint i= 0; i < value->cols(); i++) { @@ -18461,7 +18439,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table, We don't want this error to be converted to a warning, e.g. in case of INSERT IGNORE ... SELECT. */ - table->file->print_error(error, MYF(ME_FATALERROR)); + table->file->print_error(error, MYF(ME_FATAL)); DBUG_RETURN(1); } new_table= *table; @@ -18484,7 +18462,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table, new_table.no_rows= table->no_rows; if (create_internal_tmp_table(&new_table, table->key_info, start_recinfo, recinfo, - thd->lex->select_lex.options | + thd->lex->first_select_lex()->options | thd->variables.option_bits)) goto err2; if (open_tmp_table(&new_table)) @@ -22616,7 +22594,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, if (unlikely(copy_blobs(first_field))) { my_message(ER_OUTOFMEMORY, ER_THD(thd,ER_OUTOFMEMORY), - MYF(ME_FATALERROR)); + MYF(ME_FATAL)); error=0; goto err; } @@ -22891,12 +22869,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, uint counter; enum_resolution_type resolution; - /* - Local SP variables may be int but are expressions, not positions. - (And they can't be used before fix_fields is called for them). - */ - if (order_item->type() == Item::INT_ITEM && order_item->basic_const_item() && - !from_window_spec) + if (order_item->is_order_clause_position() && !from_window_spec) { /* Order by position */ uint count; if (order->counter_used) @@ -23010,7 +22983,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, inspite of that fix_fields() calls find_item_in_list() one more time. - We check order_item->fixed because Item_func_group_concat can put + We check order_item->is_fixed() because Item_func_group_concat can put arguments for which fix_fields already was called. */ if (order_item->fix_fields_if_needed_for_order_by(thd, order->item) || @@ -23120,7 +23093,7 @@ setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, all_fields, true, true, from_window_spec)) return 1; (*ord->item)->marker= UNDEF_POS; /* Mark found */ - if ((*ord->item)->with_sum_func && context_analysis_place == IN_GROUP_BY) + if ((*ord->item)->with_sum_func() && context_analysis_place == IN_GROUP_BY) { my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*ord->item)->full_name()); return 1; @@ -23278,7 +23251,7 @@ create_distinct_group(THD *thd, Ref_ptr_array ref_pointer_array, li.rewind(); while ((item=li++)) { - if (!item->const_item() && !item->with_sum_func && !item->marker) + if (!item->const_item() && !item->with_sum_func() && !item->marker) { /* Don't put duplicate columns from the SELECT list into the @@ -23375,9 +23348,11 @@ count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, } else { + With_sum_func_cache *cache= field->get_with_sum_func_cache(); param->func_count++; - if (reset_with_sum_func) - field->with_sum_func=0; + // "field" can point to Item_std_field, so "cache" can be NULL here. + if (reset_with_sum_func && cache) + cache->reset_with_sum_func(); } } } @@ -23517,7 +23492,7 @@ void calc_group_buffer(TMP_TABLE_PARAM *param, ORDER *group) { /* Group strings are taken as varstrings and require an length field. - A field is not yet created by create_tmp_field() + A field is not yet created by create_tmp_field_ex() and the sizes should match up. */ key_length+= group_item->max_length + HA_KEY_BLOB_LENGTH; @@ -23527,7 +23502,7 @@ void calc_group_buffer(TMP_TABLE_PARAM *param, ORDER *group) default: /* This case should never be choosen */ DBUG_ASSERT(0); - my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL)); } } parts++; @@ -23781,7 +23756,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, real_pos->real_type() == Item::SUBSELECT_ITEM || real_pos->type() == Item::CACHE_ITEM || real_pos->type() == Item::COND_ITEM) && - !real_pos->with_sum_func) + !real_pos->with_sum_func()) { // Save for send fields pos= real_pos; /* TODO: @@ -23988,7 +23963,7 @@ change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array, for (uint i= 0; (item= it++); i++) { Field *field; - if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) + if (item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) item_field= item; else if (item->type() == Item::FIELD_ITEM) { @@ -24296,7 +24271,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) } if (unlikely(thd->is_fatal_error)) DBUG_RETURN(TRUE); - if (!cond->fixed) + if (!cond->is_fixed()) { Item *tmp_item= (Item*) cond; cond->fix_fields(thd, &tmp_item); @@ -24515,7 +24490,7 @@ bool JOIN::rollup_init() Marking the expression item as 'with_sum_func' will ensure this. */ if (changed) - item->with_sum_func= 1; + item->get_with_sum_func_cache()->set_with_sum_func(); } } return 0; @@ -25003,7 +24978,8 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta, */ if (real_table->merged_for_insert) { - TABLE_LIST *view_child= real_table->view->select_lex.table_list.first; + TABLE_LIST *view_child= + real_table->view->first_select_lex()->table_list.first; for (;view_child; view_child= view_child->next_local) { if (view_child->table == table) @@ -25456,8 +25432,9 @@ int JOIN::save_explain_data_intern(Explain_query *output, { JOIN *join= this; /* Legacy: this code used to be a non-member function */ DBUG_ENTER("JOIN::save_explain_data_intern"); - DBUG_PRINT("info", ("Select %p, type %s, message %s", - join->select_lex, join->select_lex->type, + DBUG_PRINT("info", ("Select %p (%u), type %s, message %s", + join->select_lex, join->select_lex->select_number, + join->select_lex->type, message ? message : "NULL")); DBUG_ASSERT(have_query_plan == QEP_AVAILABLE); /* fake_select_lex is created/printed by Explain_union */ @@ -25483,7 +25460,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, explain->select_id= join->select_lex->select_number; explain->select_type= join->select_lex->type; - explain->linkage= select_lex->linkage; + explain->linkage= select_lex->get_linkage(); explain->using_temporary= need_tmp; explain->using_filesort= need_order_arg; /* Setting explain->message means that all other members are invalid */ @@ -25506,7 +25483,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, explain->select_id= select_lex->select_number; explain->select_type= select_lex->type; - explain->linkage= select_lex->linkage; + explain->linkage= select_lex->get_linkage(); explain->using_temporary= need_tmp; explain->using_filesort= need_order_arg; explain->message= "Storage engine handles GROUP BY"; @@ -25529,7 +25506,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, join->select_lex->set_explain_type(true); xpl_sel->select_id= join->select_lex->select_number; xpl_sel->select_type= join->select_lex->type; - xpl_sel->linkage= select_lex->linkage; + xpl_sel->linkage= select_lex->get_linkage(); if (select_lex->master_unit()->derived) xpl_sel->connection_type= Explain_node::EXPLAIN_NODE_DERIVED; @@ -25673,7 +25650,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, for such queries, we'll get here before having called subquery_expr->fix_fields(), which will cause failure to */ - if (unit->item && !unit->item->fixed) + if (unit->item && !unit->item->is_fixed()) { Item *ref= unit->item; if (unit->item->fix_fields(thd, &ref)) @@ -26112,6 +26089,18 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) { str->append("/* select#"); str->append_ulonglong(select_number); + if (thd->lex->describe & DESCRIBE_EXTENDED2) + { + str->append("/"); + str->append_ulonglong(nest_level); + + if (master_unit()->fake_select_lex && + master_unit()->first_select() == this) + { + str->append(" Filter Select: "); + master_unit()->fake_select_lex->print(thd, str, query_type); + } + } str->append(" */ "); } @@ -26143,18 +26132,21 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) str->append(STRING_WITH_LEN("sql_buffer_result ")); if (options & OPTION_FOUND_ROWS) str->append(STRING_WITH_LEN("sql_calc_found_rows ")); - switch (sql_cache) + if (this == parent_lex->first_select_lex()) { - case SQL_NO_CACHE: - str->append(STRING_WITH_LEN("sql_no_cache ")); - break; - case SQL_CACHE: - str->append(STRING_WITH_LEN("sql_cache ")); - break; - case SQL_CACHE_UNSPECIFIED: - break; - default: - DBUG_ASSERT(0); + switch (parent_lex->sql_cache) + { + case LEX::SQL_NO_CACHE: + str->append(STRING_WITH_LEN("sql_no_cache ")); + break; + case LEX::SQL_CACHE: + str->append(STRING_WITH_LEN("sql_cache ")); + break; + case LEX::SQL_CACHE_UNSPECIFIED: + break; + default: + DBUG_ASSERT(0); + } } //Item List diff --git a/sql/sql_select.h b/sql/sql_select.h index 2cc47f6ec3b..4140a0293f8 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1473,6 +1473,11 @@ public: Dynamic_array<KEYUSE_EXT> *ext_keyuses_for_splitting; JOIN_TAB *sort_and_group_aggr_tab; + /* + Flag is set to true if select_lex was found to be degenerated before + the optimize_cond() call in JOIN::optimize_inner() method. + */ + bool is_orig_degenerated; JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg, select_result *result_arg) @@ -1568,6 +1573,7 @@ public: emb_sjm_nest= NULL; sjm_lookup_tables= 0; sjm_scan_tables= 0; + is_orig_degenerated= false; } /* True if the plan guarantees that it will be returned zero or one row */ @@ -1747,6 +1753,7 @@ public: bool fix_all_splittings_in_plan(); bool transform_in_predicates_into_in_subq(THD *thd); + bool add_equalities_to_where_condition(THD *thd, List<Item> &eq_list); private: /** Create a temporary table to be used for processing DISTINCT/ORDER @@ -1811,10 +1818,6 @@ bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, void copy_fields(TMP_TABLE_PARAM *param); bool copy_funcs(Item **func_ptr, const THD *thd); uint find_shortest_key(TABLE *table, const key_map *usable_keys); -Field* create_tmp_field_from_field(THD *thd, Field* org_field, - LEX_CSTRING *name, TABLE *table, - Item_field *item); - bool is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args); /* functions from opt_sum.cc */ @@ -2066,12 +2069,6 @@ bool mysql_select(THD *thd, void free_underlaid_joins(THD *thd, SELECT_LEX *select); bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result); -Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, - Item ***copy_func, Field **from_field, - Field **def_field, - bool group, bool modify_item, - bool table_cant_handle_bit_fields, - bool make_copy_field); /* General routine to change field->ptr of a NULL-terminated array of Field @@ -2339,7 +2336,7 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field, extern bool test_if_ref(Item *, Item_field *left_item,Item *right_item); -inline bool optimizer_flag(THD *thd, uint flag) +inline bool optimizer_flag(THD *thd, ulonglong flag) { return (thd->variables.optimizer_switch & flag); } @@ -2455,4 +2452,13 @@ int create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort); JOIN_TAB *first_explain_order_tab(JOIN* join); JOIN_TAB *next_explain_order_tab(JOIN* join, JOIN_TAB* tab); +bool check_simple_equality(THD *thd, const Item::Context &ctx, + Item *left_item, Item *right_item, + COND_EQUAL *cond_equal); + +void propagate_new_equalities(THD *thd, Item *cond, + List<Item_equal> *new_equalities, + COND_EQUAL *inherited, + bool *is_simplifiable_cond); + #endif /* SQL_SELECT_INCLUDED */ diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index 1fb2e5e7714..1ed0bb38e64 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -220,8 +220,8 @@ bool check_sequence_fields(LEX *lex, List<Create_field> *fields) err: my_error(ER_SEQUENCE_INVALID_TABLE_STRUCTURE, MYF(0), - lex->select_lex.table_list.first->db.str, - lex->select_lex.table_list.first->table_name.str, reason); + lex->first_select_lex()->table_list.first->db.str, + lex->first_select_lex()->table_list.first->table_name.str, reason); DBUG_RETURN(TRUE); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 33b28afd734..ea6ef7d86fb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1034,9 +1034,9 @@ find_files(THD *thd, Dynamic_array<LEX_CSTRING*> *files, LEX_CSTRING *db, if (!(dirp = my_dir(path, MY_THREAD_SPECIFIC | (db ? 0 : MY_WANT_STAT)))) { if (my_errno == ENOENT) - my_error(ER_BAD_DB_ERROR, MYF(ME_BELL | ME_WAITTANG), db->str); + my_error(ER_BAD_DB_ERROR, MYF(0), db->str); else - my_error(ER_CANT_READ_DIR, MYF(ME_BELL | ME_WAITTANG), path, my_errno); + my_error(ER_CANT_READ_DIR, MYF(0), path, my_errno); DBUG_RETURN(FIND_FILES_DIR); } @@ -2184,6 +2184,12 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, field->sql_type(type); packet->append(type.ptr(), type.length(), system_charset_info); + DBUG_EXECUTE_IF("sql_type", + packet->append(" /* "); + packet->append(field->type_handler()->version().ptr()); + packet->append(" */ "); + ); + if (field->has_charset() && !(sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))) { if (field->charset() != share->table_charset) @@ -4143,8 +4149,9 @@ bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables, case SQLCOM_SHOW_TABLE_STATUS: case SQLCOM_SHOW_TRIGGERS: case SQLCOM_SHOW_EVENTS: - thd->make_lex_string(&lookup_field_values->db_value, - lex->select_lex.db.str, lex->select_lex.db.length); + thd->make_lex_string(&lookup_field_values->db_value, + lex->first_select_lex()->db.str, + lex->first_select_lex()->db.length); if (wild) { thd->make_lex_string(&lookup_field_values->table_value, @@ -4537,10 +4544,10 @@ fill_schema_table_by_open(THD *thd, MEM_ROOT *mem_root, temporary LEX. The latter is required to correctly open views and produce table describing their structure. */ - if (make_table_list(thd, &lex->select_lex, &db_name, &table_name)) + if (make_table_list(thd, lex->first_select_lex(), &db_name, &table_name)) goto end; - table_list= lex->select_lex.table_list.first; + table_list= lex->first_select_lex()->table_list.first; if (is_show_fields_or_keys) { @@ -6715,7 +6722,7 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, & 'field_translation_end' are uninitialized is this case. */ - List<Item> *fields= &tables->view->select_lex.item_list; + List<Item> *fields= &tables->view->first_select_lex()->item_list; List_iterator<Item> it(*fields); Item *item; Item_field *field; @@ -7368,7 +7375,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, break; default: DBUG_ASSERT(0); - my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL)); DBUG_RETURN(1); } table->field[7]->set_notnull(); @@ -7730,9 +7737,9 @@ int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond) TABLE *table= tables->table; CHARSET_INFO *cs= system_charset_info; OPEN_TABLE_LIST *open_list; - if (unlikely(!(open_list= list_open_tables(thd, thd->lex->select_lex.db.str, - wild))) && - unlikely(thd->is_fatal_error)) + if (!(open_list= list_open_tables(thd, thd->lex->first_select_lex()->db.str, + wild)) + && thd->is_fatal_error) DBUG_RETURN(1); for (; open_list ; open_list=open_list->next) @@ -8226,7 +8233,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) tmp_table_param->table_charset= cs; tmp_table_param->field_count= field_count; tmp_table_param->schema_table= 1; - SELECT_LEX *select_lex= thd->lex->current_select; + SELECT_LEX *select_lex= table_list->select_lex; bool keep_row_order= is_show_command(thd); if (!(table= create_tmp_table(thd, tmp_table_param, field_list, (ORDER*) 0, 0, 0, @@ -8263,7 +8270,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) static int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) { ST_FIELD_INFO *field_info= schema_table->fields_info; - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; for (; field_info->field_name; field_info++) { if (field_info->old_name) @@ -8323,14 +8330,14 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) char tmp[128]; String buffer(tmp,sizeof(tmp), thd->charset()); LEX *lex= thd->lex; - Name_resolution_context *context= &lex->select_lex.context; + Name_resolution_context *context= &lex->first_select_lex()->context; ST_FIELD_INFO *field_info= &schema_table->fields_info[2]; LEX_CSTRING field_name= {field_info->field_name, strlen(field_info->field_name) }; buffer.length(0); buffer.append(field_info->old_name); - buffer.append(&lex->select_lex.db); + buffer.append(&lex->first_select_lex()->db); if (lex->wild && lex->wild->ptr()) { buffer.append(STRING_WITH_LEN(" (")); @@ -8363,7 +8370,7 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {3, 15, 14, 6, 16, 5, 17, 18, 19, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; for (; *field_num >= 0; field_num++) { @@ -8394,7 +8401,7 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {0, 2, 1, 3, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; for (; *field_num >= 0; field_num++) { @@ -8421,7 +8428,7 @@ int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {2, 3, 4, 27, 24, 23, 22, 26, 28, 29, 30, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; for (; *field_num >= 0; field_num++) { diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc index a92d40f6bb3..83abaebd4fd 100644 --- a/sql/sql_signal.cc +++ b/sql/sql_signal.cc @@ -323,7 +323,7 @@ end: set= m_set_signal_information.m_item[i]; if (set) { - if (set->fixed) + if (set->is_fixed()) set->cleanup(); } } diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 5d5cc90431b..e7acabe8bee 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -103,8 +103,7 @@ bool String::realloc_raw(size_t alloc_length) (thread_specific ? MY_THREAD_SPECIFIC : 0))))) { - if (str_length > len - 1) - str_length= 0; + DBUG_ASSERT(str_length < len); if (str_length) // Avoid bugs in memcpy on AIX memcpy(new_ptr,Ptr,str_length); new_ptr[str_length]=0; diff --git a/sql/sql_string.h b/sql/sql_string.h index d110e10647a..d9d3f10777c 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -761,6 +761,17 @@ public: }; +class String_space: public String +{ +public: + String_space(uint n) + { + if (fill(n, ' ')) + set("", 0, &my_charset_bin); + } +}; + + static inline bool check_if_only_end_space(CHARSET_INFO *cs, const char *str, const char *end) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index daf8491a67f..92fcba4972f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4260,11 +4260,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, } /* Give warnings for not supported table options */ -#if defined(WITH_ARIA_STORAGE_ENGINE) extern handlerton *maria_hton; - if (file->partition_ht() != maria_hton) -#endif - if (create_info->transactional) + if (file->partition_ht() != maria_hton && create_info->transactional && + !file->has_transaction_manager()) push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, ER_THD(thd, ER_ILLEGAL_HA_CREATE_OPTION), @@ -4892,7 +4890,7 @@ int create_table_impl(THD *thd, /* Restart statement transactions for the case of CREATE ... SELECT. */ - if (thd->lex->select_lex.item_list.elements && + if (thd->lex->first_select_lex()->item_list.elements && restart_trans_for_tables(thd, thd->lex->query_tables)) goto err; } @@ -9565,8 +9563,6 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, } DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock"); - /* We can abort alter table for any table type */ - thd->abort_on_warning= !ignore && thd->is_strict_mode(); /* Create .FRM for new version of table with a temporary name. @@ -9596,7 +9592,6 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, C_ALTER_TABLE_FRM_ONLY, NULL, &key_info, &key_count, &frm); reenable_binlog(thd); - thd->abort_on_warning= false; if (unlikely(error)) { my_free(const_cast<uchar*>(frm.str)); @@ -10065,19 +10060,17 @@ err_new_table_cleanup: if (unlikely(alter_ctx.error_if_not_empty && thd->get_stmt_da()->current_row_for_warning())) { - const char *f_val= 0; - enum enum_mysql_timestamp_type t_type= MYSQL_TIMESTAMP_DATE; + const char *f_val= "0000-00-00"; + const char *f_type= "date"; switch (alter_ctx.datetime_field->real_field_type()) { case MYSQL_TYPE_DATE: case MYSQL_TYPE_NEWDATE: - f_val= "0000-00-00"; - t_type= MYSQL_TIMESTAMP_DATE; break; case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_DATETIME2: f_val= "0000-00-00 00:00:00"; - t_type= MYSQL_TIMESTAMP_DATETIME; + f_type= "datetime"; break; default: /* Shouldn't get here. */ @@ -10085,9 +10078,10 @@ err_new_table_cleanup: } bool save_abort_on_warning= thd->abort_on_warning; thd->abort_on_warning= true; - make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN, - f_val, strlength(f_val), t_type, - alter_ctx.datetime_field->field_name.str); + thd->push_warning_truncated_value_for_field(Sql_condition::WARN_LEVEL_WARN, + f_type, f_val, + alter_ctx.datetime_field-> + field_name.str); thd->abort_on_warning= save_abort_on_warning; } @@ -10216,10 +10210,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff); - /* Set read map for all fields in from table */ from->default_column_bitmaps(); - bitmap_set_all(from->read_set); - from->file->column_bitmaps_signal(); /* We can abort alter table for any table type */ thd->abort_on_warning= !ignore && thd->is_strict_mode(); @@ -10249,7 +10240,11 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, if (def->field == from->found_next_number_field) thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO; } - (copy_end++)->set(*ptr,def->field,0); + if (!(*ptr)->vcol_info) + { + bitmap_set_bit(from->read_set, def->field->field_index); + (copy_end++)->set(*ptr,def->field,0); + } } else { @@ -10292,8 +10287,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, Filesort_tracker dummy_tracker(false); Filesort fsort(order, HA_POS_ERROR, true, NULL); - if (thd->lex->select_lex.setup_ref_array(thd, order_num) || - setup_order(thd, thd->lex->select_lex.ref_pointer_array, + if (thd->lex->first_select_lex()->setup_ref_array(thd, order_num) || + setup_order(thd, thd->lex->first_select_lex()->ref_pointer_array, &tables, fields, all_fields, order)) goto err; @@ -10318,6 +10313,11 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, from_row_end= from->vers_end_field(); } + if (from_row_end) + bitmap_set_bit(from->read_set, from_row_end->field_index); + + from->file->column_bitmaps_signal(); + THD_STAGE_INFO(thd, stage_copy_to_tmp_table); /* Tell handler that we have values for all columns in the to table */ to->use_all_columns(); @@ -10667,7 +10667,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, ha_checksum crc= 0; uchar null_mask=256 - (1 << t->s->last_null_bit_pos); - t->use_all_columns(); + t->use_all_stored_columns(); if (t->file->ha_rnd_init(1)) protocol->store_null(); diff --git a/sql/sql_time.cc b/sql/sql_time.cc index 35ef1e50c36..c1300c78ad9 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -313,8 +313,7 @@ adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec) if (check_time_range(ltime, dec, &warnings)) return true; if (warnings) - make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, - &str, MYSQL_TIMESTAMP_TIME, NullS); + current_thd->push_warning_truncated_wrong_value("time", str.ptr()); return false; } @@ -399,11 +398,14 @@ str_to_datetime_with_warn(CHARSET_INFO *cs, THD *thd= current_thd; bool ret_val= str_to_datetime(cs, str, length, l_time, flags, &status); if (ret_val || status.warnings) + { + const ErrConvString err(str, length, &my_charset_bin); make_truncated_value_warning(thd, ret_val ? Sql_condition::WARN_LEVEL_WARN : Sql_condition::time_warn_level(status.warnings), - str, length, flags & TIME_TIME_ONLY ? + &err, flags & TIME_TIME_ONLY ? MYSQL_TIMESTAMP_TIME : l_time->time_type, NullS); + } DBUG_EXECUTE_IF("str_to_datetime_warn", push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_YES, str);); @@ -411,77 +413,11 @@ str_to_datetime_with_warn(CHARSET_INFO *cs, } -/** - converts a pair of numbers (integer part, microseconds) to MYSQL_TIME - - @param neg sign of the time value - @param nr integer part of the number to convert - @param sec_part microsecond part of the number - @param ltime converted value will be written here - @param fuzzydate conversion flags (TIME_INVALID_DATE, etc) - @param str original number, as an ErrConv. For the warning - @param field_name field name or NULL if not a field. For the warning - - @returns 0 for success, 1 for a failure -*/ -static bool number_to_time_with_warn(bool neg, ulonglong nr, ulong sec_part, - MYSQL_TIME *ltime, ulonglong fuzzydate, - const ErrConv *str, - const char *field_name) -{ - int was_cut; - longlong res; - enum_mysql_timestamp_type ts_type; - bool have_warnings; - - if (fuzzydate & TIME_TIME_ONLY) - { - fuzzydate= TIME_TIME_ONLY; // clear other flags - ts_type= MYSQL_TIMESTAMP_TIME; - res= number_to_time(neg, nr, sec_part, ltime, &was_cut); - have_warnings= MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut); - } - else - { - ts_type= MYSQL_TIMESTAMP_DATETIME; - if (neg) - { - res= -1; - } - else - { - res= number_to_datetime(nr, sec_part, ltime, fuzzydate, &was_cut); - have_warnings= was_cut && (fuzzydate & TIME_NO_ZERO_IN_DATE); - } - } - - if (res < 0 || have_warnings) - { - make_truncated_value_warning(current_thd, - Sql_condition::WARN_LEVEL_WARN, str, - res < 0 ? MYSQL_TIMESTAMP_ERROR : ts_type, - field_name); - } - return res < 0; -} - - bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime, ulonglong fuzzydate, const char *field_name) { const ErrConvDouble str(value); - bool neg= value < 0; - - if (neg) - value= -value; - - if (value > LONGLONG_MAX) - value= static_cast<double>(LONGLONG_MAX); - - longlong nr= static_cast<ulonglong>(floor(value)); - uint sec_part= static_cast<ulong>((value - floor(value))*TIME_SECOND_PART_FACTOR); - return number_to_time_with_warn(neg, nr, sec_part, ltime, fuzzydate, &str, - field_name); + return Sec6(value).convert_to_mysql_time(ltime, fuzzydate, &str, field_name); } @@ -489,11 +425,7 @@ bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime, ulonglong fuzzydate, const char *field_name) { const ErrConvDecimal str(value); - ulonglong nr; - ulong sec_part; - bool neg= my_decimal2seconds(value, &nr, &sec_part); - return number_to_time_with_warn(neg, nr, sec_part, ltime, fuzzydate, &str, - field_name); + return Sec6(value).convert_to_mysql_time(ltime, fuzzydate, &str, field_name); } @@ -501,8 +433,8 @@ bool int_to_datetime_with_warn(bool neg, ulonglong value, MYSQL_TIME *ltime, ulonglong fuzzydate, const char *field_name) { const ErrConvInteger str(neg ? - (longlong) value : (longlong) value, !neg); - return number_to_time_with_warn(neg, value, 0, ltime, - fuzzydate, &str, field_name); + Sec6 sec(neg, value, 0); + return sec.convert_to_mysql_time(ltime, fuzzydate, &str, field_name); } @@ -549,7 +481,7 @@ void localtime_to_TIME(MYSQL_TIME *to, struct tm *from) } -void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds) +void calc_time_from_sec(MYSQL_TIME *to, ulong seconds, ulong microseconds) { long t_seconds; // to->neg is not cleared, it may already be set to a useful value @@ -932,9 +864,7 @@ void make_truncated_value_warning(THD *thd, timestamp_type time_type, const char *field_name) { - char warn_buff[MYSQL_ERRMSG_SIZE]; const char *type_str; - CHARSET_INFO *cs= &my_charset_latin1; switch (time_type) { case MYSQL_TIMESTAMP_DATE: @@ -948,23 +878,9 @@ void make_truncated_value_warning(THD *thd, type_str= "datetime"; break; } - if (field_name) - cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), - ER_THD(thd, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), - type_str, sval->ptr(), field_name, - (ulong) thd->get_stmt_da()->current_row_for_warning()); - else - { - if (time_type > MYSQL_TIMESTAMP_ERROR) - cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), - ER_THD(thd, ER_TRUNCATED_WRONG_VALUE), - type_str, sval->ptr()); - else - cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), - ER_THD(thd, ER_WRONG_VALUE), type_str, sval->ptr()); - } - push_warning(thd, level, - ER_TRUNCATED_WRONG_VALUE, warn_buff); + return thd->push_warning_wrong_or_truncated_value(level, + time_type <= MYSQL_TIMESTAMP_ERROR, + type_str, sval->ptr(), field_name); } @@ -1130,7 +1046,7 @@ null_date: bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2, - int l_sign, longlong *seconds_out, long *microseconds_out) + int l_sign, ulonglong *seconds_out, ulong *microseconds_out) { long days; bool neg; @@ -1172,8 +1088,8 @@ calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2, microseconds= -microseconds; neg= 1; } - *seconds_out= microseconds/1000000L; - *microseconds_out= (long) (microseconds%1000000L); + *seconds_out= (ulonglong) microseconds/1000000L; + *microseconds_out= (ulong) (microseconds%1000000L); return neg; } @@ -1181,8 +1097,8 @@ calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2, bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2, int l_sign, MYSQL_TIME *l_time3, ulonglong fuzzydate) { - longlong seconds; - long microseconds; + ulonglong seconds; + ulong microseconds; bzero((char *) l_time3, sizeof(*l_time3)); l_time3->neg= calc_time_diff(l_time1, l_time2, l_sign, &seconds, µseconds); @@ -1201,7 +1117,7 @@ bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2, ("invalid" means > TIME_MAX_SECOND) */ set_if_smaller(seconds, INT_MAX32); - calc_time_from_sec(l_time3, (long) seconds, microseconds); + calc_time_from_sec(l_time3, (ulong) seconds, microseconds); return ((fuzzydate & TIME_NO_ZERO_DATE) && (seconds == 0) && (microseconds == 0)); } @@ -1335,8 +1251,8 @@ mix_date_and_time_complex(MYSQL_TIME *ldate, const MYSQL_TIME *ltime) { DBUG_ASSERT(ldate->time_type == MYSQL_TIMESTAMP_DATE || ldate->time_type == MYSQL_TIMESTAMP_DATETIME); - longlong seconds; - long days, useconds; + ulonglong seconds; + ulong days, useconds; int sign= ltime->neg ? 1 : -1; ldate->neg= calc_time_diff(ldate, ltime, sign, &seconds, &useconds); @@ -1442,34 +1358,13 @@ time_to_datetime_with_warn(THD *thd, check_date(to, fuzzydate, &warn))) { ErrConvTime str(from); - make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN, - &str, MYSQL_TIMESTAMP_DATETIME, 0); + thd->push_warning_truncated_wrong_value("datetime", str.ptr()); return true; } return false; } -bool datetime_to_time_with_warn(THD *thd, const MYSQL_TIME *dt, - MYSQL_TIME *tm, uint dec) -{ - if (thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST) - { - *tm= *dt; - datetime_to_time(tm); - return false; - } - else /* new mode */ - { - MYSQL_TIME current_date; - set_current_date(thd, ¤t_date); - calc_time_diff(dt, ¤t_date, 1, tm, 0); - } - int warnings= 0; - return check_time_range(tm, dec, &warnings); -} - - longlong pack_time(const MYSQL_TIME *my_time) { return ((((((my_time->year * 13ULL + @@ -1511,3 +1406,10 @@ void unpack_time(longlong packed, MYSQL_TIME *my_time, break; } } + + +bool my_decimal::to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, + const char *field_name) +{ + return decimal_to_datetime_with_warn(this, to, fuzzydate, field_name); +} diff --git a/sql/sql_time.h b/sql/sql_time.h index d3607a28a76..8c6e58856e6 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -54,50 +54,6 @@ bool time_to_datetime(THD *thd, const MYSQL_TIME *tm, MYSQL_TIME *dt); bool time_to_datetime_with_warn(THD *thd, const MYSQL_TIME *tm, MYSQL_TIME *dt, ulonglong fuzzydate); -/* - Simply truncate the YYYY-MM-DD part to 0000-00-00 - and change time_type to MYSQL_TIMESTAMP_TIME -*/ -inline void datetime_to_time(MYSQL_TIME *ltime) -{ - DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATE || - ltime->time_type == MYSQL_TIMESTAMP_DATETIME); - DBUG_ASSERT(ltime->neg == 0); - ltime->year= ltime->month= ltime->day= 0; - ltime->time_type= MYSQL_TIMESTAMP_TIME; -} - - -/** - Convert DATE/DATETIME to TIME(dec) - using CURRENT_DATE in a non-old mode, - or using simple truncation in old mode (OLD_MODE_ZERO_DATE_TIME_CAST). - - @param thd - the thread to get the variables.old_behaviour value from - @param dt - the DATE of DATETIME value to convert - @param[out] tm - store result here - @param dec - the desired scale. The fractional part of the result - is checked according to this parameter before returning - the conversion result. "dec" is important in the corner - cases near the max/min limits. - If the result is '838:59:59.999999' and the desired scale - is less than 6, an error is returned. - Note, dec is not important in the - OLD_MODE_ZERO_DATE_TIME_CAST old mode. - - - in case of OLD_MODE_ZERO_DATE_TIME_CAST - the TIME part is simply truncated and "false" is returned. - - otherwise, the result is calculated effectively similar to: - TIMEDIFF(dt, CAST(CURRENT_DATE AS DATETIME)) - If the difference fits into the supported TIME range, "false" is returned, - otherwise a warning is issued and "true" is returned. - - @return false - on success - @return true - on error -*/ -bool datetime_to_time_with_warn(THD *, const MYSQL_TIME *dt, - MYSQL_TIME *tm, uint dec); - inline void datetime_to_date(MYSQL_TIME *ltime) { @@ -120,14 +76,6 @@ void make_truncated_value_warning(THD *thd, timestamp_type time_type, const char *field_name); -static inline void make_truncated_value_warning(THD *thd, - Sql_condition::enum_warning_level level, const char *str_val, size_t str_length, timestamp_type time_type, - const char *field_name) -{ - const ErrConvString str(str_val, str_length, &my_charset_bin); - make_truncated_value_warning(thd, level, &str, time_type, field_name); -} - extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type, const char *format_str, uint format_length); @@ -141,7 +89,7 @@ bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec); bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, const INTERVAL &interval); bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2, - int l_sign, longlong *seconds_out, long *microseconds_out); + int l_sign, ulonglong *seconds_out, ulong *microseconds_out); int append_interval(String *str, interval_type int_type, const INTERVAL &interval); /** @@ -171,7 +119,7 @@ bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2, int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b); void localtime_to_TIME(MYSQL_TIME *to, struct tm *from); -void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds); +void calc_time_from_sec(MYSQL_TIME *to, ulong seconds, ulong microseconds); uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year); int calc_weekday(long daynr,bool sunday_first_day_of_week); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 755a9a9486d..9f26bff3321 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -2311,12 +2311,10 @@ void Table_triggers_list::mark_fields_used(trg_event_type event) if (trg_field->field_idx != (uint)-1) { DBUG_PRINT("info", ("marking field: %d", trg_field->field_idx)); - bitmap_set_bit(trigger_table->read_set, trg_field->field_idx); if (trg_field->get_settable_routine_parameter()) bitmap_set_bit(trigger_table->write_set, trg_field->field_idx); - if (trigger_table->field[trg_field->field_idx]->vcol_info) - trigger_table->mark_virtual_col(trigger_table-> - field[trg_field->field_idx]); + trigger_table->mark_column_with_deps( + trigger_table->field[trg_field->field_idx]); } } } diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 201825d4593..34177242704 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -493,7 +493,7 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) bool Sql_cmd_truncate_table::execute(THD *thd) { bool res= TRUE; - TABLE_LIST *table= thd->lex->select_lex.table_list.first; + TABLE_LIST *table= thd->lex->first_select_lex()->table_list.first; DBUG_ENTER("Sql_cmd_truncate_table::execute"); if (check_one_table_access(thd, DROP_ACL, table)) diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc index 188ba8c4629..43edd2d506a 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -173,7 +173,7 @@ bool get_type_attributes_for_tvc(THD *thd, Item *item; for (uint holder_pos= 0 ; (item= it++); holder_pos++) { - DBUG_ASSERT(item->fixed); + DBUG_ASSERT(item->is_fixed()); holders[holder_pos].add_argument(item); } } @@ -251,7 +251,6 @@ bool table_value_constr::prepare(THD *thd, SELECT_LEX *sl, holders[pos].type_handler(), &holders[pos]/*Type_all_attributes*/, holders[pos].get_maybe_null()); - new_holder->fix_fields(thd, 0); sl->item_list.push_back(new_holder); } @@ -296,7 +295,7 @@ int table_value_constr::save_explain_data_intern(THD *thd, explain->select_id= select_lex->select_number; explain->select_type= select_lex->type; - explain->linkage= select_lex->linkage; + explain->linkage= select_lex->get_linkage(); explain->using_temporary= false; explain->using_filesort= false; /* Setting explain->message means that all other members are invalid */ @@ -549,7 +548,7 @@ bool Item_subselect::wrap_tvc_in_derived_table(THD *thd, Item *item; SELECT_LEX *sq_select; // select for IN subquery; sq_select= lex->current_select; - sq_select->linkage= tvc_sl->linkage; + sq_select->set_linkage(tvc_sl->get_linkage()); sq_select->parsing_place= SELECT_LIST; item= new (thd->mem_root) Item_field(thd, &sq_select->context, NULL, NULL, &star_clex_str); @@ -568,7 +567,7 @@ bool Item_subselect::wrap_tvc_in_derived_table(THD *thd, goto err; tvc_select= lex->current_select; derived_unit= tvc_select->master_unit(); - tvc_select->linkage= DERIVED_TABLE_TYPE; + tvc_select->set_linkage(DERIVED_TABLE_TYPE); lex->current_select= sq_select; @@ -695,7 +694,7 @@ Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd, mysql_init_select(lex); tvc_select= lex->current_select; derived_unit= tvc_select->master_unit(); - tvc_select->linkage= DERIVED_TABLE_TYPE; + tvc_select->set_linkage(DERIVED_TABLE_TYPE); /* Create TVC used in the transformation */ if (create_value_list_for_tvc(thd, &values)) diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 22eebaf6a38..e7fcdf499ec 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -21,11 +21,13 @@ #include "sql_time.h" #include "item.h" #include "log.h" +#include "tztime.h" Type_handler_row type_handler_row; Type_handler_null type_handler_null; +Type_handler_bool type_handler_bool; Type_handler_tiny type_handler_tiny; Type_handler_short type_handler_short; Type_handler_long type_handler_long; @@ -41,6 +43,7 @@ Type_handler_olddecimal type_handler_olddecimal; Type_handler_newdecimal type_handler_newdecimal; Type_handler_year type_handler_year; +Type_handler_year type_handler_year2; Type_handler_time type_handler_time; Type_handler_date type_handler_date; Type_handler_timestamp type_handler_timestamp; @@ -56,6 +59,7 @@ Type_handler_set type_handler_set; Type_handler_string type_handler_string; Type_handler_var_string type_handler_var_string; Type_handler_varchar type_handler_varchar; +Type_handler_hex_hybrid type_handler_hex_hybrid; static Type_handler_varchar_compressed type_handler_varchar_compressed; Type_handler_tiny_blob type_handler_tiny_blob; @@ -91,6 +95,9 @@ bool Type_handler_data::init() &type_handler_geometry, &type_handler_geometry) || m_type_aggregator_for_result.add(&type_handler_geometry, + &type_handler_hex_hybrid, + &type_handler_long_blob) || + m_type_aggregator_for_result.add(&type_handler_geometry, &type_handler_tiny_blob, &type_handler_long_blob) || m_type_aggregator_for_result.add(&type_handler_geometry, @@ -125,12 +132,346 @@ bool Type_handler_data::init() Type_handler_data *type_handler_data= NULL; -void Time::make_from_item(Item *item, const Options opt) + +void VDec::set(Item *item) +{ + m_ptr= item->val_decimal(&m_buffer); + DBUG_ASSERT((m_ptr == NULL) == item->null_value); +} + + +VDec::VDec(Item *item) +{ + m_ptr= item->val_decimal(&m_buffer); + DBUG_ASSERT((m_ptr == NULL) == item->null_value); +} + + +VDec_op::VDec_op(Item_func_hybrid_field_type *item) +{ + m_ptr= item->decimal_op(&m_buffer); + DBUG_ASSERT((m_ptr == NULL) == item->null_value); +} + + +bool Dec_ptr::to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, + Item *item) +{ + if (to_datetime_with_warn(to, fuzzydate, item->field_name_or_null())) + return item->null_value|= item->make_zero_date(to, fuzzydate); + return item->null_value= false; +} + + +my_decimal *Temporal::to_decimal(my_decimal *to) const +{ + return date2my_decimal(this, to); +} + + +my_decimal *Temporal::bad_to_decimal(my_decimal *to) const +{ + my_decimal_set_zero(to); + return NULL; +} + + +Temporal_hybrid::Temporal_hybrid(THD *thd, Item *item) +{ + if (item->get_date(this, sql_mode_for_dates(thd))) + time_type= MYSQL_TIMESTAMP_NONE; +} + + +void Sec6::make_from_decimal(const my_decimal *d) +{ + m_neg= my_decimal2seconds(d, &m_sec, &m_usec); + m_truncated= (m_sec >= LONGLONG_MAX); +} + + +void Sec6::make_from_double(double nr) +{ + if ((m_neg= nr < 0)) + nr= -nr; + if ((m_truncated= nr > (double) LONGLONG_MAX)) + { + m_sec= LONGLONG_MAX; + m_usec= 0; + } + else + { + m_sec= (ulonglong) nr; + m_usec= (ulong) ((nr - floor(nr)) * 1000000); + } +} + + +void Sec6::make_truncated_warning(THD *thd, const char *type_str) const +{ + char buff[1 + MAX_BIGINT_WIDTH + 1 + 6 + 1]; // '-' int '.' frac '\0' + to_string(buff, sizeof(buff)); + current_thd->push_warning_truncated_wrong_value(type_str, buff); +} + + +bool Sec6::to_time_with_warn(MYSQL_TIME *to, const ErrConv *str, + const char *field_name) const +{ + int was_cut; + bool res= to_time(to, &was_cut); + if (res || MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut)) + current_thd-> + push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN, + res, "time", str->ptr(), + field_name); + return res; +} + + +bool Sec6::to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, + const ErrConv *str, + const char *field_name) const +{ + bool res, have_warnings= false; + int was_cut; + res= to_datetime(to, fuzzydate, &was_cut); + have_warnings= was_cut && (fuzzydate & TIME_NO_ZERO_IN_DATE); + if (res || have_warnings) + current_thd-> + push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN, + res, "datetime", str->ptr(), + field_name); + return res; +} + + +bool Sec6::convert_to_mysql_time(MYSQL_TIME *ltime, ulonglong fuzzydate, + const ErrConv *str, const char *field_name) + const +{ + bool is_time= fuzzydate & TIME_TIME_ONLY; + if (truncated()) + { + /* + The value was already truncated at the constructor call time, + and a truncation warning was issued. Here we convert silently + to avoid double warnings. + */ + current_thd-> + push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN, + !is_time, + is_time ? "time" : "datetime", + str->ptr(), field_name); + int warn; + return is_time ? to_time(ltime, &warn) : + to_datetime(ltime, fuzzydate, &warn); + } + return is_time ? to_time_with_warn(ltime, str, field_name) : + to_datetime_with_warn(ltime, fuzzydate, str, field_name); +} + + +VSec6::VSec6(Item *item, const char *type_str, ulonglong limit) +{ + if (item->decimals == 0) + { // optimize for an important special case + longlong nr= item->val_int(); + make_from_int(nr, item->unsigned_flag); + m_is_null= item->null_value; + if (!m_is_null && m_sec > limit) + { + m_sec= limit; + m_truncated= true; + ErrConvInteger err(nr, item->unsigned_flag); + current_thd->push_warning_truncated_wrong_value(type_str, err.ptr()); + } + } + else if (item->cmp_type() == REAL_RESULT) + { + double nr= item->val_real(); + make_from_double(nr); + m_is_null= item->null_value; + if (!m_is_null && m_sec > limit) + { + m_sec= limit; + m_truncated= true; + } + if (m_truncated) + { + ErrConvDouble err(nr); + current_thd->push_warning_truncated_wrong_value(type_str, err.ptr()); + } + } + else + { + VDec tmp(item); + (m_is_null= tmp.is_null()) ? reset() : make_from_decimal(tmp.ptr()); + if (!m_is_null && m_sec > limit) + { + m_sec= limit; + m_truncated= true; + } + if (m_truncated) + { + ErrConvDecimal err(tmp.ptr()); + current_thd->push_warning_truncated_wrong_value(type_str, err.ptr()); + } + } +} + + +Year::Year(longlong value, bool unsigned_flag, uint length) { + if ((m_truncated= (value < 0))) // Negative or huge unsigned + m_year= unsigned_flag ? 9999 : 0; + else if (value > 9999) + { + m_truncated= true; + m_year= 9999; + } + else if (length == 2) + { + m_year= value < 70 ? (uint) value + 2000 : + value <= 1900 ? (uint) value + 1900 : + (uint) value; + } + else + m_year= (uint) value; + DBUG_ASSERT(m_year <= 9999); +} + + +uint Year::year_precision(const Item *item) const +{ + return item->type_handler() == &type_handler_year2 ? 2 : 4; +} + + +VYear::VYear(Item *item) + :Year_null(Year(item->val_int(), item->unsigned_flag, + year_precision(item)), item->null_value) +{ } + + +VYear_op::VYear_op(Item_func_hybrid_field_type *item) + :Year_null(Year(item->int_op(), item->unsigned_flag, + year_precision(item)), item->null_value) +{ } + + +void Time::make_from_item(int *warn, Item *item, const Options opt) +{ + *warn= 0; if (item->get_date(this, opt.get_date_flags())) time_type= MYSQL_TIMESTAMP_NONE; else - valid_MYSQL_TIME_to_valid_value(opt); + valid_MYSQL_TIME_to_valid_value(warn, opt); +} + + +/** + Create from a DATETIME by subtracting a given number of days, + implementing an optimized version of calc_time_diff(). +*/ +void Time::make_from_datetime_with_days_diff(int *warn, const MYSQL_TIME *from, + long days) +{ + *warn= 0; + DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATETIME || + from->time_type == MYSQL_TIMESTAMP_DATE); + long daynr= calc_daynr(from->year, from->month, from->day); + long daydiff= daynr - days; + if (!daynr) // Zero date + { + set_zero_time(this, MYSQL_TIMESTAMP_TIME); + neg= true; + hour= TIME_MAX_HOUR + 1; // to report "out of range" in "warn" + } + else if (daydiff >=0) + { + neg= false; + year= month= day= 0; + hhmmssff_copy(from); + hour+= daydiff * 24; + time_type= MYSQL_TIMESTAMP_TIME; + } + else + { + longlong timediff= ((((daydiff * 24LL + + from->hour) * 60LL + + from->minute) * 60LL + + from->second) * 1000000LL + + from->second_part); + unpack_time(timediff, this, MYSQL_TIMESTAMP_TIME); + if (year || month) + { + *warn|= MYSQL_TIME_WARN_OUT_OF_RANGE; + year= month= day= 0; + hour= TIME_MAX_HOUR + 1; + } + } + // The above code can generate TIME values outside of the valid TIME range. + adjust_time_range_or_invalidate(warn); +} + + +void Time::make_from_datetime_move_day_to_hour(int *warn, + const MYSQL_TIME *from) +{ + *warn= 0; + DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATE || + from->time_type == MYSQL_TIMESTAMP_DATETIME); + time_type= MYSQL_TIMESTAMP_TIME; + neg= false; + year= month= day= 0; + hhmmssff_copy(from); + datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(warn, from->year, + from->month, from->day); + adjust_time_range_or_invalidate(warn); +} + + +void Time::make_from_datetime(int *warn, const MYSQL_TIME *from, long curdays) +{ + if (!curdays) + make_from_datetime_move_day_to_hour(warn, from); + else + make_from_datetime_with_days_diff(warn, from, curdays); +} + + +void Time::make_from_time(int *warn, const MYSQL_TIME *from) +{ + DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME); + if (from->year || from->month) + make_from_out_of_range(warn); + else + { + *warn= 0; + DBUG_ASSERT(from->day == 0); + *(static_cast<MYSQL_TIME*>(this))= *from; + adjust_time_range_or_invalidate(warn); + } +} + + +Time::Time(int *warn, const MYSQL_TIME *from, long curdays) +{ + switch (from->time_type) { + case MYSQL_TIMESTAMP_NONE: + case MYSQL_TIMESTAMP_ERROR: + make_from_out_of_range(warn); + break; + case MYSQL_TIMESTAMP_DATE: + case MYSQL_TIMESTAMP_DATETIME: + make_from_datetime(warn, from, curdays); + break; + case MYSQL_TIMESTAMP_TIME: + make_from_time(warn, from); + break; + } + DBUG_ASSERT(is_valid_value_slow()); } @@ -160,6 +501,71 @@ void Temporal_with_date::make_from_item(THD *thd, Item *item, sql_mode_t flags) } +void Temporal_with_date::make_from_item(THD *thd, Item *item) +{ + return make_from_item(thd, item, sql_mode_for_dates(thd)); +} + + +void Temporal_with_date::check_date_or_invalidate(int *warn, sql_mode_t flags) +{ + if (check_date(this, pack_time(this) != 0, flags, warn)) + time_type= MYSQL_TIMESTAMP_NONE; +} + + +void Datetime::make_from_time(THD *thd, int *warn, const MYSQL_TIME *from, + sql_mode_t flags) +{ + DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME); + if (time_to_datetime(thd, from, this)) + make_from_out_of_range(warn); + else + { + *warn= 0; + check_date_or_invalidate(warn, flags); + } +} + + +void Datetime::make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from, + sql_mode_t flags) +{ + DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATE || + from->time_type == MYSQL_TIMESTAMP_DATETIME); + if (from->neg || check_datetime_range(from)) + make_from_out_of_range(warn); + else + { + *warn= 0; + *(static_cast<MYSQL_TIME*>(this))= *from; + date_to_datetime(this); + check_date_or_invalidate(warn, flags); + } +} + + +Datetime::Datetime(THD *thd, int *warn, const MYSQL_TIME *from, + sql_mode_t flags) +{ + DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0); + switch (from->time_type) { + case MYSQL_TIMESTAMP_ERROR: + case MYSQL_TIMESTAMP_NONE: + make_from_out_of_range(warn); + break; + case MYSQL_TIMESTAMP_TIME: + make_from_time(thd, warn, from, flags); + break; + case MYSQL_TIMESTAMP_DATETIME: + case MYSQL_TIMESTAMP_DATE: + make_from_datetime(thd, warn, from, flags); + break; + } + DBUG_ASSERT(is_valid_value_slow()); +} + + uint Type_std_attributes::count_max_decimals(Item **item, uint nitems) { uint res= 0; @@ -280,6 +686,32 @@ bool Type_std_attributes::count_string_length(const char *func_name, } +/* + Find a handler by its ODBC literal data type. + + @param type_str - data type name, not necessarily 0-terminated + @retval - a pointer to data type handler if type_str points + to a known ODBC literal data type, or NULL otherwise +*/ +const Type_handler * +Type_handler::odbc_literal_type_handler(const LEX_CSTRING *type_str) +{ + if (type_str->length == 1) + { + if (type_str->str[0] == 'd') // {d'2001-01-01'} + return &type_handler_newdate; + else if (type_str->str[0] == 't') // {t'10:20:30'} + return &type_handler_time2; + } + else if (type_str->length == 2) // {ts'2001-01-01 10:20:30'} + { + if (type_str->str[0] == 't' && type_str->str[1] == 's') + return &type_handler_datetime2; + } + return NULL; // Not a known ODBC literal type +} + + /** This method is used by: - Item_user_var_as_out_param::field_type() @@ -433,6 +865,7 @@ const Name Type_handler_string::m_name_char(STRING_WITH_LEN("char")), Type_handler_var_string::m_name_var_string(STRING_WITH_LEN("varchar")), Type_handler_varchar::m_name_varchar(STRING_WITH_LEN("varchar")), + Type_handler_hex_hybrid::m_name_hex_hybrid(STRING_WITH_LEN("hex_hybrid")), Type_handler_tiny_blob::m_name_tinyblob(STRING_WITH_LEN("tinyblob")), Type_handler_medium_blob::m_name_mediumblob(STRING_WITH_LEN("mediumblob")), Type_handler_long_blob::m_name_longblob(STRING_WITH_LEN("longblob")), @@ -443,6 +876,7 @@ const Name Type_handler_set::m_name_set(STRING_WITH_LEN("set")); const Name + Type_handler_bool::m_name_bool(STRING_WITH_LEN("boolean")), Type_handler_tiny::m_name_tiny(STRING_WITH_LEN("tinyint")), Type_handler_short::m_name_short(STRING_WITH_LEN("smallint")), Type_handler_long::m_name_int(STRING_WITH_LEN("int")), @@ -465,6 +899,11 @@ const Name Type_handler_datetime_common::m_name_datetime(STRING_WITH_LEN("datetime")), Type_handler_timestamp_common::m_name_timestamp(STRING_WITH_LEN("timestamp")); +const Name + Type_handler::m_version_default(STRING_WITH_LEN("")), + Type_handler::m_version_mariadb53(STRING_WITH_LEN("mariadb-5.3")), + Type_handler::m_version_mysql56(STRING_WITH_LEN("mysql-5.6")); + const Type_limits_int Type_handler_tiny::m_limits_sint8= Type_limits_sint8(), @@ -1604,6 +2043,70 @@ bool Type_handler_bit:: /*************************************************************************/ +void Type_handler_blob_common:: + Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *def, + const Field *field) const +{ + DBUG_ASSERT(def->key_length == 0); +} + + +void Type_handler_typelib:: + Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *def, + const Field *field) const +{ + DBUG_ASSERT(def->flags & (ENUM_FLAG | SET_FLAG)); + def->interval= field->get_typelib(); +} + + +#ifdef HAVE_SPATIAL +void Type_handler_geometry:: + Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *def, + const Field *field) const +{ + def->geom_type= ((Field_geom*) field)->geom_type; + def->srid= ((Field_geom*) field)->srid; +} +#endif + + +void Type_handler_year:: + Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *def, + const Field *field) const +{ + if (def->length != 4) + { + char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; + my_snprintf(buff, sizeof(buff), "YEAR(%llu)", def->length); + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_WARN_DEPRECATED_SYNTAX, + ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX), + buff, "YEAR(4)"); + } +} + + +void Type_handler_real_result:: + Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *def, + const Field *field) const +{ + /* + Floating points are stored with FLOATING_POINT_DECIMALS but internally + in MariaDB used with NOT_FIXED_DEC, which is >= FLOATING_POINT_DECIMALS. + */ + if (def->decimals >= FLOATING_POINT_DECIMALS) + def->decimals= NOT_FIXED_DEC; +} + + +/*************************************************************************/ + bool Type_handler:: Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, @@ -2007,8 +2510,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_char_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); } @@ -2020,8 +2523,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_char_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); } @@ -2032,8 +2535,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_char_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); } @@ -2045,8 +2548,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_char_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); } @@ -2057,8 +2560,8 @@ 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_char_length(), - addr.null_ptr, addr.null_bit, + Field_longlong(addr.ptr(), attr.max_char_length(), + addr.null_ptr(), addr.null_bit(), Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); } @@ -2070,8 +2573,8 @@ Field *Type_handler_vers_trx_id::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_vers_trx_id(addr.ptr, attr.max_char_length(), - addr.null_ptr, addr.null_bit, + Field_vers_trx_id(addr.ptr(), attr.max_char_length(), + addr.null_ptr(), addr.null_bit(), Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); } @@ -2083,8 +2586,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_char_length(), - addr.null_ptr, addr.null_bit, + Field_float(addr.ptr(), attr.max_char_length(), + addr.null_ptr(), addr.null_bit(), Field::NONE, name, (uint8) attr.decimals, 0/*zerofill*/, attr.unsigned_flag); } @@ -2096,8 +2599,8 @@ 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_char_length(), - addr.null_ptr, addr.null_bit, + Field_double(addr.ptr(), attr.max_char_length(), + addr.null_ptr(), addr.null_bit(), Field::NONE, name, (uint8) attr.decimals, 0/*zerofill*/, attr.unsigned_flag); } @@ -2118,7 +2621,8 @@ Type_handler_olddecimal::make_table_field(const LEX_CSTRING *name, */ DBUG_ASSERT(0); return new (table->in_use->mem_root) - Field_decimal(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_decimal(addr.ptr(), attr.max_length, + addr.null_ptr(), addr.null_bit(), Field::NONE, name, (uint8) attr.decimals, 0/*zerofill*/,attr.unsigned_flag); } @@ -2165,7 +2669,7 @@ Type_handler_newdecimal::make_table_field(const LEX_CSTRING *name, len= required_length; } return new (table->in_use->mem_root) - Field_new_decimal(addr.ptr, len, addr.null_ptr, addr.null_bit, + Field_new_decimal(addr.ptr(), len, addr.null_ptr(), addr.null_bit(), Field::NONE, name, dec, 0/*zerofill*/, attr.unsigned_flag); } @@ -2177,7 +2681,8 @@ Field *Type_handler_year::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_year(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_year(addr.ptr(), attr.max_length, + addr.null_ptr(), addr.null_bit(), Field::NONE, name); } @@ -2189,7 +2694,7 @@ Field *Type_handler_null::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) - Field_null(addr.ptr, attr.max_length, + Field_null(addr.ptr(), attr.max_length, Field::NONE, name, attr.collation.collation); } @@ -2201,7 +2706,7 @@ Field *Type_handler_timestamp::make_table_field(const LEX_CSTRING *name, { return new_Field_timestamp(table->in_use->mem_root, - addr.ptr, addr.null_ptr, addr.null_bit, + addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name, table->s, attr.decimals); } @@ -2217,7 +2722,7 @@ Field *Type_handler_timestamp2::make_table_field(const LEX_CSTRING *name, make_table_field() for make_field() purposes in field.cc. */ return new_Field_timestamp(table->in_use->mem_root, - addr.ptr, addr.null_ptr, addr.null_bit, + addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name, table->s, attr.decimals); } @@ -2229,7 +2734,7 @@ Field *Type_handler_newdate::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) - Field_newdate(addr.ptr, addr.null_ptr, addr.null_bit, + Field_newdate(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name); } @@ -2246,7 +2751,7 @@ Field *Type_handler_date::make_table_field(const LEX_CSTRING *name, */ DBUG_ASSERT(0); return new (table->in_use->mem_root) - Field_date(addr.ptr, addr.null_ptr, addr.null_bit, + Field_date(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name); } @@ -2258,7 +2763,7 @@ Field *Type_handler_time::make_table_field(const LEX_CSTRING *name, { return new_Field_time(table->in_use->mem_root, - addr.ptr, addr.null_ptr, addr.null_bit, + addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name, attr.decimals); } @@ -2275,7 +2780,7 @@ Field *Type_handler_time2::make_table_field(const LEX_CSTRING *name, make_table_field() for make_field() purposes in field.cc. */ return new_Field_time(table->in_use->mem_root, - addr.ptr, addr.null_ptr, addr.null_bit, + addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name, attr.decimals); } @@ -2287,7 +2792,7 @@ Field *Type_handler_datetime::make_table_field(const LEX_CSTRING *name, { return new_Field_datetime(table->in_use->mem_root, - addr.ptr, addr.null_ptr, addr.null_bit, + addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name, attr.decimals); } @@ -2302,7 +2807,7 @@ Field *Type_handler_datetime2::make_table_field(const LEX_CSTRING *name, make_table_field() for make_field() purposes in field.cc. */ return new_Field_datetime(table->in_use->mem_root, - addr.ptr, addr.null_ptr, addr.null_bit, + addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name, attr.decimals); } @@ -2314,8 +2819,8 @@ Field *Type_handler_bit::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) - Field_bit_as_char(addr.ptr, attr.max_length, - addr.null_ptr, addr.null_bit, + Field_bit_as_char(addr.ptr(), attr.max_length, + addr.null_ptr(), addr.null_bit(), Field::NONE, name); } @@ -2327,7 +2832,8 @@ Field *Type_handler_string::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) - Field_string(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_string(addr.ptr(), attr.max_length, + addr.null_ptr(), addr.null_bit(), Field::NONE, name, attr.collation); } @@ -2339,9 +2845,9 @@ Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) - Field_varstring(addr.ptr, attr.max_length, + Field_varstring(addr.ptr(), attr.max_length, HA_VARCHAR_PACKLENGTH(attr.max_length), - addr.null_ptr, addr.null_bit, + addr.null_ptr(), addr.null_bit(), Field::NONE, name, table->s, attr.collation); } @@ -2354,7 +2860,7 @@ Field *Type_handler_tiny_blob::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) - Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name, table->s, 1, attr.collation); } @@ -2367,7 +2873,7 @@ Field *Type_handler_blob::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) - Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name, table->s, 2, attr.collation); } @@ -2381,7 +2887,7 @@ Type_handler_medium_blob::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) - Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name, table->s, 3, attr.collation); } @@ -2394,7 +2900,7 @@ Field *Type_handler_long_blob::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) - Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name, table->s, 4, attr.collation); } @@ -2408,7 +2914,7 @@ Field *Type_handler_geometry::make_table_field(const LEX_CSTRING *name, TABLE *table) const { return new (table->in_use->mem_root) - Field_geom(addr.ptr, addr.null_ptr, addr.null_bit, + Field_geom(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE, name, table->s, 4, (Field::geometry_type) attr.uint_geometry_type(), 0); @@ -2424,7 +2930,8 @@ Field *Type_handler_enum::make_table_field(const LEX_CSTRING *name, TYPELIB *typelib= attr.get_typelib(); DBUG_ASSERT(typelib); return new (table->in_use->mem_root) - Field_enum(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_enum(addr.ptr(), attr.max_length, + addr.null_ptr(), addr.null_bit(), Field::NONE, name, get_enum_pack_length(typelib->count), typelib, attr.collation); @@ -2440,7 +2947,8 @@ Field *Type_handler_set::make_table_field(const LEX_CSTRING *name, TYPELIB *typelib= attr.get_typelib(); DBUG_ASSERT(typelib); return new (table->in_use->mem_root) - Field_set(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field_set(addr.ptr(), attr.max_length, + addr.null_ptr(), addr.null_bit(), Field::NONE, name, get_enum_pack_length(typelib->count), typelib, attr.collation); @@ -2512,6 +3020,61 @@ uint32 Type_handler_general_purpose_int::max_display_length(const Item *item) /*************************************************************************/ +void Type_handler_row::Item_update_null_value(Item *item) const +{ + DBUG_ASSERT(0); + item->null_value= true; +} + + +void Type_handler_time_common::Item_update_null_value(Item *item) const +{ + MYSQL_TIME ltime; + (void) item->get_date(<ime, TIME_TIME_ONLY); +} + + +void Type_handler_temporal_with_date::Item_update_null_value(Item *item) const +{ + MYSQL_TIME ltime; + (void) item->get_date(<ime, sql_mode_for_dates(current_thd)); +} + + +void Type_handler_string_result::Item_update_null_value(Item *item) const +{ + StringBuffer<MAX_FIELD_WIDTH> tmp; + (void) item->val_str(&tmp); +} + + +void Type_handler_real_result::Item_update_null_value(Item *item) const +{ + (void) item->val_real(); +} + + +void Type_handler_decimal_result::Item_update_null_value(Item *item) const +{ + my_decimal tmp; + (void) item->val_decimal(&tmp); +} + + +void Type_handler_int_result::Item_update_null_value(Item *item) const +{ + (void) item->val_int(); +} + + +void Type_handler_bool::Item_update_null_value(Item *item) const +{ + (void) item->val_bool(); +} + + +/*************************************************************************/ + int Type_handler_time_common::Item_save_in_field(Item *item, Field *field, bool no_conversions) const { @@ -2704,7 +3267,7 @@ Type_handler_int_result::Item_get_cache(THD *thd, const Item *item) const Item_cache * Type_handler_year::Item_get_cache(THD *thd, const Item *item) const { - return new (thd->mem_root) Item_cache_year(thd); + return new (thd->mem_root) Item_cache_year(thd, item->type_handler()); } Item_cache * @@ -2824,8 +3387,21 @@ bool Type_handler_typelib:: TYPELIB *typelib= NULL; for (uint i= 0; i < nitems; i++) { - if ((typelib= items[i]->get_typelib())) - break; + TYPELIB *typelib2; + if ((typelib2= items[i]->get_typelib())) + { + if (typelib) + { + /* + Two ENUM/SET columns found. We convert such combinations to VARCHAR. + This may change in the future to preserve ENUM/SET + if typelib definitions are equal. + */ + handler->set_handler(&type_handler_varchar); + return func->aggregate_attributes_string(func_name, items, nitems); + } + typelib= typelib2; + } } DBUG_ASSERT(typelib); // There must be at least one typelib func->set_typelib(typelib); @@ -2983,6 +3559,13 @@ bool Type_handler_int_result:: } +bool Type_handler_bool:: + Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const +{ + return Item_sum_hybrid_fix_length_and_dec_numeric(func, &type_handler_bool); +} + + bool Type_handler_real_result:: Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const { @@ -3211,15 +3794,6 @@ bool Type_handler_int_result::Item_val_bool(Item *item) const return item->val_int() != 0; } -bool Type_handler_decimal_result::Item_val_bool(Item *item) const -{ - my_decimal decimal_value; - my_decimal *val= item->val_decimal(&decimal_value); - if (val) - return !my_decimal_is_zero(val); - return false; -} - bool Type_handler_temporal_result::Item_val_bool(Item *item) const { return item->val_real() != 0.0; @@ -3243,7 +3817,9 @@ bool Type_handler_int_result::Item_get_date(Item *item, MYSQL_TIME *ltime, bool Type_handler_year::Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const { - return item->get_date_from_year(ltime, fuzzydate); + return item->null_value= + VYear(item).to_mysql_time_with_warn(ltime, fuzzydate, + item->field_name_or_null()); } @@ -3254,13 +3830,6 @@ bool Type_handler_real_result::Item_get_date(Item *item, MYSQL_TIME *ltime, } -bool Type_handler_decimal_result::Item_get_date(Item *item, MYSQL_TIME *ltime, - ulonglong fuzzydate) const -{ - return item->get_date_from_decimal(ltime, fuzzydate); -} - - bool Type_handler_string_result::Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const { @@ -3324,12 +3893,6 @@ longlong Type_handler_int_result:: 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 { @@ -3390,7 +3953,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_str( Item_func_hybrid_field_type *item, String *str) const { - return item->val_str_from_decimal_op(str); + return VDec_op(item).to_string_round(str, item->decimals); } @@ -3399,7 +3962,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_real( Item_func_hybrid_field_type *item) const { - return item->val_real_from_decimal_op(); + return VDec_op(item).to_double(); } @@ -3408,7 +3971,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_int( Item_func_hybrid_field_type *item) const { - return item->val_int_from_decimal_op(); + return VDec_op(item).to_longlong(item->unsigned_flag); } @@ -3417,7 +3980,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *item, my_decimal *dec) const { - return item->val_decimal_from_decimal_op(dec); + return VDec_op(item).to_decimal(dec); } @@ -3427,7 +3990,18 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_get_date( MYSQL_TIME *ltime, ulonglong fuzzydate) const { - return item->get_date_from_decimal_op(ltime, fuzzydate); + return VDec_op(item).to_datetime_with_warn(ltime, fuzzydate, item); +} + + +bool +Type_handler_year::Item_func_hybrid_field_type_get_date( + Item_func_hybrid_field_type *item, + MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + return item->null_value= + VYear_op(item).to_mysql_time_with_warn(ltime, fuzzydate, NULL); } @@ -3707,10 +4281,16 @@ longlong Type_handler_string_result:: return func->val_int_cmp_string(); } -longlong Type_handler_temporal_result:: +longlong Type_handler_temporal_with_date:: + Item_func_between_val_int(Item_func_between *func) const +{ + return func->val_int_cmp_datetime(); +} + +longlong Type_handler_time_common:: Item_func_between_val_int(Item_func_between *func) const { - return func->val_int_cmp_temporal(); + return func->val_int_cmp_time(); } longlong Type_handler_int_result:: @@ -3930,10 +4510,31 @@ String *Type_handler_string_result:: } -String *Type_handler_temporal_result:: +String *Type_handler_time_common:: + Item_func_min_max_val_str(Item_func_min_max *func, String *str) const +{ + return Time(func).to_string(str, func->decimals); +} + + +String *Type_handler_date_common:: + Item_func_min_max_val_str(Item_func_min_max *func, String *str) const +{ + return Date(func).to_string(str); +} + + +String *Type_handler_datetime_common:: + Item_func_min_max_val_str(Item_func_min_max *func, String *str) const +{ + return Datetime(func).to_string(str, func->decimals); +} + + +String *Type_handler_timestamp_common:: Item_func_min_max_val_str(Item_func_min_max *func, String *str) const { - return func->val_string_from_date(str); + return Datetime(func).to_string(str, func->decimals); } @@ -3947,7 +4548,7 @@ String *Type_handler_int_result:: String *Type_handler_decimal_result:: Item_func_min_max_val_str(Item_func_min_max *func, String *str) const { - return func->val_string_from_decimal(str); + return VDec(func).to_string_round(str, func->decimals); } @@ -4892,7 +5493,7 @@ uint Type_handler_string_result::Item_temporal_precision(Item *item, StringBuffer<64> buf; String *tmp; MYSQL_TIME_STATUS status; - DBUG_ASSERT(item->fixed); + DBUG_ASSERT(item->is_fixed()); if ((tmp= item->val_str(&buf)) && !(is_time ? str_to_time(tmp->charset(), tmp->ptr(), tmp->length(), @@ -5393,11 +5994,10 @@ Item *Type_handler_real_result:: Item *Type_handler_decimal_result:: make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const { - my_decimal decimal_value; - my_decimal *result= item->val_decimal(&decimal_value); - if (item->null_value) + VDec result(item); + if (result.is_null()) return new (thd->mem_root) Item_null(thd, item->name.str); - return new (thd->mem_root) Item_decimal(thd, item->name.str, result, + return new (thd->mem_root) Item_decimal(thd, item->name.str, result.ptr(), item->max_length, item->decimals); } @@ -5787,6 +6387,490 @@ void Type_handler_geometry::Item_param_set_param_func(Item_param *param, /***************************************************************************/ +Field *Type_handler_row:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + DBUG_ASSERT(attr->length == 0); + DBUG_ASSERT(f_maybe_null(attr->pack_flag)); + return new (mem_root) Field_row(rec.ptr(), name); +} + + +Field *Type_handler_olddecimal:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_decimal(rec.ptr(), (uint32) attr->length, + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + f_decimals(attr->pack_flag), + f_is_zerofill(attr->pack_flag) != 0, + f_is_dec(attr->pack_flag) == 0); +} + + +Field *Type_handler_newdecimal:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_new_decimal(rec.ptr(), (uint32) attr->length, + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + f_decimals(attr->pack_flag), + f_is_zerofill(attr->pack_flag) != 0, + f_is_dec(attr->pack_flag) == 0); +} + + +Field *Type_handler_float:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + int decimals= f_decimals(attr->pack_flag); + if (decimals == FLOATING_POINT_DECIMALS) + decimals= NOT_FIXED_DEC; + return new (mem_root) + Field_float(rec.ptr(), (uint32) attr->length, + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, decimals, + f_is_zerofill(attr->pack_flag) != 0, + f_is_dec(attr->pack_flag)== 0); +} + + +Field *Type_handler_double:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + int decimals= f_decimals(attr->pack_flag); + if (decimals == FLOATING_POINT_DECIMALS) + decimals= NOT_FIXED_DEC; + return new (mem_root) + Field_double(rec.ptr(), (uint32) attr->length, + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, decimals, + f_is_zerofill(attr->pack_flag) != 0, + f_is_dec(attr->pack_flag)== 0); +} + + +Field *Type_handler_tiny:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_tiny(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + f_is_zerofill(attr->pack_flag) != 0, + f_is_dec(attr->pack_flag) == 0); +} + + +Field *Type_handler_short:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_short(rec.ptr(), (uint32) attr->length, + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + f_is_zerofill(attr->pack_flag) != 0, + f_is_dec(attr->pack_flag) == 0); +} + + +Field *Type_handler_int24:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_medium(rec.ptr(), (uint32) attr->length, + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + f_is_zerofill(attr->pack_flag) != 0, + f_is_dec(attr->pack_flag) == 0); +} + + +Field *Type_handler_long:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_long(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + f_is_zerofill(attr->pack_flag) != 0, + f_is_dec(attr->pack_flag) == 0); +} + + +Field *Type_handler_longlong:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + if (flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG)) + return new (mem_root) + Field_vers_trx_id(rec.ptr(), (uint32) attr->length, + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + f_is_zerofill(attr->pack_flag) != 0, + f_is_dec(attr->pack_flag) == 0); + return new (mem_root) + Field_longlong(rec.ptr(), (uint32) attr->length, + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + f_is_zerofill(attr->pack_flag) != 0, + f_is_dec(attr->pack_flag) == 0); +} + + +Field *Type_handler_timestamp:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new_Field_timestamp(mem_root, + rec.ptr(), rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, share, + attr->temporal_dec(MAX_DATETIME_WIDTH)); +} + + +Field *Type_handler_timestamp2:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_timestampf(rec.ptr(), rec.null_ptr(), rec.null_bit(), + attr->unireg_check, + name, share, attr->temporal_dec(MAX_DATETIME_WIDTH)); +} + + +Field *Type_handler_year:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_year(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name); +} + + +Field *Type_handler_date:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_date(rec.ptr(),rec.null_ptr(),rec.null_bit(), + attr->unireg_check, name); +} + + +Field *Type_handler_newdate:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_newdate(rec.ptr(), rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name); +} + + +Field *Type_handler_time:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new_Field_time(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + attr->temporal_dec(MIN_TIME_WIDTH)); +} + + +Field *Type_handler_time2:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_timef(rec.ptr(), rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + attr->temporal_dec(MIN_TIME_WIDTH)); +} + + +Field *Type_handler_datetime:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new_Field_datetime(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + attr->temporal_dec(MAX_DATETIME_WIDTH)); +} + + +Field *Type_handler_datetime2:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_datetimef(rec.ptr(), rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + attr->temporal_dec(MAX_DATETIME_WIDTH)); +} + + +Field *Type_handler_null:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_null(rec.ptr(), (uint32) attr->length, attr->unireg_check, + name, attr->charset); +} + + +Field *Type_handler_bit:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return f_bit_as_char(attr->pack_flag) ? + new (mem_root) Field_bit_as_char(rec.ptr(), (uint32) attr->length, + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name) : + new (mem_root) Field_bit(rec.ptr(), (uint32) attr->length, + rec.null_ptr(), rec.null_bit(), + bit.ptr(), bit.offs(), attr->unireg_check, name); +} + + +#ifdef HAVE_SPATIAL +Field *Type_handler_geometry:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + status_var_increment(current_thd->status_var.feature_gis); + return new (mem_root) + Field_geom(rec.ptr(), rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, share, + attr->pack_flag_to_pack_length(), attr->geom_type, attr->srid); +} +#endif + + +Field *Type_handler_string:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_string(rec.ptr(), (uint32) attr->length, + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, attr->charset); +} + + +Field *Type_handler_varchar:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + if (attr->unireg_check == Field::TMYSQL_COMPRESSED) + return new (mem_root) + Field_varstring_compressed(rec.ptr(), (uint32) attr->length, + HA_VARCHAR_PACKLENGTH((uint32) attr->length), + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, share, attr->charset, + zlib_compression_method); + return new (mem_root) + Field_varstring(rec.ptr(), (uint32) attr->length, + HA_VARCHAR_PACKLENGTH((uint32) attr->length), + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, share, attr->charset); +} + + +Field *Type_handler_blob_common:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + if (attr->unireg_check == Field::TMYSQL_COMPRESSED) + return new (mem_root) + Field_blob_compressed(rec.ptr(), rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, share, + attr->pack_flag_to_pack_length(), attr->charset, + zlib_compression_method); + return new (mem_root) + Field_blob(rec.ptr(), rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, share, + attr->pack_flag_to_pack_length(), attr->charset); +} + + +Field *Type_handler_enum:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_enum(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, attr->pack_flag_to_pack_length(), + attr->interval, attr->charset); +} + + +Field *Type_handler_set:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + return new (mem_root) + Field_set(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, attr->pack_flag_to_pack_length(), + attr->interval, attr->charset); +} + + +/***************************************************************************/ + +void Type_handler:: + Column_definition_attributes_frm_pack(const Column_definition_attributes *def, + uchar *buff) const +{ + def->frm_pack_basic(buff); + def->frm_pack_charset(buff); +} + + +#ifdef HAVE_SPATIAL +void Type_handler_geometry:: + Column_definition_attributes_frm_pack(const Column_definition_attributes *def, + uchar *buff) const +{ + def->frm_pack_basic(buff); + buff[11]= 0; + buff[14]= (uchar) def->geom_type; +} +#endif + + +/***************************************************************************/ + +bool Type_handler:: + Column_definition_attributes_frm_unpack(Column_definition_attributes *attr, + TABLE_SHARE *share, + const uchar *buffer, + LEX_CUSTRING *gis_options) + const +{ + attr->frm_unpack_basic(buffer); + return attr->frm_unpack_charset(share, buffer); +} + + +#ifdef HAVE_SPATIAL +bool Type_handler_geometry:: + Column_definition_attributes_frm_unpack(Column_definition_attributes *attr, + TABLE_SHARE *share, + const uchar *buffer, + LEX_CUSTRING *gis_options) + const +{ + uint gis_opt_read, gis_length, gis_decimals; + Field_geom::storage_type st_type; + attr->frm_unpack_basic(buffer); + // charset and geometry_type share the same byte in frm + attr->geom_type= (Field::geometry_type) buffer[14]; + gis_opt_read= gis_field_options_read(gis_options->str, + gis_options->length, + &st_type, &gis_length, + &gis_decimals, &attr->srid); + gis_options->str+= gis_opt_read; + gis_options->length-= gis_opt_read; + return false; +} +#endif + +/***************************************************************************/ + bool Type_handler::Vers_history_point_resolve_unit(THD *thd, Vers_history_point *point) const @@ -5845,3 +6929,360 @@ bool Type_handler_general_purpose_string:: } /***************************************************************************/ + +bool Type_handler_null::Item_const_eq(const Item_const *a, + const Item_const *b, + bool binary_cmp) const +{ + return true; +} + + +bool Type_handler_real_result::Item_const_eq(const Item_const *a, + const Item_const *b, + bool binary_cmp) const +{ + const double *va= a->const_ptr_double(); + const double *vb= b->const_ptr_double(); + return va[0] == vb[0]; +} + + +bool Type_handler_int_result::Item_const_eq(const Item_const *a, + const Item_const *b, + bool binary_cmp) const +{ + const longlong *va= a->const_ptr_longlong(); + const longlong *vb= b->const_ptr_longlong(); + bool res= va[0] == vb[0] && + (va[0] >= 0 || + (a->get_type_all_attributes_from_const()->unsigned_flag == + b->get_type_all_attributes_from_const()->unsigned_flag)); + return res; +} + + +bool Type_handler_string_result::Item_const_eq(const Item_const *a, + const Item_const *b, + bool binary_cmp) const +{ + const String *sa= a->const_ptr_string(); + const String *sb= b->const_ptr_string(); + return binary_cmp ? sa->bin_eq(sb) : + a->get_type_all_attributes_from_const()->collation.collation == + b->get_type_all_attributes_from_const()->collation.collation && + sa->eq(sb, a->get_type_all_attributes_from_const()->collation.collation); +} + + +bool +Type_handler_decimal_result::Item_const_eq(const Item_const *a, + const Item_const *b, + bool binary_cmp) const +{ + const my_decimal *da= a->const_ptr_my_decimal(); + const my_decimal *db= b->const_ptr_my_decimal(); + return !da->cmp(db) && + (!binary_cmp || + a->get_type_all_attributes_from_const()->decimals == + b->get_type_all_attributes_from_const()->decimals); +} + + +bool +Type_handler_temporal_result::Item_const_eq(const Item_const *a, + const Item_const *b, + bool binary_cmp) const +{ + const MYSQL_TIME *ta= a->const_ptr_mysql_time(); + const MYSQL_TIME *tb= b->const_ptr_mysql_time(); + return !my_time_compare(ta, tb) && + (!binary_cmp || + a->get_type_all_attributes_from_const()->decimals == + b->get_type_all_attributes_from_const()->decimals); +} + +/***************************************************************************/ + +const Type_handler * +Type_handler_hex_hybrid::cast_to_int_type_handler() const +{ + return &type_handler_longlong; +} + + +const Type_handler * +Type_handler_hex_hybrid::type_handler_for_system_time() const +{ + return &type_handler_longlong; +} + + +/***************************************************************************/ + +bool Type_handler_row::Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + DBUG_ASSERT(0); + return false; +} + + +bool Type_handler_int_result::Item_eq_value(THD *thd, + const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + longlong value0= a->val_int(); + longlong value1= b->val_int(); + return !a->null_value && !b->null_value && value0 == value1 && + (value0 >= 0 || a->unsigned_flag == b->unsigned_flag); +} + + +bool Type_handler_real_result::Item_eq_value(THD *thd, + const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + double value0= a->val_real(); + double value1= b->val_real(); + return !a->null_value && !b->null_value && value0 == value1; +} + + +bool Type_handler_time_common::Item_eq_value(THD *thd, + const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + longlong value0= a->val_time_packed(); + longlong value1= b->val_time_packed(); + return !a->null_value && !b->null_value && value0 == value1; +} + + +bool Type_handler_temporal_with_date::Item_eq_value(THD *thd, + const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + longlong value0= a->val_datetime_packed(); + longlong value1= b->val_datetime_packed(); + return !a->null_value && !b->null_value && value0 == value1; +} + + +bool Type_handler_string_result::Item_eq_value(THD *thd, + const Type_cmp_attributes *attr, + Item *a, Item *b) const +{ + String *va, *vb; + StringBuffer<128> cmp_value1, cmp_value2; + return (va= a->val_str(&cmp_value1)) && + (vb= b->val_str(&cmp_value2)) && + va->eq(vb, attr->compare_collation()); +} + + +/***************************************************************************/ + +void Type_handler_var_string:: + Column_definition_implicit_upgrade(Column_definition *c) const +{ + // Change old VARCHAR to new VARCHAR + c->set_handler(&type_handler_varchar); +} + + +void Type_handler_time_common:: + Column_definition_implicit_upgrade(Column_definition *c) const +{ + if (opt_mysql56_temporal_format) + c->set_handler(&type_handler_time2); + else + c->set_handler(&type_handler_time); +} + + +void Type_handler_datetime_common:: + Column_definition_implicit_upgrade(Column_definition *c) const +{ + if (opt_mysql56_temporal_format) + c->set_handler(&type_handler_datetime2); + else + c->set_handler(&type_handler_datetime); +} + + +void Type_handler_timestamp_common:: + Column_definition_implicit_upgrade(Column_definition *c) const +{ + if (opt_mysql56_temporal_format) + c->set_handler(&type_handler_timestamp2); + else + c->set_handler(&type_handler_timestamp); +} + + +/***************************************************************************/ + + +int Type_handler_temporal_with_date::stored_field_cmp_to_item(THD *thd, + Field *field, + Item *item) const +{ + MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time; + field->get_date(&field_time, TIME_INVALID_DATES); + item->get_date(&item_time, TIME_INVALID_DATES); + if (item_time.time_type == MYSQL_TIMESTAMP_TIME && + time_to_datetime(thd, &item_time, item_time_cmp= &item_time2)) + return 1; + return my_time_compare(&field_time, item_time_cmp); +} + + +int Type_handler_time_common::stored_field_cmp_to_item(THD *thd, + Field *field, + Item *item) const +{ + MYSQL_TIME field_time, item_time; + field->get_time(&field_time); + item->get_time(&item_time); + return my_time_compare(&field_time, &item_time); +} + + +int Type_handler_string_result::stored_field_cmp_to_item(THD *thd, + Field *field, + Item *item) const +{ + StringBuffer<MAX_FIELD_WIDTH> item_tmp; + StringBuffer<MAX_FIELD_WIDTH> field_tmp; + String *item_result= item->val_str(&item_tmp); + /* + Some implementations of Item::val_str(String*) actually modify + the field Item::null_value, hence we can't check it earlier. + */ + if (item->null_value) + return 0; + String *field_result= field->val_str(&field_tmp); + return sortcmp(field_result, item_result, field->charset()); +} + + +int Type_handler_int_result::stored_field_cmp_to_item(THD *thd, + Field *field, + Item *item) const +{ + DBUG_ASSERT(0); // Not used yet + return 0; +} + + +int Type_handler_real_result::stored_field_cmp_to_item(THD *thd, + Field *field, + Item *item) const +{ + /* + The patch for Bug#13463415 started using this function for comparing + BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode. + Prefixing the auto variables with volatile fixes the problem.... + */ + volatile double result= item->val_real(); + if (item->null_value) + return 0; + volatile double field_result= field->val_real(); + if (field_result < result) + return -1; + else if (field_result > result) + return 1; + return 0; +} + + +/***************************************************************************/ + + +static bool have_important_literal_warnings(const MYSQL_TIME_STATUS *status) +{ + return (status->warnings & ~MYSQL_TIME_NOTE_TRUNCATED) != 0; +} + + +static void literal_warn(THD *thd, const Item *item, + const char *str, size_t length, CHARSET_INFO *cs, + const MYSQL_TIME *ltime, + const MYSQL_TIME_STATUS *st, + const char *typestr, bool send_error) +{ + if (likely(item)) + { + if (st->warnings) // e.g. a note on nanosecond truncation + { + ErrConvString err(str, length, cs); + make_truncated_value_warning(thd, + Sql_condition::time_warn_level(st->warnings), + &err, ltime->time_type, 0); + } + } + else if (send_error) + { + ErrConvString err(str, length, cs); + my_error(ER_WRONG_VALUE, MYF(0), typestr, err.ptr()); + } +} + + +Item_literal * +Type_handler_date_common::create_literal_item(THD *thd, + const char *str, + size_t length, + CHARSET_INFO *cs, + bool send_error) const +{ + MYSQL_TIME_STATUS st; + MYSQL_TIME ltime; + Item_literal *item= NULL; + sql_mode_t flags= sql_mode_for_dates(thd); + if (!str_to_datetime(cs, str, length, <ime, flags, &st) && + ltime.time_type == MYSQL_TIMESTAMP_DATE && !st.warnings) + item= new (thd->mem_root) Item_date_literal(thd, <ime); + literal_warn(thd, item, str, length, cs, <ime, &st, "DATE", send_error); + return item; +} + + +Item_literal * +Type_handler_temporal_with_date::create_literal_item(THD *thd, + const char *str, + size_t length, + CHARSET_INFO *cs, + bool send_error) const +{ + MYSQL_TIME_STATUS st; + MYSQL_TIME ltime; + Item_literal *item= NULL; + sql_mode_t flags= sql_mode_for_dates(thd); + if (!str_to_datetime(cs, str, length, <ime, flags, &st) && + ltime.time_type == MYSQL_TIMESTAMP_DATETIME && + !have_important_literal_warnings(&st)) + item= new (thd->mem_root) Item_datetime_literal(thd, <ime, st.precision); + literal_warn(thd, item, str, length, cs, <ime, &st, "DATETIME", send_error); + return item; +} + + +Item_literal * +Type_handler_time_common::create_literal_item(THD *thd, + const char *str, + size_t length, + CHARSET_INFO *cs, + bool send_error) const +{ + MYSQL_TIME_STATUS st; + MYSQL_TIME ltime; + Item_literal *item= NULL; + if (!str_to_time(cs, str, length, <ime, 0, &st) && + ltime.time_type == MYSQL_TIMESTAMP_TIME && + !have_important_literal_warnings(&st)) + item= new (thd->mem_root) Item_time_literal(thd, <ime, st.precision); + literal_warn(thd, item, str, length, cs, <ime, &st, "TIME", send_error); + return item; +} diff --git a/sql/sql_type.h b/sql/sql_type.h index 1ddcef2da61..40433fdaabd 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -28,7 +28,10 @@ class Field; class Column_definition; +class Column_definition_attributes; class Item; +class Item_const; +class Item_literal; class Item_param; class Item_cache; class Item_func_or_sum; @@ -74,6 +77,438 @@ struct TABLE; struct SORT_FIELD_ATTR; class Vers_history_point; +#define my_charset_numeric my_charset_latin1 + +enum scalar_comparison_op +{ + SCALAR_CMP_EQ, + SCALAR_CMP_EQUAL, + SCALAR_CMP_LT, + SCALAR_CMP_LE, + SCALAR_CMP_GE, + SCALAR_CMP_GT +}; + + +class Dec_ptr +{ +protected: + my_decimal *m_ptr; + Dec_ptr() { } +public: + bool is_null() const { return m_ptr == NULL; } + const my_decimal *ptr() const { return m_ptr; } + const my_decimal *ptr_or(const my_decimal *def) const + { + return m_ptr ? m_ptr : def; + } + my_decimal *to_decimal(my_decimal *to) const + { + if (!m_ptr) + return NULL; + *to= *m_ptr; + return to; + } + double to_double() const { return m_ptr ? m_ptr->to_double() : 0.0; } + longlong to_longlong(bool unsigned_flag) + { return m_ptr ? m_ptr->to_longlong(unsigned_flag) : 0; } + bool to_bool() const { return m_ptr ? m_ptr->to_bool() : false; } + bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, + const char *field_name) + { + return m_ptr ? m_ptr->to_datetime_with_warn(to, fuzzydate, field_name) : + true; + } + bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, Item *item); + String *to_string(String *to) const + { + return m_ptr ? m_ptr->to_string(to) : NULL; + } + String *to_string(String *to, uint prec, uint dec, char filler) + { + return m_ptr ? m_ptr->to_string(to, prec, dec, filler) : NULL; + } + int to_binary(uchar *bin, int prec, int scale) const + { + return (m_ptr ? m_ptr : &decimal_zero)->to_binary(bin, prec, scale); + } + int cmp(const my_decimal *dec) const + { + DBUG_ASSERT(m_ptr); + DBUG_ASSERT(dec); + return m_ptr->cmp(dec); + } + int cmp(const Dec_ptr &other) const + { + return cmp(other.m_ptr); + } +}; + + +// A helper class to handle results of val_decimal(), date_op(), etc. +class Dec_ptr_and_buffer: public Dec_ptr +{ +protected: + my_decimal m_buffer; +public: + int round_to(my_decimal *to, uint scale, decimal_round_mode mode) + { + DBUG_ASSERT(m_ptr); + return m_ptr->round_to(to, scale, mode); + } + int round_self(uint scale, decimal_round_mode mode) + { + return round_to(&m_buffer, scale, mode); + } + String *to_string_round(String *to, uint dec) + { + /* + decimal_round() allows from==to + So it's save even if m_ptr points to m_buffer before this call: + */ + return m_ptr ? m_ptr->to_string_round(to, dec, &m_buffer) : NULL; + } +}; + + +// A helper class to handle val_decimal() results. +class VDec: public Dec_ptr_and_buffer +{ +public: + VDec(): Dec_ptr_and_buffer() { } + VDec(Item *item); + void set(Item *a); +}; + + +// A helper class to handler decimal_op() results. +class VDec_op: public Dec_ptr_and_buffer +{ +public: + VDec_op(Item_func_hybrid_field_type *item); +}; + + +/* + Get and cache val_decimal() values for two items. + If the first value appears to be NULL, the second value is not evaluated. +*/ +class VDec2_lazy +{ +public: + VDec m_a; + VDec m_b; + VDec2_lazy(Item *a, Item *b) :m_a(a) + { + if (!m_a.is_null()) + m_b.set(b); + } + bool has_null() const + { + return m_a.is_null() || m_b.is_null(); + } +}; + + +/** + Class Sec6 represents a fixed point value with 6 fractional digits. + Used e.g. to convert double and my_decimal values to TIME/DATETIME. +*/ + +class Sec6 +{ +protected: + ulonglong m_sec; // The integer part, between 0 and LONGLONG_MAX + ulong m_usec; // The fractional part, between 0 and 999999 + bool m_neg; // false if positive, true of negative + bool m_truncated; // Indicates if the constructor truncated the value + void make_from_decimal(const my_decimal *d); + void make_from_double(double d); + void make_from_int(longlong nr, bool unsigned_val) + { + m_neg= nr < 0 && !unsigned_val; + m_sec= m_neg ? (ulonglong) -nr : (ulonglong) nr; + m_usec= 0; + m_truncated= false; + } + void reset() + { + m_sec= m_usec= m_neg= m_truncated= 0; + } + Sec6() { } +public: + Sec6(bool neg, ulonglong nr, ulong frac) + :m_sec(nr), m_usec(frac), m_neg(neg), m_truncated(false) + { } + Sec6(double nr) + { + make_from_double(nr); + } + Sec6(const my_decimal *d) + { + make_from_decimal(d); + } + Sec6(longlong nr, bool unsigned_val) + { + make_from_int(nr, unsigned_val); + } + bool neg() const { return m_neg; } + bool truncated() const { return m_truncated; } + ulonglong sec() const { return m_sec; } + long usec() const { return m_usec; } + /** + Converts Sec6 to MYSQL_TIME + + @param ltime converted value will be written here + @param fuzzydate conversion flags (TIME_INVALID_DATE, etc) + @param str original number, as an ErrConv. For the warning + @param field_name field name or NULL if not a field. For the warning + @returns false for success, true for a failure + */ + bool convert_to_mysql_time(MYSQL_TIME *ltime, ulonglong fuzzydate, + const ErrConv *str, const char *field_name) const; + + // Convert a number in format hhhmmss.ff to TIME'hhh:mm:ss.ff' + bool to_time(MYSQL_TIME *to, int *warn) const + { + return number_to_time(m_neg, m_sec, m_usec, to, warn); + } + bool to_time_with_warn(MYSQL_TIME *to, const ErrConv *str, + const char *field_name) const; + /* + Convert a number in format YYYYMMDDhhmmss.ff to + TIMESTAMP'YYYY-MM-DD hh:mm:ss.ff' + */ + bool to_datetime(MYSQL_TIME *to, ulonglong flags, int *warn) const + { + if (m_neg) + { + *warn= MYSQL_TIME_WARN_OUT_OF_RANGE; + return true; + } + return number_to_datetime(m_sec, m_usec, to, flags, warn) == -1; + } + bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, + const ErrConv *str, const char *field_name) const; + // Convert elapsed seconds to TIME + bool sec_to_time(MYSQL_TIME *ltime, uint dec) const + { + set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); + ltime->neg= m_neg; + if (m_sec > TIME_MAX_VALUE_SECONDS) + { + // use check_time_range() to set ltime to the max value depending on dec + int unused; + ltime->hour= TIME_MAX_HOUR + 1; + check_time_range(ltime, dec, &unused); + return true; + } + DBUG_ASSERT(usec() <= TIME_MAX_SECOND_PART); + ltime->hour= (uint) (m_sec / 3600); + ltime->minute= (uint) (m_sec % 3600) / 60; + ltime->second= (uint) m_sec % 60; + ltime->second_part= m_usec; + return false; + } + size_t to_string(char *to, size_t nbytes) const + { + return m_usec ? + my_snprintf(to, nbytes, "%s%llu.%06lu", + m_neg ? "-" : "", m_sec, (uint) m_usec) : + my_snprintf(to, nbytes, "%s%llu", m_neg ? "-" : "", m_sec); + } + void make_truncated_warning(THD *thd, const char *type_str) const; +}; + + +class VSec6: public Sec6 +{ + bool m_is_null; +public: + VSec6(Item *item, const char *type_str, ulonglong limit); + bool is_null() const { return m_is_null; } +}; + + +/* + A heler class to perform additive operations between + two MYSQL_TIME structures and return the result as a + combination of seconds, microseconds and sign. +*/ +class Sec6_add +{ + ulonglong m_sec; // number of seconds + ulong m_usec; // number of microseconds + bool m_neg; // false if positive, true if negative + bool m_error; // false if the value is OK, true otherwise + void to_hh24mmssff(MYSQL_TIME *ltime, timestamp_type tstype) const + { + bzero(ltime, sizeof(*ltime)); + ltime->neg= m_neg; + calc_time_from_sec(ltime, (ulong) (m_sec % SECONDS_IN_24H), m_usec); + ltime->time_type= tstype; + } +public: + /* + @param ltime1 - the first value to add (must be a valid DATE,TIME,DATETIME) + @param ltime2 - the second value to add (must be a valid TIME) + @param sign - the sign of the operation + (+1 for addition, -1 for subtraction) + */ + Sec6_add(const MYSQL_TIME *ltime1, const MYSQL_TIME *ltime2, int sign) + { + DBUG_ASSERT(sign == -1 || sign == 1); + DBUG_ASSERT(!ltime1->neg || ltime1->time_type == MYSQL_TIMESTAMP_TIME); + if (!(m_error= (ltime2->time_type != MYSQL_TIMESTAMP_TIME))) + { + if (ltime1->neg != ltime2->neg) + sign= -sign; + m_neg= calc_time_diff(ltime1, ltime2, -sign, &m_sec, &m_usec); + if (ltime1->neg && (m_sec || m_usec)) + m_neg= !m_neg; // Swap sign + } + } + bool to_time(MYSQL_TIME *ltime, uint decimals) const + { + if (m_error) + return true; + to_hh24mmssff(ltime, MYSQL_TIMESTAMP_TIME); + ltime->hour+= to_days_abs() * 24; + return adjust_time_range_with_warn(ltime, decimals); + } + bool to_datetime(MYSQL_TIME *ltime) const + { + if (m_error || m_neg) + return true; + to_hh24mmssff(ltime, MYSQL_TIMESTAMP_DATETIME); + return get_date_from_daynr(to_days_abs(), + <ime->year, <ime->month, <ime->day) || + !ltime->day; + } + long to_days_abs() const { return (long) (m_sec / SECONDS_IN_24H); } +}; + + +class Year +{ +protected: + uint m_year; + bool m_truncated; + bool to_mysql_time_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, + const char *field_name) const + { + longlong value= m_year * 10000; // Make it YYYYMMDD + const ErrConvInteger str(value, true); + Sec6 sec(false, value, 0); + return sec.convert_to_mysql_time(to, fuzzydate, &str, field_name); + } + uint year_precision(const Item *item) const; +public: + Year(): m_year(0), m_truncated(false) { } + Year(longlong value, bool unsigned_flag, uint length); + uint year() const { return m_year; } + bool truncated() const { return m_truncated; } +}; + + +class Year_null: public Year +{ +protected: + bool m_is_null; +public: + Year_null(const Year &other, bool is_null) + :Year(is_null ? Year() : other), + m_is_null(is_null) + { } + bool is_null() const { return m_is_null; } + bool to_mysql_time_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, + const char *field_name) const + { + return m_is_null ? true : + Year::to_mysql_time_with_warn(to, fuzzydate, field_name); + } +}; + + +class VYear: public Year_null +{ +public: + VYear(Item *item); +}; + + +class VYear_op: public Year_null +{ +public: + VYear_op(Item_func_hybrid_field_type *item); +}; + + +class Temporal: protected MYSQL_TIME +{ +protected: + bool is_valid_temporal() const + { + DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR); + return time_type != MYSQL_TIMESTAMP_NONE; + } + my_decimal *bad_to_decimal(my_decimal *to) const; + my_decimal *to_decimal(my_decimal *to) const; + static double to_double(bool negate, ulonglong num, ulong frac) + { + double d= (double) num + frac / (double) TIME_SECOND_PART_FACTOR; + return negate ? -d : d; + } + longlong to_packed() const { return ::pack_time(this); } + void make_from_out_of_range(int *warn) + { + *warn= MYSQL_TIME_WARN_OUT_OF_RANGE; + time_type= MYSQL_TIMESTAMP_NONE; + } +public: + long fraction_remainder(uint dec) const + { + return my_time_fraction_remainder(second_part, dec); + } +}; + + +/* + Use this class when you need to get a MYSQL_TIME from an Item + using Item's native timestamp type, without automatic timestamp + type conversion. +*/ +class Temporal_hybrid: public Temporal +{ +public: + Temporal_hybrid(THD *thd, Item *item); + Temporal_hybrid(Item *item) { *this= Temporal_hybrid(current_thd, item); } + longlong to_longlong() const + { + if (!is_valid_temporal()) + return 0; + ulonglong v= TIME_to_ulonglong(this); + return neg ? -(longlong) v : (longlong) v; + } + double to_double() const + { + return is_valid_temporal() ? TIME_to_double(this) : 0; + } + my_decimal *to_decimal(my_decimal *to) + { + return is_valid_temporal() ? Temporal::to_decimal(to) : bad_to_decimal(to); + } + String *to_string(String *str, uint dec) const + { + if (!is_valid_temporal()) + return NULL; + str->set_charset(&my_charset_numeric); + if (!str->alloc(MAX_DATE_STRING_REP_LENGTH)) + str->length(my_TIME_to_str(this, const_cast<char*>(str->ptr()), dec)); + return str; + } +}; + /** Class Time is designed to store valid TIME values. @@ -93,13 +528,15 @@ class Vers_history_point; Time derives from MYSQL_TIME privately to make sure it is accessed externally only in the valid state. */ -class Time: private MYSQL_TIME +class Time: public Temporal { public: enum datetime_to_time_mode_t { DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS, - DATETIME_TO_TIME_YYYYMMDD_TRUNCATE + DATETIME_TO_TIME_YYYYMMDD_TRUNCATE, + DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY, + DATETIME_TO_TIME_MINUS_CURRENT_DATE }; class Options { @@ -148,41 +585,77 @@ private: second <= TIME_MAX_SECOND && second_part <= TIME_MAX_SECOND_PART; } - + void hhmmssff_copy(const MYSQL_TIME *from) + { + hour= from->hour; + minute= from->minute; + second= from->second; + second_part= from->second_part; + } + void datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(int *warn, + uint from_year, + uint from_month, + uint from_day) + { + if (from_year != 0 || from_month != 0) + *warn|= MYSQL_TIME_NOTE_TRUNCATED; + else + hour+= from_day * 24; + } + /* + The result is calculated effectively similar to: + TIMEDIFF(dt, CAST(CURRENT_DATE AS DATETIME)) + If the difference does not fit to the supported TIME range, it's truncated. + */ + void datetime_to_time_minus_current_date(THD *thd) + { + MYSQL_TIME current_date, tmp; + set_current_date(thd, ¤t_date); + calc_time_diff(this, ¤t_date, 1, &tmp, 0); + static_cast<MYSQL_TIME*>(this)[0]= tmp; + int warnings= 0; + (void) check_time_range(this, TIME_SECOND_PART_DIGITS, &warnings); + DBUG_ASSERT(is_valid_time()); + } /* Convert a valid DATE or DATETIME to TIME. Before this call, "this" must be a valid DATE or DATETIME value, - e.g. returned from Item::get_date(). + e.g. returned from Item::get_date(), str_to_time(), number_to_time(). After this call, "this" is a valid TIME value. */ - void valid_datetime_to_valid_time(const Options opt) + void valid_datetime_to_valid_time(int *warn, const Options opt) { DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATE || time_type == MYSQL_TIMESTAMP_DATETIME); /* - Make sure that day and hour are valid, so the result hour value + We're dealing with a DATE or DATETIME returned from + str_to_time(), number_to_time() or unpack_time(). + Do some asserts to make sure the result hour value after mixing days to hours does not go out of the valid TIME range. + The maximum hour value after mixing days will be 31*24+23=767, + which is within the supported TIME range. + Thus no adjust_time_range_or_invalidate() is needed here. */ DBUG_ASSERT(day < 32); DBUG_ASSERT(hour < 24); - if (year == 0 && month == 0 && - opt.datetime_to_time_mode() == - DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS) + if (opt.datetime_to_time_mode() == DATETIME_TO_TIME_MINUS_CURRENT_DATE) { - /* - The maximum hour value after mixing days will be 31*24+23=767, - which is within the supported TIME range. - Thus no adjust_time_range_or_invalidate() is needed here. - */ - hour+= day * 24; + datetime_to_time_minus_current_date(current_thd); + } + else + { + if (opt.datetime_to_time_mode() == + DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS) + datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(warn, year, month, day); + year= month= day= 0; + time_type= MYSQL_TIMESTAMP_TIME; } - year= month= day= 0; - time_type= MYSQL_TIMESTAMP_TIME; DBUG_ASSERT(is_valid_time_slow()); } /** Convert valid DATE/DATETIME to valid TIME if needed. This method is called after Item::get_date(), + str_to_time(), number_to_time(). which can return only valid TIME/DATE/DATETIME values. Before this call, "this" is: - either a valid TIME/DATE/DATETIME value @@ -192,12 +665,17 @@ private: - either a valid TIME (within the supported TIME range), - or MYSQL_TIMESTAMP_NONE */ - void valid_MYSQL_TIME_to_valid_value(const Options opt) + void valid_MYSQL_TIME_to_valid_value(int *warn, const Options opt) { switch (time_type) { case MYSQL_TIMESTAMP_DATE: case MYSQL_TIMESTAMP_DATETIME: - valid_datetime_to_valid_time(opt); + if (opt.datetime_to_time_mode() == + DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY && + (year || month || day)) + make_from_out_of_range(warn); + else + valid_datetime_to_valid_time(warn, opt); break; case MYSQL_TIMESTAMP_NONE: break; @@ -209,11 +687,73 @@ private: break; } } - void make_from_item(class Item *item, const Options opt); + + /* + This method is called after number_to_time() and str_to_time(), + which can return DATE or DATETIME values. Convert to TIME if needed. + We trust that xxx_to_time() returns a valid TIME/DATE/DATETIME value, + so here we need to do only simple validation. + */ + void xxx_to_time_result_to_valid_value(int *warn, const Options opt) + { + // str_to_time(), number_to_time() never return MYSQL_TIMESTAMP_ERROR + DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR); + valid_MYSQL_TIME_to_valid_value(warn, opt); + } + void adjust_time_range_or_invalidate(int *warn) + { + if (check_time_range(this, TIME_SECOND_PART_DIGITS, warn)) + time_type= MYSQL_TIMESTAMP_NONE; + DBUG_ASSERT(is_valid_value_slow()); + } + void make_from_datetime_move_day_to_hour(int *warn, const MYSQL_TIME *from); + void make_from_datetime_with_days_diff(int *warn, const MYSQL_TIME *from, + long curdays); + void make_from_time(int *warn, const MYSQL_TIME *from); + void make_from_datetime(int *warn, const MYSQL_TIME *from, long curdays); + void make_from_item(int *warn, Item *item, const Options opt); public: + /* + All constructors that accept an "int *warn" parameter initialize *warn. + The old value gets lost. + */ Time() { time_type= MYSQL_TIMESTAMP_NONE; } - Time(Item *item) { make_from_item(item, Options()); } - Time(Item *item, const Options opt) { make_from_item(item, opt); } + Time(Item *item) + { + int warn; + make_from_item(&warn, item, Options()); + } + Time(Item *item, const Options opt) + { + int warn; + make_from_item(&warn, item, opt); + } + Time(int *warn, const MYSQL_TIME *from, long curdays); + Time(int *warn, const char *str, size_t len, CHARSET_INFO *cs, + const Options opt) + { + MYSQL_TIME_STATUS status; + if (str_to_time(cs, str, len, this, opt.get_date_flags(), &status)) + time_type= MYSQL_TIMESTAMP_NONE; + // The below call will optionally add notes to already collected warnings: + xxx_to_time_result_to_valid_value(&status.warnings, opt); + *warn= status.warnings; + } + Time(int *warn, const Sec6 &nr, const Options opt) + { + if (nr.to_time(this, warn)) + time_type= MYSQL_TIMESTAMP_NONE; + xxx_to_time_result_to_valid_value(warn, opt); + } + Time(int *warn, double nr) + :Temporal(Time(warn, Sec6(nr), Options())) + { } + Time(int *warn, longlong nr, bool unsigned_val) + :Temporal(Time(warn, Sec6(nr, unsigned_val), Options())) + { } + Time(int *warn, const my_decimal *d) + :Temporal(Time(warn, Sec6(d), Options())) + { } static sql_mode_t flags_for_get_date() { return TIME_TIME_ONLY | TIME_INVALID_DATES; } static sql_mode_t comparison_flags_for_get_date() @@ -243,8 +783,8 @@ public: { DBUG_ASSERT(is_valid_time_slow()); DBUG_ASSERT(other->is_valid_time_slow()); - longlong p0= pack_time(this); - longlong p1= pack_time(other); + longlong p0= to_packed(); + longlong p1= other->to_packed(); if (p0 < p1) return -1; if (p0 > p1) @@ -260,6 +800,41 @@ public: { return neg ? -to_seconds_abs() : to_seconds_abs(); } + longlong to_longlong() const + { + if (!is_valid_time()) + return 0; + ulonglong v= TIME_to_ulonglong_time(this); + return neg ? -(longlong) v : (longlong) v; + } + double to_double() const + { + return !is_valid_time() ? 0 : + Temporal::to_double(neg, TIME_to_ulonglong_time(this), second_part); + } + String *to_string(String *str, uint dec) const + { + if (!is_valid_time()) + return NULL; + str->set_charset(&my_charset_numeric); + if (!str->alloc(MAX_DATE_STRING_REP_LENGTH)) + str->length(my_time_to_str(this, const_cast<char*>(str->ptr()), dec)); + return str; + } + my_decimal *to_decimal(my_decimal *to) + { + return is_valid_time() ? Temporal::to_decimal(to) : bad_to_decimal(to); + } + longlong to_packed() const + { + return is_valid_time() ? Temporal::to_packed() : 0; + } + Time trunc(uint dec) const + { + Time tm(*this); + my_time_trunc(&tm, dec); + return tm; + } }; @@ -286,14 +861,46 @@ public: it is accessed externally only in the valid state. */ -class Temporal_with_date: protected MYSQL_TIME +class Temporal_with_date: public Temporal { protected: + void check_date_or_invalidate(int *warn, sql_mode_t flags); void make_from_item(THD *thd, Item *item, sql_mode_t flags); + void make_from_item(THD *thd, Item *item); + Temporal_with_date() + { + time_type= MYSQL_TIMESTAMP_NONE; + } Temporal_with_date(THD *thd, Item *item, sql_mode_t flags) { make_from_item(thd, item, flags); } + Temporal_with_date(THD *thd, Item *item) + { + make_from_item(thd, item); + } + Temporal_with_date(int *warn, const Sec6 &nr, sql_mode_t flags) + { + DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0); + if (nr.to_datetime(this, flags, warn)) + time_type= MYSQL_TIMESTAMP_NONE; + } + Temporal_with_date(int *warn, const char *str, size_t len, CHARSET_INFO *cs, + sql_mode_t flags) + { + DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0); + MYSQL_TIME_STATUS status; + if (str_to_datetime(cs, str, len, this, flags, &status)) + time_type= MYSQL_TIMESTAMP_NONE; + *warn= status.warnings; + } +public: + bool check_date_with_warn(ulonglong flags) + { + return ::check_date_with_warn(this, flags, MYSQL_TIMESTAMP_ERROR); + } + static sql_mode_t comparison_flags_for_get_date() + { return TIME_INVALID_DATES | TIME_FUZZY_DATES; } }; @@ -325,6 +932,20 @@ public: datetime_to_date(this); DBUG_ASSERT(is_valid_value_slow()); } + Date(THD *thd, Item *item) + :Temporal_with_date(thd, item) + { + if (time_type == MYSQL_TIMESTAMP_DATETIME) + datetime_to_date(this); + DBUG_ASSERT(is_valid_value_slow()); + } + Date(Item *item) + :Temporal_with_date(current_thd, item) + { + if (time_type == MYSQL_TIMESTAMP_DATETIME) + datetime_to_date(this); + DBUG_ASSERT(is_valid_value_slow()); + } Date(const Temporal_with_date *d) :Temporal_with_date(*d) { @@ -341,6 +962,38 @@ public: DBUG_ASSERT(is_valid_date_slow()); return this; } + bool copy_to_mysql_time(MYSQL_TIME *ltime) const + { + if (time_type == MYSQL_TIMESTAMP_NONE) + { + ltime->time_type= MYSQL_TIMESTAMP_NONE; + return true; + } + DBUG_ASSERT(is_valid_date_slow()); + *ltime= *this; + return false; + } + longlong to_longlong() const + { + return is_valid_date() ? (longlong) TIME_to_ulonglong_date(this) : 0LL; + } + double to_double() const + { + return (double) to_longlong(); + } + String *to_string(String *str) const + { + if (!is_valid_date()) + return NULL; + str->set_charset(&my_charset_numeric); + if (!str->alloc(MAX_DATE_STRING_REP_LENGTH)) + str->length(my_date_to_str(this, const_cast<char*>(str->ptr()))); + return str; + } + my_decimal *to_decimal(my_decimal *to) + { + return is_valid_date() ? Temporal::to_decimal(to) : bad_to_decimal(to); + } }; @@ -365,14 +1018,72 @@ class Datetime: public Temporal_with_date DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATETIME); return !check_datetime_range(this); } + void date_to_datetime_if_needed() + { + if (time_type == MYSQL_TIMESTAMP_DATE) + date_to_datetime(this); + } + void make_from_time(THD *thd, int *warn, const MYSQL_TIME *from, + sql_mode_t flags); + void make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from, + sql_mode_t flags); public: Datetime(THD *thd, Item *item, sql_mode_t flags) :Temporal_with_date(thd, item, flags) { - if (time_type == MYSQL_TIMESTAMP_DATE) - date_to_datetime(this); + date_to_datetime_if_needed(); + DBUG_ASSERT(is_valid_value_slow()); + } + Datetime(THD *thd, Item *item) + :Temporal_with_date(thd, item) + { + date_to_datetime_if_needed(); + DBUG_ASSERT(is_valid_value_slow()); + } + Datetime(Item *item) + :Temporal_with_date(current_thd, item) + { + date_to_datetime_if_needed(); + DBUG_ASSERT(is_valid_value_slow()); + } + Datetime(THD *thd, int *warn, const MYSQL_TIME *from, sql_mode_t flags); + Datetime() + { + set_zero_time(this, MYSQL_TIMESTAMP_DATETIME); + } + Datetime(int *warn, const char *str, size_t len, CHARSET_INFO *cs, + sql_mode_t flags) + :Temporal_with_date(warn, str, len, cs, flags) + { + date_to_datetime_if_needed(); + DBUG_ASSERT(is_valid_value_slow()); + } + Datetime(int *warn, double nr, sql_mode_t flags) + :Temporal_with_date(warn, Sec6(nr), flags) + { + date_to_datetime_if_needed(); + DBUG_ASSERT(is_valid_value_slow()); + } + Datetime(int *warn, const my_decimal *d, sql_mode_t flags) + :Temporal_with_date(warn, Sec6(d), flags) + { + date_to_datetime_if_needed(); DBUG_ASSERT(is_valid_value_slow()); } + /* + Create a Datime object from a longlong number. + Note, unlike in Time(), we don't need an "unsigned_val" here, + as it's not important if overflow happened because + of a negative number, or because of a huge positive number. + */ + Datetime(int *warn, longlong sec, ulong usec, sql_mode_t flags) + :Temporal_with_date(warn, Sec6(false, (ulonglong) sec, usec), flags) + { + Sec6 nr(false, (ulonglong) sec, usec); + date_to_datetime_if_needed(); + DBUG_ASSERT(is_valid_value_slow()); + } + bool is_valid_datetime() const { /* @@ -418,8 +1129,42 @@ public: ltime->time_type= type; return false; } + longlong to_longlong() const + { + return is_valid_datetime() ? + (longlong) TIME_to_ulonglong_datetime(this) : 0LL; + } + double to_double() const + { + return !is_valid_datetime() ? 0 : + Temporal::to_double(neg, TIME_to_ulonglong_datetime(this), second_part); + } + String *to_string(String *str, uint dec) const + { + if (!is_valid_datetime()) + return NULL; + str->set_charset(&my_charset_numeric); + if (!str->alloc(MAX_DATE_STRING_REP_LENGTH)) + str->length(my_datetime_to_str(this, const_cast<char*>(str->ptr()), dec)); + return str; + } + my_decimal *to_decimal(my_decimal *to) + { + return is_valid_datetime() ? Temporal::to_decimal(to) : bad_to_decimal(to); + } + longlong to_packed() const + { + return is_valid_datetime() ? Temporal::to_packed() : 0; + } + Datetime trunc(uint dec) const + { + Datetime tm(*this); + my_time_trunc(&tm, dec); + return tm; + } }; + /* Flags for collation aggregation modes, used in TDCollation::agg(): @@ -445,7 +1190,6 @@ public: #define MY_COLL_CMP_CONV (MY_COLL_ALLOW_CONV | MY_COLL_DISALLOW_NONE) -#define my_charset_numeric my_charset_latin1 #define MY_REPERTOIRE_NUMERIC MY_REPERTOIRE_ASCII @@ -834,6 +1578,14 @@ public: }; +class Type_cmp_attributes +{ +public: + virtual ~Type_cmp_attributes() { } + virtual CHARSET_INFO *compare_collation() const= 0; +}; + + class Type_cast_attributes { CHARSET_INFO *m_charset; @@ -886,28 +1638,67 @@ public: }; -class Record_addr +class Bit_addr { -public: - uchar *ptr; // Position to field in record /** - Byte where the @c NULL bit is stored inside a record. If this Field is a - @c NOT @c NULL field, this member is @c NULL. + Byte where the bit is stored inside a record. + If the corresponding Field is a NOT NULL field, this member is NULL. + */ + uchar *m_ptr; + /** + Offset of the bit inside m_ptr[0], in the range 0..7. */ - uchar *null_ptr; - uchar null_bit; // Bit used to test null bit + uchar m_offs; +public: + Bit_addr() + :m_ptr(NULL), + m_offs(0) + { } + Bit_addr(uchar *ptr, uchar offs) + :m_ptr(ptr), m_offs(offs) + { + DBUG_ASSERT(ptr || offs == 0); + DBUG_ASSERT(offs < 8); + } + Bit_addr(bool maybe_null) + :m_ptr(maybe_null ? (uchar *) "" : NULL), + m_offs(0) + { } + uchar *ptr() const { return m_ptr; } + uchar offs() const { return m_offs; } + uchar bit() const { return m_ptr ? ((uchar) 1) << m_offs : 0; } + void inc() + { + DBUG_ASSERT(m_ptr); + m_ptr+= (m_offs == 7); + m_offs= (m_offs + 1) & 7; + } +}; + + +class Record_addr +{ + uchar *m_ptr; // Position of the field in the record + Bit_addr m_null; // Position and offset of the null bit +public: Record_addr(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg) - :ptr(ptr_arg), - null_ptr(null_ptr_arg), - null_bit(null_bit_arg) + :m_ptr(ptr_arg), + m_null(null_ptr_arg, null_bit_arg) + { } + Record_addr(uchar *ptr, const Bit_addr &null) + :m_ptr(ptr), + m_null(null) { } Record_addr(bool maybe_null) - :ptr(NULL), - null_ptr(maybe_null ? (uchar*) "" : 0), - null_bit(0) + :m_ptr(NULL), + m_null(maybe_null) { } + uchar *ptr() const { return m_ptr; } + const Bit_addr &null() const { return m_null; } + uchar *null_ptr() const { return m_null.ptr(); } + uchar null_bit() const { return m_null.bit(); } }; @@ -982,6 +1773,9 @@ public: class Type_handler { protected: + static const Name m_version_default; + static const Name m_version_mysql56; + static const Name m_version_mariadb53; String *print_item_value_csstr(THD *thd, Item *item, String *str) const; String *print_item_value_temporal(THD *thd, Item *item, String *str, const Name &type_name, String *buf) const; @@ -1014,6 +1808,7 @@ protected: enum_field_types type) const; public: + static const Type_handler *odbc_literal_type_handler(const LEX_CSTRING *str); static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length); static const Type_handler *bit_and_int_mixture_handler(uint max_char_len); @@ -1047,8 +1842,31 @@ public: const Type_handler *h2); virtual const Name name() const= 0; + virtual const Name version() const { return m_version_default; } virtual enum_field_types field_type() const= 0; virtual enum_field_types real_field_type() const { return field_type(); } + /** + Type code which is used for merging of traditional data types for result + (for UNION and for hybrid functions such as COALESCE). + Mapping can be done both ways: old->new, new->old, depending + on the particular data type implementation: + - type_handler_var_string (MySQL-4.1 old VARCHAR) is converted to + new VARCHAR before merging. + field_type_merge_rules[][] returns new VARCHAR. + - type_handler_newdate is converted to old DATE before merging. + field_type_merge_rules[][] returns NEWDATE. + - Temporal type_handler_xxx2 (new MySQL-5.6 types) are converted to + corresponding old type codes before merging (e.g. TIME2->TIME). + field_type_merge_rules[][] returns old type codes (e.g. TIME). + Then old types codes are supposed to convert to new type codes somehow, + but they do not. So UNION and COALESCE create old columns. + This is a bug and should be fixed eventually. + */ + virtual enum_field_types traditional_merge_field_type() const + { + DBUG_ASSERT(is_traditional_type()); + return field_type(); + } virtual Item_result result_type() const= 0; virtual Item_result cmp_type() const= 0; virtual enum_mysql_timestamp_type mysql_timestamp_type() const @@ -1059,6 +1877,25 @@ public: { return false; } + virtual bool is_order_clause_position_type() const + { + return false; + } + virtual bool is_limit_clause_valid_type() const + { + return false; + } + /* + Returns true if this data type supports a hack that + WHERE notnull_column IS NULL + finds zero values, e.g.: + WHERE date_notnull_column IS NULL -> + WHERE date_notnull_column = '0000-00-00' + */ + virtual bool cond_notnull_field_isnull_to_field_eq_zero() const + { + return false; + } /** Check whether a field type can be partially indexed by a key. @param type field type @@ -1097,6 +1934,12 @@ public: { return this; } + virtual const Type_handler *type_handler_for_system_time() const + { + return this; + } + virtual int + stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const= 0; virtual CHARSET_INFO *charset_for_protocol(const Item *item) const; virtual const Type_handler* type_handler_adjusted_to_max_octet_length(uint max_octet_length, @@ -1123,6 +1966,7 @@ public: virtual bool can_return_text() const { return true; } virtual bool can_return_date() const { return true; } virtual bool can_return_time() const { return true; } + virtual bool is_bool_type() const { return false; } 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; @@ -1169,7 +2013,20 @@ public: virtual Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const= 0; + // Automatic upgrade, e.g. for ALTER TABLE t1 FORCE + virtual void Column_definition_implicit_upgrade(Column_definition *c) const + { } + // Fix attributes after the parser virtual bool Column_definition_fix_attributes(Column_definition *c) const= 0; + /* + Fix attributes from an existing field. Used for: + - ALTER TABLE (for columns that do not change) + - DECLARE var TYPE OF t1.col1; (anchored SP variables) + */ + virtual void Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *c, + const Field *field) const + { } virtual bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, @@ -1208,6 +2065,23 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + virtual Field * + make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const= 0; + virtual void + Column_definition_attributes_frm_pack(const Column_definition_attributes *at, + uchar *buff) const; + virtual bool + Column_definition_attributes_frm_unpack(Column_definition_attributes *attr, + TABLE_SHARE *share, + const uchar *buffer, + LEX_CUSTRING *gis_options) const; + virtual void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const= 0; @@ -1217,6 +2091,7 @@ public: virtual uint32 max_display_length(const Item *item) const= 0; virtual uint32 calc_pack_length(uint32 length) const= 0; + virtual void Item_update_null_value(Item *item) const= 0; virtual bool Item_save_in_value(Item *item, st_value *value) const= 0; virtual void Item_param_setup_conversion(THD *thd, Item_param *) const {} virtual void Item_param_set_param_func(Item_param *param, @@ -1295,6 +2170,32 @@ public: Item *src, const Item *cmp) const= 0; virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0; + /** + A builder for literals with data type name prefix, e.g.: + TIME'00:00:00', DATE'2001-01-01', TIMESTAMP'2001-01-01 00:00:00'. + @param thd The current thread + @param str Character literal + @param length Length of str + @param cs Character set of the string + @param send_error Whether to generate an error on failure + + @retval A pointer to a new Item on success + NULL on error (wrong literal value, EOM) + */ + virtual Item_literal *create_literal_item(THD *thd, + const char *str, size_t length, + CHARSET_INFO *cs, + bool send_error) const + { + DBUG_ASSERT(0); + return NULL; + } + Item_literal *create_literal_item(THD *thd, const String *str, + bool send_error) const + { + return create_literal_item(thd, str->ptr(), str->length(), str->charset(), + send_error); + } virtual Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const { @@ -1302,6 +2203,13 @@ public: return NULL; } virtual bool set_comparator_func(Arg_comparator *cmp) const= 0; + virtual bool Item_const_eq(const Item_const *a, const Item_const *b, + bool binary_cmp) const + { + return false; + } + virtual bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const= 0; virtual bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, Type_handler_hybrid_field_type *, @@ -1447,6 +2355,11 @@ public: return ROW_RESULT; } const Type_handler *type_handler_for_comparison() const; + int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const + { + DBUG_ASSERT(0); + return 0; + } bool subquery_type_allows_materialization(const Item *inner, const Item *outer) const { @@ -1469,6 +2382,12 @@ public: { return false; } + void Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *c, + const Field *field) const + { + DBUG_ASSERT(0); + } bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, @@ -1497,6 +2416,13 @@ public: DBUG_ASSERT(0); return NULL; } + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const @@ -1518,6 +2444,8 @@ public: DBUG_ASSERT(0); return 0; } + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; uint Item_decimal_precision(const Item *item) const { DBUG_ASSERT(0); @@ -1533,6 +2461,7 @@ public: DBUG_ASSERT(0); return true; } + void Item_update_null_value(Item *item) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const { DBUG_ASSERT(0); @@ -1764,6 +2693,10 @@ public: Item_result cmp_type() const { return REAL_RESULT; } virtual ~Type_handler_real_result() {} const Type_handler *type_handler_for_comparison() const; + void Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *c, + const Field *field) const; + int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const; bool subquery_type_allows_materialization(const Item *inner, const Item *outer) const; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, @@ -1771,12 +2704,17 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool Item_const_eq(const Item_const *a, const Item_const *b, + bool binary_cmp) const; + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, const st_value *value) const; + void Item_update_null_value(Item *item) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; @@ -1837,6 +2775,11 @@ public: Item_result cmp_type() const { return DECIMAL_RESULT; } virtual ~Type_handler_decimal_result() {}; const Type_handler *type_handler_for_comparison() const; + int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const + { + VDec item_val(item); + return item_val.is_null() ? 0 : my_decimal(field).cmp(item_val.ptr()); + } bool subquery_type_allows_materialization(const Item *inner, const Item *outer) const; Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const; @@ -1848,6 +2791,14 @@ public: uint32 max_display_length(const Item *item) const; Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const; + bool Item_const_eq(const Item_const *a, const Item_const *b, + bool binary_cmp) const; + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const + { + VDec va(a), vb(b); + return va.ptr() && vb.ptr() && !va.cmp(vb); + } uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; void Item_param_set_param_func(Item_param *param, @@ -1860,6 +2811,7 @@ public: { return Item_send_str(item, protocol, buf); } + void Item_update_null_value(Item *item) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; @@ -1873,10 +2825,19 @@ 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_val_bool(Item *item) const; - bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; + bool Item_val_bool(Item *item) const + { + return VDec(item).to_bool(); + } + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const + { + return VDec(item).to_datetime_with_warn(ltime, fuzzydate, item); + } longlong Item_val_int_signed_typecast(Item *item) const; - longlong Item_val_int_unsigned_typecast(Item *item) const; + longlong Item_val_int_unsigned_typecast(Item *item) const + { + return VDec(item).to_longlong(true); + } 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; @@ -2038,8 +2999,11 @@ class Type_handler_int_result: public Type_handler_numeric public: Item_result result_type() const { return INT_RESULT; } Item_result cmp_type() const { return INT_RESULT; } + bool is_order_clause_position_type() const { return true; } + bool is_limit_clause_valid_type() const { return true; } virtual ~Type_handler_int_result() {} const Type_handler *type_handler_for_comparison() const; + int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const; bool subquery_type_allows_materialization(const Item *inner, const Item *outer) const; Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const; @@ -2048,12 +3012,17 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool Item_const_eq(const Item_const *a, const Item_const *b, + bool binary_cmp) const; + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; uint Item_decimal_precision(const Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, const st_value *value) const; + void Item_update_null_value(Item *item) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; @@ -2099,6 +3068,7 @@ public: bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const; bool Item_func_div_fix_length_and_dec(Item_func_div *) const; bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const; + }; @@ -2127,6 +3097,8 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool Item_const_eq(const Item_const *a, const Item_const *b, + bool binary_cmp) const; bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, @@ -2159,7 +3131,6 @@ public: bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *, MYSQL_TIME *, ulonglong fuzzydate) const; - String *Item_func_min_max_val_str(Item_func_min_max *, String *) const; double Item_func_min_max_val_real(Item_func_min_max *) const; longlong Item_func_min_max_val_int(Item_func_min_max *) const; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, @@ -2167,7 +3138,6 @@ public: bool Item_func_min_max_get_date(Item_func_min_max*, MYSQL_TIME *, ulonglong fuzzydate) const; bool Item_func_between_fix_length_and_dec(Item_func_between *func) const; - longlong Item_func_between_val_int(Item_func_between *func) const; bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *) const; bool Item_func_round_fix_length_and_dec(Item_func_round *) const; @@ -2192,6 +3162,7 @@ public: CHARSET_INFO *charset_for_protocol(const Item *item) const; virtual ~Type_handler_string_result() {} const Type_handler *type_handler_for_comparison() const; + int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const; const Type_handler * type_handler_adjusted_to_max_octet_length(uint max_octet_length, CHARSET_INFO *cs) const; @@ -2211,6 +3182,10 @@ public: const Schema_specification_st *schema) const; uint32 max_display_length(const Item *item) const; + bool Item_const_eq(const Item_const *a, const Item_const *b, + bool binary_cmp) const; + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; uint Item_time_precision(Item *item) const { return Item_temporal_precision(item, true); @@ -2220,6 +3195,7 @@ public: return Item_temporal_precision(item, false); } uint Item_decimal_precision(const Item *item) const; + void Item_update_null_value(Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; void Item_param_setup_conversion(THD *thd, Item_param *) const; void Item_param_set_param_func(Item_param *param, @@ -2357,6 +3333,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const; }; @@ -2391,6 +3374,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const; }; @@ -2425,11 +3415,29 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const; }; +class Type_handler_bool: public Type_handler_long +{ + static const Name m_name_bool; +public: + const Name name() const { return m_name_bool; } + bool is_bool_type() const { return true; } + void Item_update_null_value(Item *item) const; + bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const; +}; + + class Type_handler_longlong: public Type_handler_general_purpose_int { static const Name m_name_longlong; @@ -2463,6 +3471,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const; }; @@ -2508,6 +3523,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -2527,6 +3549,9 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + void Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *c, + const Field *field) const; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const @@ -2535,8 +3560,18 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; + bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *item, + MYSQL_TIME *to, + ulonglong fuzzydate) const; }; @@ -2577,6 +3612,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const; }; @@ -2607,6 +3649,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const; }; @@ -2639,6 +3688,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const; }; @@ -2655,8 +3711,12 @@ public: { return MYSQL_TIMESTAMP_TIME; } + Item_literal *create_literal_item(THD *thd, const char *str, size_t length, + CHARSET_INFO *cs, bool send_error) const; Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const; + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; uint Item_decimal_scale(const Item *item) const { return Item_decimal_scale_with_seconds(item); @@ -2667,12 +3727,15 @@ public: return Item_divisor_precision_increment_with_seconds(item); } const Type_handler *type_handler_for_comparison() const; + int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const; + void Column_definition_implicit_upgrade(Column_definition *c) const; bool Column_definition_fix_attributes(Column_definition *c) const; bool Item_save_in_value(Item *item, st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_time(item, protocol, buf); } + void Item_update_null_value(Item *item) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; String *print_item_value(THD *thd, Item *item, String *str) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; @@ -2693,8 +3756,10 @@ public: bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *, MYSQL_TIME *, ulonglong fuzzydate) const; + String *Item_func_min_max_val_str(Item_func_min_max *, String *) const; bool Item_func_min_max_get_date(Item_func_min_max*, MYSQL_TIME *, ulonglong fuzzydate) const; + longlong Item_func_between_val_int(Item_func_between *func) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; bool set_comparator_func(Arg_comparator *cmp) const; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const; @@ -2711,6 +3776,7 @@ class Type_handler_time: public Type_handler_time_common public: static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; } virtual ~Type_handler_time() {} + const Name version() const { return m_version_mariadb53; } uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; @@ -2722,6 +3788,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -2729,6 +3802,7 @@ class Type_handler_time2: public Type_handler_time_common { public: virtual ~Type_handler_time2() {} + const Name version() const { return m_version_mysql56; } enum_field_types real_field_type() const { return MYSQL_TYPE_TIME2; } uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, @@ -2741,6 +3815,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -2748,16 +3829,23 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result { public: virtual ~Type_handler_temporal_with_date() {} + Item_literal *create_literal_item(THD *thd, const char *str, size_t length, + CHARSET_INFO *cs, bool send_error) const; + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const; + int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const; bool Item_save_in_value(Item *item, st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_date(item, protocol, buf); } + void Item_update_null_value(Item *item) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; bool set_comparator_func(Arg_comparator *cmp) const; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const; in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const; + longlong Item_func_between_val_int(Item_func_between *func) const; }; @@ -2773,12 +3861,19 @@ public: { return MYSQL_TIMESTAMP_DATE; } + bool cond_notnull_field_isnull_to_field_eq_zero() const + { + return true; + } + Item_literal *create_literal_item(THD *thd, const char *str, size_t length, + CHARSET_INFO *cs, bool send_error) const; Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const; bool Column_definition_fix_attributes(Column_definition *c) const; uint Item_decimal_precision(const Item *item) const; String *print_item_value(THD *thd, Item *item, String *str) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; + String *Item_func_min_max_val_str(Item_func_min_max *, String *) const; bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, Type_handler_hybrid_field_type *, @@ -2803,6 +3898,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -2822,6 +3924,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -2837,8 +3946,13 @@ public: { return MYSQL_TIMESTAMP_DATETIME; } + bool cond_notnull_field_isnull_to_field_eq_zero() const + { + return true; + } Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const; + void Column_definition_implicit_upgrade(Column_definition *c) const; bool Column_definition_fix_attributes(Column_definition *c) const; uint Item_decimal_scale(const Item *item) const { @@ -2855,6 +3969,7 @@ public: } String *print_item_value(THD *thd, Item *item, String *str) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; + String *Item_func_min_max_val_str(Item_func_min_max *, String *) const; bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, Type_handler_hybrid_field_type *, @@ -2872,6 +3987,7 @@ class Type_handler_datetime: public Type_handler_datetime_common public: static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; } virtual ~Type_handler_datetime() {} + const Name version() const { return m_version_mariadb53; } uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; @@ -2883,6 +3999,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -2890,6 +4013,7 @@ class Type_handler_datetime2: public Type_handler_datetime_common { public: virtual ~Type_handler_datetime2() {} + const Name version() const { return m_version_mysql56; } enum_field_types real_field_type() const { return MYSQL_TYPE_DATETIME2; } uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, @@ -2902,6 +4026,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -2921,6 +4052,7 @@ public: { return true; } + void Column_definition_implicit_upgrade(Column_definition *c) const; bool Column_definition_fix_attributes(Column_definition *c) const; uint Item_decimal_scale(const Item *item) const { @@ -2937,6 +4069,7 @@ public: } String *print_item_value(THD *thd, Item *item, String *str) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; + String *Item_func_min_max_val_str(Item_func_min_max *, String *) const; bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, Type_handler_hybrid_field_type *, @@ -2954,6 +4087,7 @@ class Type_handler_timestamp: public Type_handler_timestamp_common public: static uint sec_part_bytes(uint dec) { return m_sec_part_bytes[dec]; } virtual ~Type_handler_timestamp() {} + const Name version() const { return m_version_mariadb53; } uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; @@ -2965,6 +4099,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -2972,6 +4113,7 @@ class Type_handler_timestamp2: public Type_handler_timestamp_common { public: virtual ~Type_handler_timestamp2() {} + const Name version() const { return m_version_mysql56; } enum_field_types real_field_type() const { return MYSQL_TYPE_TIMESTAMP2; } uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, @@ -2986,6 +4128,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -3010,6 +4159,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -3041,6 +4197,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -3056,6 +4219,8 @@ public: const Type_handler *type_handler_for_union(const Item *) const; uint32 max_display_length(const Item *item) const { return 0; } uint32 calc_pack_length(uint32 length) const { return 0; } + bool Item_const_eq(const Item_const *a, const Item_const *b, + bool binary_cmp) const; bool Item_save_in_value(Item *item, st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const; Field *make_conversion_table_field(TABLE *, uint metadata, @@ -3079,6 +4244,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -3115,6 +4287,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -3127,10 +4306,15 @@ public: const Name name() const { return m_name_var_string; } enum_field_types field_type() const { return MYSQL_TYPE_VAR_STRING; } enum_field_types real_field_type() const { return MYSQL_TYPE_STRING; } + enum_field_types traditional_merge_field_type() const + { + return MYSQL_TYPE_VARCHAR; + } const Type_handler *type_handler_for_tmp_table(const Item *item) const { return varstring_type_handler(item); } + void Column_definition_implicit_upgrade(Column_definition *c) const; bool Column_definition_fix_attributes(Column_definition *c) const; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, @@ -3173,10 +4357,28 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; bool adjust_spparam_type(Spvar_definition *def, Item *from) const; }; +class Type_handler_hex_hybrid: public Type_handler_varchar +{ + static const Name m_name_hex_hybrid; +public: + virtual ~Type_handler_hex_hybrid() {} + const Name name() const { return m_name_hex_hybrid; } + const Type_handler *cast_to_int_type_handler() const; + const Type_handler *type_handler_for_system_time() const; +}; + + class Type_handler_varchar_compressed: public Type_handler_varchar { public: @@ -3206,6 +4408,9 @@ public: } bool is_param_long_data_type() const { return true; } bool Column_definition_fix_attributes(Column_definition *c) const; + void Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *c, + const Field *field) const; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const; @@ -3216,6 +4421,13 @@ public: Item **items, uint nitems) const; void Item_param_setup_conversion(THD *thd, Item_param *) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -3317,7 +4529,18 @@ public: const st_value *value) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + void + Column_definition_attributes_frm_pack(const Column_definition_attributes *at, + uchar *buff) const; + bool + Column_definition_attributes_frm_unpack(Column_definition_attributes *attr, + TABLE_SHARE *share, + const uchar *buffer, + LEX_CUSTRING *gis_options) const; bool Column_definition_fix_attributes(Column_definition *c) const; + void Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *c, + const Field *field) const; bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, @@ -3331,6 +4554,14 @@ public: const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; + bool can_return_int() const { return false; } bool can_return_decimal() const { return false; } bool can_return_real() const { return false; } @@ -3380,6 +4611,9 @@ public: Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const; + void Column_definition_reuse_fix_attributes(THD *thd, + Column_definition *c, + const Field *field) const; bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, @@ -3402,7 +4636,11 @@ class Type_handler_enum: public Type_handler_typelib public: virtual ~Type_handler_enum() {} const Name name() const { return m_name_enum; } - virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; } + enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; } + enum_field_types traditional_merge_field_type() const + { + return MYSQL_TYPE_ENUM; + } uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; @@ -3414,6 +4652,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -3423,7 +4668,11 @@ class Type_handler_set: public Type_handler_typelib public: virtual ~Type_handler_set() {} const Name name() const { return m_name_set; } - virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; } + enum_field_types real_field_type() const { return MYSQL_TYPE_SET; } + enum_field_types traditional_merge_field_type() const + { + return MYSQL_TYPE_SET; + } uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; @@ -3435,6 +4684,13 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const; }; @@ -3535,12 +4791,14 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_set type_handler_set; extern MYSQL_PLUGIN_IMPORT Type_handler_string type_handler_string; extern MYSQL_PLUGIN_IMPORT Type_handler_var_string type_handler_var_string; extern MYSQL_PLUGIN_IMPORT Type_handler_varchar type_handler_varchar; +extern MYSQL_PLUGIN_IMPORT Type_handler_hex_hybrid type_handler_hex_hybrid; extern MYSQL_PLUGIN_IMPORT Type_handler_tiny_blob type_handler_tiny_blob; extern MYSQL_PLUGIN_IMPORT Type_handler_medium_blob type_handler_medium_blob; extern MYSQL_PLUGIN_IMPORT Type_handler_long_blob type_handler_long_blob; extern MYSQL_PLUGIN_IMPORT Type_handler_blob type_handler_blob; +extern MYSQL_PLUGIN_IMPORT Type_handler_bool type_handler_bool; extern MYSQL_PLUGIN_IMPORT Type_handler_tiny type_handler_tiny; extern MYSQL_PLUGIN_IMPORT Type_handler_short type_handler_short; extern MYSQL_PLUGIN_IMPORT Type_handler_int24 type_handler_int24; @@ -3553,6 +4811,7 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_newdecimal type_handler_newdecimal; extern MYSQL_PLUGIN_IMPORT Type_handler_olddecimal type_handler_olddecimal; extern MYSQL_PLUGIN_IMPORT Type_handler_year type_handler_year; +extern MYSQL_PLUGIN_IMPORT Type_handler_year type_handler_year2; extern MYSQL_PLUGIN_IMPORT Type_handler_newdate type_handler_newdate; extern MYSQL_PLUGIN_IMPORT Type_handler_date type_handler_date; extern MYSQL_PLUGIN_IMPORT Type_handler_time type_handler_time; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index c8bf9bda57b..29ea427842f 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -68,7 +68,7 @@ void select_unit::change_select() curr_sel= current_select_number; /* New SELECT processing starts */ DBUG_ASSERT(table->file->inited == 0); - step= thd->lex->current_select->linkage; + step= thd->lex->current_select->get_linkage(); switch (step) { case INTERSECT_TYPE: @@ -248,7 +248,7 @@ bool select_unit::send_eof() { if (step != INTERSECT_TYPE || (thd->lex->current_select->next_select() && - thd->lex->current_select->next_select()->linkage == INTERSECT_TYPE)) + thd->lex->current_select->next_select()->get_linkage() == INTERSECT_TYPE)) { /* it is not INTESECT or next SELECT in the sequence is INTERSECT so no @@ -752,11 +752,11 @@ bool st_select_lex_unit::join_union_type_attributes(THD *thd_arg, been fixed yet. An Item_type_holder must be created based on a fixed Item, so use the inner Item instead. */ - DBUG_ASSERT(item_tmp->fixed || + DBUG_ASSERT(item_tmp->is_fixed() || (item_tmp->type() == Item::REF_ITEM && ((Item_ref *)(item_tmp))->ref_type() == Item_ref::OUTER_REF)); - if (!item_tmp->fixed) + if (!item_tmp->is_fixed()) item_tmp= item_tmp->real_item(); holders[holder_pos].add_argument(item_tmp); } @@ -1419,7 +1419,7 @@ bool st_select_lex_unit::exec() union_result->change_select(); if (fake_select_lex) { - if (sl != &thd->lex->select_lex) + if (sl != thd->lex->first_select_lex()) fake_select_lex->uncacheable|= sl->uncacheable; else fake_select_lex->uncacheable= 0; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index cb7bcdc33a1..6994ffa04a9 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -318,7 +318,7 @@ int mysql_update(THD *thd, SQL_SELECT *select= NULL; SORT_INFO *file_sort= 0; READ_RECORD info; - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); ulonglong id; List<Item> all_fields; killed_state killed_status= NOT_KILLED; @@ -375,7 +375,7 @@ int mysql_update(THD *thd, table->covering_keys= table->s->keys_in_use; table->quick_keys.clear_all(); - query_plan.select_lex= &thd->lex->select_lex; + query_plan.select_lex= thd->lex->first_select_lex(); query_plan.table= table; #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Force privilege re-checking for views after they have been opened. */ @@ -977,7 +977,7 @@ update_begin: myf flags= 0; if (table->file->is_fatal_error(error, HA_CHECK_ALL)) - flags|= ME_FATALERROR; /* Other handler errors are fatal */ + flags|= ME_FATAL; /* Other handler errors are fatal */ prepare_record_for_error_message(error, table); table->file->print_error(error,MYF(flags)); @@ -1088,7 +1088,7 @@ update_begin: { /* purecov: begin inspected */ prepare_record_for_error_message(loc_error, table); - table->file->print_error(loc_error,MYF(ME_FATALERROR)); + table->file->print_error(loc_error,MYF(ME_FATAL)); error= 1; /* purecov: end */ } @@ -1246,7 +1246,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, TABLE *table= table_list->table; #endif List<Item> all_fields; - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); DBUG_ENTER("mysql_prepare_update"); #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1523,7 +1523,7 @@ int mysql_multi_update_prepare(THD *thd) LEX *lex= thd->lex; TABLE_LIST *table_list= lex->query_tables; TABLE_LIST *tl; - List<Item> *fields= &lex->select_lex.item_list; + List<Item> *fields= &lex->first_select_lex()->item_list; table_map tables_for_update; bool update_view= 0; /* @@ -1565,14 +1565,15 @@ int mysql_multi_update_prepare(THD *thd) if (mysql_handle_derived(lex, DT_PREPARE)) DBUG_RETURN(TRUE); - if (setup_tables_and_check_access(thd, &lex->select_lex.context, - &lex->select_lex.top_join_list, + if (setup_tables_and_check_access(thd, + &lex->first_select_lex()->context, + &lex->first_select_lex()->top_join_list, table_list, - lex->select_lex.leaf_tables, FALSE, - UPDATE_ACL, SELECT_ACL, FALSE)) + lex->first_select_lex()->leaf_tables, + FALSE, UPDATE_ACL, SELECT_ACL, FALSE)) DBUG_RETURN(TRUE); - if (lex->select_lex.handle_derived(thd->lex, DT_MERGE)) + if (lex->first_select_lex()->handle_derived(thd->lex, DT_MERGE)) DBUG_RETURN(TRUE); if (setup_fields_with_no_wrap(thd, Ref_ptr_array(), @@ -1595,13 +1596,14 @@ int mysql_multi_update_prepare(THD *thd) thd->table_map_for_update= tables_for_update= get_table_map(fields); - if (unsafe_key_update(lex->select_lex.leaf_tables, tables_for_update)) + if (unsafe_key_update(lex->first_select_lex()->leaf_tables, + tables_for_update)) DBUG_RETURN(true); /* Setup timestamp handling and locking mode */ - List_iterator<TABLE_LIST> ti(lex->select_lex.leaf_tables); + List_iterator<TABLE_LIST> ti(lex->first_select_lex()->leaf_tables); while ((tl= ti++)) { TABLE *table= tl->table; @@ -1694,7 +1696,7 @@ int mysql_multi_update_prepare(THD *thd) Check that we are not using table that we are updating, but we should skip all tables of UPDATE SELECT itself */ - lex->select_lex.exclude_from_table_unique_test= TRUE; + lex->first_select_lex()->exclude_from_table_unique_test= TRUE; /* We only need SELECT privilege for columns in the values list */ ti.rewind(); while ((tl= ti++)) @@ -1716,7 +1718,7 @@ int mysql_multi_update_prepare(THD *thd) Set exclude_from_table_unique_test value back to FALSE. It is needed for further check in multi_update::prepare whether to use record cache. */ - lex->select_lex.exclude_from_table_unique_test= FALSE; + lex->first_select_lex()->exclude_from_table_unique_test= FALSE; if (lex->save_prep_leaf_tables()) DBUG_RETURN(TRUE); @@ -1745,7 +1747,7 @@ bool mysql_multi_update(THD *thd, DBUG_ENTER("mysql_multi_update"); if (!(*result= new (thd->mem_root) multi_update(thd, table_list, - &thd->lex->select_lex.leaf_tables, + &thd->lex->first_select_lex()->leaf_tables, fields, values, handle_duplicates, ignore))) { @@ -2248,11 +2250,11 @@ int multi_update::prepare2(JOIN *join) { if (item_rowid_table(*it2) != tbl) continue; - Item *fld= new (thd->mem_root) - Item_field(thd, (*it)->get_tmp_table_field()); + Item_field *fld= new (thd->mem_root) + Item_field(thd, (*it)->get_tmp_table_field()); if (!fld) return 1; - fld->set_result_field((*it2)->get_tmp_table_field()); + fld->result_field= (*it2)->get_tmp_table_field(); *it2= fld; } } @@ -2384,7 +2386,7 @@ int multi_update::send_data(List<Item> ¬_used_values) myf flags= 0; if (table->file->is_fatal_error(error, HA_CHECK_ALL)) - flags|= ME_FATALERROR; /* Other handler errors are fatal */ + flags|= ME_FATAL; /* Other handler errors are fatal */ prepare_record_for_error_message(error, table); table->file->print_error(error,MYF(flags)); @@ -2539,17 +2541,10 @@ int multi_update::do_updates() not its dependencies */ while(TABLE *tbl= check_opt_it++) - { - if (tbl->vcol_set) - { - bitmap_clear_all(tbl->vcol_set); - for (Field **vf= tbl->vfield; *vf; vf++) - { + if (Field **vf= tbl->vfield) + for (; *vf; vf++) if (bitmap_is_set(tbl->read_set, (*vf)->field_index)) - tbl->mark_virtual_col(*vf); - } - } - } + (*vf)->vcol_info->expr->walk(&Item::register_field_in_read_map, 1, 0); for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local) { @@ -2639,10 +2634,10 @@ int multi_update::do_updates() uint field_num= 0; do { - if (unlikely((local_error= - tbl->file->ha_rnd_pos(tbl->record[0], - (uchar *) tmp_table-> - field[field_num]->ptr)))) + String rowid; + tmp_table->field[field_num]->val_str(&rowid); + if (unlikely((local_error= tbl->file->ha_rnd_pos(tbl->record[0], + (uchar*)rowid.ptr())))) { err_table= tbl; goto err; @@ -2759,7 +2754,7 @@ int multi_update::do_updates() err: { prepare_record_for_error_message(local_error, err_table); - err_table->file->print_error(local_error,MYF(ME_FATALERROR)); + err_table->file->print_error(local_error,MYF(ME_FATAL)); } err2: diff --git a/sql/sql_view.cc b/sql/sql_view.cc index f262daad89d..f2fc4b6bf75 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -254,7 +254,7 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, LEX *lex= thd->lex; /* first table in list is target VIEW name => cut off it */ TABLE_LIST *tbl; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); SELECT_LEX *sl; bool res= TRUE; DBUG_ENTER("create_view_precheck"); @@ -323,7 +323,6 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, } } - if (&lex->select_lex != lex->all_selects_list) { /* check tables of subqueries */ for (tbl= tables; tbl; tbl= tbl->next_global) @@ -399,7 +398,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, TABLE_LIST *view= lex->unlink_first_table(&link_to_local); TABLE_LIST *tables= lex->query_tables; TABLE_LIST *tbl; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); SELECT_LEX *sl; SELECT_LEX_UNIT *unit= &lex->unit; bool res= FALSE; @@ -995,7 +994,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, view->algorithm != VIEW_ALGORITHM_TMPTABLE))) { /* TODO: change here when we will support UNIONs */ - for (TABLE_LIST *tbl= lex->select_lex.table_list.first; + for (TABLE_LIST *tbl= lex->first_select_lex()->table_list.first; tbl; tbl= tbl->next_local) { @@ -1114,8 +1113,8 @@ loop_out: UNION */ if (view->updatable_view && - !lex->select_lex.master_unit()->is_unit_op() && - !(lex->select_lex.table_list.first)->next_local && + !lex->first_select_lex()->master_unit()->is_unit_op() && + !(lex->first_select_lex()->table_list.first)->next_local && find_table_in_global_list(lex->query_tables->next_global, &lex->query_tables->db, &lex->query_tables->table_name)) @@ -1162,7 +1161,8 @@ err: bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, bool open_view_no_parse) { - SELECT_LEX *end, *UNINIT_VAR(view_select); + SELECT_LEX_NODE *end; + SELECT_LEX *UNINIT_VAR(view_select); LEX *old_lex, *lex; Query_arena *arena, backup; TABLE_LIST *top_view= table->top_table(); @@ -1361,8 +1361,6 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, lex_start(thd); lex->stmt_lex= old_lex; - view_select= &lex->select_lex; - view_select->select_number= ++thd->lex->stmt_lex->current_select_number; sql_mode_t saved_mode= thd->variables.sql_mode; /* switch off modes which can prevent normal parsing of VIEW @@ -1397,6 +1395,8 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, parse_status= parse_sql(thd, & parser_state, table->view_creation_ctx); + view_select= lex->first_select_lex(); + /* Restore environment. */ if ((old_lex->sql_command == SQLCOM_SHOW_FIELDS) || @@ -1546,7 +1546,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, This may change in future, for example if we enable merging of views with subqueries in select list. */ - view_main_select_tables= lex->select_lex.table_list.first; + view_main_select_tables= lex->first_select_lex()->table_list.first; /* Let us set proper lock type for tables of the view's main @@ -1574,7 +1574,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, /* Fields in this view can be used in upper select in case of merge. */ if (table->select_lex) - table->select_lex->add_where_field(&lex->select_lex); + table->select_lex->add_where_field(lex->first_select_lex()); } /* This method has a dependency on the proper lock type being set, @@ -1596,8 +1596,8 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query && lex->safe_to_cache_query); /* move SQL_CACHE to whole query */ - if (view_select->options & OPTION_TO_QUERY_CACHE) - old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE; + if (lex->first_select_lex()->options & OPTION_TO_QUERY_CACHE) + old_lex->first_select_lex()->options|= OPTION_TO_QUERY_CACHE; #ifndef NO_EMBEDDED_ACCESS_CHECKS if (table->view_suid) @@ -1679,9 +1679,10 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, tbl->grant.want_privilege= top_view->grant.orig_want_privilege; /* prepare view context */ - lex->select_lex.context.resolve_in_table_list_only(view_main_select_tables); - lex->select_lex.context.outer_context= 0; - lex->select_lex.select_n_having_items+= + lex->first_select_lex()-> + context.resolve_in_table_list_only(view_main_select_tables); + lex->first_select_lex()->context.outer_context= 0; + lex->first_select_lex()->select_n_having_items+= table->select_lex->select_n_having_items; table->where= view_select->where; @@ -1692,12 +1693,13 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, */ if (!table->select_lex->master_unit()->is_unit_op() && table->select_lex->order_list.elements == 0) - table->select_lex->order_list.push_back(&lex->select_lex.order_list); + table->select_lex->order_list. + push_back(&lex->first_select_lex()->order_list); else { if (old_lex->sql_command == SQLCOM_SELECT && (old_lex->describe & DESCRIBE_EXTENDED) && - lex->select_lex.order_list.elements && + lex->first_select_lex()->order_list.elements && !table->select_lex->master_unit()->is_unit_op()) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, @@ -1732,7 +1734,11 @@ ok: lex->unit.include_down(table->select_lex); lex->unit.slave= view_select; // fix include_down initialisation /* global SELECT list linking */ - end= view_select; // primary SELECT_LEX is always last + /* + The primary SELECT_LEX is always last (because parsed first) if WITH not + used, otherwise it is good start point for last element finding + */ + for (end= view_select; end->link_next; end= end->link_next); end->link_next= old_lex->all_selects_list; old_lex->all_selects_list->link_prev= &end->link_next; old_lex->all_selects_list= lex->all_selects_list; @@ -1917,7 +1923,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) */ if ((!view->view && !view->belong_to_view) || thd->lex->sql_command == SQLCOM_INSERT || - thd->lex->select_lex.select_limit == 0) + thd->lex->first_select_lex()->select_limit == 0) DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */ table= view->table; view= view->top_table(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7ed44982dd6..cc22908ec4b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -491,96 +491,6 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, } /** - @brief Creates a new SELECT_LEX for a UNION branch. - - Sets up and initializes a SELECT_LEX structure for a query once the parser - discovers a UNION token. The current SELECT_LEX is pushed on the stack and - the new SELECT_LEX becomes the current one. - - @param lex The parser state. - - @param is_union_distinct True if the union preceding the new select - statement uses UNION DISTINCT. - - @param is_top_level This should be @c TRUE if the newly created SELECT_LEX - is a non-nested statement. - - @return <code>false</code> if successful, <code>true</code> if an error was - reported. In the latter case parsing should stop. - */ -bool LEX::add_select_to_union_list(bool is_union_distinct, - enum sub_select_type type, - bool is_top_level) -{ - const char *type_name= (type == INTERSECT_TYPE ? "INTERSECT" : - (type == EXCEPT_TYPE ? "EXCEPT" : "UNION")); - /* - Only the last SELECT can have INTO. Since the grammar won't allow INTO in - a nested SELECT, we make this check only when creating a top-level SELECT. - */ - if (is_top_level && result) - { - my_error(ER_WRONG_USAGE, MYF(0), type_name, "INTO"); - return TRUE; - } - if (current_select->order_list.first && !current_select->braces) - { - my_error(ER_WRONG_USAGE, MYF(0), type_name, "ORDER BY"); - return TRUE; - } - - if (current_select->explicit_limit && !current_select->braces) - { - my_error(ER_WRONG_USAGE, MYF(0), type_name, "LIMIT"); - return TRUE; - } - if (current_select->linkage == GLOBAL_OPTIONS_TYPE) - { - thd->parse_error(); - return TRUE; - } - if (!is_union_distinct && (type == INTERSECT_TYPE || type == EXCEPT_TYPE)) - { - my_error(ER_WRONG_USAGE, MYF(0), type_name, "ALL"); - return TRUE; - } - /* - Priority implementation, but also trying to keep things as flat - as possible */ - if (type == INTERSECT_TYPE && - (current_select->linkage != INTERSECT_TYPE && - current_select != current_select->master_unit()->first_select()) - && !(thd->variables.sql_mode & MODE_ORACLE)) - { - /* - This and previous SELECTs should go one level down because of - priority - */ - SELECT_LEX *prev= exclude_last_select(); - if (add_unit_in_brackets(prev)) - return TRUE; - return add_select_to_union_list(is_union_distinct, type, 0); - } - else - { - check_automatic_up(type); - } - /* This counter shouldn't be incremented for UNION parts */ - nest_level--; - if (mysql_new_select(this, 0, NULL)) - return TRUE; - mysql_init_select(this); - current_select->linkage= type; - current_select->with_all_modifier= !is_union_distinct; - if (is_union_distinct) /* UNION DISTINCT - remember position */ - current_select->master_unit()->union_distinct= current_select; - else - DBUG_ASSERT(type == UNION_TYPE); - return FALSE; -} - - -/** Create a separate LEX for each assignment if in SP. If we are in SP we want have own LEX for each assignment. @@ -621,6 +531,7 @@ void sp_create_assignment_lex(THD *thd, bool no_lookahead) lex->sphead->m_tmp_query= lip->get_tok_end(); /* Inherit from outer lex. */ lex->option_type= old_lex->option_type; + lex->main_select_push(); } } @@ -680,6 +591,9 @@ bool sp_create_assignment_instr(THD *thd, bool no_lookahead) if (sp->add_instr(i)) return true; } + lex->pop_select(); + if (Lex->check_main_unit_semantics()) + return true; enum_var_type inner_option_type= lex->option_type; if (lex->sphead->restore_lex(thd)) return true; @@ -767,6 +681,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) return v; } + %} %union { int num; @@ -796,6 +711,20 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) uint offset; } sp_cursor_name_and_offset; vers_history_point_t vers_history_point; + struct + { + enum sub_select_type unit_type; + bool distinct; + } unit_operation; + struct + { + SELECT_LEX *first; + SELECT_LEX *prev_last; + } select_list; + SQL_I_List<ORDER> *select_order; + Lex_select_lock select_lock; + Lex_select_limit select_limit; + Lex_order_limit_lock *order_limit_lock; /* pointers */ Create_field *create_field; @@ -841,6 +770,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) handlerton *db_type; st_select_lex *select_lex; + st_select_lex_unit *select_lex_unit; struct p_elem_val *p_elem_value; class Window_frame *window_frame; class Window_frame_bound *window_frame_bound; @@ -849,7 +779,6 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) /* enums */ enum enum_view_suid view_suid; - enum sub_select_type unit_type; enum Condition_information_item::Name cond_info_item_name; enum enum_diag_condition_item_name diag_condition_item_name; enum Diagnostics_information::Which_area diag_area; @@ -888,10 +817,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 62 shift/reduce conflicts. + Currently there are 58 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 62 +%expect 58 /* Comments for TOKENS. @@ -1042,6 +971,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %token LEADING /* SQL-2003-R */ %token LEAVE_SYM %token LEFT /* SQL-2003-R */ +%token LEFT_PAREN_ALT /* INTERNAL */ +%token LEFT_PAREN_WITH /* INTERNAL */ +%token LEFT_PAREN_LIKE /* INTERNAL */ %token LEX_HOSTNAME %token LIKE /* SQL-2003-R */ %token LIMIT @@ -1784,7 +1716,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); NCHAR_STRING %type <lex_str_ptr> - opt_table_alias + opt_table_alias_clause + table_alias_clause %type <ident_cli> IDENT @@ -1846,7 +1779,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); opt_temporary all_or_any opt_distinct opt_glimit_clause opt_ignore_leaves fulltext_options union_option opt_not - select_derived_init transaction_access_mode_types + transaction_access_mode_types opt_natural_language_mode opt_query_expansion opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt @@ -1966,11 +1899,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); join_table_list join_table table_factor table_ref esc_table_ref table_primary_ident table_primary_derived - select_derived derived_table_list - select_derived_union - derived_simple_table - derived_query_specification - derived_table_value_constructor + derived_table_list table_reference_list_parens + nested_table_reference_list join_table_parens %type <date_time_type> date_time_type; %type <interval> interval @@ -2004,14 +1934,19 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); UNDERSCORE_CHARSET %type <select_lex> subselect - get_select_lex get_select_lex_derived - simple_table query_specification - query_term_union_not_ready - query_term_union_ready - query_expression_body - select_paren_derived table_value_constructor + simple_table + query_primary + query_primary_parens + select_into_query_specification + + +%type <select_lex_unit> + query_specification_start + query_expression_body + query_expression + query_expression_unit %type <boolfunc2creator> comp_op @@ -2023,11 +1958,28 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %type <virtual_column> opt_check_constraint check_constraint virtual_column_func column_default_expr -%type <unit_type> unit_type_decl + +%type <unit_operation> unit_type_decl + +%type <select_lock> + opt_procedure_or_into + opt_select_lock_type + select_lock_type + opt_lock_wait_timeout_new + +%type <select_limit> opt_limit_clause limit_clause limit_options + +%type <order_limit_lock> + query_expression_tail + order_or_limit + opt_order_limit_lock + +%type <select_order> opt_order_clause order_clause order_list %type <NONE> analyze_stmt_command - query verb_clause create change select do drop insert replace insert2 + query verb_clause create change select select_into + do drop insert replace insert2 insert_values update delete truncate rename compound_statement show describe load alter optimize keycache preload flush reset purge begin commit rollback savepoint release @@ -2043,7 +1995,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); assign_to_keycache_parts preload_list preload_list_or_parts preload_keys preload_keys_parts select_item_list select_item values_list no_braces - opt_limit_clause delete_limit_clause fields opt_values values + delete_limit_clause fields opt_values values no_braces_with_names opt_values_with_names values_with_names procedure_list procedure_list2 procedure_item field_def handler opt_generated_always @@ -2064,9 +2016,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); table_to_table_list table_to_table opt_table_list opt_as handler_rkey_function handler_read_or_scan single_multi table_wild_list table_wild_one opt_wild - union_clause union_list - subselect_start opt_and charset - subselect_end select_var_list select_var_list_init help + opt_and charset + select_var_list select_var_list_init help opt_extended_describe shutdown opt_format_json prepare prepare_src execute deallocate @@ -2194,8 +2145,8 @@ rule: <-- starts at col 1 query: END_OF_INPUT { - if (likely(!thd->bootstrap) && - unlikely(!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT))) + if (!thd->bootstrap && + (!(thd->lex->lex_options & OPTION_LEX_FOUND_COMMENT))) my_yyabort_error((ER_EMPTY_QUERY, MYF(0))); thd->lex->sql_command= SQLCOM_EMPTY_QUERY; @@ -2290,6 +2241,7 @@ statement: | rollback | savepoint | select + | select_into | set | signal_stmt | show @@ -2325,6 +2277,8 @@ prepare: if (unlikely(lex->table_or_sp_used())) my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "PREPARE..FROM")); + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; lex->sql_command= SQLCOM_PREPARE; lex->prepared_stmt_name= $2; } @@ -2347,7 +2301,10 @@ execute: lex->prepared_stmt_name= $2; } execute_using - {} + { + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } | EXECUTE_SYM IMMEDIATE_SYM prepare_src { if (unlikely(Lex->table_or_sp_used())) @@ -2356,7 +2313,10 @@ execute: Lex->sql_command= SQLCOM_EXECUTE_IMMEDIATE; } execute_using - {} + { + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; execute_using: @@ -2643,17 +2603,22 @@ connection_name: /* create a table */ create: - create_or_replace opt_temporary TABLE_SYM opt_if_not_exists table_ident + create_or_replace opt_temporary TABLE_SYM opt_if_not_exists { LEX *lex= thd->lex; lex->create_info.init(); - if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, - $1 | $4))) + if (lex->main_select_push()) + MYSQL_YYABORT; + lex->current_select->parsing_place= BEFORE_OPT_LIST; + if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4)) MYSQL_YYABORT; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_UPDATING, - TL_WRITE, - MDL_EXCLUSIVE))) + } + table_ident + { + LEX *lex= thd->lex; + if (!lex->first_select_lex()-> + add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING, + TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; lex->alter_info.reset(); /* @@ -2668,7 +2633,6 @@ create: create_body { LEX *lex= thd->lex; - lex->current_select= &lex->select_lex; if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && !lex->create_info.db_type) { @@ -2677,22 +2641,24 @@ create: ER_WARN_USING_OTHER_HANDLER, ER_THD(thd, ER_WARN_USING_OTHER_HANDLER), hton_name(lex->create_info.db_type)->str, - $5->table.str); + $6->table.str); } create_table_set_open_action_and_adjust_tables(lex); + Lex->pop_select(); //main select } | create_or_replace opt_temporary SEQUENCE_SYM opt_if_not_exists table_ident { LEX *lex= thd->lex; + if (Lex->main_select_push()) + MYSQL_YYABORT; lex->create_info.init(); if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_SEQUENCE, $2, $1 | $4))) MYSQL_YYABORT; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_UPDATING, - TL_WRITE, - MDL_EXCLUSIVE))) + if (!lex->first_select_lex()-> + add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, + TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; /* @@ -2715,8 +2681,9 @@ create: if (unlikely(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.str, - lex->select_lex.table_list.first->table_name.str); + lex->first_select_lex()->table_list.first->db.str, + lex->first_select_lex()->table_list.first-> + table_name.str); MYSQL_YYABORT; } @@ -2729,10 +2696,8 @@ create: Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE; Lex->create_info.sequence= 1; - lex->current_select= &lex->select_lex; - if (unlikely((lex->create_info.used_fields & - HA_CREATE_USED_ENGINE) && - !lex->create_info.db_type)) + if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && + !lex->create_info.db_type) { lex->create_info.use_default_db_type(thd); push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, @@ -2742,44 +2707,69 @@ create: $5->table.str); } create_table_set_open_action_and_adjust_tables(lex); + Lex->pop_select(); //main select } - | create_or_replace opt_unique INDEX_SYM opt_if_not_exists ident + | create_or_replace opt_unique INDEX_SYM opt_if_not_exists + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + ident opt_key_algorithm_clause ON table_ident { - if (unlikely(Lex->add_create_index_prepare($8))) + if (Lex->add_create_index_prepare($9)) MYSQL_YYABORT; - if (unlikely(Lex->add_create_index($2, &$5, $6, $1 | $4))) + if (Lex->add_create_index($2, &$6, $7, $1 | $4)) MYSQL_YYABORT; } '(' key_list ')' opt_lock_wait_timeout normal_key_options - opt_index_lock_algorithm { } - | create_or_replace fulltext INDEX_SYM opt_if_not_exists ident + opt_index_lock_algorithm + { + Lex->pop_select(); //main select + } + | create_or_replace fulltext INDEX_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + opt_if_not_exists ident ON table_ident { - if (unlikely(Lex->add_create_index_prepare($7))) + if (Lex->add_create_index_prepare($8)) MYSQL_YYABORT; - if (unlikely(Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, - $1 | $4))) + if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5)) MYSQL_YYABORT; } '(' key_list ')' opt_lock_wait_timeout fulltext_key_options - opt_index_lock_algorithm { } - | create_or_replace spatial INDEX_SYM opt_if_not_exists ident + opt_index_lock_algorithm + { + Lex->pop_select(); //main select + } + | create_or_replace spatial INDEX_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + opt_if_not_exists ident ON table_ident { - if (unlikely(Lex->add_create_index_prepare($7))) + if (Lex->add_create_index_prepare($8)) MYSQL_YYABORT; - if (unlikely(Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, - $1 | $4))) + if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5)) MYSQL_YYABORT; } '(' key_list ')' opt_lock_wait_timeout spatial_key_options - opt_index_lock_algorithm { } + opt_index_lock_algorithm + { + Lex->pop_select(); //main select + } | create_or_replace DATABASE opt_if_not_exists ident { Lex->create_info.default_table_charset= NULL; Lex->create_info.used_fields= 0; + if (Lex->main_select_push()) + MYSQL_YYABORT; } opt_create_database_options { @@ -2788,59 +2778,103 @@ create: $1 | $3))) MYSQL_YYABORT; lex->name= $4; + Lex->pop_select(); //main select } | create_or_replace definer_opt opt_view_suid VIEW_SYM opt_if_not_exists table_ident { - if (unlikely(Lex->add_create_view(thd, $1 | $5, - DTYPE_ALGORITHM_UNDEFINED, $3, - $6))) + if (Lex->main_select_push()) + MYSQL_YYABORT; + if (Lex->add_create_view(thd, $1 | $5, + DTYPE_ALGORITHM_UNDEFINED, $3, $6)) MYSQL_YYABORT; } view_list_opt AS view_select - { } + { + Lex->pop_select(); //main select + } | create_or_replace view_algorithm definer_opt opt_view_suid VIEW_SYM opt_if_not_exists table_ident { if (unlikely(Lex->add_create_view(thd, $1 | $6, $2, $4, $7))) MYSQL_YYABORT; + if (Lex->main_select_push()) + MYSQL_YYABORT; } view_list_opt AS view_select - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer_opt TRIGGER_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } trigger_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer_opt PROCEDURE_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } sp_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer_opt EVENT_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } event_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer FUNCTION_SYM { + if (Lex->main_select_push()) + MYSQL_YYABORT; Lex->create_info.set($1); } - sf_tail_not_aggregate - { } + sf_tail + { + Lex->pop_select(); //main select + } | create_or_replace definer AGGREGATE_SYM FUNCTION_SYM { + if (Lex->main_select_push()) + MYSQL_YYABORT; Lex->create_info.set($1); } sf_tail_aggregate - { } + { + Lex->pop_select(); //main select + } | create_or_replace no_definer FUNCTION_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } create_function_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace no_definer AGGREGATE_SYM FUNCTION_SYM { + if (Lex->main_select_push()) + MYSQL_YYABORT; Lex->create_info.set($1); } create_aggregate_function_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list opt_require_clause opt_resource_options { @@ -3243,7 +3277,7 @@ clear_privileges: lex->columns.empty(); lex->grant= lex->grant_tot_col= 0; lex->all_privileges= 0; - lex->select_lex.db= null_clex_str; + lex->first_select_lex()->db= null_clex_str; lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0; bzero((char *)&(lex->mqh),sizeof(lex->mqh)); @@ -3742,7 +3776,7 @@ sp_hcond: signal_stmt: SIGNAL_SYM signal_value opt_set_signal_information { - if (unlikely(Lex->add_signal_statement(thd, $2))) + if (Lex->add_signal_statement(thd, $2)) MYSQL_YYABORT; } ; @@ -4202,7 +4236,7 @@ assignment_source_expr: $$->sp_lex_in_use= true; $$->set_item_and_free_list($3, thd->free_list); thd->free_list= NULL; - if (unlikely($$->sphead->restore_lex(thd))) + if ($$->sphead->restore_lex(thd)) MYSQL_YYABORT; } ; @@ -4211,6 +4245,7 @@ for_loop_bound_expr: assignment_source_lex { Lex->sphead->reset_lex(thd, $1); + Lex->current_select->parsing_place= FOR_LOOP_BOUND; } expr { @@ -4220,6 +4255,7 @@ for_loop_bound_expr: $$->set_item_and_free_list($3, NULL); if (unlikely($$->sphead->restore_lex(thd))) MYSQL_YYABORT; + Lex->current_select->parsing_place= NO_MATTER; } ; @@ -4453,7 +4489,8 @@ case_stmt_body: { if (unlikely(Lex->case_stmt_action_expr($2))) MYSQL_YYABORT; - if (unlikely(Lex->sphead->restore_lex(thd))) + + if (Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } simple_when_clause_list @@ -4655,7 +4692,7 @@ while_body: LEX *lex= Lex; if (unlikely(lex->sp_while_loop_expression(thd, $1))) MYSQL_YYABORT; - if (unlikely(lex->sphead->restore_lex(thd))) + if (lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } sp_proc_stmts1 END WHILE_SYM @@ -4678,7 +4715,7 @@ repeat_body: if (unlikely(i == NULL) || unlikely(lex->sphead->add_instr(i))) MYSQL_YYABORT; - if (unlikely(lex->sphead->restore_lex(thd))) + if (lex->sphead->restore_lex(thd)) MYSQL_YYABORT; /* We can shortcut the cont_backpatch here */ i->m_cont_dest= ip+1; @@ -5158,26 +5195,16 @@ size_number: */ create_body: - '(' create_field_list ')' + create_field_list_parens { Lex->create_info.option_list= NULL; } opt_create_table_options opt_create_partitioning opt_create_select {} | opt_create_table_options opt_create_partitioning opt_create_select {} - /* - the following rule is redundant, but there's a shift/reduce - conflict that prevents the rule above from parsing a syntax like - CREATE TABLE t1 (SELECT 1); - */ - | '(' create_select_query_specification ')' - | '(' create_select_query_specification ')' - { Select->set_braces(1);} union_list {} - | '(' create_select_query_specification ')' - { Select->set_braces(1);} union_order_or_limit {} | create_like { Lex->create_info.add(DDL_options_st::OPT_LIKE); - TABLE_LIST *src_table= Lex->select_lex.add_table_to_list(thd, - $1, NULL, 0, TL_READ, MDL_SHARED_READ); + TABLE_LIST *src_table= Lex->first_select_lex()-> + add_table_to_list(thd, $1, NULL, 0, TL_READ, MDL_SHARED_READ); if (unlikely(! src_table)) MYSQL_YYABORT; /* CREATE TABLE ... LIKE is not allowed for views. */ @@ -5187,7 +5214,7 @@ create_body: create_like: LIKE table_ident { $$= $2; } - | '(' LIKE table_ident ')' { $$= $3; } + | LEFT_PAREN_LIKE LIKE table_ident ')' { $$= $3; } ; opt_create_select: @@ -5196,23 +5223,19 @@ opt_create_select: ; create_select_query_expression: - opt_with_clause SELECT_SYM create_select_part2 opt_table_expression - create_select_part4 - { - Select->set_braces(0); - Select->set_with_clause($1); + query_expression + { + if (Lex->parsed_insert_select($1->first_select())) + MYSQL_YYABORT; } - union_clause - | opt_with_clause SELECT_SYM create_select_part2 - create_select_part3_union_not_ready create_select_part4 + | LEFT_PAREN_WITH with_clause query_expression_body ')' { - Select->set_with_clause($1); + SELECT_LEX *first_select= $3->first_select(); + $3->set_with_clause($2); + $2->attach_to(first_select); + if (Lex->parsed_insert_select(first_select)) + MYSQL_YYABORT; } - | '(' create_select_query_specification ')' - | '(' create_select_query_specification ')' - { Select->set_braces(1);} union_list {} - | '(' create_select_query_specification ')' - { Select->set_braces(1);} union_order_or_limit {} ; opt_create_partitioning: @@ -5295,13 +5318,17 @@ partition_entry: thd->parse_error(ER_PARTITION_ENTRY_ERROR); MYSQL_YYABORT; } - DBUG_ASSERT(Lex->part_info->table); + if (Lex->main_select_push()) + MYSQL_YYABORT; /* We enter here when opening the frm file to translate partition info string into part_info data structure. */ } - partition {} + partition + { + Lex->pop_select(); //main select + } ; partition: @@ -5955,56 +5982,6 @@ opt_versioning_interval_start: End of partition parser part */ -create_select_query_specification: - opt_with_clause SELECT_SYM create_select_part2 create_select_part3 - create_select_part4 - { - Select->set_with_clause($1); - } - ; - -create_select_part2: - { - LEX *lex=Lex; - if (lex->sql_command == SQLCOM_INSERT) - lex->sql_command= SQLCOM_INSERT_SELECT; - else if (lex->sql_command == SQLCOM_REPLACE) - lex->sql_command= SQLCOM_REPLACE_SELECT; - /* - The following work only with the local list, the global list - is created correctly in this case - */ - lex->current_select->table_list.save_and_clear(&lex->save_list); - mysql_init_select(lex); - lex->current_select->parsing_place= SELECT_LIST; - } - select_options select_item_list - { - Select->parsing_place= NO_MATTER; - } - ; - -create_select_part3: - opt_table_expression - | create_select_part3_union_not_ready - ; - -create_select_part3_union_not_ready: - table_expression order_or_limit - | order_or_limit - ; - -create_select_part4: - opt_select_lock_type - { - /* - The following work only with the local list, the global list - is created correctly in this case - */ - Lex->current_select->table_list.push_front(&Lex->save_list); - } - ; - opt_as: /* empty */ {} | AS {} @@ -6222,7 +6199,7 @@ create_table_option: } | UNION_SYM opt_equal { - Lex->select_lex.table_list.save_and_clear(&Lex->save_list); + Lex->first_select_lex()->table_list.save_and_clear(&Lex->save_list); } '(' opt_table_list ')' { @@ -6231,8 +6208,8 @@ create_table_option: from the global list. */ LEX *lex=Lex; - lex->create_info.merge_list= lex->select_lex.table_list; - lex->select_lex.table_list= lex->save_list; + lex->create_info.merge_list= lex->first_select_lex()->table_list; + lex->first_select_lex()->table_list= lex->save_list; /* When excluding union list from the global list we assume that elements of the former immediately follow elements which represent @@ -6433,6 +6410,13 @@ create_field_list: } ; +create_field_list_parens: + LEFT_PAREN_ALT field_list ')' + { + Lex->create_last_non_select_table= Lex->last_table(); + } + ; + field_list: field_list_item | field_list ',' field_list_item @@ -6727,6 +6711,8 @@ parse_vcol_expr: Prevent the end user from invoking this command. */ MYSQL_YYABORT_UNLESS(Lex->parse_vcol_expr); + if (Lex->main_select_push()) + MYSQL_YYABORT; } expr { @@ -6734,14 +6720,15 @@ parse_vcol_expr: if (unlikely(!v)) MYSQL_YYABORT; Lex->last_field->vcol_info= v; + Lex->pop_select(); //main select } ; parenthesized_expr: - subselect + remember_tok_start + query_expression { - $$= new (thd->mem_root) Item_singlerow_subselect(thd, $1); - if (unlikely($$ == NULL)) + if (!($$= Lex->create_item_query_expression(thd, $1, $2))) MYSQL_YYABORT; } | expr @@ -7658,23 +7645,25 @@ alter: Lex->name= null_clex_str; Lex->table_type= TABLE_TYPE_UNKNOWN; Lex->sql_command= SQLCOM_ALTER_TABLE; - Lex->duplicates= DUP_ERROR; - Lex->select_lex.init_order(); + Lex->duplicates= DUP_ERROR; + Lex->first_select_lex()->order_list.empty(); Lex->create_info.init(); Lex->create_info.row_type= ROW_TYPE_NOT_USED; Lex->alter_info.reset(); Lex->no_write_to_binlog= 0; Lex->create_info.storage_media= HA_SM_DEFAULT; + if (Lex->main_select_push()) + MYSQL_YYABORT; DBUG_ASSERT(!Lex->m_sql_cmd); } alter_options TABLE_SYM table_ident opt_lock_wait_timeout { - if (unlikely(!Lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_UPDATING, - TL_READ_NO_INSERT, - MDL_SHARED_UPGRADABLE))) + if (!Lex->first_select_lex()-> + add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, + TL_READ_NO_INSERT, MDL_SHARED_UPGRADABLE)) MYSQL_YYABORT; - Lex->select_lex.db= (Lex->select_lex.table_list.first)->db; + Lex->first_select_lex()->db= + (Lex->first_select_lex()->table_list.first)->db; Lex->create_last_non_select_table= Lex->last_table(); } alter_commands @@ -7686,11 +7675,14 @@ alter: if (unlikely(Lex->m_sql_cmd == NULL)) MYSQL_YYABORT; } + Lex->pop_select(); //main select } | ALTER DATABASE ident_or_empty { Lex->create_info.default_table_charset= NULL; Lex->create_info.used_fields= 0; + if (Lex->main_select_push()) + MYSQL_YYABORT; } create_database_options { @@ -7700,6 +7692,7 @@ alter: if (lex->name.str == NULL && unlikely(lex->copy_db_to(&lex->name))) MYSQL_YYABORT; + Lex->pop_select(); //main select } | ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM { @@ -7715,6 +7708,8 @@ alter: if (unlikely(lex->sphead)) my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE")); + if (Lex->main_select_push()) + MYSQL_YYABORT; lex->sp_chistics.init(); } sp_a_chistics @@ -7723,6 +7718,9 @@ alter: lex->sql_command= SQLCOM_ALTER_PROCEDURE; lex->spname= $3; + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } | ALTER FUNCTION_SYM sp_name { @@ -7730,6 +7728,8 @@ alter: if (unlikely(lex->sphead)) my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION")); + if (Lex->main_select_push()) + MYSQL_YYABORT; lex->sp_chistics.init(); } sp_a_chistics @@ -7738,14 +7738,23 @@ alter: lex->sql_command= SQLCOM_ALTER_FUNCTION; lex->spname= $3; + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } | ALTER view_algorithm definer_opt opt_view_suid VIEW_SYM table_ident { - if (unlikely(Lex->add_alter_view(thd, $2, $4, $6))) + if (Lex->main_select_push()) + MYSQL_YYABORT; + if (Lex->add_alter_view(thd, $2, $4, $6)) MYSQL_YYABORT; } view_list_opt AS view_select - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } | ALTER definer_opt opt_view_suid VIEW_SYM table_ident /* We have two separate rules for ALTER VIEW rather that @@ -7753,14 +7762,22 @@ alter: with the ALTER EVENT below. */ { - if (unlikely(Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5))) + if (Lex->main_select_push()) + MYSQL_YYABORT; + if (Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5)) MYSQL_YYABORT; } view_list_opt AS view_select - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } | ALTER definer_opt remember_name EVENT_SYM sp_name { - /* + if (Lex->main_select_push()) + MYSQL_YYABORT; + /* It is safe to use Lex->spname because ALTER EVENT xxx RENATE TO yyy DO ALTER EVENT RENAME TO is not allowed. Lex->spname is used in the case of RENAME TO @@ -7792,6 +7809,8 @@ alter: */ Lex->sql_command= SQLCOM_ALTER_EVENT; Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr(); + + Lex->pop_select(); //main select } | ALTER TABLESPACE alter_tablespace_info { @@ -7835,16 +7854,17 @@ alter: lex->create_info.init(); lex->no_write_to_binlog= 0; DBUG_ASSERT(!lex->m_sql_cmd); + if (Lex->main_select_push()) + MYSQL_YYABORT; } table_ident { LEX *lex= Lex; - if (unlikely(!(lex->create_info.seq_create_info= - new (thd->mem_root) sequence_definition())) || - unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_SEQUENCE, - TL_WRITE, - MDL_EXCLUSIVE))) + if (!(lex->create_info.seq_create_info= new (thd->mem_root) + sequence_definition()) || + !lex->first_select_lex()-> + add_table_to_list(thd, $5, NULL, TL_OPTION_SEQUENCE, + TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; } sequence_defs @@ -7853,6 +7873,9 @@ alter: Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence($3); if (unlikely(Lex->m_sql_cmd == NULL)) MYSQL_YYABORT; + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } ; @@ -8002,16 +8025,17 @@ alter_commands: WITH TABLE_SYM table_ident have_partitioning { LEX *lex= thd->lex; - lex->select_lex.db= $6->db; - if (lex->select_lex.db.str == NULL && - unlikely(lex->copy_db_to(&lex->select_lex.db))) + lex->first_select_lex()->db=$6->db; + if (lex->first_select_lex()->db.str == NULL && + lex->copy_db_to(&lex->first_select_lex()->db)) + { MYSQL_YYABORT; + } lex->name= $6->table; lex->alter_info.partition_flags|= ALTER_PARTITION_EXCHANGE; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $6, NULL, - TL_OPTION_UPDATING, - TL_READ_NO_INSERT, - MDL_SHARED_NO_WRITE))) + if (!lex->first_select_lex()-> + add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING, + TL_READ_NO_INSERT, MDL_SHARED_NO_WRITE)) MYSQL_YYABORT; DBUG_ASSERT(!lex->m_sql_cmd); lex->m_sql_cmd= new (thd->mem_root) @@ -8250,9 +8274,9 @@ alter_list_item: | RENAME opt_to table_ident { LEX *lex=Lex; - lex->select_lex.db= $3->db; - if (lex->select_lex.db.str == NULL && - unlikely(lex->copy_db_to(&lex->select_lex.db))) + lex->first_select_lex()->db= $3->db; + if (lex->first_select_lex()->db.str == NULL && + lex->copy_db_to(&lex->first_select_lex()->db)) MYSQL_YYABORT; if (unlikely(check_table_name($3->table.str,$3->table.length, FALSE)) || @@ -8947,8 +8971,8 @@ adm_partition: cache_keys_spec: { - Lex->select_lex.alloc_index_hints(thd); - Select->set_index_hint_type(INDEX_HINT_USE, + Lex->first_select_lex()->alloc_index_hints(thd); + Select->set_index_hint_type(INDEX_HINT_USE, INDEX_HINT_MASK_ALL); } cache_key_list_or_empty @@ -8969,217 +8993,218 @@ opt_ignore_leaves: Select : retrieve data from table */ - select: - opt_with_clause select_init - { - LEX *lex= Lex; - lex->sql_command= SQLCOM_SELECT; - lex->current_select->set_with_clause($1); - } - ; - -select_init: - SELECT_SYM select_options_and_item_list select_init3 - | table_value_constructor - | table_value_constructor union_list - | table_value_constructor union_order_or_limit - | '(' select_paren ')' - | '(' select_paren ')' union_list - | '(' select_paren ')' union_order_or_limit - ; - -union_list_part2: - SELECT_SYM select_options_and_item_list select_init3_union_query_term - | table_value_constructor - | table_value_constructor union_list - | table_value_constructor union_order_or_limit - | '(' select_paren_union_query_term ')' - | '(' select_paren_union_query_term ')' union_list - | '(' select_paren_union_query_term ')' union_order_or_limit - ; - -select_paren: + query_expression_body { - Lex->current_select->set_braces(true); + if (Lex->push_select($1->fake_select_lex ? + $1->fake_select_lex : + $1->first_select())) + MYSQL_YYABORT; } - table_value_constructor + opt_procedure_or_into { - DBUG_ASSERT(Lex->current_select->braces); + Lex->pop_select(); + if ($1->set_lock_to_the_last_select($3)) + MYSQL_YYABORT; + if (Lex->select_finalize($1)) + MYSQL_YYABORT; } - | + | with_clause query_expression_body { - /* - In order to correctly parse UNION's global ORDER BY we need to - set braces before parsing the clause. - */ - Lex->current_select->set_braces(true); + if (Lex->push_select($2->fake_select_lex ? + $2->fake_select_lex : + $2->first_select())) + MYSQL_YYABORT; } - SELECT_SYM select_options_and_item_list select_part3 - opt_select_lock_type + opt_procedure_or_into { - DBUG_ASSERT(Lex->current_select->braces); + Lex->pop_select(); + $2->set_with_clause($1); + $1->attach_to($2->first_select()); + if ($2->set_lock_to_the_last_select($4)) + MYSQL_YYABORT; + if (Lex->select_finalize($2)) + MYSQL_YYABORT; } - | '(' select_paren ')' ; -select_paren_union_query_term: + +select_into: + select_into_query_specification { - /* - In order to correctly parse UNION's global ORDER BY we need to - set braces before parsing the clause. - */ - Lex->current_select->set_braces(true); + if (Lex->push_select($1)) + MYSQL_YYABORT; } - SELECT_SYM select_options_and_item_list select_part3_union_query_term - opt_select_lock_type + opt_order_limit_lock { - DBUG_ASSERT(Lex->current_select->braces); - } - | '(' select_paren_union_query_term ')' + st_select_lex_unit *unit; + if (!(unit= Lex->parsed_body_select($1, $3))) + MYSQL_YYABORT; + if (Lex->select_finalize(unit)) + MYSQL_YYABORT; + } + ; + + +simple_table: + query_specification { $$= $1; } + | table_value_constructor { $$= $1; } ; -select_paren_view: +table_value_constructor: + VALUES + { + if (Lex->parsed_TVC_start()) + MYSQL_YYABORT; + } + values_list + { + if (!($$= Lex->parsed_TVC_end())) + MYSQL_YYABORT; + } + ; + +query_specification_start: + SELECT_SYM { - /* - In order to correctly parse UNION's global ORDER BY we need to - set braces before parsing the clause. - */ - Lex->current_select->set_braces(true); + SELECT_LEX *sel; + LEX *lex= Lex; + if (!(sel= lex->alloc_select(TRUE)) || + lex->push_select(sel)) + MYSQL_YYABORT; + sel->init_select(); + sel->braces= FALSE; } - SELECT_SYM select_options_and_item_list select_part3_view - opt_select_lock_type + select_options { - DBUG_ASSERT(Lex->current_select->braces); + Select->parsing_place= SELECT_LIST; } - | '(' select_paren_view ')' - ; + select_item_list + { + Select->parsing_place= NO_MATTER; + } + ; -/* The equivalent of select_paren for nested queries. */ -select_paren_derived: +query_specification: + query_specification_start + opt_from_clause + opt_where_clause + opt_group_clause + opt_having_clause + opt_window_clause { - Lex->current_select->set_braces(true); + $$= Lex->pop_select(); } - table_value_constructor + ; + +select_into_query_specification: + query_specification_start + into + opt_from_clause + opt_where_clause + opt_group_clause + opt_having_clause + opt_window_clause { - DBUG_ASSERT(Lex->current_select->braces); - $$= Lex->current_select->master_unit()->first_select(); + $$= Lex->pop_select(); } - | + ; + +opt_from_clause: + /* Empty */ + | from_clause + ; + + +query_primary: + simple_table + { $$= $1; } + | query_primary_parens + { $$= $1; } + ; + +query_primary_parens: + '(' query_expression_unit { - Lex->current_select->set_braces(true); + if (Lex->parsed_unit_in_brackets($2)) + MYSQL_YYABORT; } - SELECT_SYM select_part2_derived - opt_table_expression - opt_order_clause - opt_limit_clause - opt_select_lock_type + query_expression_tail ')' { - DBUG_ASSERT(Lex->current_select->braces); - $$= Lex->current_select->master_unit()->first_select(); + $$= Lex->parsed_unit_in_brackets_tail($2, $4); } - | '(' select_paren_derived ')' { $$= $2; } - ; - -select_init3: - opt_table_expression - opt_select_lock_type + | '(' query_primary { - /* Parentheses carry no meaning here */ - Lex->current_select->set_braces(false); + Lex->push_select($2); } - union_clause - | select_part3_union_not_ready - opt_select_lock_type + query_expression_tail ')' { - /* Parentheses carry no meaning here */ - Lex->current_select->set_braces(false); + if (!($$= Lex->parsed_select_in_brackets($2, $4))) + YYABORT; } ; - -select_init3_union_query_term: - opt_table_expression - opt_select_lock_type +query_expression_unit: + query_primary + unit_type_decl + query_primary { - /* Parentheses carry no meaning here */ - Lex->current_select->set_braces(false); + if (!($$= Lex->parsed_select_expr_start($1, $3, $2.unit_type, + $2.distinct))) + YYABORT; } - union_clause - | select_part3_union_not_ready_noproc - opt_select_lock_type + | query_expression_unit + unit_type_decl + query_primary { - /* Parentheses carry no meaning here */ - Lex->current_select->set_braces(false); + if (!($$= Lex->parsed_select_expr_cont($1, $3, $2.unit_type, + $2.distinct, FALSE))) + YYABORT; } ; - -select_init3_view: - opt_table_expression opt_select_lock_type +query_expression_body: + query_primary { - Lex->current_select->set_braces(false); + Lex->push_select($1); } - | opt_table_expression opt_select_lock_type + query_expression_tail { - Lex->current_select->set_braces(false); + if (!($$= Lex->parsed_body_select($1, $3))) + MYSQL_YYABORT; } - union_list_view - | order_or_limit opt_select_lock_type + | query_expression_unit { - Lex->current_select->set_braces(false); + if (Lex->parsed_body_unit($1)) + MYSQL_YYABORT; } - | table_expression order_or_limit opt_select_lock_type + query_expression_tail { - Lex->current_select->set_braces(false); + if (!($$= Lex->parsed_body_unit_tail($1, $3))) + MYSQL_YYABORT; } ; -/* - The SELECT parts after select_item_list that cannot be followed by UNION. -*/ - -select_part3: - opt_table_expression - | select_part3_union_not_ready - ; - -select_part3_union_query_term: - opt_table_expression - | select_part3_union_not_ready_noproc - ; - -select_part3_view: - opt_table_expression - | order_or_limit - | table_expression order_or_limit - ; - -select_part3_union_not_ready: - select_part3_union_not_ready_noproc - | table_expression procedure_clause - | table_expression order_or_limit procedure_clause +query_expression: + opt_with_clause + query_expression_body + { + if ($1) + { + $2->set_with_clause($1); + $1->attach_to($2->first_select()); + } + $$= $2; + } ; -select_part3_union_not_ready_noproc: - order_or_limit - | into opt_table_expression opt_order_clause opt_limit_clause - | table_expression into - | table_expression order_or_limit - | table_expression order_or_limit into - ; -select_options_and_item_list: - { - LEX *lex= Lex; - SELECT_LEX *sel= lex->current_select; - if (sel->linkage != UNION_TYPE) - mysql_init_select(lex); - lex->current_select->parsing_place= SELECT_LIST; - } - select_options select_item_list +subselect: + remember_tok_start + query_expression { - Select->parsing_place= NO_MATTER; + if (!($$= Lex->parsed_subselect($2, $1))) + YYABORT; } ; @@ -9187,18 +9212,6 @@ select_options_and_item_list: /** <table expression>, as in the SQL standard. */ -table_expression: - from_clause - opt_where_clause - opt_group_clause - opt_having_clause - opt_window_clause - ; - -opt_table_expression: - /* Empty */ - | table_expression - ; from_clause: FROM table_reference_list @@ -9247,8 +9260,9 @@ history_point: TIMESTAMP TEXT_STRING { Item *item; - if (!(item= create_temporal_literal(thd, $2.str, $2.length, YYCSCL, - MYSQL_TYPE_DATETIME, true))) + if (!(item= type_handler_datetime.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true))) MYSQL_YYABORT; $$= Vers_history_point(VERS_TIMESTAMP, item); } @@ -9301,59 +9315,68 @@ select_option: query_expression_option | SQL_NO_CACHE_SYM { - /* - Allow this flag only on the first top-level SELECT statement, if - SQL_CACHE wasn't specified, and only once per query. - */ - if (unlikely(Lex->current_select != &Lex->select_lex)) - my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE")); - if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE)) - my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE")); - if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE)) + /* + Allow this flag once per query. + */ + if (Select->options & OPTION_NO_QUERY_CACHE) my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE")); - - Lex->safe_to_cache_query=0; - Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE; - Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE; + Select->options|= OPTION_NO_QUERY_CACHE; } | SQL_CACHE_SYM { - /* - Allow this flag only on the first top-level SELECT statement, if - SQL_NO_CACHE wasn't specified, and only once per query. - */ - if (unlikely(Lex->current_select != &Lex->select_lex)) - my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE")); - if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE)) - my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE")); - if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE)) + /* + Allow this flag once per query. + */ + if (Select->options & OPTION_TO_QUERY_CACHE) my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE")); - - Lex->safe_to_cache_query=1; - Lex->select_lex.options|= OPTION_TO_QUERY_CACHE; - Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE; + Select->options|= OPTION_TO_QUERY_CACHE; } ; -opt_select_lock_type: - /* empty */ - | FOR_SYM UPDATE_SYM opt_lock_wait_timeout + +select_lock_type: + FOR_SYM UPDATE_SYM opt_lock_wait_timeout_new { - LEX *lex=Lex; - lex->current_select->lock_type= TL_WRITE; - lex->current_select->set_lock_for_tables(TL_WRITE); - lex->safe_to_cache_query=0; + $$= $3; + $$.defined_lock= TRUE; + $$.update_lock= TRUE; } - | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout + | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout_new { - LEX *lex=Lex; - lex->current_select->lock_type= TL_READ_WITH_SHARED_LOCKS; - lex->current_select-> - set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS); - lex->safe_to_cache_query=0; + $$= $5; + $$.defined_lock= TRUE; + $$.update_lock= FALSE; } ; +opt_select_lock_type: + /* empty */ + { + $$.empty(); + } + | select_lock_type + { + $$= $1; + } + ; + +opt_lock_wait_timeout_new: + /* empty */ + { + $$.empty(); + } + | WAIT_SYM ulong_num + { + $$.defined_timeout= TRUE; + $$.timeout= $2; + } + | NOWAIT_SYM + { + $$.defined_timeout= TRUE; + $$.timeout= 0; + } + ; + select_item_list: select_item_list ',' select_item | select_item @@ -10002,7 +10025,21 @@ column_default_non_parenthesized_expr: | param_marker { $$= $1; } | variable | sum_expr + { + if (!Lex->select_stack_top) + { + my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0)); + MYSQL_YYABORT; + } + } | window_func_expr + { + if (!Lex->select_stack_top) + { + my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0)); + MYSQL_YYABORT; + } + } | inverse_distribution_function | ROW_SYM '(' expr ',' expr_list ')' { @@ -10180,7 +10217,7 @@ function_call_keyword_timestamp: } | TIMESTAMP '(' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_add_time(thd, $3, $5, 1, 0); + $$= new (thd->mem_root) Item_func_timestamp(thd, $3, $5); if (unlikely($$ == NULL)) MYSQL_YYABORT; } @@ -11595,10 +11632,15 @@ esc_table_ref: /* Equivalent to <table reference list> in the SQL:2003 standard. */ /* Warning - may return NULL in case of incomplete SELECT */ derived_table_list: - esc_table_ref { $$=$1; } + esc_table_ref + { + $$=$1; + Select->add_joined_table($1); + } | derived_table_list ',' esc_table_ref { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); + Select->add_joined_table($3); } ; @@ -11617,11 +11659,18 @@ join_table: left-associative joins. */ table_ref normal_join table_ref %prec TABLE_REF_PRIORITY - { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=$2; } + { + MYSQL_YYABORT_UNLESS($1 && ($$=$3)); + Select->add_joined_table($1); + Select->add_joined_table($3); + $3->straight=$2; + } | table_ref normal_join table_ref ON { MYSQL_YYABORT_UNLESS($1 && $3); + Select->add_joined_table($1); + Select->add_joined_table($3); /* Change the current name resolution context to a local context. */ if (unlikely(push_new_name_resolution_context(thd, $1, $3))) MYSQL_YYABORT; @@ -11638,6 +11687,8 @@ join_table: USING { MYSQL_YYABORT_UNLESS($1 && $3); + Select->add_joined_table($1); + Select->add_joined_table($3); } '(' using_list ')' { @@ -11648,6 +11699,8 @@ join_table: | table_ref NATURAL inner_join table_factor { MYSQL_YYABORT_UNLESS($1 && ($$=$4)); + Select->add_joined_table($1); + Select->add_joined_table($4); $4->straight=$3; add_join_natural($1,$4,NULL,Select); } @@ -11657,6 +11710,8 @@ join_table: ON { MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); /* Change the current name resolution context to a local context. */ if (unlikely(push_new_name_resolution_context(thd, $1, $5))) MYSQL_YYABORT; @@ -11673,6 +11728,8 @@ join_table: | table_ref LEFT opt_outer JOIN_SYM table_factor { MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); } USING '(' using_list ')' { @@ -11683,6 +11740,8 @@ join_table: | table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor { MYSQL_YYABORT_UNLESS($1 && $6); + Select->add_joined_table($1); + Select->add_joined_table($6); add_join_natural($1,$6,NULL,Select); $6->outer_join|=JOIN_TYPE_LEFT; $$=$6; @@ -11693,6 +11752,8 @@ join_table: ON { MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); /* Change the current name resolution context to a local context. */ if (unlikely(push_new_name_resolution_context(thd, $1, $5))) MYSQL_YYABORT; @@ -11710,6 +11771,8 @@ join_table: | table_ref RIGHT opt_outer JOIN_SYM table_factor { MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); } USING '(' using_list ')' { @@ -11721,6 +11784,8 @@ join_table: | table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor { MYSQL_YYABORT_UNLESS($1 && $6); + Select->add_joined_table($1); + Select->add_joined_table($6); add_join_natural($6,$1,NULL,Select); LEX *lex= Lex; if (unlikely(!($$= lex->current_select->convert_right_join()))) @@ -11756,238 +11821,44 @@ use_partition: } ; -/* - This is a flattening of the rules <table factor> and <table primary> - in the SQL:2003 standard, since we don't have <sample clause> - - I.e. - <table factor> ::= <table primary> [ <sample clause> ] -*/ -/* Warning - may return NULL in case of incomplete SELECT */ table_factor: - table_primary_ident - | table_primary_derived + table_primary_ident { $$= $1; } + | table_primary_derived { $$= $1; } + | join_table_parens { $$= $1; } + | table_reference_list_parens { $$= $1; } ; -table_primary_ident: - { - DBUG_ASSERT(Select); - SELECT_LEX *sel= Select; - sel->table_join_options= 0; - } - table_ident opt_use_partition opt_for_system_time_clause opt_table_alias opt_key_definition - { - if (unlikely(!($$= Select->add_table_to_list(thd, $2, $5, - Select->get_table_join_options(), - YYPS->m_lock_type, - YYPS->m_mdl_type, - Select-> - pop_index_hints(), - $3)))) - MYSQL_YYABORT; - TABLE_LIST *tl= $$; - Select->add_joined_table(tl); - if ($4) - tl->vers_conditions= Lex->vers_conditions; - } - ; - - - -/* - Represents a flattening of the following rules from the SQL:2003 - standard. This sub-rule corresponds to the sub-rule - <table primary> ::= ... | <derived table> [ AS ] <correlation name> - - <derived table> ::= <table subquery> - <table subquery> ::= <subquery> - <subquery> ::= <left paren> <query expression> <right paren> - <query expression> ::= [ <with clause> ] <query expression body> - - For the time being we use the non-standard rule - select_derived_union which is a compromise between the standard - and our parser. Possibly this rule could be replaced by our - query_expression_body. -*/ - -table_primary_derived: - '(' get_select_lex select_derived_union ')' opt_for_system_time_clause opt_table_alias +table_reference_list_parens: + '(' table_reference_list_parens ')' { $$= $2; } + | '(' nested_table_reference_list ')' { - /* Use $2 instead of Lex->current_select as derived table will - alter value of Lex->current_select. */ - if (!($3 || $6) && $2->embedding && - !$2->embedding->nested_join->join_list.elements) - { - /* we have a derived table ($3 == NULL) but no alias, - Since we are nested in further parentheses so we - can pass NULL to the outer level parentheses - Permits parsing of "((((select ...))) as xyz)" */ - $$= 0; - } - else if (!$3) - { - /* Handle case of derived table, alias may be NULL if there - are no outer parentheses, add_table_to_list() will throw - error in this case */ - LEX *lex=Lex; - lex->check_automatic_up(UNSPECIFIED_TYPE); - SELECT_LEX *sel= lex->current_select; - SELECT_LEX_UNIT *unit= sel->master_unit(); - lex->current_select= sel= unit->outer_select(); - Table_ident *ti= new (thd->mem_root) Table_ident(unit); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - if (unlikely(!($$= sel->add_table_to_list(thd, - ti, $6, 0, - TL_READ, - MDL_SHARED_READ)))) - MYSQL_YYABORT; - sel->add_joined_table($$); - lex->pop_context(); - lex->nest_level--; - } - else if (unlikely($6 != NULL)) - { - /* - Tables with or without joins within parentheses cannot - have aliases, and we ruled out derived tables above. - */ - thd->parse_error(); + if (!($$= Select->end_nested_join(thd))) MYSQL_YYABORT; - } - else - { - /* nested join: FROM (t1 JOIN t2 ...), - nest_level is the same as in the outer query */ - $$= $3; - } - /* - Fields in derived table can be used in upper select in - case of merge. We do not add HAVING fields because we do - not merge such derived. We do not add union because - also do not merge them - */ - if ($$ && $$->derived && - !$$->derived->first_select()->next_select()) - $$->select_lex->add_where_field($$->derived->first_select()); - if ($5) - { - MYSQL_YYABORT_UNLESS(!$3); - $$->vers_conditions= Lex->vers_conditions; - } } - /* Represents derived table with WITH clause */ - | '(' get_select_lex subselect_start - with_clause query_expression_body - subselect_end ')' opt_for_system_time_clause opt_table_alias - { - LEX *lex=Lex; - SELECT_LEX *sel= $2; - SELECT_LEX_UNIT *unit= $5->master_unit(); - Table_ident *ti= new (thd->mem_root) Table_ident(unit); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - $5->set_with_clause($4); - lex->current_select= sel; - if (unlikely(!($$= sel->add_table_to_list(lex->thd, - ti, $9, 0, - TL_READ, - MDL_SHARED_READ)))) - MYSQL_YYABORT; - sel->add_joined_table($$); - if ($8) - $$->vers_conditions= Lex->vers_conditions; - } ; -/* - This rule accepts just about anything. The reason is that we have - empty-producing rules in the beginning of rules, in this case - subselect_start. This forces bison to take a decision which rules to - reduce by long before it has seen any tokens. This approach ties us - to a very limited class of parseable languages, and unfortunately - SQL is not one of them. The chosen 'solution' was this rule, which - produces just about anything, even complete bogus statements, for - instance ( table UNION SELECT 1 ). - Fortunately, we know that the semantic value returned by - select_derived is NULL if it contained a derived table, and a pointer to - the base table's TABLE_LIST if it was a base table. So in the rule - regarding union's, we throw a parse error manually and pretend it - was bison that did it. - - Also worth noting is that this rule concerns query expressions in - the from clause only. Top level select statements and other types of - subqueries have their own union rules. -*/ -select_derived_union: - select_derived - | select_derived union_order_or_limit +nested_table_reference_list: + table_ref ',' table_ref { - if (unlikely($1)) - { - thd->parse_error(); + if (Select->init_nested_join(thd)) MYSQL_YYABORT; - } - } - | select_derived union_head_non_top - { - if (unlikely($1)) - { - thd->parse_error(); - MYSQL_YYABORT; - } - } - union_list_derived_part2 - | derived_simple_table opt_select_lock_type - | derived_simple_table order_or_limit opt_select_lock_type - | derived_simple_table opt_select_lock_type union_list_derived - ; - -union_list_derived_part2: - query_term_union_not_ready { Lex->pop_context(); } - | query_term_union_ready { Lex->pop_context(); } - | query_term_union_ready { Lex->pop_context(); } union_list_derived - ; - -union_list_derived: - union_head_non_top union_list_derived_part2 - ; - - -/* The equivalent of select_init2 for nested queries. */ -select_init2_derived: - select_part2_derived - { - Select->set_braces(0); + Select->add_joined_table($1); + Select->add_joined_table($3); + $$= $1->embedding; } - ; - -/* The equivalent of select_part2 for nested queries. */ -select_part2_derived: + | nested_table_reference_list ',' table_ref { - LEX *lex= Lex; - SELECT_LEX *sel= lex->current_select; - if (sel->linkage != UNION_TYPE) - mysql_init_select(lex); - lex->current_select->parsing_place= SELECT_LIST; - } - opt_query_expression_options select_item_list - { - Select->parsing_place= NO_MATTER; + Select->add_joined_table($3); + $$= $1; } ; -/* handle contents of parentheses in join expression */ -select_derived: - get_select_lex_derived derived_table_list +join_table_parens: + '(' join_table_parens ')' { $$= $2; } + | '(' join_table ')' { LEX *lex= Lex; - /* for normal joins, $2 != NULL and end_nested_join() != NULL, - for derived tables, both must equal NULL */ - - if (unlikely(!($$= $1->end_nested_join(lex->thd)) && $2)) - MYSQL_YYABORT; - if (unlikely(!$2 && $$)) + if (!($$= lex->current_select->nest_last_join(thd))) { thd->parse_error(); MYSQL_YYABORT; @@ -11995,86 +11866,59 @@ select_derived: } ; -derived_simple_table: - derived_query_specification { $$= $1; } - | derived_table_value_constructor { $$= $1; } - ; -/* - Similar to query_specification, but for derived tables. - Example: the inner parenthesized SELECT in this query: - SELECT * FROM (SELECT * FROM t1); -*/ -derived_query_specification: - SELECT_SYM select_derived_init select_derived2 - { - if ($2) - Select->set_braces(1); - $$= NULL; - } - ; -derived_table_value_constructor: - VALUES - { - Lex->tvc_start(); - } - values_list +table_primary_ident: + table_ident opt_use_partition opt_for_system_time_clause + opt_table_alias_clause opt_key_definition { - if (Lex->tvc_finalize_derived()) + SELECT_LEX *sel= Select; + sel->table_join_options= 0; + if (!($$= Select->add_table_to_list(thd, $1, $4, + Select->get_table_join_options(), + YYPS->m_lock_type, + YYPS->m_mdl_type, + Select->pop_index_hints(), + $2))) MYSQL_YYABORT; - $$= NULL; + TABLE_LIST *tl= $$; + if ($3) + tl->vers_conditions= Lex->vers_conditions; } ; -select_derived2: - { - LEX *lex= Lex; - lex->derived_tables|= DERIVED_SUBQUERY; - if (unlikely(!lex->expr_allows_subselect || - lex->sql_command == (int)SQLCOM_PURGE)) - { - thd->parse_error(); - MYSQL_YYABORT; - } - if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE || - unlikely(mysql_new_select(lex, 1, NULL))) - MYSQL_YYABORT; - mysql_init_select(lex); - lex->current_select->linkage= DERIVED_TABLE_TYPE; - lex->current_select->parsing_place= SELECT_LIST; - } - select_options select_item_list - { - Select->parsing_place= NO_MATTER; - } - opt_table_expression - ; +/* + Represents a flattening of the following rules from the SQL:2003 + standard. This sub-rule corresponds to the sub-rule + <table primary> ::= ... | <derived table> [ AS ] <correlation name> -get_select_lex: - /* Empty */ { $$= Select; } - ; + <derived table> ::= <table subquery> + <table subquery> ::= <subquery> + <subquery> ::= <left paren> <query expression> <right paren> + <query expression> ::= [ <with clause> ] <query expression body> -get_select_lex_derived: - get_select_lex + For the time being we use the non-standard rule + select_derived_union which is a compromise between the standard + and our parser. Possibly this rule could be replaced by our + query_expression_body. +*/ + +table_primary_derived: + query_primary_parens opt_for_system_time_clause table_alias_clause { - LEX *lex= Lex; - if (unlikely($1->init_nested_join(lex->thd))) - MYSQL_YYABORT; + if (!($$= Lex->parsed_derived_select($1, $2, $3))) + YYABORT; } - ; - -select_derived_init: + | '(' + query_expression + ')' opt_for_system_time_clause table_alias_clause { - LEX *lex= Lex; - - TABLE_LIST *embedding= lex->current_select->embedding; - $$= embedding && - !embedding->nested_join->join_list.elements; - /* return true if we are deeply nested */ + if (!($$= Lex->parsed_derived_unit($2, $4, $5))) + YYABORT; } ; + opt_outer: /* empty */ {} | OUTER {} @@ -12205,9 +12049,14 @@ table_alias: | '=' ; -opt_table_alias: +opt_table_alias_clause: /* empty */ { $$=0; } - | table_alias ident_table_alias + + | table_alias_clause { $$= $1; } + ; + +table_alias_clause: + table_alias ident_table_alias { $$= (LEX_CSTRING*) thd->memdup(&$2,sizeof(LEX_STRING)); if (unlikely($$ == NULL)) @@ -12303,7 +12152,7 @@ olap_opt: SQL-2003: GROUP BY ... CUBE(col1, col2, col3) */ LEX *lex=Lex; - if (unlikely(lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)) + if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE)) my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH CUBE", "global union parameters")); lex->current_select->olap= CUBE_TYPE; @@ -12320,7 +12169,7 @@ olap_opt: SQL-2003: GROUP BY ... ROLLUP(col1, col2, col3) */ LEX *lex= Lex; - if (unlikely(lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)) + if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE)) my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH ROLLUP", "global union parameters")); lex->current_select->olap= ROLLUP_TYPE; @@ -12380,7 +12229,7 @@ opt_window_partition_clause: opt_window_order_clause: /* empty */ { } - | ORDER_SYM BY order_list + | ORDER_SYM BY order_list { Select->order_list= *($3); } ; opt_window_frame_clause: @@ -12504,70 +12353,35 @@ alter_order_item: opt_order_clause: /* empty */ + { $$= NULL; } | order_clause + { $$= $1; } ; order_clause: ORDER_SYM BY { - LEX *lex=Lex; - SELECT_LEX *sel= lex->current_select; - SELECT_LEX_UNIT *unit= sel-> master_unit(); - if (unlikely(sel->linkage != GLOBAL_OPTIONS_TYPE && - sel->olap != UNSPECIFIED_OLAP_TYPE && - (sel->linkage != UNION_TYPE || sel->braces))) - { - my_error(ER_WRONG_USAGE, MYF(0), - "CUBE/ROLLUP", "ORDER BY"); - MYSQL_YYABORT; - } - if (lex->sql_command != SQLCOM_ALTER_TABLE && - !unit->fake_select_lex) - { - /* - A query of the of the form (SELECT ...) ORDER BY order_list is - executed in the same way as the query - SELECT ... ORDER BY order_list - unless the SELECT construct contains ORDER BY or LIMIT clauses. - Otherwise we create a fake SELECT_LEX if it has not been - created yet. - */ - SELECT_LEX *first_sl= unit->first_select(); - if (unlikely(!unit->is_unit_op() && - (first_sl->order_list.elements || - first_sl->select_limit) && - unit->add_fake_select_lex(thd))) - MYSQL_YYABORT; - } - if (sel->master_unit()->is_unit_op() && !sel->braces) - { - /* - At this point we don't know yet whether this is the last - select in union or not, but we move ORDER BY to - fake_select_lex anyway. If there would be one more select - in union mysql_new_select will correctly throw error. - */ - DBUG_ASSERT(sel->master_unit()->fake_select_lex); - lex->current_select= sel->master_unit()->fake_select_lex; - } + thd->where= "ORDER clause"; } order_list { - + $$= $4; } ; order_list: order_list ',' order_ident order_dir { - if (unlikely(add_order_to_list(thd, $3,(bool) $4))) - MYSQL_YYABORT; - } + $$= $1; + if (add_to_list(thd, *$$, $3,(bool) $4)) + MYSQL_YYABORT; + } | order_ident order_dir { - if (unlikely(add_order_to_list(thd, $1,(bool) $2))) + $$= new (thd->mem_root) SQL_I_List<ORDER>(); + if (add_to_list(thd, *$$, $1, (bool) $2)) MYSQL_YYABORT; - } + } ; order_dir: @@ -12577,63 +12391,61 @@ order_dir: ; opt_limit_clause: - /* empty */ {} - | limit_clause {} + /* empty */ + { $$.empty(); } + | limit_clause + { $$= $1; } ; -limit_clause_init: - LIMIT - { - SELECT_LEX *sel= Select; - if (sel->master_unit()->is_unit_op() && !sel->braces) - { - /* Move LIMIT that belongs to UNION to fake_select_lex */ - Lex->current_select= sel->master_unit()->fake_select_lex; - DBUG_ASSERT(Select); - } - } - ; - limit_clause: - limit_clause_init limit_options + LIMIT limit_options { - SELECT_LEX *sel= Select; - if (!sel->select_limit->basic_const_item() || - sel->select_limit->val_int() > 0) + $$= $2; + if (!$$.select_limit->basic_const_item() || + $$.select_limit->val_int() > 0) Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); } - | limit_clause_init limit_options + | LIMIT limit_options ROWS_SYM EXAMINED_SYM limit_rows_option { + $$= $2; Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); } - | limit_clause_init ROWS_SYM EXAMINED_SYM limit_rows_option + | LIMIT ROWS_SYM EXAMINED_SYM limit_rows_option { + $$.select_limit= 0; + $$.offset_limit= 0; + $$.explicit_limit= 1; Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); } ; +opt_global_limit_clause: + opt_limit_clause + { + Select->explicit_limit= $1.explicit_limit; + Select->select_limit= $1.select_limit; + Select->offset_limit= $1.offset_limit; + } + limit_options: limit_option { - SELECT_LEX *sel= Select; - sel->select_limit= $1; - sel->offset_limit= 0; - sel->explicit_limit= 1; + $$.select_limit= $1; + $$.offset_limit= 0; + $$.explicit_limit= 1; } | limit_option ',' limit_option { - SELECT_LEX *sel= Select; - sel->select_limit= $3; - sel->offset_limit= $1; - sel->explicit_limit= 1; + $$.select_limit= $3; + $$.offset_limit= $1; + $$.explicit_limit= 1; } | limit_option OFFSET_SYM limit_option { - SELECT_LEX *sel= Select; - sel->select_limit= $1; - sel->offset_limit= $3; - sel->explicit_limit= 1; + $$.select_limit= $1; + $$.offset_limit= $3; + $$.explicit_limit= 1; } ; @@ -12696,6 +12508,77 @@ delete_limit_clause: | LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; } ; +opt_order_limit_lock: + /* empty */ + { $$= NULL; } + | order_or_limit + { + $$= $1; + $$->lock.empty(); + } + | order_or_limit select_lock_type + { + $$= $1; + $$->lock= $2; + } + | select_lock_type + { + $$= new(thd->mem_root) Lex_order_limit_lock; + if (!$$) + YYABORT; + $$->order_list= NULL; + $$->limit.empty(); + $$->lock= $1; + } + ; +query_expression_tail: + opt_order_limit_lock + ; + +opt_procedure_or_into: + /* empty */ + { + $$.empty(); + } + | procedure_clause opt_select_lock_type + { + $$= $2; + } + | into opt_select_lock_type + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_WARN_DEPRECATED_SYNTAX, + ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX), + "<select expression> INTO <destination>;", + "'SELECT <select list> INTO <destination>" + " FROM...'"); + $$= $2; + } + ; + + +order_or_limit: + order_clause opt_limit_clause + { + $$= new(thd->mem_root) Lex_order_limit_lock; + if (!$$) + YYABORT; + $$->order_list= $1; + $$->limit= $2; + } + | limit_clause + { + Lex_order_limit_lock *op= $$= new(thd->mem_root) Lex_order_limit_lock; + if (!$$) + YYABORT; + op->order_list= NULL; + op->limit= $1; + $$->order_list= NULL; + $$->limit= $1; + } + ; + + opt_plus: /* empty */ | '+' @@ -12765,14 +12648,11 @@ bool: | TRUE_SYM { $$= 1; } | FALSE_SYM { $$= 0; } - procedure_clause: PROCEDURE_SYM ident /* Procedure name */ { LEX *lex=Lex; - DBUG_ASSERT(&lex->select_lex == lex->current_select); - lex->proc_list.elements=0; lex->proc_list.first=0; lex->proc_list.next= &lex->proc_list.first; @@ -12792,6 +12672,7 @@ procedure_clause: parameters are reduced. */ Lex->expr_allows_subselect= false; + Select->options|= OPTION_PROCEDURE_CLAUSE; } '(' procedure_list ')' { @@ -12875,6 +12756,7 @@ select_outvar: into: INTO into_destination + {} ; into_destination: @@ -13068,10 +12950,11 @@ table_list: table_name: table_ident { - if (unlikely(!Select->add_table_to_list(thd, $1, NULL, - TL_OPTION_UPDATING, - YYPS->m_lock_type, - YYPS->m_mdl_type))) + if (!thd->lex->current_select_or_default()-> + add_table_to_list(thd, $1, NULL, + TL_OPTION_UPDATING, + YYPS->m_lock_type, + YYPS->m_mdl_type)) MYSQL_YYABORT; } ; @@ -13145,16 +13028,23 @@ insert: LEX *lex= Lex; lex->sql_command= SQLCOM_INSERT; lex->duplicates= DUP_ERROR; + if (Lex->main_select_push()) + MYSQL_YYABORT; mysql_init_select(lex); + lex->current_select->parsing_place= BEFORE_OPT_LIST; } insert_lock_option opt_ignore insert2 { Select->set_lock_for_tables($3); - Lex->current_select= &Lex->select_lex; + Lex->current_select= Lex->first_select_lex(); } insert_field_spec opt_insert_update - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; replace: @@ -13163,15 +13053,22 @@ replace: LEX *lex=Lex; lex->sql_command = SQLCOM_REPLACE; lex->duplicates= DUP_REPLACE; + if (Lex->main_select_push()) + MYSQL_YYABORT; mysql_init_select(lex); + lex->current_select->parsing_place= BEFORE_OPT_LIST; } replace_lock_option insert2 { Select->set_lock_for_tables($3); - Lex->current_select= &Lex->select_lex; + Lex->current_select= Lex->first_select_lex(); } insert_field_spec - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; insert_lock_option: @@ -13214,15 +13111,14 @@ insert_table: table_name_with_opt_use_partition { LEX *lex=Lex; - lex->field_list.empty(); + //lex->field_list.empty(); lex->many_values.empty(); lex->insert_list=0; }; insert_field_spec: insert_values {} - | '(' ')' insert_values {} - | '(' fields ')' insert_values {} + | insert_field_list insert_values {} | SET { LEX *lex=Lex; @@ -13230,20 +13126,33 @@ insert_field_spec: unlikely(lex->many_values.push_back(lex->insert_list, thd->mem_root))) MYSQL_YYABORT; + lex->current_select->parsing_place= NO_MATTER; } ident_eq_list ; +insert_field_list: + LEFT_PAREN_ALT opt_fields ')' + { + Lex->current_select->parsing_place= AFTER_LIST; + } + ; + +opt_fields: + /* empty */ + | fields + ; + fields: fields ',' insert_ident { Lex->field_list.push_back($3, thd->mem_root); } | insert_ident { Lex->field_list.push_back($1, thd->mem_root); } ; + + insert_values: - VALUES values_list {} - | VALUE_SYM values_list {} - | create_select_query_expression {} + create_select_query_expression {} ; values_list: @@ -13393,6 +13302,8 @@ update: UPDATE_SYM { LEX *lex= Lex; + if (Lex->main_select_push()) + MYSQL_YYABORT; mysql_init_select(lex); lex->sql_command= SQLCOM_UPDATE; lex->duplicates= DUP_ERROR; @@ -13401,13 +13312,14 @@ update: SET update_list { LEX *lex= Lex; - if (lex->select_lex.table_list.elements > 1) + if (lex->first_select_lex()->table_list.elements > 1) lex->sql_command= SQLCOM_UPDATE_MULTI; - else if (unlikely(lex->select_lex.get_table_list()->derived)) + else if (lex->first_select_lex()->get_table_list()->derived) { /* it is single table update and it is update of derived table */ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), - lex->select_lex.get_table_list()->alias.str, "UPDATE"); + lex->first_select_lex()->get_table_list()->alias.str, + "UPDATE"); MYSQL_YYABORT; } /* @@ -13417,7 +13329,14 @@ update: */ Select->set_lock_for_tables($3); } - opt_where_clause opt_order_clause delete_limit_clause {} + opt_where_clause opt_order_clause delete_limit_clause + { + if ($10) + Select->order_list= *($10); + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; update_list: @@ -13464,9 +13383,11 @@ delete: mysql_init_select(lex); YYPS->m_lock_type= TL_WRITE_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_WRITE; + if (Lex->main_select_push()) + MYSQL_YYABORT; lex->ignore= 0; - lex->select_lex.init_order(); + lex->first_select_lex()->order_list.empty(); } delete_part2 ; @@ -13487,6 +13408,7 @@ delete_part2: | HISTORY_SYM delete_single_table opt_delete_system_time { Lex->last_table()->vers_conditions= Lex->vers_conditions; + Lex->pop_select(); //main select } ; @@ -13510,7 +13432,12 @@ single_multi: opt_where_clause opt_order_clause delete_limit_clause - opt_select_expressions {} + opt_select_expressions + { + if ($3) + Select->order_list= *($3); + Lex->pop_select(); //main select + } | table_wild_list { mysql_init_multi_delete(Lex); @@ -13521,6 +13448,9 @@ single_multi: { if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex))) MYSQL_YYABORT; + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } | FROM table_alias_ref_list { @@ -13532,6 +13462,9 @@ single_multi: { if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex))) MYSQL_YYABORT; + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } ; @@ -13600,9 +13533,9 @@ truncate: LEX* lex= Lex; lex->sql_command= SQLCOM_TRUNCATE; lex->alter_info.reset(); - lex->select_lex.options= 0; - lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; - lex->select_lex.init_order(); + lex->first_select_lex()->options= 0; + lex->sql_cache= LEX::SQL_CACHE_UNSPECIFIED; + lex->first_select_lex()->order_list.empty(); YYPS->m_lock_type= TL_WRITE; YYPS->m_mdl_type= MDL_EXCLUSIVE; } @@ -13687,6 +13620,8 @@ show: LEX *lex=Lex; lex->wild=0; lex->ident= null_clex_str; + if (Lex->main_select_push()) + MYSQL_YYABORT; mysql_init_select(lex); lex->current_select->parsing_place= SELECT_LIST; lex->create_info.init(); @@ -13694,6 +13629,7 @@ show: show_param { Select->parsing_place= NO_MATTER; + Lex->pop_select(); //main select } ; @@ -13709,40 +13645,40 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TABLES; - lex->select_lex.db= $3; - if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES))) + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES)) MYSQL_YYABORT; } | opt_full TRIGGERS_SYM opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TRIGGERS; - lex->select_lex.db= $3; - if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TRIGGERS))) + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_TRIGGERS)) MYSQL_YYABORT; } | EVENTS_SYM opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_EVENTS; - lex->select_lex.db= $2; - if (unlikely(prepare_schema_table(thd, lex, 0, SCH_EVENTS))) + lex->first_select_lex()->db= $2; + if (prepare_schema_table(thd, lex, 0, SCH_EVENTS)) MYSQL_YYABORT; } | TABLE_SYM STATUS_SYM opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TABLE_STATUS; - lex->select_lex.db= $3; - if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TABLES))) + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_TABLES)) MYSQL_YYABORT; } | OPEN_SYM TABLES opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_OPEN_TABLES; - lex->select_lex.db= $3; - if (unlikely(prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES))) + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES)) MYSQL_YYABORT; } | PLUGINS_SYM @@ -13791,12 +13727,13 @@ show_param: LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS; } - opt_limit_clause + opt_global_limit_clause | RELAYLOG_SYM optional_connection_name EVENTS_SYM binlog_in binlog_from { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS; - } opt_limit_clause + } + opt_global_limit_clause | keys_or_index from_or_in table_ident opt_db opt_where_clause { LEX *lex= Lex; @@ -13838,13 +13775,13 @@ show_param: LEX_CSTRING var= {STRING_WITH_LEN("error_count")}; (void) create_select_for_variable(thd, &var); } - | WARNINGS opt_limit_clause + | WARNINGS opt_global_limit_clause { Lex->sql_command = SQLCOM_SHOW_WARNS;} - | ERRORS opt_limit_clause + | ERRORS opt_global_limit_clause { Lex->sql_command = SQLCOM_SHOW_ERRORS;} | PROFILES_SYM { Lex->sql_command = SQLCOM_SHOW_PROFILES; } - | PROFILE_SYM opt_profile_defs opt_profile_args opt_limit_clause + | PROFILE_SYM opt_profile_defs opt_profile_args opt_global_limit_clause { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_PROFILE; @@ -13906,7 +13843,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL,0))) + if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL,0)) MYSQL_YYABORT; lex->create_info.storage_media= HA_SM_DEFAULT; } @@ -13914,7 +13851,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL, 0))) + if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0)) MYSQL_YYABORT; lex->table_type= TABLE_TYPE_VIEW; } @@ -13922,7 +13859,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL, 0))) + if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0)) MYSQL_YYABORT; lex->table_type= TABLE_TYPE_SEQUENCE; } @@ -14139,7 +14076,7 @@ describe: mysql_init_select(lex); lex->current_select->parsing_place= SELECT_LIST; lex->sql_command= SQLCOM_SHOW_FIELDS; - lex->select_lex.db= null_clex_str; + lex->first_select_lex()->db= null_clex_str; lex->verbose= 0; if (unlikely(prepare_schema_table(thd, lex, $2, SCH_COLUMNS))) MYSQL_YYABORT; @@ -14153,12 +14090,13 @@ describe: explainable_command { LEX *lex=Lex; - lex->select_lex.options|= SELECT_DESCRIBE; + lex->first_select_lex()->options|= SELECT_DESCRIBE; } ; explainable_command: select + | select_into | insert | replace | update @@ -14179,6 +14117,8 @@ analyze_stmt_command: opt_extended_describe: EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; } + | EXTENDED_SYM ALL + { Lex->describe|= DESCRIBE_EXTENDED | DESCRIBE_EXTENDED2; } | PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; } | opt_format_json {} ; @@ -14221,8 +14161,7 @@ flush: lex->type= 0; lex->no_write_to_binlog= $2; } - flush_options - {} + flush_options {} ; flush_options: @@ -14239,6 +14178,7 @@ flush_options: opt_table_list opt_flush_lock {} | flush_options_list + {} ; opt_flush_lock: @@ -14434,6 +14374,8 @@ purge_option: lex->value_list.empty(); lex->value_list.push_front($2, thd->mem_root); lex->sql_command= SQLCOM_PURGE_BEFORE; + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } ; @@ -14494,7 +14436,7 @@ use: { LEX *lex=Lex; lex->sql_command=SQLCOM_CHANGE_DB; - lex->select_lex.db= $2; + lex->first_select_lex()->db= $2; } ; @@ -14511,6 +14453,9 @@ load: $2 == FILETYPE_CSV ? "LOAD DATA" : "LOAD XML"); MYSQL_YYABORT; } + if (lex->main_select_push()) + MYSQL_YYABORT; + mysql_init_select(lex); } load_data_lock opt_local INFILE TEXT_STRING_filesystem { @@ -14540,7 +14485,11 @@ load: opt_xml_rows_identified_by opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec opt_load_data_set_spec - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; data_or_xml: @@ -14738,11 +14687,6 @@ hex_or_bin_String: $1.length); if (unlikely(tmp == NULL)) MYSQL_YYABORT; - /* - it is OK only emulate fix_fields, because we need only - value of constant - */ - tmp->quick_fix_field(); $$= tmp->val_str((String*) 0); } | HEX_STRING @@ -14751,7 +14695,6 @@ hex_or_bin_String: $1.length); if (unlikely(tmp == NULL)) MYSQL_YYABORT; - tmp->quick_fix_field(); $$= tmp->val_str((String*) 0); } | BIN_NUM @@ -14764,7 +14707,6 @@ hex_or_bin_String: it is OK only emulate fix_fields, because we need only value of constant */ - tmp->quick_fix_field(); $$= tmp->val_str((String*) 0); } ; @@ -14900,26 +14842,23 @@ NUM_literal: temporal_literal: DATE_SYM TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_DATE, - true)))) + if (unlikely(!($$= type_handler_newdate.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } | TIME_SYM TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_TIME, - true)))) + if (unlikely(!($$= type_handler_time2.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } | TIMESTAMP TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_DATETIME, - true)))) + if (unlikely(!($$= type_handler_datetime.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } ; @@ -14935,17 +14874,21 @@ opt_with_clause: with_clause: - WITH opt_recursive + WITH opt_recursive { + LEX *lex= Lex; With_clause *with_clause= new With_clause($2, Lex->curr_with_clause); if (unlikely(with_clause == NULL)) MYSQL_YYABORT; - Lex->derived_tables|= DERIVED_WITH; - Lex->curr_with_clause= with_clause; + lex->derived_tables|= DERIVED_WITH; + lex->curr_with_clause= with_clause; with_clause->add_to_list(Lex->with_clauses_list_last_next); + if (lex->current_select && + lex->current_select->parsing_place == BEFORE_OPT_LIST) + lex->current_select->parsing_place= NO_MATTER; } - with_list + with_list { $$= Lex->curr_with_clause; Lex->curr_with_clause= Lex->curr_with_clause->pop(); @@ -14974,11 +14917,10 @@ with_list_element: MYSQL_YYABORT; Lex->with_column_list.empty(); } - AS '(' remember_name subselect remember_end ')' + AS '(' remember_name query_expression remember_end ')' { - With_element *elem= new With_element($1, *$2, $7->master_unit()); - if (unlikely(elem == NULL) || - unlikely(Lex->curr_with_clause->add_with_element(elem))) + With_element *elem= new With_element($1, *$2, $7); + if (elem == NULL || Lex->curr_with_clause->add_with_element(elem)) MYSQL_YYABORT; if (unlikely(elem->set_unparsed_spec(thd, $6+1, $8))) MYSQL_YYABORT; @@ -15917,14 +15859,22 @@ set: SET { LEX *lex=Lex; + if (lex->main_select_push()) + MYSQL_YYABORT; lex->set_stmt_init(); lex->var_list.empty(); sp_create_assignment_lex(thd, yychar == YYEMPTY); } start_option_value_list - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } | SET STATEMENT_SYM { + if (Lex->main_select_push()) + MYSQL_YYABORT; Lex->set_stmt_init(); } set_stmt_option_value_following_option_type_list @@ -15934,6 +15884,9 @@ set: my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT")); lex->stmt_var_list= lex->var_list; lex->var_list.empty(); + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } FOR_SYM verb_clause {} @@ -16352,7 +16305,7 @@ table_lock_list: ; table_lock: - table_ident opt_table_alias lock_option + table_ident opt_table_alias_clause lock_option { thr_lock_type lock_type= (thr_lock_type) $3; bool lock_for_write= (lock_type >= TL_WRITE_ALLOW_WRITE); @@ -16397,27 +16350,36 @@ unlock: */ handler: - HANDLER_SYM table_ident OPEN_SYM opt_table_alias + HANDLER_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + handler_tail + { + Lex->pop_select(); //main select + } + +handler_tail: + table_ident OPEN_SYM opt_table_alias_clause { LEX *lex= Lex; if (unlikely(lex->sphead)) my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); lex->sql_command = SQLCOM_HA_OPEN; - if (unlikely(!lex->current_select->add_table_to_list(thd, $2, $4, - 0))) + if (!lex->current_select->add_table_to_list(thd, $1, $3, 0)) MYSQL_YYABORT; } - | HANDLER_SYM table_ident_nodb CLOSE_SYM + | table_ident_nodb CLOSE_SYM { LEX *lex= Lex; if (unlikely(lex->sphead)) my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); lex->sql_command = SQLCOM_HA_CLOSE; - if (unlikely(!lex->current_select->add_table_to_list(thd, $2, 0, - 0))) + if (!lex->current_select->add_table_to_list(thd, $1, 0, 0)) MYSQL_YYABORT; } - | HANDLER_SYM table_ident_nodb READ_SYM + | table_ident_nodb READ_SYM { LEX *lex=Lex; if (unlikely(lex->sphead)) @@ -16431,15 +16393,24 @@ handler: lex->current_select->select_limit= one; lex->current_select->offset_limit= 0; lex->limit_rows_examined= 0; - if (unlikely(!lex->current_select->add_table_to_list(thd, $2, 0, - 0))) + if (!lex->current_select->add_table_to_list(thd, $1, 0, 0)) MYSQL_YYABORT; } - handler_read_or_scan opt_where_clause opt_limit_clause + handler_read_or_scan opt_where_clause opt_global_limit_clause { - Lex->expr_allows_subselect= TRUE; + LEX *lex=Lex; + lex->expr_allows_subselect= TRUE; + if (!lex->current_select->explicit_limit) + { + Item *one= new (thd->mem_root) Item_int(thd, (int32) 1); + if (one == NULL) + MYSQL_YYABORT; + lex->current_select->select_limit= one; + lex->current_select->offset_limit= 0; + lex->limit_rows_examined= 0; + } /* Stored functions are not supported for HANDLER READ. */ - if (unlikely(Lex->uses_stored_routines())) + if (lex->uses_stored_routines()) { my_error(ER_NOT_SUPPORTED_YET, MYF(0), "stored functions in HANDLER ... READ"); @@ -17075,212 +17046,27 @@ release: */ unit_type_decl: - UNION_SYM - { $$= UNION_TYPE; } + UNION_SYM union_option + { $$.unit_type= UNION_TYPE; $$.distinct= $2; } | INTERSECT_SYM - { $$= INTERSECT_TYPE; } + { $$.unit_type= INTERSECT_TYPE; $$.distinct= 1; } | EXCEPT_SYM - { $$= EXCEPT_TYPE; } - - -union_clause: - /* empty */ {} - | union_list - ; - -union_list: - unit_type_decl union_option - { - if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, TRUE))) - MYSQL_YYABORT; - } - union_list_part2 - { - /* - Remove from the name resolution context stack the context of the - last select in the union. - */ - Lex->pop_context(); - } - ; - -union_list_view: - unit_type_decl union_option - { - if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, TRUE))) - MYSQL_YYABORT; - } - query_expression_body_view - { - Lex->pop_context(); - } - ; + { $$.unit_type= EXCEPT_TYPE; $$.distinct= 1; } -union_order_or_limit: - { - LEX *lex= thd->lex; - DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE); - SELECT_LEX *sel= lex->current_select; - SELECT_LEX_UNIT *unit= sel->master_unit(); - SELECT_LEX *fake= unit->fake_select_lex; - if (fake) - { - fake->no_table_names_allowed= 1; - lex->current_select= fake; - } - thd->where= "global ORDER clause"; - } - order_or_limit - { - thd->lex->current_select->no_table_names_allowed= 0; - thd->where= ""; - } - ; - -order_or_limit: - order_clause opt_limit_clause - | limit_clause - ; /* Start a UNION, for non-top level query expressions. */ -union_head_non_top: - unit_type_decl union_option - { - if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, FALSE))) - MYSQL_YYABORT; - } - ; - union_option: /* empty */ { $$=1; } | DISTINCT { $$=1; } | ALL { $$=0; } ; -simple_table: - query_specification { $$= $1; } - | table_value_constructor { $$= $1; } - ; - -table_value_constructor: - VALUES - { - Lex->tvc_start(); - } - values_list - { - $$= Lex->current_select; - if (Lex->tvc_finalize()) - MYSQL_YYABORT; - } - ; - -/* - Corresponds to the SQL Standard - <query specification> ::= - SELECT [ <set quantifier> ] <select list> <table expression> - - Notes: - - We allow more options in addition to <set quantifier> - - <table expression> is optional in MariaDB -*/ -query_specification: - SELECT_SYM select_init2_derived opt_table_expression - { - $$= Lex->current_select->master_unit()->first_select(); - } - ; - -query_term_union_not_ready: - simple_table order_or_limit opt_select_lock_type { $$= $1; } - | '(' select_paren_derived ')' union_order_or_limit { $$= $2; } - ; - -query_term_union_ready: - simple_table opt_select_lock_type { $$= $1; } - | '(' select_paren_derived ')' { $$= $2; } - ; - -query_expression_body: - query_term_union_not_ready { $$= $1; } - | query_term_union_ready { $$= $1; } - | query_term_union_ready union_list_derived { $$= $1; } - ; - -/* Corresponds to <query expression> in the SQL:2003 standard. */ -subselect: - subselect_start opt_with_clause query_expression_body subselect_end - { - $3->set_with_clause($2); - $$= $3; - } - ; - -subselect_start: - { - LEX *lex=Lex; - if (unlikely(!lex->expr_allows_subselect || - lex->sql_command == (int)SQLCOM_PURGE)) - { - thd->parse_error(); - MYSQL_YYABORT; - } - /* - we are making a "derived table" for the parenthesis - as we need to have a lex level to fit the union - after the parenthesis, e.g. - (SELECT .. ) UNION ... becomes - SELECT * FROM ((SELECT ...) UNION ...) - */ - if (unlikely(mysql_new_select(Lex, 1, NULL))) - MYSQL_YYABORT; - } - ; - -subselect_end: - { - LEX *lex=Lex; - - lex->check_automatic_up(UNSPECIFIED_TYPE); - lex->pop_context(); - SELECT_LEX *child= lex->current_select; - lex->current_select = lex->current_select->return_after_parsing(); - lex->nest_level--; - lex->current_select->n_child_sum_items += child->n_sum_items; - /* - A subselect can add fields to an outer select. Reserve space for - them. - */ - lex->current_select->select_n_where_fields+= - child->select_n_where_fields; - - /* - Aggregate functions in having clause may add fields to an outer - select. Count them also. - */ - lex->current_select->select_n_having_items+= - child->select_n_having_items; - } - ; - -opt_query_expression_options: - /* empty */ - | query_expression_option_list - ; - -query_expression_option_list: - query_expression_option_list query_expression_option - | query_expression_option - ; - query_expression_option: STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; } | HIGH_PRIORITY { - if (unlikely(Lex->check_simple_select(&$1))) - MYSQL_YYABORT; YYPS->m_lock_type= TL_READ_HIGH_PRIORITY; YYPS->m_mdl_type= MDL_SHARED_READ; Select->options|= SELECT_HIGH_PRIORITY; @@ -17288,18 +17074,8 @@ query_expression_option: | DISTINCT { Select->options|= SELECT_DISTINCT; } | SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; } | SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; } - | SQL_BUFFER_RESULT - { - if (unlikely(Lex->check_simple_select(&$1))) - MYSQL_YYABORT; - Select->options|= OPTION_BUFFER_RESULT; - } - | SQL_CALC_FOUND_ROWS - { - if (unlikely(Lex->check_simple_select(&$1))) - MYSQL_YYABORT; - Select->options|= OPTION_FOUND_ROWS; - } + | SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; } + | SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; } | ALL { Select->options|= SELECT_ALL; } ; @@ -17387,35 +17163,14 @@ view_select: lex->parsing_options.allows_variable= FALSE; lex->create_view->select.str= (char *) YYLIP->get_cpp_ptr(); } - opt_with_clause query_expression_body_view view_check_option + query_expression + view_check_option { - LEX *lex= Lex; - size_t len= YYLIP->get_cpp_ptr() - lex->create_view->select.str; - void *create_view_select= thd->memdup(lex->create_view->select.str, len); - lex->create_view->select.length= len; - lex->create_view->select.str= (char *) create_view_select; - trim_whitespace(thd->charset(), - &lex->create_view->select); - lex->create_view->check= $4; - lex->parsing_options.allows_variable= TRUE; - lex->current_select->set_with_clause($2); + if (Lex->parsed_create_view($2, $3)) + MYSQL_YYABORT; } ; -/* - SQL Standard <query expression body> for VIEWs. - Does not include INTO and PROCEDURE clauses. -*/ -query_expression_body_view: - SELECT_SYM select_options_and_item_list select_init3_view - | table_value_constructor - | table_value_constructor union_order_or_limit - | table_value_constructor union_list_view - | '(' select_paren_view ')' - | '(' select_paren_view ')' union_order_or_limit - | '(' select_paren_view ')' union_list_view - ; - view_check_option: /* empty */ { $$= VIEW_CHECK_NONE; } | WITH CHECK_SYM OPTION { $$= VIEW_CHECK_CASCADED; } @@ -17514,11 +17269,10 @@ trigger_tail: sp_proc_stmt alternatives are not saving/restoring LEX, so lex->query_tables can be wiped out. */ - if (unlikely(!lex->select_lex. - add_table_to_list(thd, $10, (LEX_CSTRING*) 0, - TL_OPTION_UPDATING, - TL_READ_NO_INSERT, - MDL_SHARED_NO_WRITE))) + if (!lex->first_select_lex()-> + add_table_to_list(thd, $10, (LEX_CSTRING*) 0, + TL_OPTION_UPDATING, TL_READ_NO_INSERT, + MDL_SHARED_NO_WRITE)) MYSQL_YYABORT; } ; diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 8f98cfa3694..d4838590075 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -189,6 +189,20 @@ void ORAerror(THD *thd, const char *s) uint offset; } sp_cursor_name_and_offset; vers_history_point_t vers_history_point; + struct + { + enum sub_select_type unit_type; + bool distinct; + } unit_operation; + struct + { + SELECT_LEX *first; + SELECT_LEX *prev_last; + } select_list; + SQL_I_List<ORDER> *select_order; + Lex_select_lock select_lock; + Lex_select_limit select_limit; + Lex_order_limit_lock *order_limit_lock; /* pointers */ Create_field *create_field; @@ -234,6 +248,7 @@ void ORAerror(THD *thd, const char *s) handlerton *db_type; st_select_lex *select_lex; + st_select_lex_unit *select_lex_unit; struct p_elem_val *p_elem_value; class Window_frame *window_frame; class Window_frame_bound *window_frame_bound; @@ -243,7 +258,6 @@ void ORAerror(THD *thd, const char *s) /* enums */ enum enum_sp_suid_behaviour sp_suid; enum enum_view_suid view_suid; - enum sub_select_type unit_type; enum Condition_information_item::Name cond_info_item_name; enum enum_diag_condition_item_name diag_condition_item_name; enum Diagnostics_information::Which_area diag_area; @@ -282,10 +296,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 63 shift/reduce conflicts. + Currently there are 59 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 63 +%expect 59 /* Comments for TOKENS. @@ -436,6 +450,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %token LEADING /* SQL-2003-R */ %token LEAVE_SYM %token LEFT /* SQL-2003-R */ +%token LEFT_PAREN_ALT /* INTERNAL */ +%token LEFT_PAREN_WITH /* INTERNAL */ +%token LEFT_PAREN_LIKE /* INTERNAL */ %token LEX_HOSTNAME %token LIKE /* SQL-2003-R */ %token LIMIT @@ -1181,7 +1198,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); NCHAR_STRING %type <lex_str_ptr> - opt_table_alias + opt_table_alias_clause + table_alias_clause %type <ident_cli> IDENT @@ -1248,7 +1266,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); opt_temporary all_or_any opt_distinct opt_glimit_clause opt_ignore_leaves fulltext_options union_option opt_not - select_derived_init transaction_access_mode_types + transaction_access_mode_types opt_natural_language_mode opt_query_expansion opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt @@ -1371,11 +1389,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); join_table_list join_table table_factor table_ref esc_table_ref table_primary_ident table_primary_derived - select_derived derived_table_list - select_derived_union - derived_simple_table - derived_query_specification - derived_table_value_constructor + derived_table_list table_reference_list_parens + nested_table_reference_list join_table_parens %type <date_time_type> date_time_type; %type <interval> interval @@ -1411,14 +1426,19 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); UNDERSCORE_CHARSET %type <select_lex> subselect - get_select_lex get_select_lex_derived - simple_table query_specification - query_term_union_not_ready - query_term_union_ready - query_expression_body - select_paren_derived table_value_constructor + simple_table + query_primary + query_primary_parens + select_into_query_specification + + +%type <select_lex_unit> + query_specification_start + query_expression_body + query_expression + query_expression_unit %type <boolfunc2creator> comp_op @@ -1430,11 +1450,28 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %type <virtual_column> opt_check_constraint check_constraint virtual_column_func column_default_expr -%type <unit_type> unit_type_decl + +%type <unit_operation> unit_type_decl + +%type <select_lock> + opt_procedure_or_into + opt_select_lock_type + select_lock_type + opt_lock_wait_timeout_new + +%type <select_limit> opt_limit_clause limit_clause limit_options + +%type <order_limit_lock> + query_expression_tail + order_or_limit + opt_order_limit_lock + +%type <select_order> opt_order_clause order_clause order_list %type <NONE> analyze_stmt_command - query verb_clause create change select do drop insert replace insert2 + query verb_clause create change select select_into + do drop insert replace insert2 insert_values update delete truncate rename compound_statement show describe load alter optimize keycache preload flush reset purge commit rollback savepoint release @@ -1451,7 +1488,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); preload_list preload_list_or_parts preload_keys preload_keys_parts select_item_list select_item values_list no_braces no_braces_with_names opt_values_with_names values_with_names - opt_limit_clause delete_limit_clause fields opt_values values + delete_limit_clause fields opt_values values procedure_list procedure_list2 procedure_item field_def handler opt_generated_always opt_ignore opt_column opt_restrict @@ -1471,9 +1508,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); table_to_table_list table_to_table opt_table_list opt_as handler_rkey_function handler_read_or_scan single_multi table_wild_list table_wild_one opt_wild - union_clause union_list - subselect_start opt_and charset - subselect_end select_var_list select_var_list_init help + opt_and charset + select_var_list select_var_list_init help opt_extended_describe shutdown opt_format_json prepare prepare_src execute deallocate @@ -1624,8 +1660,8 @@ rule: <-- starts at col 1 query: END_OF_INPUT { - if (likely(!thd->bootstrap) && - unlikely(!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT))) + if (!thd->bootstrap && + (!(thd->lex->lex_options & OPTION_LEX_FOUND_COMMENT))) my_yyabort_error((ER_EMPTY_QUERY, MYF(0))); thd->lex->sql_command= SQLCOM_EMPTY_QUERY; @@ -1720,6 +1756,7 @@ statement: | rollback | savepoint | select + | select_into | set | set_assign | signal_stmt @@ -2074,17 +2111,22 @@ connection_name: /* create a table */ create: - create_or_replace opt_temporary TABLE_SYM opt_if_not_exists table_ident + create_or_replace opt_temporary TABLE_SYM opt_if_not_exists { LEX *lex= thd->lex; lex->create_info.init(); - if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, - $1 | $4))) + if (lex->main_select_push()) + MYSQL_YYABORT; + lex->current_select->parsing_place= BEFORE_OPT_LIST; + if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4)) MYSQL_YYABORT; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_UPDATING, - TL_WRITE, - MDL_EXCLUSIVE))) + } + table_ident + { + LEX *lex= thd->lex; + if (!lex->first_select_lex()-> + add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING, + TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; lex->alter_info.reset(); /* @@ -2099,7 +2141,6 @@ create: create_body { LEX *lex= thd->lex; - lex->current_select= &lex->select_lex; if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && !lex->create_info.db_type) { @@ -2108,22 +2149,24 @@ create: ER_WARN_USING_OTHER_HANDLER, ER_THD(thd, ER_WARN_USING_OTHER_HANDLER), hton_name(lex->create_info.db_type)->str, - $5->table.str); + $6->table.str); } create_table_set_open_action_and_adjust_tables(lex); + Lex->pop_select(); //main select } | create_or_replace opt_temporary SEQUENCE_SYM opt_if_not_exists table_ident { LEX *lex= thd->lex; + if (Lex->main_select_push()) + MYSQL_YYABORT; lex->create_info.init(); if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_SEQUENCE, $2, $1 | $4))) MYSQL_YYABORT; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_UPDATING, - TL_WRITE, - MDL_EXCLUSIVE))) + if (!lex->first_select_lex()-> + add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, + TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; /* @@ -2146,8 +2189,9 @@ create: if (unlikely(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.str, - lex->select_lex.table_list.first->table_name.str); + lex->first_select_lex()->table_list.first->db.str, + lex->first_select_lex()->table_list.first-> + table_name.str); MYSQL_YYABORT; } @@ -2160,10 +2204,8 @@ create: Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE; Lex->create_info.sequence= 1; - lex->current_select= &lex->select_lex; - if (unlikely((lex->create_info.used_fields & - HA_CREATE_USED_ENGINE) && - !lex->create_info.db_type)) + if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && + !lex->create_info.db_type) { lex->create_info.use_default_db_type(thd); push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, @@ -2173,44 +2215,69 @@ create: $5->table.str); } create_table_set_open_action_and_adjust_tables(lex); + Lex->pop_select(); //main select } - | create_or_replace opt_unique INDEX_SYM opt_if_not_exists ident + | create_or_replace opt_unique INDEX_SYM opt_if_not_exists + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + ident opt_key_algorithm_clause ON table_ident { - if (unlikely(Lex->add_create_index_prepare($8))) + if (Lex->add_create_index_prepare($9)) MYSQL_YYABORT; - if (unlikely(Lex->add_create_index($2, &$5, $6, $1 | $4))) + if (Lex->add_create_index($2, &$6, $7, $1 | $4)) MYSQL_YYABORT; } '(' key_list ')' opt_lock_wait_timeout normal_key_options - opt_index_lock_algorithm { } - | create_or_replace fulltext INDEX_SYM opt_if_not_exists ident + opt_index_lock_algorithm + { + Lex->pop_select(); //main select + } + | create_or_replace fulltext INDEX_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + opt_if_not_exists ident ON table_ident { - if (unlikely(Lex->add_create_index_prepare($7))) + if (Lex->add_create_index_prepare($8)) MYSQL_YYABORT; - if (unlikely(Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, - $1 | $4))) + if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5)) MYSQL_YYABORT; } '(' key_list ')' opt_lock_wait_timeout fulltext_key_options - opt_index_lock_algorithm { } - | create_or_replace spatial INDEX_SYM opt_if_not_exists ident + opt_index_lock_algorithm + { + Lex->pop_select(); //main select + } + | create_or_replace spatial INDEX_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + opt_if_not_exists ident ON table_ident { - if (unlikely(Lex->add_create_index_prepare($7))) + if (Lex->add_create_index_prepare($8)) MYSQL_YYABORT; - if (unlikely(Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, - $1 | $4))) + if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5)) MYSQL_YYABORT; } '(' key_list ')' opt_lock_wait_timeout spatial_key_options - opt_index_lock_algorithm { } + opt_index_lock_algorithm + { + Lex->pop_select(); //main select + } | create_or_replace DATABASE opt_if_not_exists ident { Lex->create_info.default_table_charset= NULL; Lex->create_info.used_fields= 0; + if (Lex->main_select_push()) + MYSQL_YYABORT; } opt_create_database_options { @@ -2219,52 +2286,94 @@ create: $1 | $3))) MYSQL_YYABORT; lex->name= $4; + Lex->pop_select(); //main select } | create_or_replace definer_opt opt_view_suid VIEW_SYM opt_if_not_exists table_ident { - if (unlikely(Lex->add_create_view(thd, $1 | $5, - DTYPE_ALGORITHM_UNDEFINED, $3, - $6))) + if (Lex->main_select_push()) + MYSQL_YYABORT; + if (Lex->add_create_view(thd, $1 | $5, + DTYPE_ALGORITHM_UNDEFINED, $3, $6)) MYSQL_YYABORT; } view_list_opt AS view_select - { } + { + Lex->pop_select(); //main select + } | create_or_replace view_algorithm definer_opt opt_view_suid VIEW_SYM opt_if_not_exists table_ident { - if (unlikely(Lex->add_create_view(thd, $1 | $6, $2, $4, $7))) + if (Lex->main_select_push()) + MYSQL_YYABORT; + if (Lex->add_create_view(thd, $1 | $6, $2, $4, $7)) MYSQL_YYABORT; } view_list_opt AS view_select - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer_opt TRIGGER_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } trigger_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer_opt PROCEDURE_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } sp_tail_standalone - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer_opt EVENT_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } event_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer FUNCTION_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } sf_tail_standalone - { } + { + Lex->pop_select(); //main select + } | create_or_replace no_definer FUNCTION_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } create_function_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace no_definer AGGREGATE_SYM FUNCTION_SYM { + if (Lex->main_select_push()) + MYSQL_YYABORT; Lex->create_info.set($1); Lex->udf.type= UDFTYPE_AGGREGATE; } udf_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list opt_require_clause opt_resource_options { @@ -2887,7 +2996,7 @@ clear_privileges: lex->columns.empty(); lex->grant= lex->grant_tot_col= 0; lex->all_privileges= 0; - lex->select_lex.db= null_clex_str; + lex->first_select_lex()->db= null_clex_str; lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0; bzero((char *)&(lex->mqh),sizeof(lex->mqh)); @@ -3517,7 +3626,7 @@ raise_stmt: signal_stmt: SIGNAL_SYM signal_value opt_set_signal_information { - if (unlikely(Lex->add_signal_statement(thd, $2))) + if (Lex->add_signal_statement(thd, $2)) MYSQL_YYABORT; } ; @@ -3964,7 +4073,9 @@ sp_proc_stmt_return: ; reset_lex_expr: - { Lex->sphead->reset_lex(thd); } expr { $$= $2; } + { Lex->sphead->reset_lex(thd); } + expr + { $$= $2; } ; sp_proc_stmt_exit: @@ -3980,14 +4091,14 @@ sp_proc_stmt_exit: } | EXIT_SYM WHEN_SYM reset_lex_expr { - if (unlikely(Lex->sp_exit_statement(thd, $3)) || - unlikely(Lex->sphead->restore_lex(thd))) + if (Lex->sp_exit_statement(thd, $3) || + Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } | EXIT_SYM label_ident WHEN_SYM reset_lex_expr { - if (unlikely(Lex->sp_exit_statement(thd, &$2, $4)) || - unlikely(Lex->sphead->restore_lex(thd))) + if (Lex->sp_exit_statement(thd, &$2, $4) || + Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } ; @@ -4005,14 +4116,14 @@ sp_proc_stmt_continue: } | CONTINUE_SYM WHEN_SYM reset_lex_expr { - if (unlikely(Lex->sp_continue_statement(thd, $3)) || - unlikely(Lex->sphead->restore_lex(thd))) + if (Lex->sp_continue_statement(thd, $3) || + Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } | CONTINUE_SYM label_ident WHEN_SYM reset_lex_expr { - if (unlikely(Lex->sp_continue_statement(thd, &$2, $4)) || - unlikely(Lex->sphead->restore_lex(thd))) + if (Lex->sp_continue_statement(thd, &$2, $4) || + Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } ; @@ -4071,7 +4182,7 @@ assignment_source_expr: $$->sp_lex_in_use= true; $$->set_item_and_free_list($3, thd->free_list); thd->free_list= NULL; - if (unlikely($$->sphead->restore_lex(thd))) + if ($$->sphead->restore_lex(thd)) MYSQL_YYABORT; } ; @@ -4080,6 +4191,7 @@ for_loop_bound_expr: assignment_source_lex { Lex->sphead->reset_lex(thd, $1); + Lex->current_select->parsing_place= FOR_LOOP_BOUND; } expr { @@ -4089,6 +4201,7 @@ for_loop_bound_expr: $$->set_item_and_free_list($3, NULL); if (unlikely($$->sphead->restore_lex(thd))) MYSQL_YYABORT; + Lex->current_select->parsing_place= NO_MATTER; } ; @@ -4310,7 +4423,8 @@ case_stmt_body: { if (unlikely(Lex->case_stmt_action_expr($2))) MYSQL_YYABORT; - if (unlikely(Lex->sphead->restore_lex(thd))) + + if (Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } simple_when_clause_list @@ -4602,7 +4716,7 @@ while_body: LEX *lex= Lex; if (unlikely(lex->sp_while_loop_expression(thd, $1))) MYSQL_YYABORT; - if (unlikely(lex->sphead->restore_lex(thd))) + if (lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } sp_proc_stmts1 END LOOP_SYM @@ -4625,7 +4739,7 @@ repeat_body: if (unlikely(i == NULL) || unlikely(lex->sphead->add_instr(i))) MYSQL_YYABORT; - if (unlikely(lex->sphead->restore_lex(thd))) + if (lex->sphead->restore_lex(thd)) MYSQL_YYABORT; /* We can shortcut the cont_backpatch here */ i->m_cont_dest= ip+1; @@ -5105,26 +5219,16 @@ size_number: */ create_body: - '(' create_field_list ')' + create_field_list_parens { Lex->create_info.option_list= NULL; } opt_create_table_options opt_create_partitioning opt_create_select {} | opt_create_table_options opt_create_partitioning opt_create_select {} - /* - the following rule is redundant, but there's a shift/reduce - conflict that prevents the rule above from parsing a syntax like - CREATE TABLE t1 (SELECT 1); - */ - | '(' create_select_query_specification ')' - | '(' create_select_query_specification ')' - { Select->set_braces(1);} union_list {} - | '(' create_select_query_specification ')' - { Select->set_braces(1);} union_order_or_limit {} | create_like { Lex->create_info.add(DDL_options_st::OPT_LIKE); - TABLE_LIST *src_table= Lex->select_lex.add_table_to_list(thd, - $1, NULL, 0, TL_READ, MDL_SHARED_READ); + TABLE_LIST *src_table= Lex->first_select_lex()-> + add_table_to_list(thd, $1, NULL, 0, TL_READ, MDL_SHARED_READ); if (unlikely(! src_table)) MYSQL_YYABORT; /* CREATE TABLE ... LIKE is not allowed for views. */ @@ -5134,7 +5238,7 @@ create_body: create_like: LIKE table_ident { $$= $2; } - | '(' LIKE table_ident ')' { $$= $3; } + | LEFT_PAREN_LIKE LIKE table_ident ')' { $$= $3; } ; opt_create_select: @@ -5143,23 +5247,20 @@ opt_create_select: ; create_select_query_expression: - opt_with_clause SELECT_SYM create_select_part2 opt_table_expression - create_select_part4 - { - Select->set_braces(0); - Select->set_with_clause($1); + query_expression + { + if (Lex->parsed_insert_select($1->first_select())) + MYSQL_YYABORT; } - union_clause - | opt_with_clause SELECT_SYM create_select_part2 - create_select_part3_union_not_ready create_select_part4 + | LEFT_PAREN_WITH with_clause query_expression_body ')' { - Select->set_with_clause($1); + SELECT_LEX *first_select= $3->first_select(); + $3->set_with_clause($2); + $2->attach_to(first_select); + + if (Lex->parsed_insert_select(first_select)) + MYSQL_YYABORT; } - | '(' create_select_query_specification ')' - | '(' create_select_query_specification ')' - { Select->set_braces(1);} union_list {} - | '(' create_select_query_specification ')' - { Select->set_braces(1);} union_order_or_limit {} ; opt_create_partitioning: @@ -5247,8 +5348,13 @@ partition_entry: We enter here when opening the frm file to translate partition info string into part_info data structure. */ + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + partition + { + Lex->pop_select(); //main select } - partition {} ; partition: @@ -5902,56 +6008,6 @@ opt_versioning_interval_start: End of partition parser part */ -create_select_query_specification: - opt_with_clause SELECT_SYM create_select_part2 create_select_part3 - create_select_part4 - { - Select->set_with_clause($1); - } - ; - -create_select_part2: - { - LEX *lex=Lex; - if (lex->sql_command == SQLCOM_INSERT) - lex->sql_command= SQLCOM_INSERT_SELECT; - else if (lex->sql_command == SQLCOM_REPLACE) - lex->sql_command= SQLCOM_REPLACE_SELECT; - /* - The following work only with the local list, the global list - is created correctly in this case - */ - lex->current_select->table_list.save_and_clear(&lex->save_list); - mysql_init_select(lex); - lex->current_select->parsing_place= SELECT_LIST; - } - select_options select_item_list - { - Select->parsing_place= NO_MATTER; - } - ; - -create_select_part3: - opt_table_expression - | create_select_part3_union_not_ready - ; - -create_select_part3_union_not_ready: - table_expression order_or_limit - | order_or_limit - ; - -create_select_part4: - opt_select_lock_type - { - /* - The following work only with the local list, the global list - is created correctly in this case - */ - Lex->current_select->table_list.push_front(&Lex->save_list); - } - ; - opt_as: /* empty */ {} | AS {} @@ -6169,7 +6225,7 @@ create_table_option: } | UNION_SYM opt_equal { - Lex->select_lex.table_list.save_and_clear(&Lex->save_list); + Lex->first_select_lex()->table_list.save_and_clear(&Lex->save_list); } '(' opt_table_list ')' { @@ -6178,8 +6234,8 @@ create_table_option: from the global list. */ LEX *lex=Lex; - lex->create_info.merge_list= lex->select_lex.table_list; - lex->select_lex.table_list= lex->save_list; + lex->create_info.merge_list= lex->first_select_lex()->table_list; + lex->first_select_lex()->table_list= lex->save_list; /* When excluding union list from the global list we assume that elements of the former immediately follow elements which represent @@ -6380,6 +6436,13 @@ create_field_list: } ; +create_field_list_parens: + LEFT_PAREN_ALT field_list ')' + { + Lex->create_last_non_select_table= Lex->last_table(); + } + ; + field_list: field_list_item | field_list ',' field_list_item @@ -6674,6 +6737,8 @@ parse_vcol_expr: Prevent the end user from invoking this command. */ MYSQL_YYABORT_UNLESS(Lex->parse_vcol_expr); + if (Lex->main_select_push()) + MYSQL_YYABORT; } expr { @@ -6681,14 +6746,15 @@ parse_vcol_expr: if (unlikely(!v)) MYSQL_YYABORT; Lex->last_field->vcol_info= v; + Lex->pop_select(); //main select } ; parenthesized_expr: - subselect + remember_tok_start + query_expression { - $$= new (thd->mem_root) Item_singlerow_subselect(thd, $1); - if (unlikely($$ == NULL)) + if (!($$= Lex->create_item_query_expression(thd, $1, $2))) MYSQL_YYABORT; } | expr @@ -7714,23 +7780,25 @@ alter: Lex->name= null_clex_str; Lex->table_type= TABLE_TYPE_UNKNOWN; Lex->sql_command= SQLCOM_ALTER_TABLE; - Lex->duplicates= DUP_ERROR; - Lex->select_lex.init_order(); + Lex->duplicates= DUP_ERROR; + Lex->first_select_lex()->order_list.empty(); Lex->create_info.init(); Lex->create_info.row_type= ROW_TYPE_NOT_USED; Lex->alter_info.reset(); Lex->no_write_to_binlog= 0; Lex->create_info.storage_media= HA_SM_DEFAULT; + if (Lex->main_select_push()) + MYSQL_YYABORT; DBUG_ASSERT(!Lex->m_sql_cmd); } alter_options TABLE_SYM table_ident opt_lock_wait_timeout { - if (unlikely(!Lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_UPDATING, - TL_READ_NO_INSERT, - MDL_SHARED_UPGRADABLE))) + if (!Lex->first_select_lex()-> + add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, + TL_READ_NO_INSERT, MDL_SHARED_UPGRADABLE)) MYSQL_YYABORT; - Lex->select_lex.db= (Lex->select_lex.table_list.first)->db; + Lex->first_select_lex()->db= + (Lex->first_select_lex()->table_list.first)->db; Lex->create_last_non_select_table= Lex->last_table(); } alter_commands @@ -7742,11 +7810,14 @@ alter: if (unlikely(Lex->m_sql_cmd == NULL)) MYSQL_YYABORT; } + Lex->pop_select(); //main select } | ALTER DATABASE ident_or_empty { Lex->create_info.default_table_charset= NULL; Lex->create_info.used_fields= 0; + if (Lex->main_select_push()) + MYSQL_YYABORT; } create_database_options { @@ -7756,6 +7827,7 @@ alter: if (lex->name.str == NULL && unlikely(lex->copy_db_to(&lex->name))) MYSQL_YYABORT; + Lex->pop_select(); //main select } | ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM { @@ -7771,6 +7843,8 @@ alter: if (unlikely(lex->sphead)) my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE")); + if (Lex->main_select_push()) + MYSQL_YYABORT; lex->sp_chistics.init(); } sp_a_chistics @@ -7779,6 +7853,9 @@ alter: lex->sql_command= SQLCOM_ALTER_PROCEDURE; lex->spname= $3; + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } | ALTER FUNCTION_SYM sp_name { @@ -7786,6 +7863,8 @@ alter: if (unlikely(lex->sphead)) my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION")); + if (Lex->main_select_push()) + MYSQL_YYABORT; lex->sp_chistics.init(); } sp_a_chistics @@ -7794,14 +7873,23 @@ alter: lex->sql_command= SQLCOM_ALTER_FUNCTION; lex->spname= $3; + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } | ALTER view_algorithm definer_opt opt_view_suid VIEW_SYM table_ident { - if (unlikely(Lex->add_alter_view(thd, $2, $4, $6))) + if (Lex->main_select_push()) + MYSQL_YYABORT; + if (Lex->add_alter_view(thd, $2, $4, $6)) MYSQL_YYABORT; } view_list_opt AS view_select - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } | ALTER definer_opt opt_view_suid VIEW_SYM table_ident /* We have two separate rules for ALTER VIEW rather that @@ -7809,14 +7897,22 @@ alter: with the ALTER EVENT below. */ { - if (unlikely(Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5))) + if (Lex->main_select_push()) + MYSQL_YYABORT; + if (Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5)) MYSQL_YYABORT; } view_list_opt AS view_select - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } | ALTER definer_opt remember_name EVENT_SYM sp_name { - /* + if (Lex->main_select_push()) + MYSQL_YYABORT; + /* It is safe to use Lex->spname because ALTER EVENT xxx RENATE TO yyy DO ALTER EVENT RENAME TO is not allowed. Lex->spname is used in the case of RENAME TO @@ -7848,6 +7944,8 @@ alter: */ Lex->sql_command= SQLCOM_ALTER_EVENT; Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr(); + + Lex->pop_select(); //main select } | ALTER TABLESPACE alter_tablespace_info { @@ -7891,16 +7989,17 @@ alter: lex->create_info.init(); lex->no_write_to_binlog= 0; DBUG_ASSERT(!lex->m_sql_cmd); + if (Lex->main_select_push()) + MYSQL_YYABORT; } table_ident { LEX *lex= Lex; - if (unlikely(!(lex->create_info.seq_create_info= - new (thd->mem_root) sequence_definition())) || - unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_SEQUENCE, - TL_WRITE, - MDL_EXCLUSIVE))) + if (!(lex->create_info.seq_create_info= new (thd->mem_root) + sequence_definition()) || + !lex->first_select_lex()-> + add_table_to_list(thd, $5, NULL, TL_OPTION_SEQUENCE, + TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; } sequence_defs @@ -7909,6 +8008,9 @@ alter: Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence($3); if (unlikely(Lex->m_sql_cmd == NULL)) MYSQL_YYABORT; + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } ; @@ -8058,16 +8160,14 @@ alter_commands: WITH TABLE_SYM table_ident have_partitioning { LEX *lex= thd->lex; - lex->select_lex.db= $6->db; - if (lex->select_lex.db.str == NULL && - unlikely(lex->copy_db_to(&lex->select_lex.db))) + if (lex->first_select_lex()->db.str == NULL && + lex->copy_db_to(&lex->first_select_lex()->db)) MYSQL_YYABORT; lex->name= $6->table; lex->alter_info.partition_flags|= ALTER_PARTITION_EXCHANGE; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $6, NULL, - TL_OPTION_UPDATING, - TL_READ_NO_INSERT, - MDL_SHARED_NO_WRITE))) + if (!lex->first_select_lex()-> + add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING, + TL_READ_NO_INSERT, MDL_SHARED_NO_WRITE)) MYSQL_YYABORT; DBUG_ASSERT(!lex->m_sql_cmd); lex->m_sql_cmd= new (thd->mem_root) @@ -8306,10 +8406,11 @@ alter_list_item: | RENAME opt_to table_ident { LEX *lex=Lex; - lex->select_lex.db= $3->db; - if (lex->select_lex.db.str == NULL && - unlikely(lex->copy_db_to(&lex->select_lex.db))) + lex->first_select_lex()->db= $3->db; + if (lex->first_select_lex()->db.str == NULL && + lex->copy_db_to(&lex->first_select_lex()->db)) MYSQL_YYABORT; + if (unlikely(check_table_name($3->table.str,$3->table.length, FALSE)) || ($3->db.str && unlikely(check_db_name((LEX_STRING*) &$3->db)))) @@ -9003,8 +9104,8 @@ adm_partition: cache_keys_spec: { - Lex->select_lex.alloc_index_hints(thd); - Select->set_index_hint_type(INDEX_HINT_USE, + Lex->first_select_lex()->alloc_index_hints(thd); + Select->set_index_hint_type(INDEX_HINT_USE, INDEX_HINT_MASK_ALL); } cache_key_list_or_empty @@ -9027,215 +9128,211 @@ opt_ignore_leaves: select: - opt_with_clause select_init - { - LEX *lex= Lex; - lex->sql_command= SQLCOM_SELECT; - lex->current_select->set_with_clause($1); - } - ; - -select_init: - SELECT_SYM select_options_and_item_list select_init3 - | table_value_constructor - | table_value_constructor union_list - | table_value_constructor union_order_or_limit - | '(' select_paren ')' - | '(' select_paren ')' union_list - | '(' select_paren ')' union_order_or_limit - ; - -union_list_part2: - SELECT_SYM select_options_and_item_list select_init3_union_query_term - | table_value_constructor - | table_value_constructor union_list - | table_value_constructor union_order_or_limit - | '(' select_paren_union_query_term ')' - | '(' select_paren_union_query_term ')' union_list - | '(' select_paren_union_query_term ')' union_order_or_limit - ; - -select_paren: + query_expression_body { - Lex->current_select->set_braces(true); + if (Lex->push_select($1->fake_select_lex ? + $1->fake_select_lex : + $1->first_select())) + MYSQL_YYABORT; } - table_value_constructor + opt_procedure_or_into { - DBUG_ASSERT(Lex->current_select->braces); + Lex->pop_select(); + if (Lex->select_finalize($1)) + MYSQL_YYABORT; } - | + | with_clause query_expression_body { - /* - In order to correctly parse UNION's global ORDER BY we need to - set braces before parsing the clause. - */ - Lex->current_select->set_braces(true); + if (Lex->push_select($2->fake_select_lex ? + $2->fake_select_lex : + $2->first_select())) + MYSQL_YYABORT; } - SELECT_SYM select_options_and_item_list select_part3 - opt_select_lock_type + opt_procedure_or_into { - DBUG_ASSERT(Lex->current_select->braces); + Lex->pop_select(); + $2->set_with_clause($1); + $1->attach_to($2->first_select()); + if (Lex->select_finalize($2)) + MYSQL_YYABORT; } - | '(' select_paren ')' ; -select_paren_union_query_term: + +select_into: + select_into_query_specification { - /* - In order to correctly parse UNION's global ORDER BY we need to - set braces before parsing the clause. - */ - Lex->current_select->set_braces(true); + if (Lex->push_select($1)) + MYSQL_YYABORT; } - SELECT_SYM select_options_and_item_list select_part3_union_query_term - opt_select_lock_type + opt_order_limit_lock { - DBUG_ASSERT(Lex->current_select->braces); - } - | '(' select_paren_union_query_term ')' - ; + st_select_lex_unit *unit; + if (!(unit= Lex->parsed_body_select($1, $3))) + MYSQL_YYABORT; + if (Lex->select_finalize(unit)) + MYSQL_YYABORT; + } + ; -select_paren_view: + +simple_table: + query_specification { $$= $1; } + | table_value_constructor { $$= $1; } + ; + +table_value_constructor: + VALUES + { + if (Lex->parsed_TVC_start()) + MYSQL_YYABORT; + } + values_list + { + if (!($$= Lex->parsed_TVC_end())) + MYSQL_YYABORT; + } + ; + +query_specification_start: + SELECT_SYM { - /* - In order to correctly parse UNION's global ORDER BY we need to - set braces before parsing the clause. - */ - Lex->current_select->set_braces(true); + SELECT_LEX *sel; + LEX *lex= Lex; + if (!(sel= lex->alloc_select(TRUE)) || + lex->push_select(sel)) + MYSQL_YYABORT; + sel->init_select(); + sel->braces= FALSE; } - SELECT_SYM select_options_and_item_list select_part3_view - opt_select_lock_type + select_options { - DBUG_ASSERT(Lex->current_select->braces); + Select->parsing_place= SELECT_LIST; } - | '(' select_paren_view ')' - ; + select_item_list + { + Select->parsing_place= NO_MATTER; + } + ; -/* The equivalent of select_paren for nested queries. */ -select_paren_derived: +query_specification: + query_specification_start + opt_from_clause + opt_where_clause + opt_group_clause + opt_having_clause + opt_window_clause { - Lex->current_select->set_braces(true); + $$= Lex->pop_select(); } - table_value_constructor + ; + +select_into_query_specification: + query_specification_start + into + opt_from_clause + opt_where_clause + opt_group_clause + opt_having_clause + opt_window_clause { - DBUG_ASSERT(Lex->current_select->braces); - $$= Lex->current_select->master_unit()->first_select(); + $$= Lex->pop_select(); } - | + ; + +opt_from_clause: + /* Empty */ + | from_clause + ; + +query_primary: + simple_table + { $$= $1; } + | query_primary_parens + { $$= $1; } + ; + +query_primary_parens: + '(' query_expression_unit { - Lex->current_select->set_braces(true); + if (Lex->parsed_unit_in_brackets($2)) + MYSQL_YYABORT; } - SELECT_SYM select_part2_derived - opt_table_expression - opt_order_clause - opt_limit_clause - opt_select_lock_type + query_expression_tail ')' { - DBUG_ASSERT(Lex->current_select->braces); - $$= Lex->current_select->master_unit()->first_select(); + $$= Lex->parsed_unit_in_brackets_tail($2, $4); } - | '(' select_paren_derived ')' { $$= $2; } - ; - -select_init3: - opt_table_expression - opt_select_lock_type + | '(' query_primary { - /* Parentheses carry no meaning here */ - Lex->current_select->set_braces(false); + Lex->push_select($2); } - union_clause - | select_part3_union_not_ready - opt_select_lock_type + query_expression_tail ')' { - /* Parentheses carry no meaning here */ - Lex->current_select->set_braces(false); + if (!($$= Lex->parsed_select_in_brackets($2, $4))) + YYABORT; } ; - -select_init3_union_query_term: - opt_table_expression - opt_select_lock_type +query_expression_unit: + query_primary + unit_type_decl + query_primary { - /* Parentheses carry no meaning here */ - Lex->current_select->set_braces(false); + if (!($$= Lex->parsed_select_expr_start($1, $3, $2.unit_type, + $2.distinct))) + YYABORT; } - union_clause - | select_part3_union_not_ready_noproc - opt_select_lock_type + | query_expression_unit + unit_type_decl + query_primary { - /* Parentheses carry no meaning here */ - Lex->current_select->set_braces(false); + if (!($$= Lex->parsed_select_expr_cont($1, $3, $2.unit_type, + $2.distinct, TRUE))) + YYABORT; } ; - -select_init3_view: - opt_table_expression opt_select_lock_type +query_expression_body: + query_primary { - Lex->current_select->set_braces(false); + Lex->push_select($1); } - | opt_table_expression opt_select_lock_type + query_expression_tail { - Lex->current_select->set_braces(false); + if (!($$= Lex->parsed_body_select($1, $3))) + MYSQL_YYABORT; } - union_list_view - | order_or_limit opt_select_lock_type + | query_expression_unit { - Lex->current_select->set_braces(false); + if (Lex->parsed_body_unit($1)) + MYSQL_YYABORT; } - | table_expression order_or_limit opt_select_lock_type + query_expression_tail { - Lex->current_select->set_braces(false); + if (!($$= Lex->parsed_body_unit_tail($1, $3))) + MYSQL_YYABORT; } ; -/* - The SELECT parts after select_item_list that cannot be followed by UNION. -*/ - -select_part3: - opt_table_expression - | select_part3_union_not_ready - ; - -select_part3_union_query_term: - opt_table_expression - | select_part3_union_not_ready_noproc - ; - -select_part3_view: - opt_table_expression - | order_or_limit - | table_expression order_or_limit - ; - -select_part3_union_not_ready: - select_part3_union_not_ready_noproc - | table_expression procedure_clause - | table_expression order_or_limit procedure_clause - ; - -select_part3_union_not_ready_noproc: - order_or_limit - | into opt_table_expression opt_order_clause opt_limit_clause - | table_expression into - | table_expression order_or_limit - | table_expression order_or_limit into - ; - -select_options_and_item_list: +query_expression: + opt_with_clause + query_expression_body { - LEX *lex= Lex; - SELECT_LEX *sel= lex->current_select; - if (sel->linkage != UNION_TYPE) - mysql_init_select(lex); - lex->current_select->parsing_place= SELECT_LIST; + if ($1) + { + $2->set_with_clause($1); + $1->attach_to($2->first_select()); + } + $$= $2; } - select_options select_item_list + ; + +subselect: + remember_tok_start + query_expression { - Select->parsing_place= NO_MATTER; + if (!($$= Lex->parsed_subselect($2, $1))) + YYABORT; } ; @@ -9243,18 +9340,6 @@ select_options_and_item_list: /** <table expression>, as in the SQL standard. */ -table_expression: - from_clause - opt_where_clause - opt_group_clause - opt_having_clause - opt_window_clause - ; - -opt_table_expression: - /* Empty */ - | table_expression - ; from_clause: FROM table_reference_list @@ -9303,8 +9388,9 @@ history_point: TIMESTAMP TEXT_STRING { Item *item; - if (!(item= create_temporal_literal(thd, $2.str, $2.length, YYCSCL, - MYSQL_TYPE_DATETIME, true))) + if (!(item= type_handler_datetime2.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true))) MYSQL_YYABORT; $$= Vers_history_point(VERS_TIMESTAMP, item); } @@ -9357,59 +9443,70 @@ select_option: query_expression_option | SQL_NO_CACHE_SYM { - /* - Allow this flag only on the first top-level SELECT statement, if - SQL_CACHE wasn't specified, and only once per query. - */ - if (unlikely(Lex->current_select != &Lex->select_lex)) - my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE")); - if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE)) - my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE")); - if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE)) + /* + Allow this flag once per query. + */ + if (Select->options & OPTION_NO_QUERY_CACHE) my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE")); - - Lex->safe_to_cache_query=0; - Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE; - Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE; + Select->options|= OPTION_NO_QUERY_CACHE; } | SQL_CACHE_SYM { - /* - Allow this flag only on the first top-level SELECT statement, if - SQL_NO_CACHE wasn't specified, and only once per query. - */ - if (unlikely(Lex->current_select != &Lex->select_lex)) - my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE")); - if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE)) - my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE")); - if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE)) + /* + Allow this flag once per query. + */ + if (Select->options & OPTION_TO_QUERY_CACHE) my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE")); - - Lex->safe_to_cache_query=1; - Lex->select_lex.options|= OPTION_TO_QUERY_CACHE; - Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE; + Select->options|= OPTION_TO_QUERY_CACHE; } ; -opt_select_lock_type: - /* empty */ - | FOR_SYM UPDATE_SYM opt_lock_wait_timeout + +select_lock_type: + FOR_SYM UPDATE_SYM opt_lock_wait_timeout_new { - LEX *lex=Lex; - lex->current_select->lock_type= TL_WRITE; - lex->current_select->set_lock_for_tables(TL_WRITE); - lex->safe_to_cache_query=0; + $$= $3; + $$.defined_lock= TRUE; + $$.update_lock= TRUE; } - | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout + | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout_new { - LEX *lex=Lex; - lex->current_select->lock_type= TL_READ_WITH_SHARED_LOCKS; - lex->current_select-> - set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS); - lex->safe_to_cache_query=0; + $$= $5; + $$.defined_lock= TRUE; + $$.update_lock= FALSE; } ; + +opt_select_lock_type: + /* empty */ + { + $$.empty(); + } + | select_lock_type + { + $$= $1; + } + ; + + +opt_lock_wait_timeout_new: + /* empty */ + { + $$.empty(); + } + | WAIT_SYM ulong_num + { + $$.defined_timeout= TRUE; + $$.timeout= $2; + } + | NOWAIT_SYM + { + $$.defined_timeout= TRUE; + $$.timeout= 0; + } + ; + select_item_list: select_item_list ',' select_item | select_item @@ -10106,7 +10203,21 @@ column_default_non_parenthesized_expr: | param_marker { $$= $1; } | variable | sum_expr + { + if (!Lex->select_stack_top) + { + my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0)); + MYSQL_YYABORT; + } + } | window_func_expr + { + if (!Lex->select_stack_top) + { + my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0)); + MYSQL_YYABORT; + } + } | inverse_distribution_function | ROW_SYM '(' expr ',' expr_list ')' { @@ -10303,7 +10414,7 @@ function_call_keyword_timestamp: } | TIMESTAMP '(' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_add_time(thd, $3, $5, 1, 0); + $$= new (thd->mem_root) Item_func_timestamp(thd, $3, $5); if (unlikely($$ == NULL)) MYSQL_YYABORT; } @@ -11735,10 +11846,15 @@ esc_table_ref: /* Equivalent to <table reference list> in the SQL:2003 standard. */ /* Warning - may return NULL in case of incomplete SELECT */ derived_table_list: - esc_table_ref { $$=$1; } + esc_table_ref + { + $$=$1; + Select->add_joined_table($1); + } | derived_table_list ',' esc_table_ref { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); + Select->add_joined_table($3); } ; @@ -11757,11 +11873,18 @@ join_table: left-associative joins. */ table_ref normal_join table_ref %prec TABLE_REF_PRIORITY - { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=$2; } + { + MYSQL_YYABORT_UNLESS($1 && ($$=$3)); + Select->add_joined_table($1); + Select->add_joined_table($3); + $3->straight=$2; + } | table_ref normal_join table_ref ON { MYSQL_YYABORT_UNLESS($1 && $3); + Select->add_joined_table($1); + Select->add_joined_table($3); /* Change the current name resolution context to a local context. */ if (unlikely(push_new_name_resolution_context(thd, $1, $3))) MYSQL_YYABORT; @@ -11778,6 +11901,8 @@ join_table: USING { MYSQL_YYABORT_UNLESS($1 && $3); + Select->add_joined_table($1); + Select->add_joined_table($3); } '(' using_list ')' { @@ -11788,6 +11913,8 @@ join_table: | table_ref NATURAL inner_join table_factor { MYSQL_YYABORT_UNLESS($1 && ($$=$4)); + Select->add_joined_table($1); + Select->add_joined_table($4); $4->straight=$3; add_join_natural($1,$4,NULL,Select); } @@ -11797,6 +11924,8 @@ join_table: ON { MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); /* Change the current name resolution context to a local context. */ if (unlikely(push_new_name_resolution_context(thd, $1, $5))) MYSQL_YYABORT; @@ -11813,6 +11942,8 @@ join_table: | table_ref LEFT opt_outer JOIN_SYM table_factor { MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); } USING '(' using_list ')' { @@ -11823,6 +11954,8 @@ join_table: | table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor { MYSQL_YYABORT_UNLESS($1 && $6); + Select->add_joined_table($1); + Select->add_joined_table($6); add_join_natural($1,$6,NULL,Select); $6->outer_join|=JOIN_TYPE_LEFT; $$=$6; @@ -11833,6 +11966,8 @@ join_table: ON { MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); /* Change the current name resolution context to a local context. */ if (unlikely(push_new_name_resolution_context(thd, $1, $5))) MYSQL_YYABORT; @@ -11850,6 +11985,8 @@ join_table: | table_ref RIGHT opt_outer JOIN_SYM table_factor { MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); } USING '(' using_list ')' { @@ -11861,6 +11998,8 @@ join_table: | table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor { MYSQL_YYABORT_UNLESS($1 && $6); + Select->add_joined_table($1); + Select->add_joined_table($6); add_join_natural($6,$1,NULL,Select); LEX *lex= Lex; if (unlikely(!($$= lex->current_select->convert_right_join()))) @@ -11895,238 +12034,45 @@ use_partition: $$= $3; } ; - -/* - This is a flattening of the rules <table factor> and <table primary> - in the SQL:2003 standard, since we don't have <sample clause> - I.e. - <table factor> ::= <table primary> [ <sample clause> ] -*/ -/* Warning - may return NULL in case of incomplete SELECT */ table_factor: - table_primary_ident - | table_primary_derived - ; - -table_primary_ident: - { - DBUG_ASSERT(Select); - SELECT_LEX *sel= Select; - sel->table_join_options= 0; - } - table_ident opt_use_partition opt_for_system_time_clause opt_table_alias opt_key_definition - { - if (unlikely(!($$= Select->add_table_to_list(thd, $2, $5, - Select->get_table_join_options(), - YYPS->m_lock_type, - YYPS->m_mdl_type, - Select-> - pop_index_hints(), - $3)))) - MYSQL_YYABORT; - Select->add_joined_table($$); - if ($4) - $$->vers_conditions= Lex->vers_conditions; - } + table_primary_ident { $$= $1; } + | table_primary_derived { $$= $1; } + | join_table_parens { $$= $1; } + | table_reference_list_parens { $$= $1; } ; - - -/* - Represents a flattening of the following rules from the SQL:2003 - standard. This sub-rule corresponds to the sub-rule - <table primary> ::= ... | <derived table> [ AS ] <correlation name> - - <derived table> ::= <table subquery> - <table subquery> ::= <subquery> - <subquery> ::= <left paren> <query expression> <right paren> - <query expression> ::= [ <with clause> ] <query expression body> - - For the time being we use the non-standard rule - select_derived_union which is a compromise between the standard - and our parser. Possibly this rule could be replaced by our - query_expression_body. -*/ - -table_primary_derived: - '(' get_select_lex select_derived_union ')' opt_for_system_time_clause opt_table_alias +table_reference_list_parens: + '(' table_reference_list_parens ')' { $$= $2; } + | '(' nested_table_reference_list ')' { - /* Use $2 instead of Lex->current_select as derived table will - alter value of Lex->current_select. */ - if (!($3 || $6) && $2->embedding && - !$2->embedding->nested_join->join_list.elements) - { - /* we have a derived table ($3 == NULL) but no alias, - Since we are nested in further parentheses so we - can pass NULL to the outer level parentheses - Permits parsing of "((((select ...))) as xyz)" */ - $$= 0; - } - else if (!$3) - { - /* Handle case of derived table, alias may be NULL if there - are no outer parentheses, add_table_to_list() will throw - error in this case */ - LEX *lex=Lex; - lex->check_automatic_up(UNSPECIFIED_TYPE); - SELECT_LEX *sel= lex->current_select; - SELECT_LEX_UNIT *unit= sel->master_unit(); - lex->current_select= sel= unit->outer_select(); - Table_ident *ti= new (thd->mem_root) Table_ident(unit); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - if (unlikely(!($$= sel->add_table_to_list(thd, - ti, $6, 0, - TL_READ, - MDL_SHARED_READ)))) - MYSQL_YYABORT; - sel->add_joined_table($$); - lex->pop_context(); - lex->nest_level--; - } - else if (unlikely($6 != NULL)) - { - /* - Tables with or without joins within parentheses cannot - have aliases, and we ruled out derived tables above. - */ - thd->parse_error(); + if (!($$= Select->end_nested_join(thd))) MYSQL_YYABORT; - } - else - { - /* nested join: FROM (t1 JOIN t2 ...), - nest_level is the same as in the outer query */ - $$= $3; - } - /* - Fields in derived table can be used in upper select in - case of merge. We do not add HAVING fields because we do - not merge such derived. We do not add union because - also do not merge them - */ - if ($$ && $$->derived && - !$$->derived->first_select()->next_select()) - $$->select_lex->add_where_field($$->derived->first_select()); - if ($5) - { - MYSQL_YYABORT_UNLESS(!$3); - $$->vers_conditions= Lex->vers_conditions; - } } - /* Represents derived table with WITH clause */ - | '(' get_select_lex subselect_start - with_clause query_expression_body - subselect_end ')' opt_for_system_time_clause opt_table_alias - { - LEX *lex=Lex; - SELECT_LEX *sel= $2; - SELECT_LEX_UNIT *unit= $5->master_unit(); - Table_ident *ti= new (thd->mem_root) Table_ident(unit); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - $5->set_with_clause($4); - lex->current_select= sel; - if (unlikely(!($$= sel->add_table_to_list(lex->thd, - ti, $9, 0, - TL_READ, - MDL_SHARED_READ)))) - MYSQL_YYABORT; - sel->add_joined_table($$); - if ($8) - $$->vers_conditions= Lex->vers_conditions; - } ; -/* - This rule accepts just about anything. The reason is that we have - empty-producing rules in the beginning of rules, in this case - subselect_start. This forces bison to take a decision which rules to - reduce by long before it has seen any tokens. This approach ties us - to a very limited class of parseable languages, and unfortunately - SQL is not one of them. The chosen 'solution' was this rule, which - produces just about anything, even complete bogus statements, for - instance ( table UNION SELECT 1 ). - Fortunately, we know that the semantic value returned by - select_derived is NULL if it contained a derived table, and a pointer to - the base table's TABLE_LIST if it was a base table. So in the rule - regarding union's, we throw a parse error manually and pretend it - was bison that did it. - - Also worth noting is that this rule concerns query expressions in - the from clause only. Top level select statements and other types of - subqueries have their own union rules. -*/ -select_derived_union: - select_derived - | select_derived union_order_or_limit - { - if (unlikely($1)) - { - thd->parse_error(); - MYSQL_YYABORT; - } - } - | select_derived union_head_non_top +nested_table_reference_list: + table_ref ',' table_ref { - if (unlikely($1)) - { - thd->parse_error(); + if (Select->init_nested_join(thd)) MYSQL_YYABORT; - } - } - union_list_derived_part2 - | derived_simple_table opt_select_lock_type - | derived_simple_table order_or_limit opt_select_lock_type - | derived_simple_table opt_select_lock_type union_list_derived - ; - -union_list_derived_part2: - query_term_union_not_ready { Lex->pop_context(); } - | query_term_union_ready { Lex->pop_context(); } - | query_term_union_ready { Lex->pop_context(); } union_list_derived - ; - -union_list_derived: - union_head_non_top union_list_derived_part2 - ; - - -/* The equivalent of select_init2 for nested queries. */ -select_init2_derived: - select_part2_derived - { - Select->set_braces(0); - } - ; - -/* The equivalent of select_part2 for nested queries. */ -select_part2_derived: - { - LEX *lex= Lex; - SELECT_LEX *sel= lex->current_select; - if (sel->linkage != UNION_TYPE) - mysql_init_select(lex); - lex->current_select->parsing_place= SELECT_LIST; + Select->add_joined_table($1); + Select->add_joined_table($3); + $$= $1->embedding; } - opt_query_expression_options select_item_list + | nested_table_reference_list ',' table_ref { - Select->parsing_place= NO_MATTER; + Select->add_joined_table($3); + $$= $1; } ; -/* handle contents of parentheses in join expression */ -select_derived: - get_select_lex_derived derived_table_list +join_table_parens: + '(' join_table_parens ')' { $$= $2; } + | '(' join_table ')' { LEX *lex= Lex; - /* for normal joins, $2 != NULL and end_nested_join() != NULL, - for derived tables, both must equal NULL */ - - if (unlikely(!($$= $1->end_nested_join(lex->thd)) && $2)) - MYSQL_YYABORT; - if (unlikely(!$2 && $$)) + if (!($$= lex->current_select->nest_last_join(thd))) { thd->parse_error(); MYSQL_YYABORT; @@ -12134,83 +12080,54 @@ select_derived: } ; -derived_simple_table: - derived_query_specification { $$= $1; } - | derived_table_value_constructor { $$= $1; } - ; -/* - Similar to query_specification, but for derived tables. - Example: the inner parenthesized SELECT in this query: - SELECT * FROM (SELECT * FROM t1); -*/ -derived_query_specification: - SELECT_SYM select_derived_init select_derived2 - { - if ($2) - Select->set_braces(1); - $$= NULL; - } - ; -derived_table_value_constructor: - VALUES - { - Lex->tvc_start(); - } - values_list +table_primary_ident: + table_ident opt_use_partition opt_for_system_time_clause + opt_table_alias_clause opt_key_definition { - if (Lex->tvc_finalize_derived()) + SELECT_LEX *sel= Select; + sel->table_join_options= 0; + if (!($$= Select->add_table_to_list(thd, $1, $4, + Select->get_table_join_options(), + YYPS->m_lock_type, + YYPS->m_mdl_type, + Select->pop_index_hints(), + $2))) MYSQL_YYABORT; - $$= NULL; + if ($3) + $$->vers_conditions= Lex->vers_conditions; } ; -select_derived2: - { - LEX *lex= Lex; - lex->derived_tables|= DERIVED_SUBQUERY; - if (unlikely(!lex->expr_allows_subselect || - lex->sql_command == (int)SQLCOM_PURGE)) - { - thd->parse_error(); - MYSQL_YYABORT; - } - if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE || - unlikely(mysql_new_select(lex, 1, NULL))) - MYSQL_YYABORT; - mysql_init_select(lex); - lex->current_select->linkage= DERIVED_TABLE_TYPE; - lex->current_select->parsing_place= SELECT_LIST; - } - select_options select_item_list - { - Select->parsing_place= NO_MATTER; - } - opt_table_expression - ; +/* + Represents a flattening of the following rules from the SQL:2003 + standard. This sub-rule corresponds to the sub-rule + <table primary> ::= ... | <derived table> [ AS ] <correlation name> -get_select_lex: - /* Empty */ { $$= Select; } - ; + <derived table> ::= <table subquery> + <table subquery> ::= <subquery> + <subquery> ::= <left paren> <query expression> <right paren> + <query expression> ::= [ <with clause> ] <query expression body> + + For the time being we use the non-standard rule + select_derived_union which is a compromise between the standard + and our parser. Possibly this rule could be replaced by our + query_expression_body. +*/ -get_select_lex_derived: - get_select_lex +table_primary_derived: + query_primary_parens opt_for_system_time_clause table_alias_clause { - LEX *lex= Lex; - if (unlikely($1->init_nested_join(lex->thd))) - MYSQL_YYABORT; + if (!($$= Lex->parsed_derived_select($1, $2, $3))) + YYABORT; } - ; - -select_derived_init: + | '(' + query_expression + ')' opt_for_system_time_clause table_alias_clause { - LEX *lex= Lex; - - TABLE_LIST *embedding= lex->current_select->embedding; - $$= embedding && - !embedding->nested_join->join_list.elements; - /* return true if we are deeply nested */ + if (!($$= Lex->parsed_derived_unit($2, $4, $5))) + YYABORT; } ; @@ -12344,9 +12261,14 @@ table_alias: | '=' ; -opt_table_alias: +opt_table_alias_clause: /* empty */ { $$=0; } - | table_alias ident_table_alias + + | table_alias_clause { $$= $1; } + ; + +table_alias_clause: + table_alias ident_table_alias { $$= (LEX_CSTRING*) thd->memdup(&$2,sizeof(LEX_STRING)); if (unlikely($$ == NULL)) @@ -12442,7 +12364,7 @@ olap_opt: SQL-2003: GROUP BY ... CUBE(col1, col2, col3) */ LEX *lex=Lex; - if (unlikely(lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)) + if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE)) my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH CUBE", "global union parameters")); lex->current_select->olap= CUBE_TYPE; @@ -12459,7 +12381,7 @@ olap_opt: SQL-2003: GROUP BY ... ROLLUP(col1, col2, col3) */ LEX *lex= Lex; - if (unlikely(lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)) + if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE)) my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH ROLLUP", "global union parameters")); lex->current_select->olap= ROLLUP_TYPE; @@ -12519,7 +12441,7 @@ opt_window_partition_clause: opt_window_order_clause: /* empty */ { } - | ORDER_SYM BY order_list + | ORDER_SYM BY order_list { Select->order_list= *($3); } ; opt_window_frame_clause: @@ -12643,70 +12565,35 @@ alter_order_item: opt_order_clause: /* empty */ + { $$= NULL; } | order_clause + { $$= $1; } ; order_clause: ORDER_SYM BY { - LEX *lex=Lex; - SELECT_LEX *sel= lex->current_select; - SELECT_LEX_UNIT *unit= sel-> master_unit(); - if (unlikely(sel->linkage != GLOBAL_OPTIONS_TYPE && - sel->olap != UNSPECIFIED_OLAP_TYPE && - (sel->linkage != UNION_TYPE || sel->braces))) - { - my_error(ER_WRONG_USAGE, MYF(0), - "CUBE/ROLLUP", "ORDER BY"); - MYSQL_YYABORT; - } - if (lex->sql_command != SQLCOM_ALTER_TABLE && - !unit->fake_select_lex) - { - /* - A query of the of the form (SELECT ...) ORDER BY order_list is - executed in the same way as the query - SELECT ... ORDER BY order_list - unless the SELECT construct contains ORDER BY or LIMIT clauses. - Otherwise we create a fake SELECT_LEX if it has not been - created yet. - */ - SELECT_LEX *first_sl= unit->first_select(); - if (unlikely(!unit->is_unit_op() && - (first_sl->order_list.elements || - first_sl->select_limit) && - unit->add_fake_select_lex(thd))) - MYSQL_YYABORT; - } - if (sel->master_unit()->is_unit_op() && !sel->braces) - { - /* - At this point we don't know yet whether this is the last - select in union or not, but we move ORDER BY to - fake_select_lex anyway. If there would be one more select - in union mysql_new_select will correctly throw error. - */ - DBUG_ASSERT(sel->master_unit()->fake_select_lex); - lex->current_select= sel->master_unit()->fake_select_lex; - } + thd->where= "ORDER clause"; } order_list { - + $$= $4; } ; order_list: order_list ',' order_ident order_dir { - if (unlikely(add_order_to_list(thd, $3,(bool) $4))) - MYSQL_YYABORT; - } + $$= $1; + if (add_to_list(thd, *$$, $3,(bool) $4)) + MYSQL_YYABORT; + } | order_ident order_dir { - if (unlikely(add_order_to_list(thd, $1,(bool) $2))) + $$= new (thd->mem_root) SQL_I_List<ORDER>(); + if (add_to_list(thd, *$$, $1, (bool) $2)) MYSQL_YYABORT; - } + } ; order_dir: @@ -12716,63 +12603,61 @@ order_dir: ; opt_limit_clause: - /* empty */ {} - | limit_clause {} + /* empty */ + { $$.empty(); } + | limit_clause + { $$= $1; } ; -limit_clause_init: - LIMIT - { - SELECT_LEX *sel= Select; - if (sel->master_unit()->is_unit_op() && !sel->braces) - { - /* Move LIMIT that belongs to UNION to fake_select_lex */ - Lex->current_select= sel->master_unit()->fake_select_lex; - DBUG_ASSERT(Select); - } - } - ; - limit_clause: - limit_clause_init limit_options + LIMIT limit_options { - SELECT_LEX *sel= Select; - if (!sel->select_limit->basic_const_item() || - sel->select_limit->val_int() > 0) + $$= $2; + if (!$$.select_limit->basic_const_item() || + $$.select_limit->val_int() > 0) Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); } - | limit_clause_init limit_options + | LIMIT limit_options ROWS_SYM EXAMINED_SYM limit_rows_option { + $$= $2; Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); } - | limit_clause_init ROWS_SYM EXAMINED_SYM limit_rows_option + | LIMIT ROWS_SYM EXAMINED_SYM limit_rows_option { + $$.select_limit= 0; + $$.offset_limit= 0; + $$.explicit_limit= 1; Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); } ; +opt_global_limit_clause: + opt_limit_clause + { + Select->explicit_limit= $1.explicit_limit; + Select->select_limit= $1.select_limit; + Select->offset_limit= $1.offset_limit; + } + limit_options: limit_option { - SELECT_LEX *sel= Select; - sel->select_limit= $1; - sel->offset_limit= 0; - sel->explicit_limit= 1; + $$.select_limit= $1; + $$.offset_limit= 0; + $$.explicit_limit= 1; } | limit_option ',' limit_option { - SELECT_LEX *sel= Select; - sel->select_limit= $3; - sel->offset_limit= $1; - sel->explicit_limit= 1; + $$.select_limit= $3; + $$.offset_limit= $1; + $$.explicit_limit= 1; } | limit_option OFFSET_SYM limit_option { - SELECT_LEX *sel= Select; - sel->select_limit= $1; - sel->offset_limit= $3; - sel->explicit_limit= 1; + $$.select_limit= $1; + $$.offset_limit= $3; + $$.explicit_limit= 1; } ; @@ -12835,6 +12720,77 @@ delete_limit_clause: | LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; } ; +opt_order_limit_lock: + /* empty */ + { $$= NULL; } + | order_or_limit + { + $$= $1; + $$->lock.empty(); + } + | order_or_limit select_lock_type + { + $$= $1; + $$->lock= $2; + } + | select_lock_type + { + $$= new(thd->mem_root) Lex_order_limit_lock; + if (!$$) + YYABORT; + $$->order_list= NULL; + $$->limit.empty(); + $$->lock= $1; + } + ; +query_expression_tail: + opt_order_limit_lock + ; + +opt_procedure_or_into: + /* empty */ + { + $$.empty(); + } + | procedure_clause opt_select_lock_type + { + $$= $2; + } + | into opt_select_lock_type + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_WARN_DEPRECATED_SYNTAX, + ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX), + "<select expression> INTO <destination>;", + "'SELECT <select list> INTO <destination>" + " FROM...'"); + $$= $2; + } + ; + + +order_or_limit: + order_clause opt_limit_clause + { + $$= new(thd->mem_root) Lex_order_limit_lock; + if (!$$) + YYABORT; + $$->order_list= $1; + $$->limit= $2; + } + | limit_clause + { + Lex_order_limit_lock *op= $$= new(thd->mem_root) Lex_order_limit_lock; + if (!$$) + YYABORT; + op->order_list= NULL; + op->limit= $1; + $$->order_list= NULL; + $$->limit= $1; + } + ; + + opt_plus: /* empty */ | '+' @@ -12904,14 +12860,11 @@ bool: | TRUE_SYM { $$= 1; } | FALSE_SYM { $$= 0; } - procedure_clause: PROCEDURE_SYM ident /* Procedure name */ { LEX *lex=Lex; - DBUG_ASSERT(&lex->select_lex == lex->current_select); - lex->proc_list.elements=0; lex->proc_list.first=0; lex->proc_list.next= &lex->proc_list.first; @@ -12931,6 +12884,7 @@ procedure_clause: parameters are reduced. */ Lex->expr_allows_subselect= false; + Select->options|= OPTION_PROCEDURE_CLAUSE; } '(' procedure_list ')' { @@ -13014,6 +12968,7 @@ select_outvar: into: INTO into_destination + {} ; into_destination: @@ -13223,10 +13178,11 @@ table_list: table_name: table_ident { - if (unlikely(!Select->add_table_to_list(thd, $1, NULL, - TL_OPTION_UPDATING, - YYPS->m_lock_type, - YYPS->m_mdl_type))) + if (!thd->lex->current_select_or_default()-> + add_table_to_list(thd, $1, NULL, + TL_OPTION_UPDATING, + YYPS->m_lock_type, + YYPS->m_mdl_type)) MYSQL_YYABORT; } ; @@ -13299,17 +13255,24 @@ insert: { LEX *lex= Lex; lex->sql_command= SQLCOM_INSERT; - lex->duplicates= DUP_ERROR; - mysql_init_select(lex); + lex->duplicates= DUP_ERROR; + if (Lex->main_select_push()) + MYSQL_YYABORT; + mysql_init_select(lex); + lex->current_select->parsing_place= BEFORE_OPT_LIST; } insert_lock_option opt_ignore insert2 { Select->set_lock_for_tables($3); - Lex->current_select= &Lex->select_lex; + Lex->current_select= Lex->first_select_lex(); } insert_field_spec opt_insert_update - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; replace: @@ -13318,15 +13281,22 @@ replace: LEX *lex=Lex; lex->sql_command = SQLCOM_REPLACE; lex->duplicates= DUP_REPLACE; - mysql_init_select(lex); + if (Lex->main_select_push()) + MYSQL_YYABORT; + mysql_init_select(lex); + lex->current_select->parsing_place= BEFORE_OPT_LIST; } replace_lock_option insert2 { Select->set_lock_for_tables($3); - Lex->current_select= &Lex->select_lex; + Lex->current_select= Lex->first_select_lex(); } insert_field_spec - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; insert_lock_option: @@ -13369,15 +13339,14 @@ insert_table: table_name_with_opt_use_partition { LEX *lex=Lex; - lex->field_list.empty(); + //lex->field_list.empty(); lex->many_values.empty(); lex->insert_list=0; }; insert_field_spec: insert_values {} - | '(' ')' insert_values {} - | '(' fields ')' insert_values {} + | insert_field_list insert_values {} | SET { LEX *lex=Lex; @@ -13385,20 +13354,33 @@ insert_field_spec: unlikely(lex->many_values.push_back(lex->insert_list, thd->mem_root))) MYSQL_YYABORT; + lex->current_select->parsing_place= NO_MATTER; } ident_eq_list ; +insert_field_list: + LEFT_PAREN_ALT opt_fields ')' + { + Lex->current_select->parsing_place= AFTER_LIST; + } + ; + +opt_fields: + /* empty */ + | fields + ; + fields: fields ',' insert_ident { Lex->field_list.push_back($3, thd->mem_root); } | insert_ident { Lex->field_list.push_back($1, thd->mem_root); } ; + + insert_values: - VALUES values_list {} - | VALUE_SYM values_list {} - | create_select_query_expression {} + create_select_query_expression {} ; values_list: @@ -13548,6 +13530,8 @@ update: UPDATE_SYM { LEX *lex= Lex; + if (Lex->main_select_push()) + MYSQL_YYABORT; mysql_init_select(lex); lex->sql_command= SQLCOM_UPDATE; lex->duplicates= DUP_ERROR; @@ -13556,13 +13540,14 @@ update: SET update_list { LEX *lex= Lex; - if (lex->select_lex.table_list.elements > 1) + if (lex->first_select_lex()->table_list.elements > 1) lex->sql_command= SQLCOM_UPDATE_MULTI; - else if (unlikely(lex->select_lex.get_table_list()->derived)) + else if (lex->first_select_lex()->get_table_list()->derived) { /* it is single table update and it is update of derived table */ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), - lex->select_lex.get_table_list()->alias.str, "UPDATE"); + lex->first_select_lex()->get_table_list()->alias.str, + "UPDATE"); MYSQL_YYABORT; } /* @@ -13572,7 +13557,14 @@ update: */ Select->set_lock_for_tables($3); } - opt_where_clause opt_order_clause delete_limit_clause {} + opt_where_clause opt_order_clause delete_limit_clause + { + if ($10) + Select->order_list= *($10); + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; update_list: @@ -13619,9 +13611,11 @@ delete: mysql_init_select(lex); YYPS->m_lock_type= TL_WRITE_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_WRITE; + if (Lex->main_select_push()) + MYSQL_YYABORT; lex->ignore= 0; - lex->select_lex.init_order(); + lex->first_select_lex()->order_list.empty(); } delete_part2 ; @@ -13645,6 +13639,7 @@ delete_part2: } ; + delete_single_table: FROM table_ident opt_use_partition { @@ -13665,7 +13660,12 @@ single_multi: opt_where_clause opt_order_clause delete_limit_clause - opt_select_expressions {} + opt_select_expressions + { + if ($3) + Select->order_list= *($3); + Lex->pop_select(); //main select + } | table_wild_list { mysql_init_multi_delete(Lex); @@ -13676,6 +13676,9 @@ single_multi: { if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex))) MYSQL_YYABORT; + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } | FROM table_alias_ref_list { @@ -13687,9 +13690,13 @@ single_multi: { if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex))) MYSQL_YYABORT; + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } ; + opt_select_expressions: /* empty */ | RETURNING_SYM select_item_list @@ -13755,9 +13762,9 @@ truncate: LEX* lex= Lex; lex->sql_command= SQLCOM_TRUNCATE; lex->alter_info.reset(); - lex->select_lex.options= 0; - lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; - lex->select_lex.init_order(); + lex->first_select_lex()->options= 0; + lex->sql_cache= LEX::SQL_CACHE_UNSPECIFIED; + lex->first_select_lex()->order_list.empty(); YYPS->m_lock_type= TL_WRITE; YYPS->m_mdl_type= MDL_EXCLUSIVE; } @@ -13849,6 +13856,8 @@ show: LEX *lex=Lex; lex->wild=0; lex->ident= null_clex_str; + if (Lex->main_select_push()) + MYSQL_YYABORT; mysql_init_select(lex); lex->current_select->parsing_place= SELECT_LIST; lex->create_info.init(); @@ -13856,6 +13865,7 @@ show: show_param { Select->parsing_place= NO_MATTER; + Lex->pop_select(); //main select } ; @@ -13871,40 +13881,40 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TABLES; - lex->select_lex.db= $3; - if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES))) + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES)) MYSQL_YYABORT; } | opt_full TRIGGERS_SYM opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TRIGGERS; - lex->select_lex.db= $3; - if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TRIGGERS))) + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_TRIGGERS)) MYSQL_YYABORT; } | EVENTS_SYM opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_EVENTS; - lex->select_lex.db= $2; - if (unlikely(prepare_schema_table(thd, lex, 0, SCH_EVENTS))) + lex->first_select_lex()->db= $2; + if (prepare_schema_table(thd, lex, 0, SCH_EVENTS)) MYSQL_YYABORT; } | TABLE_SYM STATUS_SYM opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TABLE_STATUS; - lex->select_lex.db= $3; - if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TABLES))) + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_TABLES)) MYSQL_YYABORT; } | OPEN_SYM TABLES opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_OPEN_TABLES; - lex->select_lex.db= $3; - if (unlikely(prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES))) + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES)) MYSQL_YYABORT; } | PLUGINS_SYM @@ -13953,12 +13963,13 @@ show_param: LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS; } - opt_limit_clause + opt_global_limit_clause | RELAYLOG_SYM optional_connection_name EVENTS_SYM binlog_in binlog_from { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS; - } opt_limit_clause + } + opt_global_limit_clause | keys_or_index from_or_in table_ident opt_db opt_where_clause { LEX *lex= Lex; @@ -14000,13 +14011,13 @@ show_param: LEX_CSTRING var= {STRING_WITH_LEN("error_count")}; (void) create_select_for_variable(thd, &var); } - | WARNINGS opt_limit_clause + | WARNINGS opt_global_limit_clause { Lex->sql_command = SQLCOM_SHOW_WARNS;} - | ERRORS opt_limit_clause + | ERRORS opt_global_limit_clause { Lex->sql_command = SQLCOM_SHOW_ERRORS;} | PROFILES_SYM { Lex->sql_command = SQLCOM_SHOW_PROFILES; } - | PROFILE_SYM opt_profile_defs opt_profile_args opt_limit_clause + | PROFILE_SYM opt_profile_defs opt_profile_args opt_global_limit_clause { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_PROFILE; @@ -14068,7 +14079,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL,0))) + if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL,0)) MYSQL_YYABORT; lex->create_info.storage_media= HA_SM_DEFAULT; } @@ -14076,7 +14087,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL, 0))) + if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0)) MYSQL_YYABORT; lex->table_type= TABLE_TYPE_VIEW; } @@ -14084,7 +14095,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL, 0))) + if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0)) MYSQL_YYABORT; lex->table_type= TABLE_TYPE_SEQUENCE; } @@ -14301,7 +14312,7 @@ describe: mysql_init_select(lex); lex->current_select->parsing_place= SELECT_LIST; lex->sql_command= SQLCOM_SHOW_FIELDS; - lex->select_lex.db= null_clex_str; + lex->first_select_lex()->db= null_clex_str; lex->verbose= 0; if (unlikely(prepare_schema_table(thd, lex, $2, SCH_COLUMNS))) MYSQL_YYABORT; @@ -14315,12 +14326,13 @@ describe: explainable_command { LEX *lex=Lex; - lex->select_lex.options|= SELECT_DESCRIBE; + lex->first_select_lex()->options|= SELECT_DESCRIBE; } ; explainable_command: select + | select_into | insert | replace | update @@ -14341,6 +14353,8 @@ analyze_stmt_command: opt_extended_describe: EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; } + | EXTENDED_SYM ALL + { Lex->describe|= DESCRIBE_EXTENDED | DESCRIBE_EXTENDED2; } | PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; } | opt_format_json {} ; @@ -14383,8 +14397,7 @@ flush: lex->type= 0; lex->no_write_to_binlog= $2; } - flush_options - {} + flush_options {} ; flush_options: @@ -14401,6 +14414,7 @@ flush_options: opt_table_list opt_flush_lock {} | flush_options_list + {} ; opt_flush_lock: @@ -14656,7 +14670,7 @@ use: { LEX *lex=Lex; lex->sql_command=SQLCOM_CHANGE_DB; - lex->select_lex.db= $2; + lex->first_select_lex()->db= $2; } ; @@ -14673,6 +14687,8 @@ load: $2 == FILETYPE_CSV ? "LOAD DATA" : "LOAD XML"); MYSQL_YYABORT; } + if (Lex->main_select_push()) + MYSQL_YYABORT; } load_data_lock opt_local INFILE TEXT_STRING_filesystem { @@ -14702,7 +14718,11 @@ load: opt_xml_rows_identified_by opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec opt_load_data_set_spec - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; data_or_xml: @@ -14900,11 +14920,6 @@ hex_or_bin_String: $1.length); if (unlikely(tmp == NULL)) MYSQL_YYABORT; - /* - it is OK only emulate fix_fields, because we need only - value of constant - */ - tmp->quick_fix_field(); $$= tmp->val_str((String*) 0); } | HEX_STRING @@ -14913,7 +14928,6 @@ hex_or_bin_String: $1.length); if (unlikely(tmp == NULL)) MYSQL_YYABORT; - tmp->quick_fix_field(); $$= tmp->val_str((String*) 0); } | BIN_NUM @@ -14926,7 +14940,6 @@ hex_or_bin_String: it is OK only emulate fix_fields, because we need only value of constant */ - tmp->quick_fix_field(); $$= tmp->val_str((String*) 0); } ; @@ -15074,26 +15087,23 @@ NUM_literal: temporal_literal: DATE_SYM TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_DATE, - true)))) + if (unlikely(!($$= type_handler_newdate.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } | TIME_SYM TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_TIME, - true)))) + if (unlikely(!($$= type_handler_time2.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } | TIMESTAMP TEXT_STRING { - if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length, - YYCSCL, - MYSQL_TYPE_DATETIME, - true)))) + if (unlikely(!($$= type_handler_datetime2.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) MYSQL_YYABORT; } ; @@ -15109,17 +15119,21 @@ opt_with_clause: with_clause: - WITH opt_recursive + WITH opt_recursive { + LEX *lex= Lex; With_clause *with_clause= new With_clause($2, Lex->curr_with_clause); if (unlikely(with_clause == NULL)) MYSQL_YYABORT; - Lex->derived_tables|= DERIVED_WITH; - Lex->curr_with_clause= with_clause; + lex->derived_tables|= DERIVED_WITH; + lex->curr_with_clause= with_clause; with_clause->add_to_list(Lex->with_clauses_list_last_next); + if (lex->current_select && + lex->current_select->parsing_place == BEFORE_OPT_LIST) + lex->current_select->parsing_place= NO_MATTER; } - with_list + with_list { $$= Lex->curr_with_clause; Lex->curr_with_clause= Lex->curr_with_clause->pop(); @@ -15148,11 +15162,10 @@ with_list_element: MYSQL_YYABORT; Lex->with_column_list.empty(); } - AS '(' remember_name subselect remember_end ')' + AS '(' remember_name query_expression remember_end ')' { - With_element *elem= new With_element($1, *$2, $7->master_unit()); - if (unlikely(elem == NULL) || - unlikely(Lex->curr_with_clause->add_with_element(elem))) + With_element *elem= new With_element($1, *$2, $7); + if (elem == NULL || Lex->curr_with_clause->add_with_element(elem)) MYSQL_YYABORT; if (unlikely(elem->set_unparsed_spec(thd, $6+1, $8))) MYSQL_YYABORT; @@ -16123,14 +16136,22 @@ set: SET { LEX *lex=Lex; + if (lex->main_select_push()) + MYSQL_YYABORT; lex->set_stmt_init(); lex->var_list.empty(); sp_create_assignment_lex(thd, yychar == YYEMPTY); } start_option_value_list - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } | SET STATEMENT_SYM { + if (Lex->main_select_push()) + MYSQL_YYABORT; Lex->set_stmt_init(); } set_stmt_option_value_following_option_type_list @@ -16140,6 +16161,9 @@ set: my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT")); lex->stmt_var_list= lex->var_list; lex->var_list.empty(); + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; } FOR_SYM verb_clause {} @@ -16608,7 +16632,7 @@ table_lock_list: ; table_lock: - table_ident opt_table_alias lock_option + table_ident opt_table_alias_clause lock_option { thr_lock_type lock_type= (thr_lock_type) $3; bool lock_for_write= (lock_type >= TL_WRITE_ALLOW_WRITE); @@ -16653,27 +16677,36 @@ unlock: */ handler: - HANDLER_SYM table_ident OPEN_SYM opt_table_alias + HANDLER_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + handler_tail + { + Lex->pop_select(); //main select + } + +handler_tail: + table_ident OPEN_SYM opt_table_alias_clause { LEX *lex= Lex; if (unlikely(lex->sphead)) my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); lex->sql_command = SQLCOM_HA_OPEN; - if (unlikely(!lex->current_select->add_table_to_list(thd, $2, $4, - 0))) + if (!lex->current_select->add_table_to_list(thd, $1, $3, 0)) MYSQL_YYABORT; } - | HANDLER_SYM table_ident_nodb CLOSE_SYM + | table_ident_nodb CLOSE_SYM { LEX *lex= Lex; if (unlikely(lex->sphead)) my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); lex->sql_command = SQLCOM_HA_CLOSE; - if (unlikely(!lex->current_select->add_table_to_list(thd, $2, 0, - 0))) + if (!lex->current_select->add_table_to_list(thd, $1, 0, 0)) MYSQL_YYABORT; } - | HANDLER_SYM table_ident_nodb READ_SYM + | table_ident_nodb READ_SYM { LEX *lex=Lex; if (unlikely(lex->sphead)) @@ -16687,15 +16720,24 @@ handler: lex->current_select->select_limit= one; lex->current_select->offset_limit= 0; lex->limit_rows_examined= 0; - if (unlikely(!lex->current_select->add_table_to_list(thd, $2, 0, - 0))) + if (!lex->current_select->add_table_to_list(thd, $1, 0, 0)) MYSQL_YYABORT; } - handler_read_or_scan opt_where_clause opt_limit_clause + handler_read_or_scan opt_where_clause opt_global_limit_clause { - Lex->expr_allows_subselect= TRUE; + LEX *lex=Lex; + lex->expr_allows_subselect= TRUE; + if (!lex->current_select->explicit_limit) + { + Item *one= new (thd->mem_root) Item_int(thd, (int32) 1); + if (one == NULL) + MYSQL_YYABORT; + lex->current_select->select_limit= one; + lex->current_select->offset_limit= 0; + lex->limit_rows_examined= 0; + } /* Stored functions are not supported for HANDLER READ. */ - if (unlikely(Lex->uses_stored_routines())) + if (lex->uses_stored_routines()) { my_error(ER_NOT_SUPPORTED_YET, MYF(0), "stored functions in HANDLER ... READ"); @@ -17347,83 +17389,16 @@ release: */ unit_type_decl: - UNION_SYM - { $$= UNION_TYPE; } + UNION_SYM union_option + { $$.unit_type= UNION_TYPE; $$.distinct= $2; } | INTERSECT_SYM - { $$= INTERSECT_TYPE; } + { $$.unit_type= INTERSECT_TYPE; $$.distinct= 1; } | EXCEPT_SYM - { $$= EXCEPT_TYPE; } - - -union_clause: - /* empty */ {} - | union_list - ; - -union_list: - unit_type_decl union_option - { - if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, TRUE))) - MYSQL_YYABORT; - } - union_list_part2 - { - /* - Remove from the name resolution context stack the context of the - last select in the union. - */ - Lex->pop_context(); - } - ; - -union_list_view: - unit_type_decl union_option - { - if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, TRUE))) - MYSQL_YYABORT; - } - query_expression_body_view - { - Lex->pop_context(); - } - ; - -union_order_or_limit: - { - LEX *lex= thd->lex; - DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE); - SELECT_LEX *sel= lex->current_select; - SELECT_LEX_UNIT *unit= sel->master_unit(); - SELECT_LEX *fake= unit->fake_select_lex; - if (fake) - { - fake->no_table_names_allowed= 1; - lex->current_select= fake; - } - thd->where= "global ORDER clause"; - } - order_or_limit - { - thd->lex->current_select->no_table_names_allowed= 0; - thd->where= ""; - } - ; - -order_or_limit: - order_clause opt_limit_clause - | limit_clause - ; + { $$.unit_type= EXCEPT_TYPE; $$.distinct= 1; } /* Start a UNION, for non-top level query expressions. */ -union_head_non_top: - unit_type_decl union_option - { - if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, FALSE))) - MYSQL_YYABORT; - } - ; union_option: /* empty */ { $$=1; } @@ -17431,128 +17406,10 @@ union_option: | ALL { $$=0; } ; -simple_table: - query_specification { $$= $1; } - | table_value_constructor { $$= $1; } - ; - -table_value_constructor: - VALUES - { - Lex->tvc_start(); - } - values_list - { - $$= Lex->current_select; - if (Lex->tvc_finalize()) - MYSQL_YYABORT; - } - ; - -/* - Corresponds to the SQL Standard - <query specification> ::= - SELECT [ <set quantifier> ] <select list> <table expression> - - Notes: - - We allow more options in addition to <set quantifier> - - <table expression> is optional in MariaDB -*/ -query_specification: - SELECT_SYM select_init2_derived opt_table_expression - { - $$= Lex->current_select->master_unit()->first_select(); - } - ; - -query_term_union_not_ready: - simple_table order_or_limit opt_select_lock_type { $$= $1; } - | '(' select_paren_derived ')' union_order_or_limit { $$= $2; } - ; - -query_term_union_ready: - simple_table opt_select_lock_type { $$= $1; } - | '(' select_paren_derived ')' { $$= $2; } - ; - -query_expression_body: - query_term_union_not_ready { $$= $1; } - | query_term_union_ready { $$= $1; } - | query_term_union_ready union_list_derived { $$= $1; } - ; - -/* Corresponds to <query expression> in the SQL:2003 standard. */ -subselect: - subselect_start opt_with_clause query_expression_body subselect_end - { - $3->set_with_clause($2); - $$= $3; - } - ; - -subselect_start: - { - LEX *lex=Lex; - if (unlikely(!lex->expr_allows_subselect || - lex->sql_command == (int)SQLCOM_PURGE)) - { - thd->parse_error(); - MYSQL_YYABORT; - } - /* - we are making a "derived table" for the parenthesis - as we need to have a lex level to fit the union - after the parenthesis, e.g. - (SELECT .. ) UNION ... becomes - SELECT * FROM ((SELECT ...) UNION ...) - */ - if (unlikely(mysql_new_select(Lex, 1, NULL))) - MYSQL_YYABORT; - } - ; - -subselect_end: - { - LEX *lex=Lex; - - lex->check_automatic_up(UNSPECIFIED_TYPE); - lex->pop_context(); - SELECT_LEX *child= lex->current_select; - lex->current_select = lex->current_select->return_after_parsing(); - lex->nest_level--; - lex->current_select->n_child_sum_items += child->n_sum_items; - /* - A subselect can add fields to an outer select. Reserve space for - them. - */ - lex->current_select->select_n_where_fields+= - child->select_n_where_fields; - - /* - Aggregate functions in having clause may add fields to an outer - select. Count them also. - */ - lex->current_select->select_n_having_items+= - child->select_n_having_items; - } - ; - -opt_query_expression_options: - /* empty */ - | query_expression_option_list - ; - -query_expression_option_list: - query_expression_option_list query_expression_option - | query_expression_option - ; - query_expression_option: STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; } | HIGH_PRIORITY { - if (unlikely(Lex->check_simple_select(&$1))) - MYSQL_YYABORT; YYPS->m_lock_type= TL_READ_HIGH_PRIORITY; YYPS->m_mdl_type= MDL_SHARED_READ; Select->options|= SELECT_HIGH_PRIORITY; @@ -17561,18 +17418,8 @@ query_expression_option: | UNIQUE_SYM { Select->options|= SELECT_DISTINCT; } | SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; } | SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; } - | SQL_BUFFER_RESULT - { - if (unlikely(Lex->check_simple_select(&$1))) - MYSQL_YYABORT; - Select->options|= OPTION_BUFFER_RESULT; - } - | SQL_CALC_FOUND_ROWS - { - if (unlikely(Lex->check_simple_select(&$1))) - MYSQL_YYABORT; - Select->options|= OPTION_FOUND_ROWS; - } + | SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; } + | SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; } | ALL { Select->options|= SELECT_ALL; } ; @@ -17660,35 +17507,14 @@ view_select: lex->parsing_options.allows_variable= FALSE; lex->create_view->select.str= (char *) YYLIP->get_cpp_ptr(); } - opt_with_clause query_expression_body_view view_check_option + query_expression + view_check_option { - LEX *lex= Lex; - size_t len= YYLIP->get_cpp_ptr() - lex->create_view->select.str; - void *create_view_select= thd->memdup(lex->create_view->select.str, len); - lex->create_view->select.length= len; - lex->create_view->select.str= (char *) create_view_select; - trim_whitespace(thd->charset(), - &lex->create_view->select); - lex->create_view->check= $4; - lex->parsing_options.allows_variable= TRUE; - lex->current_select->set_with_clause($2); + if (Lex->parsed_create_view($2, $3)) + MYSQL_YYABORT; } ; -/* - SQL Standard <query expression body> for VIEWs. - Does not include INTO and PROCEDURE clauses. -*/ -query_expression_body_view: - SELECT_SYM select_options_and_item_list select_init3_view - | table_value_constructor - | table_value_constructor union_order_or_limit - | table_value_constructor union_list_view - | '(' select_paren_view ')' - | '(' select_paren_view ')' union_order_or_limit - | '(' select_paren_view ')' union_list_view - ; - view_check_option: /* empty */ { $$= VIEW_CHECK_NONE; } | WITH CHECK_SYM OPTION { $$= VIEW_CHECK_CASCADED; } @@ -17789,11 +17615,10 @@ trigger_tail: sp_proc_stmt alternatives are not saving/restoring LEX, so lex->query_tables can be wiped out. */ - if (unlikely(!lex->select_lex. - add_table_to_list(thd, $10, (LEX_CSTRING*) 0, - TL_OPTION_UPDATING, - TL_READ_NO_INSERT, - MDL_SHARED_NO_WRITE))) + if (!lex->first_select_lex()-> + add_table_to_list(thd, $10, (LEX_CSTRING*) 0, + TL_OPTION_UPDATING, TL_READ_NO_INSERT, + MDL_SHARED_NO_WRITE)) MYSQL_YYABORT; } ; diff --git a/sql/structs.h b/sql/structs.h index d8b95a3509a..355d6e75e48 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -758,6 +758,43 @@ public: }; +class st_select_lex; + +class Lex_select_lock +{ +public: + struct + { + uint defined_lock:1; + uint update_lock:1; + uint defined_timeout:1; + }; + ulong timeout; + + + void empty() + { + defined_lock= update_lock= defined_timeout= FALSE; + timeout= 0; + } + void set_to(st_select_lex *sel); +}; + +class Lex_select_limit +{ +public: + bool explicit_limit; + Item *select_limit, *offset_limit; + + void empty() + { + explicit_limit= FALSE; + select_limit= offset_limit= NULL; + } +}; + +struct st_order; + class Load_data_param { protected: @@ -794,4 +831,20 @@ public: }; +class Timeval: public timeval +{ +public: + Timeval(my_time_t sec, ulong usec) + { + tv_sec= sec; + tv_usec= usec; + } + Timeval &trunc(uint dec) + { + my_timeval_trunc(this, dec); + return *this; + } +}; + + #endif /* STRUCTS_INCLUDED */ diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 6d4c135683a..6d2dbbf646e 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2496,6 +2496,7 @@ export const char *optimizer_switch_names[]= "orderby_uses_equalities", "condition_pushdown_for_derived", "split_materialized", + "condition_pushdown_for_subquery", "default", NullS }; @@ -2720,17 +2721,6 @@ static Sys_var_ulong Sys_query_prealloc_size( BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_thd_mem_root)); -#ifdef HAVE_SMEM -static Sys_var_mybool Sys_shared_memory( - "shared_memory", "Enable the shared memory", - READ_ONLY GLOBAL_VAR(opt_enable_shared_memory), CMD_LINE(OPT_ARG), - DEFAULT(FALSE)); - -static Sys_var_charptr Sys_shared_memory_base_name( - "shared_memory_base_name", "Base name of shared memory", - READ_ONLY GLOBAL_VAR(shared_memory_base_name), CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT(0)); -#endif // this has to be NO_CMD_LINE as the command-line option has a different name static Sys_var_mybool Sys_skip_external_locking( @@ -4052,6 +4042,16 @@ static bool fix_sql_log_bin_after_update(sys_var *self, THD *thd, return FALSE; } +static bool check_session_only_variable(sys_var *self, THD *,set_var *var) +{ + if (unlikely(var->type == OPT_GLOBAL)) + { + my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), self->name.str, "SESSION"); + return true; + } + return false; +} + /** This function checks if the sql_log_bin can be changed, what is possible if: @@ -4067,20 +4067,17 @@ static bool fix_sql_log_bin_after_update(sys_var *self, THD *thd, static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var) { if (check_has_super(self, thd, var)) - return TRUE; + return true; - if (unlikely(var->type == OPT_GLOBAL)) - { - my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), self->name.str, "SESSION"); - return TRUE; - } + if (check_session_only_variable(self, thd, var)) + return true; if (unlikely(error_if_in_trans_or_substatement(thd, ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN, ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN))) - return TRUE; + return true; - return FALSE; + return false; } static Sys_var_mybool Sys_log_binlog( @@ -5592,6 +5589,27 @@ static Sys_var_int Sys_keepalive_probes( BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL)); + +static bool update_tcp_nodelay(sys_var *self, THD *thd, + enum_var_type type) +{ + DBUG_ASSERT(thd); + + Vio *vio = thd->net.vio; + if (vio) + return (MY_TEST(vio_nodelay(vio, thd->variables.tcp_nodelay))); + + return false; +} + +static Sys_var_mybool Sys_tcp_nodelay( + "tcp_nodelay", + "Set option TCP_NODELAY (disable Nagle's algorithm) on socket", + SESSION_VAR(tcp_nodelay), CMD_LINE(OPT_ARG), + DEFAULT(TRUE),NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(check_session_only_variable), + ON_UPDATE(update_tcp_nodelay)); + static Sys_var_charptr Sys_ignore_db_dirs( "ignore_db_dirs", "Specifies a directory to add to the ignore list when collecting " diff --git a/sql/table.cc b/sql/table.cc index 5eb789b779b..de5a71f6af1 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -44,6 +44,7 @@ #include "sql_cte.h" #include "ha_sequence.h" #include "sql_show.h" +#include <atomic> /* For MySQL 5.7 virtual fields */ #define MYSQL57_GENERATED_FIELD 128 @@ -79,7 +80,7 @@ LEX_CSTRING MYSQL_PROC_NAME= {STRING_WITH_LEN("proc")}; */ static LEX_CSTRING parse_vcol_keyword= { STRING_WITH_LEN("PARSE_VCOL_EXPR ") }; -static int64 last_table_id; +static std::atomic<ulong> last_table_id; /* Functions defined in this file */ @@ -343,8 +344,8 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name, */ do { - share->table_map_id=(ulong) my_atomic_add64_explicit(&last_table_id, 1, - MY_MEMORY_ORDER_RELAXED); + share->table_map_id= + last_table_id.fetch_add(1, std::memory_order_relaxed); } while (unlikely(share->table_map_id == ~0UL)); } DBUG_RETURN(share); @@ -915,6 +916,54 @@ static uint upgrade_collation(ulong mysql_version, uint cs_number) } +void Column_definition_attributes::frm_pack_basic(uchar *buff) const +{ + int2store(buff + 3, length); + int2store(buff + 8, pack_flag); + buff[10]= (uchar) unireg_check; +} + + +void Column_definition_attributes::frm_unpack_basic(const uchar *buff) +{ + length= uint2korr(buff + 3); + pack_flag= uint2korr(buff + 8); + unireg_check= (Field::utype) MTYP_TYPENR((uint) buff[10]); +} + + +void Column_definition_attributes::frm_pack_charset(uchar *buff) const +{ + buff[11]= (uchar) (charset->number >> 8); + buff[14]= (uchar) charset->number; +} + + +bool Column_definition_attributes::frm_unpack_charset(TABLE_SHARE *share, + const uchar *buff) +{ + uint cs_org= buff[14] + (((uint) buff[11]) << 8); + uint cs_new= upgrade_collation(share->mysql_version, cs_org); + if (cs_org != cs_new) + share->incompatible_version|= HA_CREATE_USED_CHARSET; + if (cs_new && !(charset= get_charset(cs_new, MYF(0)))) + { + const char *csname= get_charset_name((uint) cs_new); + char tmp[10]; + if (!csname || csname[0] =='?') + { + my_snprintf(tmp, sizeof(tmp), "#%u", cs_new); + csname= tmp; + } + my_printf_error(ER_UNKNOWN_COLLATION, + "Unknown collation '%s' in table '%-.64s' definition", + MYF(0), csname, share->table_name.str); + return true; + } + return false; +} + + /* In MySQL 5.7 the null bits for not stored virtual fields are last. Calculate the position for these bits @@ -1145,6 +1194,38 @@ end: DBUG_RETURN(res); } + +static const Type_handler *old_frm_type_handler(uint pack_flag, + uint interval_nr) +{ + enum_field_types field_type= (enum_field_types) f_packtype(pack_flag); + DBUG_ASSERT(field_type < 16); + + if (!f_is_alpha(pack_flag)) + return Type_handler::get_handler_by_real_type(field_type); + + if (!f_is_packed(pack_flag)) + { + if (field_type == MYSQL_TYPE_DECIMAL) // 3.23 or 4.0 string + return &type_handler_string; + if (field_type == MYSQL_TYPE_VARCHAR) // Since mysql-5.0 + return &type_handler_varchar; + return NULL; // Error (bad frm?) + } + + if (f_is_blob(pack_flag)) + return &type_handler_blob; // QQ: exact type?? + + if (interval_nr) + { + if (f_is_enum(pack_flag)) + return &type_handler_enum; + return &type_handler_set; + } + return Type_handler::get_handler_by_real_type(field_type); +} + + /** Read data from a binary .frm file image into a TABLE_SHARE @@ -1191,8 +1272,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, size_t UNINIT_VAR(options_len); uchar *vcol_screen_pos; const uchar *options= 0; - size_t UNINIT_VAR(gis_options_len); - const uchar *gis_options= 0; + LEX_CUSTRING gis_options= { NULL, 0}; KEY first_keyinfo; uint len; uint ext_key_parts= 0; @@ -1288,10 +1368,10 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, case EXTRA2_GIS: #ifdef HAVE_SPATIAL { - if (gis_options) + if (gis_options.str) goto err; - gis_options= extra2; - gis_options_len= length; + gis_options.str= extra2; + gis_options.length= length; } #endif /*HAVE_SPATIAL*/ break; @@ -1782,83 +1862,19 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++) { - uint pack_flag, interval_nr, unireg_type, recpos, field_length; - uint vcol_info_length=0; - uint vcol_expr_length=0; - enum_field_types field_type; - CHARSET_INFO *charset=NULL; - Field::geometry_type geom_type= Field::GEOM_GEOMETRY; + uint interval_nr= 0, recpos; LEX_CSTRING comment; LEX_CSTRING name; Virtual_column_info *vcol_info= 0; - uint gis_length, gis_decimals, srid= 0; - Field::utype unireg_check; const Type_handler *handler; uint32 flags= 0; + Column_definition_attributes attr; if (new_frm_ver >= 3) { /* new frm file in 4.1 */ - field_length= uint2korr(strpos+3); recpos= uint3korr(strpos+5); - pack_flag= uint2korr(strpos+8); - unireg_type= (uint) strpos[10]; - interval_nr= (uint) strpos[12]; uint comment_length=uint2korr(strpos+15); - field_type=(enum_field_types) (uint) strpos[13]; - - /* charset and geometry_type share the same byte in frm */ - if (field_type == MYSQL_TYPE_GEOMETRY) - { -#ifdef HAVE_SPATIAL - uint gis_opt_read; - Field_geom::storage_type st_type; - geom_type= (Field::geometry_type) strpos[14]; - charset= &my_charset_bin; - gis_opt_read= gis_field_options_read(gis_options, gis_options_len, - &st_type, &gis_length, &gis_decimals, &srid); - gis_options+= gis_opt_read; - gis_options_len-= gis_opt_read; -#else - goto err; -#endif - } - else - { - uint cs_org= strpos[14] + (((uint) strpos[11]) << 8); - uint cs_new= upgrade_collation(share->mysql_version, cs_org); - if (cs_org != cs_new) - share->incompatible_version|= HA_CREATE_USED_CHARSET; - if (!cs_new) - charset= &my_charset_bin; - else if (!(charset= get_charset(cs_new, MYF(0)))) - { - const char *csname= get_charset_name((uint) cs_new); - char tmp[10]; - if (!csname || csname[0] =='?') - { - my_snprintf(tmp, sizeof(tmp), "#%u", cs_new); - csname= tmp; - } - my_printf_error(ER_UNKNOWN_COLLATION, - "Unknown collation '%s' in table '%-.64s' definition", - MYF(0), csname, share->table_name.str); - goto err; - } - } - - if ((uchar)field_type == (uchar)MYSQL_TYPE_VIRTUAL) - { - if (!interval_nr) // Expect non-null expression - goto err; - /* - MariaDB version 10.0 version. - The interval_id byte in the .frm file stores the length of the - expression statement for a virtual column. - */ - vcol_info_length= interval_nr; - interval_nr= 0; - } if (!comment_length) { @@ -1872,32 +1888,21 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, comment_pos+= comment_length; } - if (unireg_type & MYSQL57_GENERATED_FIELD) + if ((uchar) strpos[13] == (uchar) MYSQL_TYPE_VIRTUAL) { - unireg_type&= MYSQL57_GENERATED_FIELD; - /* - MySQL 5.7 generated fields - - byte 1 = 1 - byte 2,3 = expr length - byte 4 = stored_in_db - byte 5.. = expr + MariaDB version 10.0 version. + The interval_id byte in the .frm file stores the length of the + expression statement for a virtual column. */ - if ((uint)(vcol_screen_pos)[0] != 1) + uint vcol_info_length= (uint) strpos[12]; + + if (!vcol_info_length) // Expect non-null expression goto err; - vcol_info= new (&share->mem_root) Virtual_column_info(); - vcol_info_length= uint2korr(vcol_screen_pos + 1); - DBUG_ASSERT(vcol_info_length); - vcol_info->stored_in_db= vcol_screen_pos[3]; - vcol_info->utf8= 0; - vcol_screen_pos+= vcol_info_length + MYSQL57_GCOL_HEADER_SIZE;; - share->virtual_fields++; - vcol_info_length= 0; - } - if (vcol_info_length) - { + attr.frm_unpack_basic(strpos); + if (attr.frm_unpack_charset(share, strpos)) + goto err; /* Old virtual field information before 10.2 @@ -1911,7 +1916,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, vcol_info= new (&share->mem_root) Virtual_column_info(); bool opt_interval_id= (uint)vcol_screen_pos[0] == 2; - field_type= (enum_field_types) (uchar) vcol_screen_pos[1]; + enum_field_types ftype= (enum_field_types) (uchar) vcol_screen_pos[1]; + if (!(handler= Type_handler::get_handler_by_real_type(ftype))) + goto err; if (opt_interval_id) interval_nr= (uint)vcol_screen_pos[3]; else if ((uint)vcol_screen_pos[0] != 1) @@ -1919,26 +1926,63 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, bool stored= vcol_screen_pos[2] & 1; vcol_info->stored_in_db= stored; vcol_info->set_vcol_type(stored ? VCOL_GENERATED_STORED : VCOL_GENERATED_VIRTUAL); - vcol_expr_length= vcol_info_length - - (uint)(FRM_VCOL_OLD_HEADER_SIZE(opt_interval_id)); + uint vcol_expr_length= vcol_info_length - + (uint)(FRM_VCOL_OLD_HEADER_SIZE(opt_interval_id)); vcol_info->utf8= 0; // before 10.2.1 the charset was unknown int2store(vcol_screen_pos+1, vcol_expr_length); // for parse_vcol_defs() vcol_screen_pos+= vcol_info_length; share->virtual_fields++; } + else + { + interval_nr= (uint) strpos[12]; + enum_field_types field_type= (enum_field_types) strpos[13]; + if (!(handler= Type_handler::get_handler_by_real_type(field_type))) + goto err; // Not supported field type + if (handler->Column_definition_attributes_frm_unpack(&attr, share, + strpos, + &gis_options)) + goto err; + } + + if (((uint) strpos[10]) & MYSQL57_GENERATED_FIELD) + { + attr.unireg_check= Field::NONE; + + /* + MySQL 5.7 generated fields + + byte 1 = 1 + byte 2,3 = expr length + byte 4 = stored_in_db + byte 5.. = expr + */ + if ((uint)(vcol_screen_pos)[0] != 1) + goto err; + vcol_info= new (&share->mem_root) Virtual_column_info(); + uint vcol_info_length= uint2korr(vcol_screen_pos + 1); + DBUG_ASSERT(vcol_info_length); + vcol_info->stored_in_db= vcol_screen_pos[3]; + vcol_info->utf8= 0; + vcol_screen_pos+= vcol_info_length + MYSQL57_GCOL_HEADER_SIZE;; + share->virtual_fields++; + } } else { - field_length= (uint) strpos[3]; + attr.length= (uint) strpos[3]; recpos= uint2korr(strpos+4), - pack_flag= uint2korr(strpos+6); - pack_flag&= ~FIELDFLAG_NO_DEFAULT; // Safety for old files - unireg_type= (uint) strpos[8]; + attr.pack_flag= uint2korr(strpos+6); + attr.pack_flag&= ~FIELDFLAG_NO_DEFAULT; // Safety for old files + attr.unireg_check= (Field::utype) MTYP_TYPENR((uint) strpos[8]); interval_nr= (uint) strpos[10]; /* old frm file */ - field_type= (enum_field_types) f_packtype(pack_flag); - if (f_is_binary(pack_flag)) + enum_field_types ftype= (enum_field_types) f_packtype(attr.pack_flag); + if (!(handler= Type_handler::get_handler_by_real_type(ftype))) + goto err; // Not supported field type + + if (f_is_binary(attr.pack_flag)) { /* Try to choose the best 4.1 type: @@ -1946,26 +1990,26 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, try to find a binary collation for character set. - for other types (e.g. BLOB) just use my_charset_bin. */ - if (!f_is_blob(pack_flag)) + if (!f_is_blob(attr.pack_flag)) { // 3.23 or 4.0 string - if (!(charset= get_charset_by_csname(share->table_charset->csname, - MY_CS_BINSORT, MYF(0)))) - charset= &my_charset_bin; + if (!(attr.charset= get_charset_by_csname(share->table_charset->csname, + MY_CS_BINSORT, MYF(0)))) + attr.charset= &my_charset_bin; } - else - charset= &my_charset_bin; } else - charset= share->table_charset; + attr.charset= share->table_charset; bzero((char*) &comment, sizeof(comment)); + if ((!(handler= old_frm_type_handler(attr.pack_flag, interval_nr)))) + goto err; // Not supported field type } /* Remove >32 decimals from old files */ if (share->mysql_version < 100200) - pack_flag&= ~FIELDFLAG_LONG_DECIMAL; + attr.pack_flag&= ~FIELDFLAG_LONG_DECIMAL; - if (interval_nr && charset->mbminlen > 1) + if (interval_nr && attr.charset->mbminlen > 1) { /* Unescape UCS2 intervals from HEX notation */ TYPELIB *interval= share->intervals + interval_nr - 1; @@ -1973,17 +2017,18 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } #ifndef TO_BE_DELETED_ON_PRODUCTION - if (field_type == MYSQL_TYPE_NEWDECIMAL && !share->mysql_version) + if (handler->real_field_type() == MYSQL_TYPE_NEWDECIMAL && + !share->mysql_version) { /* Fix pack length of old decimal values from 5.0.3 -> 5.0.4 The difference is that in the old version we stored precision in the .frm table while we now store the display_length */ - uint decimals= f_decimals(pack_flag); - field_length= my_decimal_precision_to_length(field_length, - decimals, - f_is_dec(pack_flag) == 0); + uint decimals= f_decimals(attr.pack_flag); + attr.length= + my_decimal_precision_to_length((uint) attr.length, decimals, + f_is_dec(attr.pack_flag) == 0); sql_print_error("Found incompatible DECIMAL field '%s' in %s; " "Please do \"ALTER TABLE '%s' FORCE\" to fix it!", share->fieldnames.type_names[i], share->table_name.str, @@ -2014,7 +2059,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (flags & VERS_SYSTEM_FIELD) { - switch (field_type) + switch (handler->real_field_type()) { case MYSQL_TYPE_TIMESTAMP2: case MYSQL_TYPE_DATETIME2: @@ -2036,22 +2081,17 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } /* Convert pre-10.2.2 timestamps to use Field::default_value */ - unireg_check= (Field::utype) MTYP_TYPENR(unireg_type); name.str= fieldnames.type_names[i]; name.length= strlen(name.str); - if (!(handler= Type_handler::get_handler_by_real_type(field_type))) - goto err; // Not supported field type + attr.interval= interval_nr ? share->intervals + interval_nr - 1 : NULL; + Record_addr addr(record + recpos, null_pos, null_bit_pos); *field_ptr= reg_field= - make_field(share, &share->mem_root, record+recpos, (uint32) field_length, - null_pos, null_bit_pos, pack_flag, handler, charset, - geom_type, srid, unireg_check, - (interval_nr ? share->intervals+interval_nr-1 : NULL), - &name, flags); + attr.make_field(share, &share->mem_root, &addr, handler, &name, flags); if (!reg_field) // Not supported field type goto err; - if (unireg_check == Field::TIMESTAMP_DNUN_FIELD || - unireg_check == Field::TIMESTAMP_DN_FIELD) + if (attr.unireg_check == Field::TIMESTAMP_DNUN_FIELD || + attr.unireg_check == Field::TIMESTAMP_DN_FIELD) { reg_field->default_value= new (&share->mem_root) Virtual_column_info(); reg_field->default_value->set_vcol_type(VCOL_DEFAULT); @@ -2075,10 +2115,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, status_var_increment(thd->status_var.feature_invisible_columns); if (!reg_field->invisible) share->visible_fields++; - if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag)) + if (handler->real_field_type() == MYSQL_TYPE_BIT && + !f_bit_as_char(attr.pack_flag)) { null_bits_are_used= 1; - if ((null_bit_pos+= field_length & 7) > 7) + if ((null_bit_pos+= (uint) (attr.length & 7)) > 7) { null_pos++; null_bit_pos-= 8; @@ -2101,7 +2142,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } } - if (f_no_default(pack_flag)) + if (f_no_default(attr.pack_flag)) reg_field->flags|= NO_DEFAULT_VALUE_FLAG; if (reg_field->unireg_check == Field::NEXT_NUMBER) @@ -2693,7 +2734,7 @@ static bool sql_unusable_for_discovery(THD *thd, handlerton *engine, if (lex->create_info.like()) return 1; // ... create select - if (lex->select_lex.item_list.elements) + if (lex->first_select_lex()->item_list.elements) return 1; // ... temporary if (create_info->tmp_table()) @@ -2882,7 +2923,7 @@ bool fix_session_vcol_expr(THD *thd, Virtual_column_info *vcol) DBUG_RETURN(0); vcol->expr->walk(&Item::cleanup_excluding_fields_processor, 0, 0); - DBUG_ASSERT(!vcol->expr->fixed); + DBUG_ASSERT(!vcol->expr->is_fixed()); DBUG_RETURN(fix_vcol_expr(thd, vcol)); } @@ -2937,7 +2978,7 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table, DBUG_PRINT("info", ("vcol: %p", vcol)); DBUG_ASSERT(func_expr); - if (func_expr->fixed) + if (func_expr->is_fixed()) DBUG_RETURN(0); // nothing to do if (fix_vcol_expr(thd, vcol)) @@ -2981,7 +3022,7 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table, of the statement because the field item does not have a field pointer at that time */ - myf warn= table->s->frm_version < FRM_VER_EXPRESSSIONS ? ME_JUST_WARNING : 0; + myf warn= table->s->frm_version < FRM_VER_EXPRESSSIONS ? ME_WARNING : 0; my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(warn), "AUTO_INCREMENT", vcol->get_vcol_type_name(), res.name); if (!warn) @@ -3428,17 +3469,6 @@ partititon_err: (my_bitmap_map*) bitmaps, share->fields, FALSE); bitmaps+= bitmap_size; - /* Don't allocate vcol_bitmap if we don't need it */ - if (share->virtual_fields) - { - if (!(outparam->def_vcol_set= (MY_BITMAP*) - alloc_root(&outparam->mem_root, sizeof(*outparam->def_vcol_set)))) - goto err; - my_bitmap_init(outparam->def_vcol_set, - (my_bitmap_map*) bitmaps, share->fields, FALSE); - bitmaps+= bitmap_size; - } - my_bitmap_init(&outparam->has_value_set, (my_bitmap_map*) bitmaps, share->fields, FALSE); bitmaps+= bitmap_size; @@ -3631,7 +3661,7 @@ void open_table_error(TABLE_SHARE *share, enum open_frm_error error, int db_errno) { char buff[FN_REFLEN]; - const myf errortype= ME_ERROR+ME_WAITTANG; // Write fatals error to log + const myf errortype= ME_ERROR_LOG; // Write fatals error to log DBUG_ENTER("open_table_error"); DBUG_PRINT("info", ("error: %d db_errno: %d", error, db_errno)); @@ -4887,7 +4917,7 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds, if (where) { - if (where->fixed) + if (where->is_fixed()) where->update_used_tables(); else if (where->fix_fields(thd, &where)) DBUG_RETURN(TRUE); @@ -4947,13 +4977,13 @@ bool TABLE_LIST::single_table_updatable() { if (!updatable) return false; - if (view && view->select_lex.table_list.elements == 1) + if (view && view->first_select_lex()->table_list.elements == 1) { /* We need to check deeply only single table views. Multi-table views will be turned to multi-table updates and then checked by leaf tables */ - return (((TABLE_LIST *)view->select_lex.table_list.first)-> + return (((TABLE_LIST *)view->first_select_lex()->table_list.first)-> single_table_updatable()); } return true; @@ -4990,7 +5020,8 @@ merge_on_conds(THD *thd, TABLE_LIST *table, bool is_cascaded) cond= table->on_expr->copy_andor_structure(thd); if (!table->view) DBUG_RETURN(cond); - for (TABLE_LIST *tbl= (TABLE_LIST*)table->view->select_lex.table_list.first; + for (TABLE_LIST *tbl= + (TABLE_LIST*)table->view->first_select_lex()->table_list.first; tbl; tbl= tbl->next_local) { @@ -5032,7 +5063,7 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) { DBUG_ENTER("TABLE_LIST::prep_check_option"); bool is_cascaded= check_opt_type == VIEW_CHECK_CASCADED; - TABLE_LIST *merge_underlying_list= view->select_lex.get_table_list(); + TABLE_LIST *merge_underlying_list= view->first_select_lex()->get_table_list(); for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local) { /* see comment of check_opt_type parameter */ @@ -5150,7 +5181,7 @@ TABLE_LIST *TABLE_LIST::find_underlying_table(TABLE *table_to_find) if (!view) return 0; - for (TABLE_LIST *tbl= view->select_lex.get_table_list(); + for (TABLE_LIST *tbl= view->first_select_lex()->get_table_list(); tbl; tbl= tbl->next_local) { @@ -5212,7 +5243,7 @@ int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure) main_view->db.str); const char *name_table= (main_view->view ? main_view->view_name.str : main_view->table_name.str); - my_error(ER_VIEW_CHECK_FAILED, MYF(ignore_failure ? ME_JUST_WARNING : 0), + my_error(ER_VIEW_CHECK_FAILED, MYF(ignore_failure ? ME_WARNING : 0), name_db, name_table); return ignore_failure ? VIEW_CHECK_SKIP : VIEW_CHECK_ERROR; } @@ -5256,7 +5287,7 @@ int TABLE::verify_constraints(bool ignore_failure) } field_error.append((*chk)->name.str); my_error(ER_CONSTRAINT_FAILED, - MYF(ignore_failure ? ME_JUST_WARNING : 0), field_error.c_ptr(), + MYF(ignore_failure ? ME_WARNING : 0), field_error.c_ptr(), s->db.str, s->error_table_name()); return ignore_failure ? VIEW_CHECK_SKIP : VIEW_CHECK_ERROR; } @@ -5348,7 +5379,8 @@ bool TABLE_LIST::set_insert_values(MEM_ROOT *mem_root) { DBUG_PRINT("info", ("setting insert_value for view")); DBUG_ASSERT(is_view_or_derived() && is_merged_derived()); - for (TABLE_LIST *tbl= (TABLE_LIST*)view->select_lex.table_list.first; + for (TABLE_LIST *tbl= + (TABLE_LIST*)view->first_select_lex()->table_list.first; tbl; tbl= tbl->next_local) if (tbl->set_insert_values(mem_root)) @@ -5515,7 +5547,7 @@ void TABLE_LIST::register_want_access(ulong want_access) } if (!view) return; - for (TABLE_LIST *tbl= view->select_lex.get_table_list(); + for (TABLE_LIST *tbl= view->first_select_lex()->get_table_list(); tbl; tbl= tbl->next_local) tbl->register_want_access(want_access); @@ -5707,6 +5739,7 @@ void TABLE_LIST::set_check_materialized() The subtree should be already excluded */ DBUG_ASSERT(!derived->first_select()->first_inner_unit() || + derived->first_select()->first_inner_unit()->with_element || derived->first_select()->first_inner_unit()->first_select()-> exclude_from_table_unique_test); } @@ -5723,14 +5756,14 @@ TABLE *TABLE_LIST::get_real_join_table() break; /* we do not support merging of union yet */ DBUG_ASSERT(tbl->view == NULL || - tbl->view->select_lex.next_select() == NULL); + tbl->view->first_select_lex()->next_select() == NULL); DBUG_ASSERT(tbl->derived == NULL || tbl->derived->first_select()->next_select() == NULL); { List_iterator_fast<TABLE_LIST> ti(tbl->view != NULL ? - tbl->view->select_lex.top_join_list : + tbl->view->first_select_lex()->top_join_list : tbl->derived->first_select()->top_join_list); for (;;) { @@ -5901,7 +5934,7 @@ Item *Field_iterator_view::create_item(THD *thd) Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, LEX_CSTRING *name) { - bool save_wrapper= thd->lex->select_lex.no_wrap_view_item; + bool save_wrapper= thd->lex->first_select_lex()->no_wrap_view_item; Item *field= *field_ref; DBUG_ENTER("create_view_field"); @@ -5912,13 +5945,13 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, ('mysql_schema_table' function). So we can return directly the field. This case happens only for 'show & where' commands. */ - DBUG_ASSERT(field && field->fixed); + DBUG_ASSERT(field && field->is_fixed()); DBUG_RETURN(field); } DBUG_ASSERT(field); thd->lex->current_select->no_wrap_view_item= TRUE; - if (!field->fixed) + if (!field->is_fixed()) { if (field->fix_fields(thd, field_ref)) { @@ -5932,8 +5965,9 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, { DBUG_RETURN(field); } - Name_resolution_context *context= view->view ? &view->view->select_lex.context : - &thd->lex->select_lex.context; + Name_resolution_context *context= (view->view ? + &view->view->first_select_lex()->context: + &thd->lex->first_select_lex()->context); Item *item= (new (thd->mem_root) Item_direct_view_ref(thd, context, field_ref, view->alias.str, name, view)); @@ -6256,13 +6290,12 @@ void TABLE::clear_column_bitmaps() Reset column read/write usage. It's identical to: bitmap_clear_all(&table->def_read_set); bitmap_clear_all(&table->def_write_set); - if (s->virtual_fields) bitmap_clear_all(table->def_vcol_set); The code assumes that the bitmaps are allocated after each other, as guaranteed by open_table_from_share() */ bzero((char*) def_read_set.bitmap, s->column_bitmap_size * (s->virtual_fields ? 3 : 2)); - column_bitmaps_set(&def_read_set, &def_write_set, def_vcol_set); + column_bitmaps_set(&def_read_set, &def_write_set); rpl_write_set= 0; // Safety } @@ -6409,13 +6442,8 @@ void TABLE::mark_columns_needed_for_delete() Field **reg_field; for (reg_field= field ; *reg_field ; reg_field++) { - Field *cur_field= *reg_field; - if (cur_field->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) - { - bitmap_set_bit(read_set, cur_field->field_index); - if (cur_field->vcol_info) - bitmap_set_bit(vcol_set, cur_field->field_index); - } + if ((*reg_field)->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) + mark_column_with_deps(*reg_field); } need_signal= true; } @@ -6494,13 +6522,7 @@ void TABLE::mark_columns_needed_for_update() if (any_written && !all_read) { for (KEY_PART_INFO *kp= k->key_part; kp < kpend; kp++) - { - int idx= kp->fieldnr - 1; - if (bitmap_fast_test_and_set(read_set, idx)) - continue; - if (field[idx]->vcol_info) - mark_virtual_col(field[idx]); - } + mark_column_with_deps(field[kp->fieldnr - 1]); } } need_signal= true; @@ -6697,49 +6719,12 @@ void TABLE::mark_columns_per_binlog_row_image() DBUG_ASSERT(FALSE); } } - /* - We have to ensure that all virtual columns that are part of read set - are calculated. - */ - if (vcol_set) - bitmap_union(vcol_set, read_set); file->column_bitmaps_signal(); } DBUG_VOID_RETURN; } -/* - @brief Mark a column as virtual used by the query - - @param field the field for the column to be marked - - @details - The function marks the column for 'field' as virtual (computed) - in the bitmap vcol_set. - If the column is marked for the first time the expression to compute - the column is traversed and all columns that are occurred there are - marked in the read_set of the table. - - @retval - TRUE if column is marked for the first time - @retval - FALSE otherwise -*/ - -bool TABLE::mark_virtual_col(Field *field) -{ - bool res; - DBUG_ASSERT(field->vcol_info); - if (!(res= bitmap_fast_test_and_set(vcol_set, field->field_index))) - { - Item *vcol_item= field->vcol_info->expr; - DBUG_ASSERT(vcol_item); - vcol_item->walk(&Item::register_field_in_read_map, 1, 0); - } - return res; -} - /* @brief Mark virtual columns for update/insert commands @@ -6781,13 +6766,13 @@ bool TABLE::mark_virtual_columns_for_write(bool insert_fl { tmp_vfield= *vfield_ptr; if (bitmap_is_set(write_set, tmp_vfield->field_index)) - bitmap_updated|= mark_virtual_col(tmp_vfield); + bitmap_updated|= mark_virtual_column_with_deps(tmp_vfield); else if (tmp_vfield->vcol_info->stored_in_db || (tmp_vfield->flags & (PART_KEY_FLAG | FIELD_IN_PART_FUNC_FLAG | PART_INDIRECT_KEY_FLAG))) { bitmap_set_bit(write_set, tmp_vfield->field_index); - mark_virtual_col(tmp_vfield); + mark_virtual_column_with_deps(tmp_vfield); bitmap_updated= true; } } @@ -6917,8 +6902,6 @@ void TABLE::mark_columns_used_by_virtual_fields(void) void TABLE::mark_check_constraint_columns_for_read(void) { bitmap_union(read_set, s->check_set); - if (vcol_set) - bitmap_union(vcol_set, s->check_set); } @@ -7672,6 +7655,20 @@ public: } }; + +/* + to satisfy ASSERT_COLUMN_MARKED_FOR_WRITE Field's assert we temporarily + mark field for write before storing the generated value in it +*/ +#ifndef DBUG_OFF +#define DBUG_FIX_WRITE_SET(f) bool _write_set_fixed= !bitmap_fast_test_and_set(write_set, (f)->field_index) +#define DBUG_RESTORE_WRITE_SET(f) if (_write_set_fixed) bitmap_clear_bit(write_set, (f)->field_index) +#else +#define DBUG_FIX_WRITE_SET(f) +#define DBUG_RESTORE_WRITE_SET(f) +#endif + + /* @brief Compute values for virtual columns used in query @@ -7735,17 +7732,17 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) switch (update_mode) { case VCOL_UPDATE_FOR_READ: update= (!vcol_info->stored_in_db && - bitmap_is_set(vcol_set, vf->field_index)); + bitmap_is_set(read_set, vf->field_index)); swap_values= 1; break; case VCOL_UPDATE_FOR_DELETE: case VCOL_UPDATE_FOR_WRITE: - update= bitmap_is_set(vcol_set, vf->field_index); + update= bitmap_is_set(read_set, vf->field_index); break; case VCOL_UPDATE_FOR_REPLACE: update= ((!vcol_info->stored_in_db && (vf->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) && - bitmap_is_set(vcol_set, vf->field_index)) || + bitmap_is_set(read_set, vf->field_index)) || update_all_columns); if (update && (vf->flags & BLOB_FLAG)) { @@ -7765,7 +7762,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) /* Read indexed fields that was not updated in VCOL_UPDATE_FOR_READ */ update= (!vcol_info->stored_in_db && (vf->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) && - !bitmap_is_set(vcol_set, vf->field_index)); + !bitmap_is_set(read_set, vf->field_index)); swap_values= 1; break; } @@ -7774,8 +7771,10 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) { int field_error __attribute__((unused)) = 0; /* Compute the actual value of the virtual fields */ + DBUG_FIX_WRITE_SET(vf); if (vcol_info->expr->save_in_field(vf, 0)) field_error= error= 1; + DBUG_RESTORE_WRITE_SET(vf); DBUG_PRINT("info", ("field '%s' - updated error: %d", vf->field_name.str, field_error)); if (swap_values && (vf->flags & BLOB_FLAG)) @@ -7809,7 +7808,9 @@ int TABLE::update_virtual_field(Field *vf) in_use->set_n_backup_active_arena(expr_arena, &backup_arena); bitmap_clear_all(&tmp_set); vf->vcol_info->expr->walk(&Item::update_vcol_processor, 0, &tmp_set); + DBUG_FIX_WRITE_SET(vf); vf->vcol_info->expr->save_in_field(vf, 0); + DBUG_RESTORE_WRITE_SET(vf); in_use->restore_active_arena(expr_arena, &backup_arena); DBUG_RETURN(in_use->is_error()); } @@ -8474,200 +8475,6 @@ double KEY::actual_rec_per_key(uint i) } -/** - @brief - Mark subformulas of a condition unusable for the condition pushed into table - - @param cond The condition whose subformulas are to be marked - - @details - This method recursively traverses the AND-OR condition cond and for each subformula - of the codition it checks whether it can be usable for the extraction of a condition - that can be pushed into this table. The subformulas that are not usable are - marked with the flag NO_EXTRACTION_FL. - @note - This method is called before any call of TABLE_LIST::build_pushable_cond_for_table. - The flag NO_EXTRACTION_FL set in a subformula allows to avoid building clone - for the subformula when extracting the pushable condition. -*/ - -void TABLE_LIST::check_pushable_cond_for_table(Item *cond) -{ - table_map tab_map= table->map; - cond->clear_extraction_flag(); - if (cond->type() == Item::COND_ITEM) - { - bool and_cond= ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC; - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); - uint count= 0; - Item *item; - while ((item=li++)) - { - check_pushable_cond_for_table(item); - if (item->get_extraction_flag() != NO_EXTRACTION_FL) - count++; - else if (!and_cond) - break; - } - if ((and_cond && count == 0) || item) - { - cond->set_extraction_flag(NO_EXTRACTION_FL); - if (and_cond) - li.rewind(); - while ((item= li++)) - item->clear_extraction_flag(); - } - } - else if (!cond->excl_dep_on_table(tab_map)) - cond->set_extraction_flag(NO_EXTRACTION_FL); -} - - -/** - @brief - Build condition extractable from the given one depended only on this table - - @param thd The thread handle - @param cond The condition from which the pushable one is to be extracted - - @details - For the given condition cond this method finds out what condition depended - only on this table can be extracted from cond. If such condition C exists - the method builds the item for it. - The method uses the flag NO_EXTRACTION_FL set by the preliminary call of - the method TABLE_LIST::check_pushable_cond_for_table to figure out whether - a subformula depends only on this table or not. - @note - The built condition C is always implied by the condition cond - (cond => C). The method tries to build the most restictive such - condition (i.e. for any other condition C' such that cond => C' - we have C => C'). - @note - The build item is not ready for usage: substitution for the field items - has to be done and it has to be re-fixed. - - @retval - the built condition pushable into this table if such a condition exists - NULL if there is no such a condition -*/ - -Item* TABLE_LIST::build_pushable_cond_for_table(THD *thd, Item *cond) -{ - table_map tab_map= table->map; - bool is_multiple_equality= cond->type() == Item::FUNC_ITEM && - ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC; - if (cond->get_extraction_flag() == NO_EXTRACTION_FL) - return 0; - if (cond->type() == Item::COND_ITEM) - { - bool cond_and= false; - Item_cond *new_cond; - if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) - { - cond_and= true; - new_cond=new (thd->mem_root) Item_cond_and(thd); - } - else - new_cond= new (thd->mem_root) Item_cond_or(thd); - if (!new_cond) - return 0; - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); - Item *item; - bool is_fix_needed= false; - while ((item=li++)) - { - if (item->get_extraction_flag() == NO_EXTRACTION_FL) - { - if (!cond_and) - return 0; - continue; - } - Item *fix= build_pushable_cond_for_table(thd, item); - if (!fix && !cond_and) - return 0; - if (!fix) - continue; - - if (fix->type() == Item::COND_ITEM && - ((Item_cond*) fix)->functype() == Item_func::COND_AND_FUNC) - is_fix_needed= true; - - new_cond->argument_list()->push_back(fix, thd->mem_root); - } - if (is_fix_needed && new_cond->fix_fields(thd, 0)) - return 0; - - switch (new_cond->argument_list()->elements) - { - case 0: - return 0; - case 1: - return new_cond->argument_list()->head(); - default: - return new_cond; - } - } - else if (is_multiple_equality) - { - if (!(cond->used_tables() & tab_map)) - return 0; - Item *new_cond= NULL; - int i= 0; - Item_equal *item_equal= (Item_equal *) cond; - Item *left_item = item_equal->get_const(); - Item_equal_fields_iterator it(*item_equal); - Item *item; - if (!left_item) - { - while ((item=it++)) - if (item->used_tables() == tab_map) - { - left_item= item; - break; - } - } - if (!left_item) - return 0; - while ((item=it++)) - { - if (!(item->used_tables() == tab_map)) - continue; - Item_func_eq *eq= 0; - Item *left_item_clone= left_item->build_clone(thd); - Item *right_item_clone= item->build_clone(thd); - if (left_item_clone && right_item_clone) - { - left_item_clone->set_item_equal(NULL); - right_item_clone->set_item_equal(NULL); - eq= new (thd->mem_root) Item_func_eq(thd, right_item_clone, - left_item_clone); - } - if (eq) - { - i++; - switch (i) - { - case 1: - new_cond= eq; - break; - case 2: - new_cond= new (thd->mem_root) Item_cond_and(thd, new_cond, eq); - break; - default: - ((Item_cond_and*)new_cond)->argument_list()->push_back(eq, - thd->mem_root); - } - } - } - if (new_cond) - new_cond->fix_fields(thd, &new_cond); - return new_cond; - } - else if (cond->get_extraction_flag() != NO_EXTRACTION_FL) - return cond->build_clone(thd); - return 0; -} - LEX_CSTRING *fk_option_name(enum_fk_option opt) { static LEX_CSTRING names[]= @@ -8754,7 +8561,7 @@ bool TR_table::update(ulonglong start_id, ulonglong end_id) return true; store(FLD_BEGIN_TS, thd->transaction_time()); - timeval end_time= {thd->query_start(), long(thd->query_start_sec_part())}; + timeval end_time= {thd->query_start(), int(thd->query_start_sec_part())}; store(FLD_TRX_ID, start_id); store(FLD_COMMIT_ID, end_id); store(FLD_COMMIT_TS, end_time); @@ -8775,7 +8582,7 @@ bool TR_table::query(ulonglong trx_id) READ_RECORD info; int error; List<TABLE_LIST> dummy; - SELECT_LEX &slex= thd->lex->select_lex; + SELECT_LEX &slex= *(thd->lex->first_select_lex()); Name_resolution_context_backup backup(slex.context, *this); Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_TRX_ID]); Item *value= newx Item_int(thd, trx_id); @@ -8805,7 +8612,7 @@ bool TR_table::query(MYSQL_TIME &commit_time, bool backwards) READ_RECORD info; int error; List<TABLE_LIST> dummy; - SELECT_LEX &slex= thd->lex->select_lex; + SELECT_LEX &slex= *(thd->lex->first_select_lex()); Name_resolution_context_backup backup(slex.context, *this); Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_COMMIT_TS]); Item *value= newx Item_datetime_literal(thd, &commit_time, 6); @@ -9054,7 +8861,8 @@ bool Vers_history_point::resolve_unit(THD *thd) return false; if (item->fix_fields_if_needed(thd, &item)) return true; - return item->this_item()->type_handler_for_system_time()-> + return item->this_item()->real_type_handler()-> + type_handler_for_system_time()-> Vers_history_point_resolve_unit(thd, this); } diff --git a/sql/table.h b/sql/table.h index 80f5e1283a3..b75fa9074a4 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1153,8 +1153,6 @@ public: MY_BITMAP cond_set; /* used to mark fields from sargable conditions*/ /* Active column sets */ MY_BITMAP *read_set, *write_set, *rpl_write_set; - /* Set if using virtual fields */ - MY_BITMAP *vcol_set, *def_vcol_set; /* On INSERT: fields that the user specified a value for */ MY_BITMAP has_value_set; @@ -1375,7 +1373,9 @@ public: void mark_columns_needed_for_delete(void); void mark_columns_needed_for_insert(void); void mark_columns_per_binlog_row_image(void); - bool mark_virtual_col(Field *field); + inline bool mark_column_with_deps(Field *field); + inline bool mark_virtual_column_with_deps(Field *field); + inline void mark_virtual_column_deps(Field *field); bool mark_virtual_columns_for_write(bool insert_fl); bool check_virtual_columns_marked_for_read(); bool check_virtual_columns_marked_for_write(); @@ -1397,39 +1397,21 @@ public: if (file) file->column_bitmaps_signal(); } - inline void column_bitmaps_set(MY_BITMAP *read_set_arg, - MY_BITMAP *write_set_arg, - MY_BITMAP *vcol_set_arg) - { - read_set= read_set_arg; - write_set= write_set_arg; - vcol_set= vcol_set_arg; - if (file) - file->column_bitmaps_signal(); - } inline void column_bitmaps_set_no_signal(MY_BITMAP *read_set_arg, MY_BITMAP *write_set_arg) { read_set= read_set_arg; write_set= write_set_arg; } - inline void column_bitmaps_set_no_signal(MY_BITMAP *read_set_arg, - MY_BITMAP *write_set_arg, - MY_BITMAP *vcol_set_arg) - { - read_set= read_set_arg; - write_set= write_set_arg; - vcol_set= vcol_set_arg; - } inline void use_all_columns() { column_bitmaps_set(&s->all_set, &s->all_set); } + inline void use_all_stored_columns(); inline void default_column_bitmaps() { read_set= &def_read_set; write_set= &def_write_set; - vcol_set= def_vcol_set; /* Note that this may be 0 */ rpl_write_set= 0; } /** Should this instance of the table be reopened? */ @@ -2601,8 +2583,6 @@ struct TABLE_LIST return false; } void set_lock_type(THD* thd, enum thr_lock_type lock); - void check_pushable_cond_for_table(Item *cond); - Item *build_pushable_cond_for_table(THD *thd, Item *cond); private: bool prep_check_option(THD *thd, uint8 check_opt_type); diff --git a/sql/table_cache.cc b/sql/table_cache.cc index 61e54c8f0f9..e82bb13228b 100644 --- a/sql/table_cache.cc +++ b/sql/table_cache.cc @@ -645,7 +645,7 @@ bool tdc_init(void) void tdc_start_shutdown(void) { - DBUG_ENTER("table_def_start_shutdown"); + DBUG_ENTER("tdc_start_shutdown"); if (tdc_inited) { /* diff --git a/sql/threadpool_win.cc b/sql/threadpool_win.cc index 0cc683c631d..3bc1ae3b371 100644 --- a/sql/threadpool_win.cc +++ b/sql/threadpool_win.cc @@ -75,7 +75,6 @@ static bool skip_completion_port_on_success = false; io_completion_callback - handle client request timer_callback - handle wait timeout (kill connection) - shm_read_callback, shm_close_callback - shared memory stuff login_callback - user login (submitted as threadpool work) */ @@ -89,9 +88,6 @@ static void CALLBACK io_completion_callback(PTP_CALLBACK_INSTANCE instance, static void CALLBACK work_callback(PTP_CALLBACK_INSTANCE instance, PVOID context, PTP_WORK work); -static void CALLBACK shm_read_callback(PTP_CALLBACK_INSTANCE instance, - PVOID Context, PTP_WAIT wait,TP_WAIT_RESULT wait_result); - static void pre_callback(PVOID context, PTP_CALLBACK_INSTANCE instance); /* Get current time as Windows time */ @@ -120,7 +116,6 @@ public: PTP_CALLBACK_INSTANCE callback_instance; PTP_IO io; PTP_TIMER timer; - PTP_WAIT shm_read; PTP_WORK work; bool long_callback; @@ -149,7 +144,6 @@ TP_connection_win::TP_connection_win(CONNECT *c) : callback_instance(0), io(0), timer(0), - shm_read(0), work(0) { } @@ -170,30 +164,20 @@ int TP_connection_win::init() case VIO_TYPE_NAMEDPIPE: handle= (HANDLE)vio->hPipe; break; - case VIO_TYPE_SHARED_MEMORY: - handle= vio->event_server_wrote; - break; default: abort(); } - if (vio_type == VIO_TYPE_SHARED_MEMORY) + + /* Performance tweaks (s. MSDN documentation)*/ + UCHAR flags= FILE_SKIP_SET_EVENT_ON_HANDLE; + if (skip_completion_port_on_success) { - CHECK_ALLOC_ERROR(shm_read= CreateThreadpoolWait(shm_read_callback, this, &callback_environ)); + flags |= FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; } - else - { - /* Performance tweaks (s. MSDN documentation)*/ - UCHAR flags= FILE_SKIP_SET_EVENT_ON_HANDLE; - if (skip_completion_port_on_success) - { - flags |= FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; - } - (void)SetFileCompletionNotificationModes(handle, flags); - /* Assign io completion callback */ - CHECK_ALLOC_ERROR(io= CreateThreadpoolIo(handle, io_completion_callback, this, &callback_environ)); - } - + (void)SetFileCompletionNotificationModes(handle, flags); + /* Assign io completion callback */ + CHECK_ALLOC_ERROR(io= CreateThreadpoolIo(handle, io_completion_callback, this, &callback_environ)); CHECK_ALLOC_ERROR(timer= CreateThreadpoolTimer(timer_callback, this, &callback_environ)); CHECK_ALLOC_ERROR(work= CreateThreadpoolWork(work_callback, this, &callback_environ)); return 0; @@ -214,11 +198,6 @@ int TP_connection_win::start_io() DWORD last_error= 0; int retval; - if (shm_read) - { - SetThreadpoolWait(shm_read, handle, NULL); - return 0; - } StartThreadpoolIo(io); if (vio_type == VIO_TYPE_TCPIP || vio_type == VIO_TYPE_SSL) @@ -297,9 +276,6 @@ TP_connection_win::~TP_connection_win() if (io) CloseThreadpoolIo(io); - if (shm_read) - CloseThreadpoolWait(shm_read); - if (work) CloseThreadpoolWork(work); @@ -420,29 +396,6 @@ static VOID CALLBACK timer_callback(PTP_CALLBACK_INSTANCE instance, } } - -/* - Shared memory read callback. - Invoked when read event is set on connection. -*/ - -static void CALLBACK shm_read_callback(PTP_CALLBACK_INSTANCE instance, - PVOID context, PTP_WAIT wait,TP_WAIT_RESULT wait_result) -{ - TP_connection_win *c= (TP_connection_win *)context; - /* Disarm wait. */ - SetThreadpoolWait(wait, NULL, NULL); - - /* - This is an autoreset event, and one wakeup is eaten already by threadpool, - and the current state is "not set". Thus we need to reset the event again, - or vio_read will hang. - */ - SetEvent(c->handle); - tp_callback(instance, context); -} - - static void CALLBACK work_callback(PTP_CALLBACK_INSTANCE instance, PVOID context, PTP_WORK work) { tp_callback(instance, context); diff --git a/sql/unireg.cc b/sql/unireg.cc index 6540e11578b..4692b2d74d1 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -897,32 +897,12 @@ static bool pack_fields(uchar **buff_arg, List<Create_field> &create_fields, while ((field=it++)) { uint recpos; - int2store(buff+3, field->length); /* The +1 is here becasue the col offset in .frm file have offset 1 */ recpos= field->offset+1 + (uint) data_offset; int3store(buff+5,recpos); - int2store(buff+8,field->pack_flag); - buff[10]= (uchar) field->unireg_check; buff[12]= (uchar) field->interval_id; - buff[13]= (uchar) field->real_field_type(); - if (field->real_field_type() == MYSQL_TYPE_GEOMETRY) - { - buff[11]= 0; - buff[14]= (uchar) field->geom_type; -#ifndef HAVE_SPATIAL - DBUG_ASSERT(0); // Should newer happen -#endif - } - else if (field->charset) - { - buff[11]= (uchar) (field->charset->number >> 8); - buff[14]= (uchar) field->charset->number; - } - else - { - buff[11]= buff[14]= 0; // Numerical - } - + buff[13]= (uchar) field->type_handler()->real_field_type(); + field->type_handler()->Column_definition_attributes_frm_pack(field, buff); int2store(buff+15, field->comment.length); comment_length+= field->comment.length; set_if_bigger(int_count,field->interval_id); @@ -1043,21 +1023,16 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options, thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values while ((field=it++)) { + Record_addr addr(buff + field->offset + data_offset, + null_pos + null_count / 8, null_count & 7); + Column_definition_attributes tmp(*field); + tmp.interval= field->save_interval ? + field->save_interval : field->interval; /* regfield don't have to be deleted as it's allocated on THD::mem_root */ - Field *regfield= make_field(&share, thd->mem_root, - buff+field->offset + data_offset, - (uint32)field->length, - null_pos + null_count / 8, - null_count & 7, - field->pack_flag, - field->type_handler(), - field->charset, - field->geom_type, field->srid, - field->unireg_check, - field->save_interval ? field->save_interval - : field->interval, - &field->field_name, - field->flags); + Field *regfield= tmp.make_field(&share, thd->mem_root, &addr, + field->type_handler(), + &field->field_name, + field->flags); if (!regfield) { error= 1; diff --git a/sql/unireg.h b/sql/unireg.h index 88d0c882824..6f224ab4894 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -56,11 +56,6 @@ #endif #define ER_THD_OR_DEFAULT(thd,X) ((thd) ? ER_THD(thd, (X)) : ER_DEFAULT(X)) - -#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 */ #define SPECIAL_NO_NEW_FUNC 2 /* Skip new functions */ #define SPECIAL_SKIP_SHOW_DB 4 /* Don't allow 'show db' */ diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 76b27c91d01..667fdb779ea 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1327,7 +1327,7 @@ static int create_view_query(THD *thd, uchar** buf, size_t* buf_len) { LEX *lex= thd->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); TABLE_LIST *first_table= select_lex->table_list.first; TABLE_LIST *views = first_table; LEX_USER *definer; @@ -1419,7 +1419,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, DBUG_ASSERT(table_list || db); LEX* lex= thd->lex; - SELECT_LEX* select_lex= &lex->select_lex; + SELECT_LEX* select_lex= lex->first_select_lex(); TABLE_LIST* first_table= select_lex->table_list.first; switch (lex->sql_command) |