summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc277
1 files changed, 186 insertions, 91 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 27cb6d49fd4..6e661afbd91 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -61,7 +61,7 @@ Hybrid_type_traits::val_decimal(Hybrid_type *val, my_decimal *to) const
String *
Hybrid_type_traits::val_str(Hybrid_type *val, String *to, uint8 decimals) const
{
- to->set(val->real, decimals, &my_charset_bin);
+ to->set_real(val->real, decimals, &my_charset_bin);
return to;
}
@@ -202,7 +202,7 @@ String *Item::val_string_from_real(String *str)
double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
- str->set(nr,decimals, &my_charset_bin);
+ str->set_real(nr,decimals, &my_charset_bin);
return str;
}
@@ -212,10 +212,7 @@ String *Item::val_string_from_int(String *str)
longlong nr= val_int();
if (null_value)
return 0;
- if (unsigned_flag)
- str->set((ulonglong) nr, &my_charset_bin);
- else
- str->set(nr, &my_charset_bin);
+ str->set_int(nr, unsigned_flag, &my_charset_bin);
return str;
}
@@ -551,6 +548,23 @@ bool Item_field::find_item_in_field_list_processor(byte *arg)
}
+/*
+ Mark field in read_map
+
+ NOTES
+ This is used by filesort to register used fields in a a temporary
+ column read set or to register used fields in a view
+*/
+
+bool Item_field::register_field_in_read_map(byte *arg)
+{
+ TABLE *table= (TABLE *) arg;
+ if (field->table == table || !table)
+ bitmap_set_bit(field->table->read_set, field->field_index);
+ return 0;
+}
+
+
bool Item::check_cols(uint c)
{
if (c != 1)
@@ -671,6 +685,7 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
{
Item_string *conv;
uint conv_errors;
+ char *ptr;
String tmp, cstr, *ostr= val_str(&tmp);
cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
if (conv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(),
@@ -685,7 +700,9 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
*/
return NULL;
}
- conv->str_value.copy();
+ if (!(ptr= current_thd->memdup(cstr.ptr(), cstr.length() + 1 )))
+ return NULL;
+ conv->str_value.set(ptr, cstr.length(), cstr.charset());
/* Ensure that no one is going to change the result string */
conv->str_value.mark_as_const();
return conv;
@@ -793,14 +810,25 @@ CHARSET_INFO *Item::default_charset()
}
+/*
+ Save value in field, but don't give any warnings
+
+ NOTES
+ This is used to temporary store and retrieve a value in a column,
+ for example in opt_range to adjust the key value to fit the column.
+*/
+
int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
{
int res;
- THD *thd= field->table->in_use;
+ TABLE *table= field->table;
+ THD *thd= table->in_use;
enum_check_fields tmp= thd->count_cuted_fields;
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
res= save_in_field(field, no_conversions);
thd->count_cuted_fields= tmp;
+ dbug_tmp_restore_column_map(table->write_set, old_map);
return res;
}
@@ -1399,7 +1427,11 @@ bool agg_item_collations_for_comparison(DTCollation &c, const char *fname,
bool agg_item_charsets(DTCollation &coll, const char *fname,
Item **args, uint nargs, uint flags, int item_sep)
{
- Item **arg, *safe_args[2];
+ Item **arg, **last, *safe_args[2];
+
+ LINT_INIT(safe_args[0]);
+ LINT_INIT(safe_args[1]);
+
if (agg_item_collations(coll, fname, args, nargs, flags, item_sep))
return TRUE;
@@ -1493,20 +1525,21 @@ void Item_ident_for_show::make_field(Send_field *tmp_field)
Item_field::Item_field(Field *f)
:Item_ident(0, NullS, *f->table_name, f->field_name),
- item_equal(0), no_const_subst(0),
+ item_equal(0), no_const_subst(0),
have_privileges(0), any_privileges(0)
{
set_field(f);
/*
- field_name and talbe_name should not point to garbage
+ field_name and table_name should not point to garbage
if this item is to be reused
*/
orig_table_name= orig_field_name= "";
}
+
Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
Field *f)
- :Item_ident(context_arg, f->table->s->db, *f->table_name, f->field_name),
+ :Item_ident(context_arg, f->table->s->db.str, *f->table_name, f->field_name),
item_equal(0), no_const_subst(0),
have_privileges(0), any_privileges(0)
{
@@ -1573,7 +1606,7 @@ void Item_field::set_field(Field *field_par)
max_length= field_par->max_length();
table_name= *field_par->table_name;
field_name= field_par->field_name;
- db_name= field_par->table->s->db;
+ db_name= field_par->table->s->db.str;
alias_name_used= field_par->table->alias_name_used;
unsigned_flag=test(field_par->flags & UNSIGNED_FLAG);
collation.set(field_par->charset(), DERIVATION_IMPLICIT);
@@ -2036,7 +2069,7 @@ String *Item_float::val_str(String *str)
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
- str->set(value,decimals,&my_charset_bin);
+ str->set_real(value,decimals,&my_charset_bin);
return str;
}
@@ -2389,7 +2422,8 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
CHARSET_INFO *tocs= thd->variables.collation_connection;
uint32 dummy_offset;
- value.cs_info.character_set_of_placeholder= fromcs;
+ value.cs_info.character_set_of_placeholder=
+ value.cs_info.character_set_client= fromcs;
/*
Setup source and destination character sets so that they
are different only if conversion is necessary: this will
@@ -2630,7 +2664,7 @@ String *Item_param::val_str(String* str)
case LONG_DATA_VALUE:
return &str_value_ptr;
case REAL_VALUE:
- str->set(value.real, NOT_FIXED_DEC, &my_charset_bin);
+ str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
return str;
case INT_VALUE:
str->set(value.integer, &my_charset_bin);
@@ -2670,7 +2704,7 @@ const String *Item_param::query_val_str(String* str) const
str->set(value.integer, &my_charset_bin);
break;
case REAL_VALUE:
- str->set(value.real, NOT_FIXED_DEC, &my_charset_bin);
+ str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
break;
case DECIMAL_VALUE:
if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
@@ -3592,7 +3626,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
Item** res= find_item_in_list(this, thd->lex->current_select->item_list,
&counter, REPORT_EXCEPT_NOT_FOUND,
&not_used);
- if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM)
+ if (res != (Item **)not_found_item &&
+ (*res)->type() == Item::FIELD_ITEM)
{
set_field((*((Item_field**)res))->field);
return 0;
@@ -3611,7 +3646,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
if it is not expression from merged VIEW we will set this field.
We can leave expression substituted from view for next PS/SP rexecution
- (i.e. do not register this substitution for reverting on cleupup()
+ (i.e. do not register this substitution for reverting on cleanup()
(register_item_tree_changing())), because this subtree will be
fix_field'ed during setup_tables()->setup_underlying() (i.e. before
all other expressions of query, and references on tables which do
@@ -3623,13 +3658,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
return FALSE;
if (!outer_fixed && cached_table && cached_table->select_lex &&
- context->select_lex &&
- cached_table->select_lex != context->select_lex)
+ context->select_lex &&
+ cached_table->select_lex != context->select_lex)
{
int ret;
if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
goto error;
- else if (!ret)
+ if (!ret)
return FALSE;
}
@@ -3640,13 +3675,29 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
set_if_bigger(thd->lex->in_sum_func->max_arg_level,
thd->lex->current_select->nest_level);
}
- else if (thd->set_query_id && field->query_id != thd->query_id)
+ else if (thd->mark_used_columns != MARK_COLUMNS_NONE)
{
- /* We only come here in unions */
- TABLE *table=field->table;
- field->query_id=thd->query_id;
- table->used_fields++;
- table->used_keys.intersect(field->part_of_key);
+ TABLE *table= field->table;
+ MY_BITMAP *current_bitmap, *other_bitmap;
+ if (thd->mark_used_columns == MARK_COLUMNS_READ)
+ {
+ current_bitmap= table->read_set;
+ other_bitmap= table->write_set;
+ }
+ else
+ {
+ current_bitmap= table->write_set;
+ other_bitmap= table->read_set;
+ }
+ if (!bitmap_fast_test_and_set(current_bitmap, field->field_index))
+ {
+ if (!bitmap_is_set(other_bitmap, field->field_index))
+ {
+ /* First usage of column */
+ table->used_fields++; // Used to optimize loops
+ table->used_keys.intersect(field->part_of_key);
+ }
+ }
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (any_privileges)
@@ -3900,17 +3951,22 @@ enum_field_types Item::field_type() const
Field *Item::make_string_field(TABLE *table)
{
+ Field *field;
DBUG_ASSERT(collation.collation);
if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB)
- return new Field_blob(max_length, maybe_null, name, table,
+ field= new Field_blob(max_length, maybe_null, name,
collation.collation);
/* Item_type_holder holds the exact type, do not change it */
- if (max_length > 0 &&
+ else if (max_length > 0 &&
(type() != Item::TYPE_HOLDER || field_type() != MYSQL_TYPE_STRING))
- return new Field_varstring(max_length, maybe_null, name, table,
+ field= new Field_varstring(max_length, maybe_null, name, table->s,
collation.collation);
- return new Field_string(max_length, maybe_null, name, table,
- collation.collation);
+ else
+ field= new Field_string(max_length, maybe_null, name,
+ collation.collation);
+ if (field)
+ field->init(table);
+ return field;
}
@@ -3918,74 +3974,97 @@ Field *Item::make_string_field(TABLE *table)
Create a field based on field_type of argument
For now, this is only used to create a field for
- IFNULL(x,something)
+ IFNULL(x,something) and time functions
RETURN
0 error
# Created field
*/
-Field *Item::tmp_table_field_from_field_type(TABLE *table)
+Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length)
{
/*
The field functions defines a field to be not null if null_ptr is not 0
*/
uchar *null_ptr= maybe_null ? (uchar*) "" : 0;
+ Field *field;
switch (field_type()) {
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_NEWDECIMAL:
- return new Field_new_decimal((char*) 0, max_length, null_ptr, 0,
- Field::NONE, name, table, decimals, 0,
+ field= new Field_new_decimal((char*) 0, max_length, null_ptr, 0,
+ Field::NONE, name, decimals, 0,
unsigned_flag);
+ break;
case MYSQL_TYPE_TINY:
- return new Field_tiny((char*) 0, max_length, null_ptr, 0, Field::NONE,
- name, table, 0, unsigned_flag);
+ field= new Field_tiny((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ name, 0, unsigned_flag);
+ break;
case MYSQL_TYPE_SHORT:
- return new Field_short((char*) 0, max_length, null_ptr, 0, Field::NONE,
- name, table, 0, unsigned_flag);
+ field= new Field_short((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ name, 0, unsigned_flag);
+ break;
case MYSQL_TYPE_LONG:
- return new Field_long((char*) 0, max_length, null_ptr, 0, Field::NONE,
- name, table, 0, unsigned_flag);
+ field= new Field_long((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ name, 0, unsigned_flag);
+ break;
#ifdef HAVE_LONG_LONG
case MYSQL_TYPE_LONGLONG:
- return new Field_longlong((char*) 0, max_length, null_ptr, 0, Field::NONE,
- name, table, 0, unsigned_flag);
+ field= new Field_longlong((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ name, 0, unsigned_flag);
+ break;
#endif
case MYSQL_TYPE_FLOAT:
- return new Field_float((char*) 0, max_length, null_ptr, 0, Field::NONE,
- name, table, decimals, 0, unsigned_flag);
+ field= new Field_float((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ name, decimals, 0, unsigned_flag);
+ break;
case MYSQL_TYPE_DOUBLE:
- return new Field_double((char*) 0, max_length, null_ptr, 0, Field::NONE,
- name, table, decimals, 0, unsigned_flag);
+ field= new Field_double((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ name, decimals, 0, unsigned_flag);
+ break;
case MYSQL_TYPE_NULL:
- return new Field_null((char*) 0, max_length, Field::NONE,
- name, table, &my_charset_bin);
+ field= new Field_null((char*) 0, max_length, Field::NONE,
+ name, &my_charset_bin);
+ break;
case MYSQL_TYPE_INT24:
- return new Field_medium((char*) 0, max_length, null_ptr, 0, Field::NONE,
- name, table, 0, unsigned_flag);
+ field= new Field_medium((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ name, 0, unsigned_flag);
+ break;
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_DATE:
- return new Field_date(maybe_null, name, table, &my_charset_bin);
+ field= new Field_date(maybe_null, name, &my_charset_bin);
+ break;
case MYSQL_TYPE_TIME:
- return new Field_time(maybe_null, name, table, &my_charset_bin);
+ field= new Field_time(maybe_null, name, &my_charset_bin);
+ break;
case MYSQL_TYPE_TIMESTAMP:
- return new Field_timestamp(maybe_null, name, table, &my_charset_bin);
+ field= new Field_timestamp(maybe_null, name, &my_charset_bin);
+ break;
case MYSQL_TYPE_DATETIME:
- return new Field_datetime(maybe_null, name, table, &my_charset_bin);
+ field= new Field_datetime(maybe_null, name, &my_charset_bin);
+ break;
case MYSQL_TYPE_YEAR:
- return new Field_year((char*) 0, max_length, null_ptr, 0, Field::NONE,
- name, table);
+ field= new Field_year((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ name);
+ break;
case MYSQL_TYPE_BIT:
- return new Field_bit_as_char(NULL, max_length, null_ptr, 0,
- Field::NONE, name, table);
+ field= new Field_bit_as_char(NULL, max_length, null_ptr, 0,
+ Field::NONE, name);
+ break;
default:
/* This case should never be chosen */
DBUG_ASSERT(0);
/* If something goes awfully wrong, it's better to get a string than die */
+ case MYSQL_TYPE_STRING:
+ if (fixed_length && max_length < CONVERT_IF_BIGGER_TO_BLOB)
+ {
+ field= new Field_string(max_length, maybe_null, name,
+ collation.collation);
+ break;
+ }
+ /* Fall through to make_string_field() */
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
- case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_VARCHAR:
return make_string_field(table);
@@ -3995,13 +4074,15 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_GEOMETRY:
if (this->type() == Item::TYPE_HOLDER)
- return new Field_blob(max_length, maybe_null, name, table,
- collation.collation, 1);
+ field= new Field_blob(max_length, maybe_null, name, collation.collation,
+ 1);
else
- return new Field_blob(max_length, maybe_null, name, table,
- collation.collation);
+ field= new Field_blob(max_length, maybe_null, name, collation.collation);
break; // Blob handled outside of case
}
+ if (field)
+ field->init(table);
+ return field;
}
@@ -4284,7 +4365,7 @@ void Item_float::print(String *str)
}
char buffer[20];
String num(buffer, sizeof(buffer), &my_charset_bin);
- num.set(value, decimals, &my_charset_bin);
+ num.set_real(value, decimals, &my_charset_bin);
str->append(num);
}
@@ -5237,8 +5318,9 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
if (!(def_field= (Field*) sql_alloc(field_arg->field->size_of())))
goto error;
memcpy(def_field, field_arg->field, field_arg->field->size_of());
- def_field->move_field(def_field->table->s->default_values -
- def_field->table->record[0]);
+ def_field->move_field_offset((my_ptrdiff_t)
+ (def_field->table->s->default_values -
+ def_field->table->record[0]));
set_field(def_field);
return FALSE;
@@ -5340,16 +5422,22 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
if (!def_field)
return TRUE;
memcpy(def_field, field_arg->field, field_arg->field->size_of());
- def_field->move_field(def_field->table->insert_values -
- def_field->table->record[0]);
+ def_field->move_field_offset((my_ptrdiff_t)
+ (def_field->table->insert_values -
+ def_field->table->record[0]));
set_field(def_field);
}
else
{
Field *tmp_field= field_arg->field;
/* charset doesn't matter here, it's to avoid sigsegv only */
- set_field(new Field_null(0, 0, Field::NONE, tmp_field->field_name,
- tmp_field->table, &my_charset_bin));
+ tmp_field= new Field_null(0, 0, Field::NONE, field_arg->field->field_name,
+ &my_charset_bin);
+ if (tmp_field)
+ {
+ tmp_field->init(field_arg->field->table);
+ set_field(tmp_field);
+ }
}
return FALSE;
}
@@ -5388,21 +5476,21 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table,
GRANT_INFO *table_grant_info)
{
/*
- There is no sense in marking fields used by trigger with current value
- of THD::query_id since it is completely unrelated to the THD::query_id
- value for statements which will invoke trigger. So instead we use
- Table_triggers_list::mark_fields_used() method which is called during
- execution of these statements.
+ It is too early to mark fields used here, because before execution
+ of statement that will invoke trigger other statements may use same
+ TABLE object, so all such mark-up will be wiped out.
+ So instead we do it in Table_triggers_list::mark_fields_used()
+ method which is called during execution of these statements.
*/
- bool save_set_query_id= thd->set_query_id;
- thd->set_query_id= 0;
+ enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
+ thd->mark_used_columns= MARK_COLUMNS_NONE;
/*
Try to find field by its name and if it will be found
set field_idx properly.
*/
(void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
0, &field_idx);
- thd->set_query_id= save_set_query_id;
+ thd->mark_used_columns= save_mark_used_columns;
triggers= table->triggers;
table_grants= table_grant_info;
}
@@ -5460,8 +5548,8 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items)
{
table_grants->want_privilege= want_privilege;
- if (check_grant_column(thd, table_grants, triggers->table->s->db,
- triggers->table->s->table_name, field_name,
+ if (check_grant_column(thd, table_grants, triggers->table->s->db.str,
+ triggers->table->s->table_name.str, field_name,
strlen(field_name), thd->security_ctx))
return TRUE;
}
@@ -5724,7 +5812,7 @@ longlong Item_cache_real::val_int()
String* Item_cache_real::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- str->set(value, decimals, default_charset());
+ str->set_real(value, decimals, default_charset());
return str;
}
@@ -6197,24 +6285,31 @@ Field *Item_type_holder::make_field_by_type(TABLE *table)
The field functions defines a field to be not null if null_ptr is not 0
*/
uchar *null_ptr= maybe_null ? (uchar*) "" : 0;
- switch (fld_type)
- {
+ Field *field;
+
+ switch (fld_type) {
case MYSQL_TYPE_ENUM:
DBUG_ASSERT(enum_set_typelib);
- return new Field_enum((char *) 0, max_length, null_ptr, 0,
+ field= new Field_enum((char *) 0, max_length, null_ptr, 0,
Field::NONE, name,
- table, get_enum_pack_length(enum_set_typelib->count),
+ get_enum_pack_length(enum_set_typelib->count),
enum_set_typelib, collation.collation);
+ if (field)
+ field->init(table);
+ return field;
case MYSQL_TYPE_SET:
DBUG_ASSERT(enum_set_typelib);
- return new Field_set((char *) 0, max_length, null_ptr, 0,
+ field= new Field_set((char *) 0, max_length, null_ptr, 0,
Field::NONE, name,
- table, get_set_pack_length(enum_set_typelib->count),
+ get_set_pack_length(enum_set_typelib->count),
enum_set_typelib, collation.collation);
+ if (field)
+ field->init(table);
+ return field;
default:
break;
}
- return tmp_table_field_from_field_type(table);
+ return tmp_table_field_from_field_type(table, 0);
}