2006-12-31 01:02:27 +01:00
|
|
|
/* Copyright (C) 2000-2006 MySQL AB
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
2006-12-23 20:17:15 +01:00
|
|
|
the Free Software Foundation; version 2 of the License.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
|
|
|
|
|
|
/* This file defines all compare functions */
|
|
|
|
|
2005-05-26 12:09:14 +02:00
|
|
|
#ifdef USE_PRAGMA_IMPLEMENTATION
|
2000-07-31 21:29:14 +02:00
|
|
|
#pragma implementation // gcc: Class implementation
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "mysql_priv.h"
|
|
|
|
#include <m_ctype.h>
|
2003-10-31 10:02:16 +01:00
|
|
|
#include "sql_select.h"
|
2003-06-24 12:11:07 +02:00
|
|
|
|
2005-11-07 23:59:52 +01:00
|
|
|
static bool convert_constant_item(THD *thd, Field *field, Item **item);
|
|
|
|
|
2007-01-22 11:52:23 +01:00
|
|
|
static Item_result item_store_type(Item_result a, Item *item,
|
|
|
|
my_bool unsigned_flag)
|
2003-07-18 12:50:40 +02:00
|
|
|
{
|
2007-01-22 11:52:23 +01:00
|
|
|
Item_result b= item->result_type();
|
|
|
|
|
2003-07-18 12:50:40 +02:00
|
|
|
if (a == STRING_RESULT || b == STRING_RESULT)
|
|
|
|
return STRING_RESULT;
|
|
|
|
else if (a == REAL_RESULT || b == REAL_RESULT)
|
|
|
|
return REAL_RESULT;
|
2007-01-22 11:52:23 +01:00
|
|
|
else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT ||
|
|
|
|
unsigned_flag != item->unsigned_flag)
|
2005-02-08 23:50:45 +01:00
|
|
|
return DECIMAL_RESULT;
|
2003-07-18 12:50:40 +02:00
|
|
|
else
|
|
|
|
return INT_RESULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void agg_result_type(Item_result *type, Item **items, uint nitems)
|
|
|
|
{
|
2006-03-06 13:38:35 +01:00
|
|
|
Item **item, **item_end;
|
2007-01-22 11:52:23 +01:00
|
|
|
my_bool unsigned_flag= 0;
|
2006-03-06 13:38:35 +01:00
|
|
|
|
|
|
|
*type= STRING_RESULT;
|
|
|
|
/* Skip beginning NULL items */
|
|
|
|
for (item= items, item_end= item + nitems; item < item_end; item++)
|
2006-04-21 08:48:00 +02:00
|
|
|
{
|
2006-03-06 13:38:35 +01:00
|
|
|
if ((*item)->type() != Item::NULL_ITEM)
|
|
|
|
{
|
|
|
|
*type= (*item)->result_type();
|
2007-01-22 11:52:23 +01:00
|
|
|
unsigned_flag= (*item)->unsigned_flag;
|
2006-03-06 13:38:35 +01:00
|
|
|
item++;
|
|
|
|
break;
|
|
|
|
}
|
2006-04-21 08:48:00 +02:00
|
|
|
}
|
|
|
|
/* Combine result types. Note: NULL items don't affect the result */
|
2006-03-06 13:38:35 +01:00
|
|
|
for (; item < item_end; item++)
|
2006-04-21 08:48:00 +02:00
|
|
|
{
|
2006-03-06 13:38:35 +01:00
|
|
|
if ((*item)->type() != Item::NULL_ITEM)
|
2007-01-22 11:52:23 +01:00
|
|
|
*type= item_store_type(*type, *item, unsigned_flag);
|
2006-04-21 08:48:00 +02:00
|
|
|
}
|
2003-07-18 12:50:40 +02:00
|
|
|
}
|
|
|
|
|
2005-11-07 23:59:52 +01:00
|
|
|
|
2006-05-30 21:05:34 +02:00
|
|
|
/*
|
2007-04-11 20:41:12 +02:00
|
|
|
Compare row signature of two expressions
|
2006-05-30 21:05:34 +02:00
|
|
|
|
2007-04-11 20:41:12 +02:00
|
|
|
SYNOPSIS:
|
|
|
|
cmp_row_type()
|
|
|
|
item1 the first expression
|
|
|
|
item2 the second expression
|
2006-05-30 21:05:34 +02:00
|
|
|
|
|
|
|
DESCRIPTION
|
2007-04-11 20:41:12 +02:00
|
|
|
The function checks that two expressions have compatible row signatures
|
|
|
|
i.e. that the number of columns they return are the same and that if they
|
|
|
|
are both row expressions then each component from the first expression has
|
|
|
|
a row signature compatible with the signature of the corresponding component
|
|
|
|
of the second expression.
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
1 type incompatibility has been detected
|
|
|
|
0 otherwise
|
2006-05-30 21:05:34 +02:00
|
|
|
*/
|
|
|
|
|
2007-04-11 20:41:12 +02:00
|
|
|
static int cmp_row_type(Item* item1, Item* item2)
|
2003-07-18 12:50:40 +02:00
|
|
|
{
|
2007-04-11 20:41:12 +02:00
|
|
|
uint n= item1->cols();
|
|
|
|
if (item2->check_cols(n))
|
|
|
|
return 1;
|
|
|
|
for (uint i=0; i<n; i++)
|
|
|
|
{
|
2007-04-11 21:45:27 +02:00
|
|
|
if (item2->element_index(i)->check_cols(item1->element_index(i)->cols()) ||
|
|
|
|
(item1->element_index(i)->result_type() == ROW_RESULT &&
|
|
|
|
cmp_row_type(item1->element_index(i), item2->element_index(i))))
|
2007-04-11 20:41:12 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2006-09-26 18:52:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2006-05-30 21:05:34 +02:00
|
|
|
Aggregates result types from the array of items.
|
2006-09-26 18:52:54 +02:00
|
|
|
|
2006-05-30 21:05:34 +02:00
|
|
|
SYNOPSIS:
|
|
|
|
agg_cmp_type()
|
|
|
|
type [out] the aggregated type
|
|
|
|
items array of items to aggregate the type from
|
|
|
|
nitems number of items in the array
|
2006-09-26 18:52:54 +02:00
|
|
|
|
|
|
|
DESCRIPTION
|
2006-05-30 21:05:34 +02:00
|
|
|
This function aggregates result types from the array of items. Found type
|
|
|
|
supposed to be used later for comparison of values of these items.
|
|
|
|
Aggregation itself is performed by the item_cmp_type() function.
|
2007-04-11 20:41:12 +02:00
|
|
|
The function also checks compatibility of row signatures for the
|
|
|
|
submitted items (see the spec for the cmp_row_type function).
|
2006-09-26 18:52:54 +02:00
|
|
|
|
2007-04-11 20:41:12 +02:00
|
|
|
RETURN VALUES
|
|
|
|
1 type incompatibility has been detected
|
|
|
|
0 otherwise
|
2006-09-26 18:52:54 +02:00
|
|
|
*/
|
|
|
|
|
2007-04-12 02:10:44 +02:00
|
|
|
static int agg_cmp_type(Item_result *type, Item **items, uint nitems)
|
2006-09-26 18:52:54 +02:00
|
|
|
{
|
|
|
|
uint i;
|
2006-09-07 22:59:34 +02:00
|
|
|
type[0]= items[0]->result_type();
|
|
|
|
for (i= 1 ; i < nitems ; i++)
|
2007-04-11 20:41:12 +02:00
|
|
|
{
|
2006-09-07 22:59:34 +02:00
|
|
|
type[0]= item_cmp_type(type[0], items[i]->result_type());
|
2007-04-11 20:41:12 +02:00
|
|
|
/*
|
|
|
|
When aggregating types of two row expressions we have to check
|
|
|
|
that they have the same cardinality and that each component
|
|
|
|
of the first row expression has a compatible row signature with
|
|
|
|
the signature of the corresponding component of the second row
|
|
|
|
expression.
|
|
|
|
*/
|
|
|
|
if (type[0] == ROW_RESULT && cmp_row_type(items[0], items[i]))
|
|
|
|
return 1; // error found: invalid usage of rows
|
|
|
|
}
|
|
|
|
return 0;
|
2003-07-18 12:50:40 +02:00
|
|
|
}
|
|
|
|
|
2005-11-07 23:59:52 +01:00
|
|
|
|
2007-04-12 02:10:44 +02:00
|
|
|
/*
|
|
|
|
Collects different types for comparison of first item with each other items
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
collect_cmp_types()
|
|
|
|
items Array of items to collect types from
|
|
|
|
nitems Number of items in the array
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
This function collects different result types for comparison of the first
|
|
|
|
item in the list with each of the remaining items in the 'items' array.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 - if row type incompatibility has been detected (see cmp_row_type)
|
|
|
|
Bitmap of collected types - otherwise
|
|
|
|
*/
|
|
|
|
|
|
|
|
static uint collect_cmp_types(Item **items, uint nitems)
|
|
|
|
{
|
|
|
|
uint i;
|
|
|
|
uint found_types;
|
|
|
|
Item_result left_result= items[0]->result_type();
|
|
|
|
DBUG_ASSERT(nitems > 1);
|
|
|
|
found_types= 0;
|
|
|
|
for (i= 1; i < nitems ; i++)
|
|
|
|
{
|
|
|
|
if ((left_result == ROW_RESULT ||
|
|
|
|
items[i]->result_type() == ROW_RESULT) &&
|
|
|
|
cmp_row_type(items[0], items[i]))
|
|
|
|
return 0;
|
|
|
|
found_types|= 1<< (uint)item_cmp_type(left_result,
|
|
|
|
items[i]->result_type());
|
|
|
|
}
|
|
|
|
return found_types;
|
|
|
|
}
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
|
|
|
|
const char *fname)
|
2003-06-24 12:11:07 +02:00
|
|
|
{
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0),
|
|
|
|
c1.collation->name,c1.derivation_name(),
|
|
|
|
c2.collation->name,c2.derivation_name(),
|
|
|
|
fname);
|
2003-06-24 12:11:07 +02:00
|
|
|
}
|
|
|
|
|
2003-11-03 11:28:36 +01:00
|
|
|
|
|
|
|
Item_bool_func2* Eq_creator::create(Item *a, Item *b) const
|
2002-11-07 22:45:19 +01:00
|
|
|
{
|
|
|
|
return new Item_func_eq(a, b);
|
|
|
|
}
|
2003-11-03 11:28:36 +01:00
|
|
|
|
|
|
|
|
|
|
|
Item_bool_func2* Ne_creator::create(Item *a, Item *b) const
|
2002-11-07 22:45:19 +01:00
|
|
|
{
|
|
|
|
return new Item_func_ne(a, b);
|
|
|
|
}
|
2003-11-03 11:28:36 +01:00
|
|
|
|
|
|
|
|
|
|
|
Item_bool_func2* Gt_creator::create(Item *a, Item *b) const
|
2002-11-07 22:45:19 +01:00
|
|
|
{
|
|
|
|
return new Item_func_gt(a, b);
|
|
|
|
}
|
2003-11-03 11:28:36 +01:00
|
|
|
|
|
|
|
|
|
|
|
Item_bool_func2* Lt_creator::create(Item *a, Item *b) const
|
2002-11-07 22:45:19 +01:00
|
|
|
{
|
|
|
|
return new Item_func_lt(a, b);
|
|
|
|
}
|
2003-11-03 11:28:36 +01:00
|
|
|
|
|
|
|
|
|
|
|
Item_bool_func2* Ge_creator::create(Item *a, Item *b) const
|
2002-11-07 22:45:19 +01:00
|
|
|
{
|
|
|
|
return new Item_func_ge(a, b);
|
|
|
|
}
|
2003-11-03 11:28:36 +01:00
|
|
|
|
|
|
|
|
|
|
|
Item_bool_func2* Le_creator::create(Item *a, Item *b) const
|
2002-11-07 22:45:19 +01:00
|
|
|
{
|
|
|
|
return new Item_func_le(a, b);
|
|
|
|
}
|
2002-02-22 12:24:42 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*
|
2002-05-04 10:11:00 +02:00
|
|
|
Test functions
|
2002-11-11 14:57:35 +01:00
|
|
|
Most of these returns 0LL if false and 1LL if true and
|
|
|
|
NULL if some arg is NULL.
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
longlong Item_func_not::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2005-02-08 23:50:45 +01:00
|
|
|
bool value= args[0]->val_bool();
|
2000-07-31 21:29:14 +02:00
|
|
|
null_value=args[0]->null_value;
|
2004-11-18 17:10:07 +01:00
|
|
|
return ((!null_value && value == 0) ? 1 : 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2007-01-18 05:13:45 +01:00
|
|
|
/*
|
|
|
|
We put any NOT expression into parenthesis to avoid
|
|
|
|
possible problems with internal view representations where
|
|
|
|
any '!' is converted to NOT. It may cause a problem if
|
|
|
|
'!' is used in an expression together with other operators
|
|
|
|
whose precedence is lower than the precedence of '!' yet
|
|
|
|
higher than the precedence of NOT.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Item_func_not::print(String *str)
|
|
|
|
{
|
|
|
|
str->append('(');
|
|
|
|
Item_func::print(str);
|
|
|
|
str->append(')');
|
|
|
|
}
|
|
|
|
|
2003-07-24 14:26:21 +02:00
|
|
|
/*
|
|
|
|
special NOT for ALL subquery
|
|
|
|
*/
|
|
|
|
|
|
|
|
longlong Item_func_not_all::val_int()
|
2004-03-18 14:14:36 +01:00
|
|
|
{
|
|
|
|
DBUG_ASSERT(fixed == 1);
|
2005-02-08 23:50:45 +01:00
|
|
|
bool value= args[0]->val_bool();
|
2004-11-18 17:10:07 +01:00
|
|
|
|
|
|
|
/*
|
2005-02-08 23:50:45 +01:00
|
|
|
return TRUE if there was records in underlying select in max/min
|
|
|
|
optimization (ALL subquery)
|
2004-11-18 17:10:07 +01:00
|
|
|
*/
|
|
|
|
if (empty_underlying_subquery())
|
|
|
|
return 1;
|
|
|
|
|
2003-07-24 14:26:21 +02:00
|
|
|
null_value= args[0]->null_value;
|
2004-11-18 17:10:07 +01:00
|
|
|
return ((!null_value && value == 0) ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Item_func_not_all::empty_underlying_subquery()
|
|
|
|
{
|
|
|
|
return ((test_sum_item && !test_sum_item->any_value()) ||
|
|
|
|
(test_sub_item && !test_sub_item->any_value()));
|
2003-07-24 14:26:21 +02:00
|
|
|
}
|
|
|
|
|
2003-10-16 14:54:47 +02:00
|
|
|
void Item_func_not_all::print(String *str)
|
|
|
|
{
|
|
|
|
if (show)
|
|
|
|
Item_func::print(str);
|
|
|
|
else
|
|
|
|
args[0]->print(str);
|
|
|
|
}
|
|
|
|
|
2004-11-18 17:10:07 +01:00
|
|
|
|
|
|
|
/*
|
2004-12-07 20:18:15 +01:00
|
|
|
Special NOP (No OPeration) for ALL subquery it is like Item_func_not_all
|
2005-02-08 23:50:45 +01:00
|
|
|
(return TRUE if underlying subquery do not return rows) but if subquery
|
2004-12-07 20:18:15 +01:00
|
|
|
returns some rows it return same value as argument (TRUE/FALSE).
|
2004-11-18 17:10:07 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
longlong Item_func_nop_all::val_int()
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(fixed == 1);
|
2004-12-30 23:44:00 +01:00
|
|
|
longlong value= args[0]->val_int();
|
2004-11-18 17:10:07 +01:00
|
|
|
|
|
|
|
/*
|
2005-02-08 23:50:45 +01:00
|
|
|
return FALSE if there was records in underlying select in max/min
|
|
|
|
optimization (SAME/ANY subquery)
|
2004-11-18 17:10:07 +01:00
|
|
|
*/
|
|
|
|
if (empty_underlying_subquery())
|
2004-12-13 00:21:14 +01:00
|
|
|
return 0;
|
2004-11-18 17:10:07 +01:00
|
|
|
|
|
|
|
null_value= args[0]->null_value;
|
|
|
|
return (null_value || value == 0) ? 0 : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-08-17 17:02:56 +02:00
|
|
|
/*
|
2006-05-17 22:55:28 +02:00
|
|
|
Convert a constant item to an int and replace the original item
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
convert_constant_item()
|
|
|
|
thd thread handle
|
|
|
|
field item will be converted using the type of this field
|
|
|
|
item [in/out] reference to the item to convert
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
The function converts a constant expression or string to an integer.
|
|
|
|
On successful conversion the original item is substituted for the
|
|
|
|
result of the item evaluation.
|
|
|
|
This is done when comparing DATE/TIME of different formats and
|
|
|
|
also when comparing bigint to strings (in which case strings
|
|
|
|
are converted to bigints).
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
This function is called only at prepare stage.
|
|
|
|
As all derived tables are filled only after all derived tables
|
|
|
|
are prepared we do not evaluate items with subselects here because
|
|
|
|
they can contain derived tables and thus we may attempt to use a
|
|
|
|
table that has not been populated yet.
|
2002-08-30 11:40:40 +02:00
|
|
|
|
|
|
|
RESULT VALUES
|
|
|
|
0 Can't convert item
|
|
|
|
1 Item was replaced with an integer version of the item
|
2002-08-17 17:02:56 +02:00
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-10-08 00:21:19 +02:00
|
|
|
static bool convert_constant_item(THD *thd, Field *field, Item **item)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
int result= 0;
|
2006-06-19 02:26:27 +02:00
|
|
|
|
2006-05-17 22:55:28 +02:00
|
|
|
if (!(*item)->with_subselect && (*item)->const_item())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-06-19 02:26:27 +02:00
|
|
|
TABLE *table= field->table;
|
|
|
|
ulong orig_sql_mode= thd->variables.sql_mode;
|
2007-03-23 21:08:31 +01:00
|
|
|
enum_check_fields orig_count_cuted_fields= thd->count_cuted_fields;
|
2006-06-19 02:26:27 +02:00
|
|
|
my_bitmap_map *old_write_map;
|
|
|
|
my_bitmap_map *old_read_map;
|
|
|
|
|
2006-11-01 18:41:09 +01:00
|
|
|
LINT_INIT(old_write_map);
|
|
|
|
LINT_INIT(old_read_map);
|
|
|
|
|
2006-06-19 02:26:27 +02:00
|
|
|
if (table)
|
|
|
|
{
|
|
|
|
old_write_map= dbug_tmp_use_all_columns(table, table->write_set);
|
|
|
|
old_read_map= dbug_tmp_use_all_columns(table, table->read_set);
|
|
|
|
}
|
2005-11-03 11:53:49 +01:00
|
|
|
/* For comparison purposes allow invalid dates like 2000-01-32 */
|
2006-12-21 10:53:34 +01:00
|
|
|
thd->variables.sql_mode= (orig_sql_mode & ~MODE_NO_ZERO_DATE) |
|
|
|
|
MODE_INVALID_DATES;
|
2007-03-23 21:08:31 +01:00
|
|
|
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
|
2002-12-05 18:38:42 +01:00
|
|
|
if (!(*item)->save_in_field(field, 1) && !((*item)->null_value))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
Item *tmp= new Item_int_with_ref(field->val_int(), *item,
|
|
|
|
test(field->flags & UNSIGNED_FLAG));
|
2002-05-15 00:01:26 +02:00
|
|
|
if (tmp)
|
2004-10-10 01:10:00 +02:00
|
|
|
thd->change_item_tree(item, tmp);
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
result= 1; // Item was replaced
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2006-06-19 02:26:27 +02:00
|
|
|
thd->variables.sql_mode= orig_sql_mode;
|
2007-03-23 21:08:31 +01:00
|
|
|
thd->count_cuted_fields= orig_count_cuted_fields;
|
2006-06-19 02:26:27 +02:00
|
|
|
if (table)
|
|
|
|
{
|
|
|
|
dbug_tmp_restore_column_map(table->write_set, old_write_map);
|
|
|
|
dbug_tmp_restore_column_map(table->read_set, old_read_map);
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
return result;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-05-21 20:39:58 +02:00
|
|
|
|
2003-06-24 14:12:07 +02:00
|
|
|
void Item_bool_func2::fix_length_and_dec()
|
|
|
|
{
|
|
|
|
max_length= 1; // Function returns 0 or 1
|
2006-12-14 23:51:37 +01:00
|
|
|
THD *thd;
|
2003-06-24 14:12:07 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
As some compare functions are generated after sql_yacc,
|
|
|
|
we have to check for out of memory conditions here
|
|
|
|
*/
|
|
|
|
if (!args[0] || !args[1])
|
|
|
|
return;
|
2003-05-23 07:45:46 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
We allow to convert to Unicode character sets in some cases.
|
|
|
|
The conditions when conversion is possible are:
|
|
|
|
- arguments A and B have different charsets
|
|
|
|
- A wins according to coercibility rules
|
|
|
|
- character set of A is superset for character set of B
|
|
|
|
|
|
|
|
If all of the above is true, then it's possible to convert
|
|
|
|
B into the character set of A, and then compare according
|
|
|
|
to the collation of A.
|
|
|
|
*/
|
|
|
|
|
2003-06-24 14:12:07 +02:00
|
|
|
|
2004-10-29 13:00:03 +02:00
|
|
|
DTCollation coll;
|
|
|
|
if (args[0]->result_type() == STRING_RESULT &&
|
|
|
|
args[1]->result_type() == STRING_RESULT &&
|
2006-06-30 09:26:36 +02:00
|
|
|
agg_arg_charsets(coll, args, 2, MY_COLL_CMP_CONV, 1))
|
2004-11-02 13:02:12 +01:00
|
|
|
return;
|
2004-11-04 14:06:24 +01:00
|
|
|
|
2006-08-20 22:23:57 +02:00
|
|
|
args[0]->cmp_context= args[1]->cmp_context=
|
|
|
|
item_cmp_type(args[0]->result_type(), args[1]->result_type());
|
2000-07-31 21:29:14 +02:00
|
|
|
// Make a special case of compare with fields to get nicer DATE comparisons
|
2004-03-11 15:21:57 +01:00
|
|
|
|
|
|
|
if (functype() == LIKE_FUNC) // Disable conversion in case of LIKE function.
|
|
|
|
{
|
|
|
|
set_cmp_func();
|
|
|
|
return;
|
|
|
|
}
|
2005-07-15 23:01:44 +02:00
|
|
|
|
2006-12-14 23:51:37 +01:00
|
|
|
thd= current_thd;
|
2005-07-15 23:01:44 +02:00
|
|
|
if (!thd->is_context_analysis_only())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
Item *arg_real_item= args[0]->real_item();
|
|
|
|
if (arg_real_item->type() == FIELD_ITEM)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
Field *field=((Item_field*) arg_real_item)->field;
|
2007-04-26 22:12:09 +02:00
|
|
|
if (field->can_be_compared_as_longlong() &&
|
|
|
|
!(arg_real_item->is_datetime() &&
|
|
|
|
args[1]->result_type() == STRING_RESULT))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-07-15 23:01:44 +02:00
|
|
|
if (convert_constant_item(thd, field,&args[1]))
|
|
|
|
{
|
|
|
|
cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
|
|
|
|
INT_RESULT); // Works for all types.
|
2006-08-20 22:23:57 +02:00
|
|
|
args[0]->cmp_context= args[1]->cmp_context= INT_RESULT;
|
2005-07-15 23:01:44 +02:00
|
|
|
return;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
2006-12-14 23:51:37 +01:00
|
|
|
arg_real_item= args[1]->real_item();
|
|
|
|
if (arg_real_item->type() == FIELD_ITEM)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
Field *field=((Item_field*) arg_real_item)->field;
|
2007-04-26 22:12:09 +02:00
|
|
|
if (field->can_be_compared_as_longlong() &&
|
|
|
|
!(arg_real_item->is_datetime() &&
|
|
|
|
args[0]->result_type() == STRING_RESULT))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-07-15 23:01:44 +02:00
|
|
|
if (convert_constant_item(thd, field,&args[0]))
|
|
|
|
{
|
|
|
|
cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
|
|
|
|
INT_RESULT); // Works for all types.
|
2006-08-20 22:23:57 +02:00
|
|
|
args[0]->cmp_context= args[1]->cmp_context= INT_RESULT;
|
2005-07-15 23:01:44 +02:00
|
|
|
return;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-11-28 00:00:09 +01:00
|
|
|
set_cmp_func();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-02-12 20:55:37 +01:00
|
|
|
|
2002-11-28 00:00:09 +01:00
|
|
|
int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-11-28 00:00:09 +01:00
|
|
|
owner= item;
|
2004-08-07 23:18:13 +02:00
|
|
|
func= comparator_matrix[type]
|
|
|
|
[test(owner->functype() == Item_func::EQUAL_FUNC)];
|
2005-07-04 02:42:33 +02:00
|
|
|
switch (type) {
|
2005-02-08 23:50:45 +01:00
|
|
|
case ROW_RESULT:
|
2002-11-15 19:32:09 +01:00
|
|
|
{
|
2002-12-04 10:01:48 +01:00
|
|
|
uint n= (*a)->cols();
|
|
|
|
if (n != (*b)->cols())
|
2002-11-28 00:00:09 +01:00
|
|
|
{
|
2003-10-06 21:35:05 +02:00
|
|
|
my_error(ER_OPERAND_COLUMNS, MYF(0), n);
|
2002-11-28 00:00:09 +01:00
|
|
|
comparators= 0;
|
|
|
|
return 1;
|
|
|
|
}
|
2005-02-28 10:59:46 +01:00
|
|
|
if (!(comparators= new Arg_comparator[n]))
|
2003-05-21 20:39:58 +02:00
|
|
|
return 1;
|
|
|
|
for (uint i=0; i < n; i++)
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
if ((*a)->element_index(i)->cols() != (*b)->element_index(i)->cols())
|
2002-12-08 02:19:03 +01:00
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols());
|
2003-05-21 20:39:58 +02:00
|
|
|
return 1;
|
2002-12-08 02:19:03 +01:00
|
|
|
}
|
2003-05-21 20:39:58 +02:00
|
|
|
comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i));
|
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
2002-11-28 00:00:09 +01:00
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
case STRING_RESULT:
|
2003-07-03 14:00:01 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
We must set cmp_charset here as we may be called from for an automatic
|
|
|
|
generated item, like in natural join
|
|
|
|
*/
|
2003-07-29 14:39:39 +02:00
|
|
|
if (cmp_collation.set((*a)->collation, (*b)->collation) ||
|
|
|
|
cmp_collation.derivation == DERIVATION_NONE)
|
2003-07-03 14:00:01 +02:00
|
|
|
{
|
|
|
|
my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name());
|
|
|
|
return 1;
|
|
|
|
}
|
2004-08-19 12:15:10 +02:00
|
|
|
if (cmp_collation.collation == &my_charset_bin)
|
2004-02-16 09:03:25 +01:00
|
|
|
{
|
|
|
|
/*
|
2004-08-19 12:15:10 +02:00
|
|
|
We are using BLOB/BINARY/VARBINARY, change to compare byte by byte,
|
2004-02-16 09:03:25 +01:00
|
|
|
without removing end space
|
|
|
|
*/
|
|
|
|
if (func == &Arg_comparator::compare_string)
|
|
|
|
func= &Arg_comparator::compare_binary_string;
|
|
|
|
else if (func == &Arg_comparator::compare_e_string)
|
|
|
|
func= &Arg_comparator::compare_e_binary_string;
|
2004-11-03 11:39:38 +01:00
|
|
|
|
|
|
|
/*
|
2005-02-08 23:50:45 +01:00
|
|
|
As this is binary compassion, mark all fields that they can't be
|
2004-11-03 11:39:38 +01:00
|
|
|
transformed. Otherwise we would get into trouble with comparisons
|
|
|
|
like:
|
|
|
|
WHERE col= 'j' AND col LIKE BINARY 'j'
|
|
|
|
which would be transformed to:
|
|
|
|
WHERE col= 'j'
|
|
|
|
*/
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
(*a)->walk(&Item::set_no_const_sub, FALSE, (uchar*) 0);
|
|
|
|
(*b)->walk(&Item::set_no_const_sub, FALSE, (uchar*) 0);
|
2004-02-16 09:03:25 +01:00
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
2003-07-03 14:00:01 +02:00
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
case INT_RESULT:
|
2004-08-11 21:08:20 +02:00
|
|
|
{
|
2004-08-18 00:37:31 +02:00
|
|
|
if (func == &Arg_comparator::compare_int_signed)
|
2004-08-11 21:08:20 +02:00
|
|
|
{
|
|
|
|
if ((*a)->unsigned_flag)
|
2005-02-08 23:50:45 +01:00
|
|
|
func= (((*b)->unsigned_flag)?
|
|
|
|
&Arg_comparator::compare_int_unsigned :
|
|
|
|
&Arg_comparator::compare_int_unsigned_signed);
|
2004-08-11 21:08:20 +02:00
|
|
|
else if ((*b)->unsigned_flag)
|
|
|
|
func= &Arg_comparator::compare_int_signed_unsigned;
|
|
|
|
}
|
2004-08-17 00:59:24 +02:00
|
|
|
else if (func== &Arg_comparator::compare_e_int)
|
|
|
|
{
|
|
|
|
if ((*a)->unsigned_flag ^ (*b)->unsigned_flag)
|
|
|
|
func= &Arg_comparator::compare_e_int_diff_signedness;
|
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DECIMAL_RESULT:
|
|
|
|
break;
|
|
|
|
case REAL_RESULT:
|
2007-01-31 06:51:05 +01:00
|
|
|
{
|
|
|
|
if ((*a)->decimals < NOT_FIXED_DEC && (*b)->decimals < NOT_FIXED_DEC)
|
|
|
|
{
|
|
|
|
precision= 5 * log_01[max((*a)->decimals, (*b)->decimals)];
|
|
|
|
if (func == &Arg_comparator::compare_real)
|
|
|
|
func= &Arg_comparator::compare_real_fixed;
|
|
|
|
else if (func == &Arg_comparator::compare_e_real)
|
|
|
|
func= &Arg_comparator::compare_e_real_fixed;
|
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
2007-01-31 08:14:32 +01:00
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
2004-08-11 21:08:20 +02:00
|
|
|
}
|
2002-11-28 00:00:09 +01:00
|
|
|
return 0;
|
2002-11-15 19:32:09 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-05-21 20:39:58 +02:00
|
|
|
|
2007-04-26 22:12:09 +02:00
|
|
|
/*
|
|
|
|
Convert date provided in a string to the int representation.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
get_date_from_str()
|
|
|
|
thd Thread handle
|
|
|
|
str a string to convert
|
|
|
|
warn_type type of the timestamp for issuing the warning
|
|
|
|
warn_name field name for issuing the warning
|
|
|
|
error_arg [out] TRUE if string isn't a DATETIME or clipping occur
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Convert date provided in the string str to the int representation.
|
|
|
|
if the string contains wrong date or doesn't contain it at all
|
|
|
|
then the warning is issued and TRUE returned in the error_arg argument.
|
|
|
|
The warn_type and the warn_name arguments are used as the name and the
|
|
|
|
type of the field when issuing the warning.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
converted value.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static ulonglong
|
|
|
|
get_date_from_str(THD *thd, String *str, timestamp_type warn_type,
|
|
|
|
char *warn_name, bool *error_arg)
|
|
|
|
{
|
2007-04-27 22:04:50 +02:00
|
|
|
ulonglong value= 0;
|
2007-04-26 22:12:09 +02:00
|
|
|
int error;
|
|
|
|
MYSQL_TIME l_time;
|
|
|
|
enum_mysql_timestamp_type ret;
|
|
|
|
*error_arg= TRUE;
|
|
|
|
|
|
|
|
ret= str_to_datetime(str->ptr(), str->length(), &l_time,
|
|
|
|
(TIME_FUZZY_DATE | MODE_INVALID_DATES |
|
|
|
|
(thd->variables.sql_mode &
|
|
|
|
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))),
|
|
|
|
&error);
|
|
|
|
if ((ret == MYSQL_TIMESTAMP_DATETIME || ret == MYSQL_TIMESTAMP_DATE))
|
|
|
|
{
|
|
|
|
value= TIME_to_ulonglong_datetime(&l_time);
|
|
|
|
*error_arg= FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error || *error_arg)
|
|
|
|
{
|
2007-04-29 15:46:06 +02:00
|
|
|
make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
str->ptr(), str->length(),
|
|
|
|
warn_type, warn_name);
|
2007-04-26 22:12:09 +02:00
|
|
|
*error_arg= TRUE;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Check whether compare_datetime() can be used to compare items.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Arg_comparator::can_compare_as_dates()
|
|
|
|
a, b [in] items to be compared
|
|
|
|
const_value [out] converted value of the string constant, if any
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Check several cases when the DATE/DATETIME comparator should be used.
|
|
|
|
The following cases are checked:
|
|
|
|
1. Both a and b is a DATE/DATETIME field/function returning string or
|
|
|
|
int result.
|
|
|
|
2. Only a or b is a DATE/DATETIME field/function returning string or
|
|
|
|
int result and the other item (b or a) is an item with string result.
|
|
|
|
If the second item is a constant one then it's checked to be
|
|
|
|
convertible to the DATE/DATETIME type. If the constant can't be
|
|
|
|
converted to a DATE/DATETIME then the compare_datetime() comparator
|
|
|
|
isn't used and the warning about wrong DATE/DATETIME value is issued.
|
|
|
|
In all other cases (date-[int|real|decimal]/[int|real|decimal]-date)
|
|
|
|
the comparison is handled by other comparators.
|
|
|
|
If the datetime comparator can be used and one the operands of the
|
|
|
|
comparison is a string constant that was successfully converted to a
|
|
|
|
DATE/DATETIME type then the result of the conversion is returned in the
|
|
|
|
const_value if it is provided. If there is no constant or
|
|
|
|
compare_datetime() isn't applicable then the *const_value remains
|
|
|
|
unchanged.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
the found type of date comparison
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum Arg_comparator::enum_date_cmp_type
|
|
|
|
Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value)
|
|
|
|
{
|
|
|
|
enum enum_date_cmp_type cmp_type= CMP_DATE_DFLT;
|
|
|
|
Item *str_arg= 0, *date_arg= 0;
|
|
|
|
|
|
|
|
if (a->type() == Item::ROW_ITEM || b->type() == Item::ROW_ITEM)
|
|
|
|
return CMP_DATE_DFLT;
|
|
|
|
|
|
|
|
if (a->is_datetime())
|
|
|
|
{
|
|
|
|
if (b->is_datetime())
|
|
|
|
cmp_type= CMP_DATE_WITH_DATE;
|
|
|
|
else if (b->result_type() == STRING_RESULT)
|
|
|
|
{
|
|
|
|
cmp_type= CMP_DATE_WITH_STR;
|
|
|
|
date_arg= a;
|
|
|
|
str_arg= b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (b->is_datetime() && a->result_type() == STRING_RESULT)
|
|
|
|
{
|
|
|
|
cmp_type= CMP_STR_WITH_DATE;
|
|
|
|
date_arg= b;
|
|
|
|
str_arg= a;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmp_type != CMP_DATE_DFLT)
|
|
|
|
{
|
2007-05-17 21:09:45 +02:00
|
|
|
/*
|
|
|
|
Do not cache GET_USER_VAR() function as its const_item() may return TRUE
|
|
|
|
for the current thread but it still may change during the execution.
|
|
|
|
*/
|
|
|
|
if (cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() &&
|
|
|
|
(str_arg->type() != Item::FUNC_ITEM ||
|
|
|
|
((Item_func*)str_arg)->functype() != Item_func::GUSERVAR_FUNC))
|
2007-04-26 22:12:09 +02:00
|
|
|
{
|
|
|
|
THD *thd= current_thd;
|
|
|
|
ulonglong value;
|
|
|
|
bool error;
|
|
|
|
String tmp, *str_val= 0;
|
|
|
|
timestamp_type t_type= (date_arg->field_type() == MYSQL_TYPE_DATE ?
|
|
|
|
MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME);
|
|
|
|
|
|
|
|
str_val= str_arg->val_str(&tmp);
|
|
|
|
if (str_arg->null_value)
|
|
|
|
return CMP_DATE_DFLT;
|
|
|
|
value= get_date_from_str(thd, str_val, t_type, date_arg->name, &error);
|
|
|
|
if (error)
|
|
|
|
return CMP_DATE_DFLT;
|
|
|
|
if (const_value)
|
|
|
|
*const_value= value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cmp_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
|
|
|
Item **a1, Item **a2,
|
|
|
|
Item_result type)
|
|
|
|
{
|
|
|
|
enum enum_date_cmp_type cmp_type;
|
2007-05-15 22:30:12 +02:00
|
|
|
ulonglong const_value= (ulonglong)-1;
|
2007-04-26 22:12:09 +02:00
|
|
|
a= a1;
|
|
|
|
b= a2;
|
|
|
|
|
|
|
|
if ((cmp_type= can_compare_as_dates(*a, *b, &const_value)))
|
|
|
|
{
|
|
|
|
thd= current_thd;
|
|
|
|
owner= owner_arg;
|
|
|
|
a_type= (*a)->field_type();
|
|
|
|
b_type= (*b)->field_type();
|
|
|
|
a_cache= 0;
|
|
|
|
b_cache= 0;
|
|
|
|
|
2007-05-15 22:30:12 +02:00
|
|
|
if (const_value != (ulonglong)-1)
|
2007-04-26 22:12:09 +02:00
|
|
|
{
|
|
|
|
Item_cache_int *cache= new Item_cache_int();
|
|
|
|
/* Mark the cache as non-const to prevent re-caching. */
|
|
|
|
cache->set_used_tables(1);
|
|
|
|
if (!(*a)->is_datetime())
|
|
|
|
{
|
|
|
|
cache->store((*a), const_value);
|
|
|
|
a_cache= cache;
|
|
|
|
a= (Item **)&a_cache;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cache->store((*b), const_value);
|
|
|
|
b_cache= cache;
|
|
|
|
b= (Item **)&b_cache;
|
|
|
|
}
|
|
|
|
}
|
2007-04-26 22:40:35 +02:00
|
|
|
is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC);
|
2007-04-26 22:12:09 +02:00
|
|
|
func= &Arg_comparator::compare_datetime;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return set_compare_func(owner_arg, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 22:40:35 +02:00
|
|
|
void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1)
|
|
|
|
{
|
|
|
|
thd= current_thd;
|
|
|
|
/* A caller will handle null values by itself. */
|
|
|
|
owner= NULL;
|
|
|
|
a= a1;
|
|
|
|
b= b1;
|
|
|
|
a_type= (*a)->field_type();
|
|
|
|
b_type= (*b)->field_type();
|
|
|
|
a_cache= 0;
|
|
|
|
b_cache= 0;
|
|
|
|
is_nulls_eq= FALSE;
|
|
|
|
func= &Arg_comparator::compare_datetime;
|
|
|
|
}
|
|
|
|
|
2007-04-26 22:12:09 +02:00
|
|
|
/*
|
|
|
|
Retrieves correct DATETIME value from given item.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
get_datetime_value()
|
|
|
|
thd thread handle
|
|
|
|
item_arg [in/out] item to retrieve DATETIME value from
|
|
|
|
cache_arg [in/out] pointer to place to store the caching item to
|
|
|
|
warn_item [in] item for issuing the conversion warning
|
|
|
|
is_null [out] TRUE <=> the item_arg is null
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Retrieves the correct DATETIME value from given item for comparison by the
|
|
|
|
compare_datetime() function.
|
|
|
|
If item's result can be compared as longlong then its int value is used
|
|
|
|
and its string value is used otherwise. Strings are always parsed and
|
|
|
|
converted to int values by the get_date_from_str() function.
|
|
|
|
This allows us to compare correctly string dates with missed insignificant
|
|
|
|
zeros. If an item is a constant one then its value is cached and it isn't
|
|
|
|
get parsed again. An Item_cache_int object is used for caching values. It
|
|
|
|
seamlessly substitutes the original item. The cache item is marked as
|
|
|
|
non-constant to prevent re-caching it again. In order to compare
|
|
|
|
correctly DATE and DATETIME items the result of the former are treated as
|
|
|
|
a DATETIME with zero time (00:00:00).
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
obtained value
|
|
|
|
*/
|
|
|
|
|
2007-05-04 16:57:10 +02:00
|
|
|
ulonglong
|
2007-04-26 22:12:09 +02:00
|
|
|
get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
|
|
|
|
Item *warn_item, bool *is_null)
|
|
|
|
{
|
2007-04-27 22:04:50 +02:00
|
|
|
ulonglong value= 0;
|
2007-04-26 22:12:09 +02:00
|
|
|
String buf, *str= 0;
|
|
|
|
Item *item= **item_arg;
|
|
|
|
|
|
|
|
if (item->result_as_longlong())
|
|
|
|
{
|
|
|
|
value= item->val_int();
|
|
|
|
*is_null= item->null_value;
|
2007-05-29 22:33:12 +02:00
|
|
|
/*
|
|
|
|
Item_date_add_interval may return MYSQL_TYPE_STRING as the result
|
|
|
|
field type. To detect that the DATE value has been returned we
|
|
|
|
compare it with 1000000L - any DATE value should be less than it.
|
|
|
|
*/
|
|
|
|
if (item->field_type() == MYSQL_TYPE_DATE || value < 100000000L)
|
2007-04-26 22:12:09 +02:00
|
|
|
value*= 1000000L;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
str= item->val_str(&buf);
|
|
|
|
*is_null= item->null_value;
|
|
|
|
}
|
|
|
|
if (*is_null)
|
|
|
|
return -1;
|
|
|
|
/*
|
|
|
|
Convert strings to the integer DATE/DATETIME representation.
|
|
|
|
Even if both dates provided in strings we can't compare them directly as
|
|
|
|
strings as there is no warranty that they are correct and do not miss
|
|
|
|
some insignificant zeros.
|
|
|
|
*/
|
|
|
|
if (str)
|
|
|
|
{
|
|
|
|
bool error;
|
|
|
|
enum_field_types f_type= warn_item->field_type();
|
|
|
|
timestamp_type t_type= f_type ==
|
|
|
|
MYSQL_TYPE_DATE ? MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME;
|
|
|
|
value= get_date_from_str(thd, str, t_type, warn_item->name, &error);
|
|
|
|
}
|
2007-05-17 21:09:45 +02:00
|
|
|
/*
|
|
|
|
Do not cache GET_USER_VAR() function as its const_item() may return TRUE
|
|
|
|
for the current thread but it still may change during the execution.
|
|
|
|
*/
|
|
|
|
if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM ||
|
|
|
|
((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC))
|
2007-04-26 22:12:09 +02:00
|
|
|
{
|
|
|
|
Item_cache_int *cache= new Item_cache_int();
|
|
|
|
/* Mark the cache as non-const to prevent re-caching. */
|
|
|
|
cache->set_used_tables(1);
|
|
|
|
cache->store(item, value);
|
|
|
|
*cache_arg= cache;
|
|
|
|
*item_arg= cache_arg;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Compare items values as dates.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Arg_comparator::compare_datetime()
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Compare items values as DATE/DATETIME for both EQUAL_FUNC and from other
|
|
|
|
comparison functions. The correct DATETIME values are obtained
|
|
|
|
with help of the get_datetime_value() function.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
If is_nulls_eq is TRUE:
|
|
|
|
1 if items are equal or both are null
|
|
|
|
0 otherwise
|
|
|
|
If is_nulls_eq is FALSE:
|
|
|
|
-1 a < b or one of items is null
|
|
|
|
0 a == b
|
|
|
|
1 a > b
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Arg_comparator::compare_datetime()
|
|
|
|
{
|
|
|
|
bool is_null= FALSE;
|
|
|
|
ulonglong a_value, b_value;
|
|
|
|
|
|
|
|
/* Get DATE/DATETIME value of the 'a' item. */
|
|
|
|
a_value= get_datetime_value(thd, &a, &a_cache, *b, &is_null);
|
|
|
|
if (!is_nulls_eq && is_null)
|
|
|
|
{
|
2007-04-26 22:40:35 +02:00
|
|
|
if (owner)
|
|
|
|
owner->null_value= 1;
|
2007-04-26 22:12:09 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get DATE/DATETIME value of the 'b' item. */
|
|
|
|
b_value= get_datetime_value(thd, &b, &b_cache, *a, &is_null);
|
|
|
|
if (is_null)
|
|
|
|
{
|
2007-04-26 22:40:35 +02:00
|
|
|
if (owner)
|
|
|
|
owner->null_value= is_nulls_eq ? 0 : 1;
|
2007-04-26 22:12:09 +02:00
|
|
|
return is_nulls_eq ? 1 : -1;
|
|
|
|
}
|
|
|
|
|
2007-04-26 22:40:35 +02:00
|
|
|
if (owner)
|
|
|
|
owner->null_value= 0;
|
2007-04-26 22:12:09 +02:00
|
|
|
|
|
|
|
/* Compare values. */
|
|
|
|
if (is_nulls_eq)
|
|
|
|
return (a_value == b_value);
|
|
|
|
return a_value < b_value ? -1 : (a_value > b_value ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-28 00:00:09 +01:00
|
|
|
int Arg_comparator::compare_string()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
String *res1,*res2;
|
2002-12-04 10:01:48 +01:00
|
|
|
if ((res1= (*a)->val_str(&owner->tmp_value1)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-12-04 10:01:48 +01:00
|
|
|
if ((res2= (*b)->val_str(&owner->tmp_value2)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-11-15 19:32:09 +01:00
|
|
|
owner->null_value= 0;
|
2003-07-03 14:00:01 +02:00
|
|
|
return sortcmp(res1,res2,cmp_collation.collation);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
2002-11-15 19:32:09 +01:00
|
|
|
owner->null_value= 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-02-16 09:03:25 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Compare strings byte by byte. End spaces are also compared.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
< 0 *a < *b
|
|
|
|
0 *b == *b
|
|
|
|
> 0 *a > *b
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Arg_comparator::compare_binary_string()
|
|
|
|
{
|
|
|
|
String *res1,*res2;
|
|
|
|
if ((res1= (*a)->val_str(&owner->tmp_value1)))
|
|
|
|
{
|
|
|
|
if ((res2= (*b)->val_str(&owner->tmp_value2)))
|
|
|
|
{
|
|
|
|
owner->null_value= 0;
|
|
|
|
uint res1_length= res1->length();
|
|
|
|
uint res2_length= res2->length();
|
|
|
|
int cmp= memcmp(res1->ptr(), res2->ptr(), min(res1_length,res2_length));
|
|
|
|
return cmp ? cmp : (int) (res1_length - res2_length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
owner->null_value= 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Compare strings, but take into account that NULL == NULL
|
|
|
|
*/
|
|
|
|
|
2002-11-28 08:11:35 +01:00
|
|
|
int Arg_comparator::compare_e_string()
|
|
|
|
{
|
|
|
|
String *res1,*res2;
|
2002-12-04 10:01:48 +01:00
|
|
|
res1= (*a)->val_str(&owner->tmp_value1);
|
|
|
|
res2= (*b)->val_str(&owner->tmp_value2);
|
2002-11-28 08:11:35 +01:00
|
|
|
if (!res1 || !res2)
|
|
|
|
return test(res1 == res2);
|
2003-07-03 14:00:01 +02:00
|
|
|
return test(sortcmp(res1, res2, cmp_collation.collation) == 0);
|
2002-11-28 08:11:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-16 09:03:25 +01:00
|
|
|
int Arg_comparator::compare_e_binary_string()
|
|
|
|
{
|
|
|
|
String *res1,*res2;
|
|
|
|
res1= (*a)->val_str(&owner->tmp_value1);
|
|
|
|
res2= (*b)->val_str(&owner->tmp_value2);
|
|
|
|
if (!res1 || !res2)
|
|
|
|
return test(res1 == res2);
|
|
|
|
return test(stringcmp(res1, res2) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-28 00:00:09 +01:00
|
|
|
int Arg_comparator::compare_real()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-03-31 01:44:51 +02:00
|
|
|
/*
|
|
|
|
Fix yet another manifestation of Bug#2338. 'Volatile' will instruct
|
|
|
|
gcc to flush double values out of 80-bit Intel FPU registers before
|
|
|
|
performing the comparison.
|
|
|
|
*/
|
|
|
|
volatile double val1, val2;
|
2005-04-01 10:13:37 +02:00
|
|
|
val1= (*a)->val_real();
|
2002-12-04 10:01:48 +01:00
|
|
|
if (!(*a)->null_value)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-04-01 10:13:37 +02:00
|
|
|
val2= (*b)->val_real();
|
2002-12-04 10:01:48 +01:00
|
|
|
if (!(*b)->null_value)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-11-15 19:32:09 +01:00
|
|
|
owner->null_value= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
if (val1 < val2) return -1;
|
|
|
|
if (val1 == val2) return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2002-11-15 19:32:09 +01:00
|
|
|
owner->null_value= 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
int Arg_comparator::compare_decimal()
|
|
|
|
{
|
|
|
|
my_decimal value1;
|
|
|
|
my_decimal *val1= (*a)->val_decimal(&value1);
|
|
|
|
if (!(*a)->null_value)
|
|
|
|
{
|
|
|
|
my_decimal value2;
|
|
|
|
my_decimal *val2= (*b)->val_decimal(&value2);
|
|
|
|
if (!(*b)->null_value)
|
|
|
|
{
|
|
|
|
owner->null_value= 0;
|
|
|
|
return my_decimal_cmp(val1, val2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
owner->null_value= 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2002-11-28 08:11:35 +01:00
|
|
|
int Arg_comparator::compare_e_real()
|
|
|
|
{
|
2004-11-11 19:39:35 +01:00
|
|
|
double val1= (*a)->val_real();
|
|
|
|
double val2= (*b)->val_real();
|
2002-12-04 10:01:48 +01:00
|
|
|
if ((*a)->null_value || (*b)->null_value)
|
|
|
|
return test((*a)->null_value && (*b)->null_value);
|
2002-11-28 08:11:35 +01:00
|
|
|
return test(val1 == val2);
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
int Arg_comparator::compare_e_decimal()
|
|
|
|
{
|
|
|
|
my_decimal value1, value2;
|
|
|
|
my_decimal *val1= (*a)->val_decimal(&value1);
|
|
|
|
my_decimal *val2= (*b)->val_decimal(&value2);
|
|
|
|
if ((*a)->null_value || (*b)->null_value)
|
|
|
|
return test((*a)->null_value && (*b)->null_value);
|
|
|
|
return test(my_decimal_cmp(val1, val2) == 0);
|
|
|
|
}
|
|
|
|
|
2007-01-31 06:51:05 +01:00
|
|
|
|
|
|
|
int Arg_comparator::compare_real_fixed()
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Fix yet another manifestation of Bug#2338. 'Volatile' will instruct
|
|
|
|
gcc to flush double values out of 80-bit Intel FPU registers before
|
|
|
|
performing the comparison.
|
|
|
|
*/
|
|
|
|
volatile double val1, val2;
|
2007-01-31 08:14:32 +01:00
|
|
|
val1= (*a)->val_real();
|
2007-01-31 06:51:05 +01:00
|
|
|
if (!(*a)->null_value)
|
|
|
|
{
|
2007-01-31 08:14:32 +01:00
|
|
|
val2= (*b)->val_real();
|
2007-01-31 06:51:05 +01:00
|
|
|
if (!(*b)->null_value)
|
|
|
|
{
|
|
|
|
owner->null_value= 0;
|
|
|
|
if (val1 == val2 || fabs(val1 - val2) < precision)
|
|
|
|
return 0;
|
|
|
|
if (val1 < val2)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
owner->null_value= 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Arg_comparator::compare_e_real_fixed()
|
|
|
|
{
|
2007-01-31 08:14:32 +01:00
|
|
|
double val1= (*a)->val_real();
|
|
|
|
double val2= (*b)->val_real();
|
2007-01-31 06:51:05 +01:00
|
|
|
if ((*a)->null_value || (*b)->null_value)
|
|
|
|
return test((*a)->null_value && (*b)->null_value);
|
|
|
|
return test(val1 == val2 || fabs(val1 - val2) < precision);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-18 00:37:31 +02:00
|
|
|
int Arg_comparator::compare_int_signed()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-12-04 10:01:48 +01:00
|
|
|
longlong val1= (*a)->val_int();
|
|
|
|
if (!(*a)->null_value)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-12-04 10:01:48 +01:00
|
|
|
longlong val2= (*b)->val_int();
|
|
|
|
if (!(*b)->null_value)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-11-15 19:32:09 +01:00
|
|
|
owner->null_value= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
if (val1 < val2) return -1;
|
|
|
|
if (val1 == val2) return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2002-11-15 19:32:09 +01:00
|
|
|
owner->null_value= 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-08-11 21:08:20 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Compare values as BIGINT UNSIGNED.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Arg_comparator::compare_int_unsigned()
|
|
|
|
{
|
|
|
|
ulonglong val1= (*a)->val_int();
|
|
|
|
if (!(*a)->null_value)
|
|
|
|
{
|
|
|
|
ulonglong val2= (*b)->val_int();
|
|
|
|
if (!(*b)->null_value)
|
|
|
|
{
|
|
|
|
owner->null_value= 0;
|
|
|
|
if (val1 < val2) return -1;
|
|
|
|
if (val1 == val2) return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
owner->null_value= 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Compare signed (*a) with unsigned (*B)
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Arg_comparator::compare_int_signed_unsigned()
|
|
|
|
{
|
|
|
|
longlong sval1= (*a)->val_int();
|
|
|
|
if (!(*a)->null_value)
|
|
|
|
{
|
|
|
|
ulonglong uval2= (ulonglong)(*b)->val_int();
|
|
|
|
if (!(*b)->null_value)
|
|
|
|
{
|
|
|
|
owner->null_value= 0;
|
2006-09-13 12:41:28 +02:00
|
|
|
if (sval1 < 0 || (ulonglong)sval1 < uval2)
|
|
|
|
return -1;
|
|
|
|
if ((ulonglong)sval1 == uval2)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
2004-08-11 21:08:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
owner->null_value= 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Compare unsigned (*a) with signed (*B)
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Arg_comparator::compare_int_unsigned_signed()
|
|
|
|
{
|
|
|
|
ulonglong uval1= (ulonglong)(*a)->val_int();
|
|
|
|
if (!(*a)->null_value)
|
|
|
|
{
|
|
|
|
longlong sval2= (*b)->val_int();
|
|
|
|
if (!(*b)->null_value)
|
|
|
|
{
|
|
|
|
owner->null_value= 0;
|
2006-09-13 12:41:28 +02:00
|
|
|
if (sval2 < 0)
|
|
|
|
return 1;
|
|
|
|
if (uval1 < (ulonglong)sval2)
|
|
|
|
return -1;
|
|
|
|
if (uval1 == (ulonglong)sval2)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
2004-08-11 21:08:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
owner->null_value= 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-28 08:11:35 +01:00
|
|
|
int Arg_comparator::compare_e_int()
|
|
|
|
{
|
2002-12-04 10:01:48 +01:00
|
|
|
longlong val1= (*a)->val_int();
|
|
|
|
longlong val2= (*b)->val_int();
|
|
|
|
if ((*a)->null_value || (*b)->null_value)
|
|
|
|
return test((*a)->null_value && (*b)->null_value);
|
2002-11-28 08:11:35 +01:00
|
|
|
return test(val1 == val2);
|
|
|
|
}
|
|
|
|
|
2004-08-17 00:59:24 +02:00
|
|
|
/*
|
|
|
|
Compare unsigned *a with signed *b or signed *a with unsigned *b.
|
|
|
|
*/
|
|
|
|
int Arg_comparator::compare_e_int_diff_signedness()
|
|
|
|
{
|
|
|
|
longlong val1= (*a)->val_int();
|
|
|
|
longlong val2= (*b)->val_int();
|
|
|
|
if ((*a)->null_value || (*b)->null_value)
|
|
|
|
return test((*a)->null_value && (*b)->null_value);
|
|
|
|
return (val1 >= 0) && test(val1 == val2);
|
|
|
|
}
|
2002-11-28 08:11:35 +01:00
|
|
|
|
2002-11-28 00:00:09 +01:00
|
|
|
int Arg_comparator::compare_row()
|
2002-11-15 19:32:09 +01:00
|
|
|
{
|
|
|
|
int res= 0;
|
2005-08-18 11:07:14 +02:00
|
|
|
bool was_null= 0;
|
2002-12-19 06:38:33 +01:00
|
|
|
(*a)->bring_value();
|
|
|
|
(*b)->bring_value();
|
2002-12-04 10:01:48 +01:00
|
|
|
uint n= (*a)->cols();
|
2002-11-27 18:16:06 +01:00
|
|
|
for (uint i= 0; i<n; i++)
|
2002-11-15 19:32:09 +01:00
|
|
|
{
|
2005-08-18 11:07:14 +02:00
|
|
|
res= comparators[i].compare();
|
2002-11-15 19:32:09 +01:00
|
|
|
if (owner->null_value)
|
2005-08-18 11:07:14 +02:00
|
|
|
{
|
|
|
|
// NULL was compared
|
2007-04-20 12:14:09 +02:00
|
|
|
switch (owner->functype()) {
|
|
|
|
case Item_func::NE_FUNC:
|
|
|
|
break; // NE never aborts on NULL even if abort_on_null is set
|
|
|
|
case Item_func::LT_FUNC:
|
|
|
|
case Item_func::LE_FUNC:
|
|
|
|
case Item_func::GT_FUNC:
|
|
|
|
case Item_func::GE_FUNC:
|
|
|
|
return -1; // <, <=, > and >= always fail on NULL
|
|
|
|
default: // EQ_FUNC
|
|
|
|
if (owner->abort_on_null)
|
|
|
|
return -1; // We do not need correct NULL returning
|
|
|
|
}
|
2005-08-18 11:07:14 +02:00
|
|
|
was_null= 1;
|
|
|
|
owner->null_value= 0;
|
|
|
|
res= 0; // continue comparison (maybe we will meet explicit difference)
|
|
|
|
}
|
2005-08-22 00:13:37 +02:00
|
|
|
else if (res)
|
2005-08-18 11:07:14 +02:00
|
|
|
return res;
|
2002-11-15 19:32:09 +01:00
|
|
|
}
|
2005-08-18 11:07:14 +02:00
|
|
|
if (was_null)
|
|
|
|
{
|
|
|
|
/*
|
2007-04-20 12:14:09 +02:00
|
|
|
There was NULL(s) in comparison in some parts, but there was no
|
|
|
|
explicit difference in other parts, so we have to return NULL.
|
2005-08-18 11:07:14 +02:00
|
|
|
*/
|
|
|
|
owner->null_value= 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
2002-11-15 19:32:09 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-08-22 00:13:37 +02:00
|
|
|
|
2002-11-28 08:11:35 +01:00
|
|
|
int Arg_comparator::compare_e_row()
|
|
|
|
{
|
2002-12-19 06:38:33 +01:00
|
|
|
(*a)->bring_value();
|
|
|
|
(*b)->bring_value();
|
2002-12-04 10:01:48 +01:00
|
|
|
uint n= (*a)->cols();
|
2002-11-28 08:11:35 +01:00
|
|
|
for (uint i= 0; i<n; i++)
|
|
|
|
{
|
2003-11-20 21:06:25 +01:00
|
|
|
if (!comparators[i].compare())
|
2003-03-10 19:54:18 +01:00
|
|
|
return 0;
|
2002-11-28 08:11:35 +01:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2003-05-14 20:51:33 +02:00
|
|
|
|
Bug#24532 (The return data type of IS TRUE is different from similar
operations)
Before this change, the boolean predicates:
- X IS TRUE,
- X IS NOT TRUE,
- X IS FALSE,
- X IS NOT FALSE
were implemented by expanding the Item tree in the parser, by using a
construct like:
Item_func_if(Item_func_ifnull(X, <value>), <value>, <value>)
Each <value> was a constant integer, either 0 or 1.
A bug in the implementation of the function IF(a, b, c), in
Item_func_if::fix_length_and_dec(), would cause the following :
When the arguments b and c are both unsigned, the result type of the
function was signed, instead of unsigned.
When the result of the if function is signed, space for the sign could be
counted twice (in the max() expression for a signed argument, and in the
total), causing the member max_length to be too high.
An effect of this is that the final type of IF(x, int(1), int(1)) would be
int(2) instead of int(1).
With this fix, the problems found in Item_func_if::fix_length_and_dec()
have been fixed.
While it's semantically correct to represent 'X IS TRUE' with
Item_func_if(Item_func_ifnull(X, <value>), <value>, <value>),
there are however more problems with this construct.
a)
Building the parse tree involves :
- creating 5 Item instances (3 ints, 1 ifnull, 1 if),
- creating each Item calls my_pthread_getspecific_ptr() once in the operator
new(size), and a second time in the Item::Item() constructor, resulting
in a total of 10 calls to get the current thread.
Evaluating the expression involves evaluating up to 4 nodes at runtime.
This representation could be greatly simplified and improved.
b)
Transforming the parse tree internally with if(ifnull(...)) is fine as long
as this transformation is internal to the server implementation.
With views however, the result of the parse tree is later exposed by the
::print() functions, and stored as part of the view definition.
Doing this has long term consequences:
1)
The original semantic 'X IS TRUE' is lost, and replaced by the
if(ifnull(...)) expression. As a result, SHOW CREATE VIEW does not restore
the original code.
2)
Should a future version of MySQL implement the SQL BOOLEAN data type for
example, views created today using 'X IS NULL' can be exported using
mysqldump, and imported again. Such views would be converted correctly and
automatically to use a BOOLEAN column in the future version.
With 'X IS TRUE' and the current implementations, views using these
"boolean" predicates would not be converted during the export/import, and
would use integer columns instead.
The difference traces back to how SHOW CREATE VIEW preserves 'X IS NULL' but
does not preserve the 'X IS TRUE' semantic.
With this fix, internal representation of 'X IS TRUE' booleans predicates
has changed, so that:
- dedicated Item classes are created for each predicate,
- only 1 Item is created to represent 1 predicate
- my_pthread_getspecific_ptr() is invoked 1 time instead of 10
- SHOW CREATE VIEW preserves the original semantic, and prints 'X IS TRUE'.
Note that, because of the fix in Item_func_if, views created before this fix
will:
- correctly use a int(1) type instead of int(2) for boolean predicates,
- incorrectly print the if(ifnull(...), ...) expression in SHOW CREATE VIEW,
since the original semantic (X IS TRUE) has been lost.
- except for the syntax used in SHOW CREATE VIEW, these views will operate
properly, no action is needed.
Views created after this fix will operate correctly, and will preserve the
original code semantic in SHOW CREATE VIEW.
2007-02-12 21:59:29 +01:00
|
|
|
void Item_func_truth::fix_length_and_dec()
|
|
|
|
{
|
|
|
|
maybe_null= 0;
|
|
|
|
null_value= 0;
|
|
|
|
decimals= 0;
|
|
|
|
max_length= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Item_func_truth::print(String *str)
|
|
|
|
{
|
|
|
|
str->append('(');
|
|
|
|
args[0]->print(str);
|
|
|
|
str->append(STRING_WITH_LEN(" is "));
|
|
|
|
if (! affirmative)
|
|
|
|
str->append(STRING_WITH_LEN("not "));
|
|
|
|
if (value)
|
|
|
|
str->append(STRING_WITH_LEN("true"));
|
|
|
|
else
|
|
|
|
str->append(STRING_WITH_LEN("false"));
|
|
|
|
str->append(')');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Item_func_truth::val_bool()
|
|
|
|
{
|
|
|
|
bool val= args[0]->val_bool();
|
|
|
|
if (args[0]->null_value)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
NULL val IS {TRUE, FALSE} --> FALSE
|
|
|
|
NULL val IS NOT {TRUE, FALSE} --> TRUE
|
|
|
|
*/
|
|
|
|
return (! affirmative);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (affirmative)
|
|
|
|
{
|
|
|
|
/* {TRUE, FALSE} val IS {TRUE, FALSE} value */
|
|
|
|
return (val == value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* {TRUE, FALSE} val IS NOT {TRUE, FALSE} value */
|
|
|
|
return (val != value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
longlong Item_func_truth::val_int()
|
|
|
|
{
|
|
|
|
return (val_bool() ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-01 06:05:42 +02:00
|
|
|
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
|
2002-12-19 20:15:09 +01:00
|
|
|
{
|
2005-07-01 06:05:42 +02:00
|
|
|
if (!args[0]->fixed && args[0]->fix_fields(thd, args) ||
|
2004-04-10 00:14:32 +02:00
|
|
|
!cache && !(cache= Item_cache::get_cache(args[0]->result_type())))
|
2003-05-14 20:51:33 +02:00
|
|
|
return 1;
|
2004-04-07 23:16:17 +02:00
|
|
|
|
2003-05-14 20:51:33 +02:00
|
|
|
cache->setup(args[0]);
|
2003-01-26 20:13:37 +01:00
|
|
|
if (cache->cols() == 1)
|
2003-03-11 11:43:30 +01:00
|
|
|
{
|
2003-08-20 16:35:12 +02:00
|
|
|
if ((used_tables_cache= args[0]->used_tables()))
|
2003-05-06 00:38:38 +02:00
|
|
|
cache->set_used_tables(OUTER_REF_TABLE_BIT);
|
2003-03-11 11:43:30 +01:00
|
|
|
else
|
|
|
|
cache->set_used_tables(0);
|
|
|
|
}
|
2003-01-26 20:13:37 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
uint n= cache->cols();
|
|
|
|
for (uint i= 0; i < n; i++)
|
2003-03-11 11:43:30 +01:00
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
if (args[0]->element_index(i)->used_tables())
|
|
|
|
((Item_cache *)cache->element_index(i))->set_used_tables(OUTER_REF_TABLE_BIT);
|
2003-03-11 11:43:30 +01:00
|
|
|
else
|
2006-12-14 23:51:37 +01:00
|
|
|
((Item_cache *)cache->element_index(i))->set_used_tables(0);
|
2003-03-11 11:43:30 +01:00
|
|
|
}
|
2003-08-20 16:35:12 +02:00
|
|
|
used_tables_cache= args[0]->used_tables();
|
2003-01-26 20:13:37 +01:00
|
|
|
}
|
2003-08-20 16:35:12 +02:00
|
|
|
not_null_tables_cache= args[0]->not_null_tables();
|
|
|
|
with_sum_func= args[0]->with_sum_func;
|
2006-12-03 18:49:26 +01:00
|
|
|
if ((const_item_cache= args[0]->const_item()))
|
|
|
|
cache->store(args[0]);
|
2003-08-07 10:16:02 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-01 06:05:42 +02:00
|
|
|
bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
|
2003-08-07 10:16:02 +02:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
DBUG_ASSERT(fixed == 0);
|
2005-07-01 06:05:42 +02:00
|
|
|
if (fix_left(thd, ref))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2003-08-07 10:16:02 +02:00
|
|
|
if (args[0]->maybe_null)
|
|
|
|
maybe_null=1;
|
|
|
|
|
2005-07-01 06:05:42 +02:00
|
|
|
if (!args[1]->fixed && args[1]->fix_fields(thd, args+1))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2002-12-19 20:15:09 +01:00
|
|
|
Item_in_subselect * sub= (Item_in_subselect *)args[1];
|
|
|
|
if (args[0]->cols() != sub->engine->cols())
|
|
|
|
{
|
2003-10-06 21:35:05 +02:00
|
|
|
my_error(ER_OPERAND_COLUMNS, MYF(0), args[0]->cols());
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2002-12-19 20:15:09 +01:00
|
|
|
}
|
2002-12-19 12:35:12 +01:00
|
|
|
if (args[1]->maybe_null)
|
|
|
|
maybe_null=1;
|
|
|
|
with_sum_func= with_sum_func || args[1]->with_sum_func;
|
|
|
|
used_tables_cache|= args[1]->used_tables();
|
2003-08-20 16:35:12 +02:00
|
|
|
not_null_tables_cache|= args[1]->not_null_tables();
|
2002-12-19 12:35:12 +01:00
|
|
|
const_item_cache&= args[1]->const_item();
|
2004-03-17 13:26:26 +01:00
|
|
|
fixed= 1;
|
2004-10-20 03:04:37 +02:00
|
|
|
return FALSE;
|
2002-12-19 12:35:12 +01:00
|
|
|
}
|
|
|
|
|
2004-02-12 02:10:26 +01:00
|
|
|
|
2002-12-06 20:55:53 +01:00
|
|
|
longlong Item_in_optimizer::val_int()
|
|
|
|
{
|
2007-02-23 12:13:55 +01:00
|
|
|
bool tmp;
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2002-12-19 12:35:12 +01:00
|
|
|
cache->store(args[0]);
|
2006-10-31 18:51:09 +01:00
|
|
|
|
2002-12-19 12:35:12 +01:00
|
|
|
if (cache->null_value)
|
2002-12-06 20:55:53 +01:00
|
|
|
{
|
2006-10-31 18:51:09 +01:00
|
|
|
if (((Item_in_subselect*)args[1])->is_top_level_item())
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We're evaluating "NULL IN (SELECT ...)". The result can be NULL or
|
|
|
|
FALSE, and we can return one instead of another. Just return NULL.
|
|
|
|
*/
|
|
|
|
null_value= 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!((Item_in_subselect*)args[1])->is_correlated &&
|
|
|
|
result_for_null_param != UNKNOWN)
|
|
|
|
{
|
|
|
|
/* Use cached value from previous execution */
|
|
|
|
null_value= result_for_null_param;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We're evaluating "NULL IN (SELECT ...)". The result is:
|
|
|
|
FALSE if SELECT produces an empty set, or
|
|
|
|
NULL otherwise.
|
|
|
|
We disable the predicates we've pushed down into subselect, run the
|
|
|
|
subselect and see if it has produced any rows.
|
|
|
|
*/
|
2007-01-12 21:22:41 +01:00
|
|
|
Item_in_subselect *item_subs=(Item_in_subselect*)args[1];
|
|
|
|
if (cache->cols() == 1)
|
|
|
|
{
|
|
|
|
item_subs->set_cond_guard_var(0, FALSE);
|
2007-01-29 00:57:07 +01:00
|
|
|
(void) args[1]->val_bool_result();
|
2007-01-12 21:22:41 +01:00
|
|
|
result_for_null_param= null_value= !item_subs->engine->no_rows();
|
|
|
|
item_subs->set_cond_guard_var(0, TRUE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint i;
|
|
|
|
uint ncols= cache->cols();
|
|
|
|
/*
|
|
|
|
Turn off the predicates that are based on column compares for
|
|
|
|
which the left part is currently NULL
|
|
|
|
*/
|
|
|
|
for (i= 0; i < ncols; i++)
|
|
|
|
{
|
2007-01-29 15:13:18 +01:00
|
|
|
if (cache->element_index(i)->null_value)
|
2007-01-12 21:22:41 +01:00
|
|
|
item_subs->set_cond_guard_var(i, FALSE);
|
|
|
|
}
|
|
|
|
|
2007-01-29 00:57:07 +01:00
|
|
|
(void) args[1]->val_bool_result();
|
2007-01-12 21:22:41 +01:00
|
|
|
result_for_null_param= null_value= !item_subs->engine->no_rows();
|
|
|
|
|
|
|
|
/* Turn all predicates back on */
|
|
|
|
for (i= 0; i < ncols; i++)
|
|
|
|
item_subs->set_cond_guard_var(i, TRUE);
|
|
|
|
}
|
2006-10-31 18:51:09 +01:00
|
|
|
}
|
|
|
|
}
|
2002-12-06 20:55:53 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2007-02-23 12:13:55 +01:00
|
|
|
tmp= args[1]->val_bool_result();
|
2002-12-10 17:10:00 +01:00
|
|
|
null_value= args[1]->null_value;
|
2002-12-06 20:55:53 +01:00
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
2004-02-12 02:10:26 +01:00
|
|
|
|
|
|
|
void Item_in_optimizer::keep_top_level_cache()
|
|
|
|
{
|
|
|
|
cache->keep_array();
|
|
|
|
save_cache= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-08 19:14:13 +01:00
|
|
|
void Item_in_optimizer::cleanup()
|
|
|
|
{
|
|
|
|
DBUG_ENTER("Item_in_optimizer::cleanup");
|
|
|
|
Item_bool_func::cleanup();
|
2004-02-12 02:10:26 +01:00
|
|
|
if (!save_cache)
|
|
|
|
cache= 0;
|
2004-02-08 19:14:13 +01:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
2004-02-12 02:10:26 +01:00
|
|
|
|
2002-12-19 12:35:12 +01:00
|
|
|
bool Item_in_optimizer::is_null()
|
2002-12-06 20:55:53 +01:00
|
|
|
{
|
2002-12-19 12:35:12 +01:00
|
|
|
cache->store(args[0]);
|
|
|
|
return (null_value= (cache->null_value || args[1]->is_null()));
|
2002-12-06 20:55:53 +01:00
|
|
|
}
|
2002-11-28 08:11:35 +01:00
|
|
|
|
2004-02-12 02:10:26 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong Item_func_eq::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2002-12-04 10:01:48 +01:00
|
|
|
int value= cmp.compare();
|
2000-07-31 21:29:14 +02:00
|
|
|
return value == 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2004-02-12 02:10:26 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Same as Item_func_eq, but NULL = NULL */
|
|
|
|
|
2000-12-15 15:12:31 +01:00
|
|
|
void Item_func_equal::fix_length_and_dec()
|
|
|
|
{
|
|
|
|
Item_bool_func2::fix_length_and_dec();
|
|
|
|
maybe_null=null_value=0;
|
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong Item_func_equal::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2002-12-04 10:01:48 +01:00
|
|
|
return cmp.compare();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
longlong Item_func_ne::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2002-12-04 10:01:48 +01:00
|
|
|
int value= cmp.compare();
|
2000-10-17 22:57:26 +02:00
|
|
|
return value != 0 && !null_value ? 1 : 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
longlong Item_func_ge::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2002-12-04 10:01:48 +01:00
|
|
|
int value= cmp.compare();
|
2000-07-31 21:29:14 +02:00
|
|
|
return value >= 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
longlong Item_func_gt::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2002-12-04 10:01:48 +01:00
|
|
|
int value= cmp.compare();
|
2000-07-31 21:29:14 +02:00
|
|
|
return value > 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
longlong Item_func_le::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2002-12-04 10:01:48 +01:00
|
|
|
int value= cmp.compare();
|
2000-07-31 21:29:14 +02:00
|
|
|
return value <= 0 && !null_value ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
longlong Item_func_lt::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2002-12-04 10:01:48 +01:00
|
|
|
int value= cmp.compare();
|
2000-07-31 21:29:14 +02:00
|
|
|
return value < 0 && !null_value ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
longlong Item_func_strcmp::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
String *a=args[0]->val_str(&tmp_value1);
|
|
|
|
String *b=args[1]->val_str(&tmp_value2);
|
|
|
|
if (!a || !b)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
2003-07-03 14:00:01 +02:00
|
|
|
int value= sortcmp(a,b,cmp.cmp_collation.collation);
|
2000-07-31 21:29:14 +02:00
|
|
|
null_value=0;
|
|
|
|
return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-03 23:32:16 +02:00
|
|
|
bool Item_func_opt_neg::eq(const Item *item, bool binary_cmp) const
|
|
|
|
{
|
|
|
|
/* Assume we don't have rtti */
|
|
|
|
if (this == item)
|
|
|
|
return 1;
|
|
|
|
if (item->type() != FUNC_ITEM)
|
|
|
|
return 0;
|
|
|
|
Item_func *item_func=(Item_func*) item;
|
|
|
|
if (arg_count != item_func->arg_count ||
|
|
|
|
functype() != item_func->functype())
|
|
|
|
return 0;
|
|
|
|
if (negated != ((Item_func_opt_neg *) item_func)->negated)
|
|
|
|
return 0;
|
|
|
|
for (uint i=0; i < arg_count ; i++)
|
|
|
|
if (!args[i]->eq(item_func->arguments()[i], binary_cmp))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void Item_func_interval::fix_length_and_dec()
|
|
|
|
{
|
2007-01-29 15:13:18 +01:00
|
|
|
use_decimal_comparison= ((row->element_index(0)->result_type() ==
|
|
|
|
DECIMAL_RESULT) ||
|
|
|
|
(row->element_index(0)->result_type() ==
|
|
|
|
INT_RESULT));
|
2003-01-26 20:01:45 +01:00
|
|
|
if (row->cols() > 8)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-01-26 20:01:45 +01:00
|
|
|
bool consts=1;
|
|
|
|
|
|
|
|
for (uint i=1 ; consts && i < row->cols() ; i++)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
consts&= row->element_index(i)->const_item();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2003-01-26 20:01:45 +01:00
|
|
|
|
|
|
|
if (consts &&
|
2005-02-08 23:50:45 +01:00
|
|
|
(intervals=
|
|
|
|
(interval_range*) sql_alloc(sizeof(interval_range)*(row->cols()-1))))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
if (use_decimal_comparison)
|
|
|
|
{
|
|
|
|
for (uint i=1 ; i < row->cols(); i++)
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
Item *el= row->element_index(i);
|
2005-02-08 23:50:45 +01:00
|
|
|
interval_range *range= intervals + (i-1);
|
|
|
|
if ((el->result_type() == DECIMAL_RESULT) ||
|
|
|
|
(el->result_type() == INT_RESULT))
|
|
|
|
{
|
|
|
|
range->type= DECIMAL_RESULT;
|
|
|
|
range->dec.init();
|
|
|
|
my_decimal *dec= el->val_decimal(&range->dec);
|
|
|
|
if (dec != &range->dec)
|
|
|
|
{
|
|
|
|
range->dec= *dec;
|
|
|
|
range->dec.fix_buffer_pointer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
range->type= REAL_RESULT;
|
|
|
|
range->dbl= el->val_real();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (uint i=1 ; i < row->cols(); i++)
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
intervals[i-1].dbl= row->element_index(i)->val_real();
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
2002-12-10 17:10:00 +01:00
|
|
|
maybe_null= 0;
|
|
|
|
max_length= 2;
|
2003-02-07 14:47:24 +01:00
|
|
|
used_tables_cache|= row->used_tables();
|
2004-11-28 18:19:01 +01:00
|
|
|
not_null_tables_cache= row->not_null_tables();
|
2003-02-07 14:47:24 +01:00
|
|
|
with_sum_func= with_sum_func || row->with_sum_func;
|
2003-08-29 12:44:35 +02:00
|
|
|
const_item_cache&= row->const_item();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-02-04 20:52:14 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*
|
2005-02-15 18:25:42 +01:00
|
|
|
Execute Item_func_interval()
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Item_func_interval::val_int()
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
If we are doing a decimal comparison, we are
|
|
|
|
evaluating the first item twice.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
-1 if null value,
|
|
|
|
0 if lower than lowest
|
|
|
|
1 - arg_count-1 if between args[n] and args[n+1]
|
|
|
|
arg_count if higher than biggest argument
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
longlong Item_func_interval::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2005-02-16 08:19:47 +01:00
|
|
|
double value;
|
2005-02-08 23:50:45 +01:00
|
|
|
my_decimal dec_buf, *dec= NULL;
|
2005-02-15 18:25:42 +01:00
|
|
|
uint i;
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
if (use_decimal_comparison)
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
dec= row->element_index(0)->val_decimal(&dec_buf);
|
|
|
|
if (row->element_index(0)->null_value)
|
2005-02-16 08:19:47 +01:00
|
|
|
return -1;
|
|
|
|
my_decimal2double(E_DEC_FATAL_ERROR, dec, &value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
value= row->element_index(0)->val_real();
|
|
|
|
if (row->element_index(0)->null_value)
|
2005-02-16 08:19:47 +01:00
|
|
|
return -1;
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
2003-08-11 21:44:43 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
if (intervals)
|
|
|
|
{ // Use binary search to find interval
|
|
|
|
uint start,end;
|
2003-12-13 16:20:35 +01:00
|
|
|
start= 0;
|
2003-08-11 21:44:43 +02:00
|
|
|
end= row->cols()-2;
|
2000-07-31 21:29:14 +02:00
|
|
|
while (start != end)
|
|
|
|
{
|
2003-07-10 12:27:02 +02:00
|
|
|
uint mid= (start + end + 1) / 2;
|
2005-02-08 23:50:45 +01:00
|
|
|
interval_range *range= intervals + mid;
|
|
|
|
my_bool cmp_result;
|
2005-02-15 18:25:42 +01:00
|
|
|
/*
|
|
|
|
The values in the range intervall may have different types,
|
|
|
|
Only do a decimal comparision of the first argument is a decimal
|
|
|
|
and we are comparing against a decimal
|
|
|
|
*/
|
2005-02-08 23:50:45 +01:00
|
|
|
if (dec && range->type == DECIMAL_RESULT)
|
|
|
|
cmp_result= my_decimal_cmp(&range->dec, dec) <= 0;
|
|
|
|
else
|
|
|
|
cmp_result= (range->dbl <= value);
|
|
|
|
if (cmp_result)
|
2003-07-10 12:27:02 +02:00
|
|
|
start= mid;
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
2003-07-10 12:27:02 +02:00
|
|
|
end= mid - 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
interval_range *range= intervals+start;
|
|
|
|
return ((dec && range->type == DECIMAL_RESULT) ?
|
2005-02-15 18:25:42 +01:00
|
|
|
my_decimal_cmp(dec, &range->dec) < 0 :
|
2005-02-08 23:50:45 +01:00
|
|
|
value < range->dbl) ? 0 : start + 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2003-01-26 20:01:45 +01:00
|
|
|
|
|
|
|
for (i=1 ; i < row->cols() ; i++)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
Item *el= row->element_index(i);
|
2005-02-08 23:50:45 +01:00
|
|
|
if (use_decimal_comparison &&
|
|
|
|
((el->result_type() == DECIMAL_RESULT) ||
|
|
|
|
(el->result_type() == INT_RESULT)))
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
my_decimal e_dec_buf, *e_dec= row->element_index(i)->val_decimal(&e_dec_buf);
|
2005-02-08 23:50:45 +01:00
|
|
|
if (my_decimal_cmp(e_dec, dec) > 0)
|
|
|
|
return i-1;
|
|
|
|
}
|
2006-12-14 23:51:37 +01:00
|
|
|
else if (row->element_index(i)->val_real() > value)
|
2005-02-15 18:25:42 +01:00
|
|
|
return i-1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2003-01-26 20:01:45 +01:00
|
|
|
return i-1;
|
2002-11-13 23:26:18 +01:00
|
|
|
}
|
|
|
|
|
2005-02-15 18:25:42 +01:00
|
|
|
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
/*
|
|
|
|
Perform context analysis of a BETWEEN item tree
|
|
|
|
|
|
|
|
SYNOPSIS:
|
|
|
|
fix_fields()
|
|
|
|
thd reference to the global context of the query thread
|
|
|
|
tables list of all open tables involved in the query
|
|
|
|
ref pointer to Item* variable where pointer to resulting "fixed"
|
|
|
|
item is to be assigned
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
This function performs context analysis (name resolution) and calculates
|
|
|
|
various attributes of the item tree with Item_func_between as its root.
|
|
|
|
The function saves in ref the pointer to the item or to a newly created
|
|
|
|
item that is considered as a replacement for the original one.
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on
|
|
|
|
a predicate/function level. Then it's easy to show that:
|
|
|
|
T0(e BETWEEN e1 AND e2) = union(T1(e),T1(e1),T1(e2))
|
|
|
|
T1(e BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2)))
|
|
|
|
T0(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2)))
|
|
|
|
T1(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2)))
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 ok
|
|
|
|
1 got error
|
|
|
|
*/
|
|
|
|
|
2005-09-13 00:44:50 +02:00
|
|
|
bool Item_func_between::fix_fields(THD *thd, Item **ref)
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
{
|
2005-09-07 15:42:47 +02:00
|
|
|
if (Item_func_opt_neg::fix_fields(thd, ref))
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
return 1;
|
|
|
|
|
2006-10-16 23:25:28 +02:00
|
|
|
thd->lex->current_select->between_count++;
|
|
|
|
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
/* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */
|
|
|
|
if (pred_level && !negated)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* not_null_tables_cache == union(T1(e), intersection(T1(e1),T1(e2))) */
|
2005-09-12 17:48:17 +02:00
|
|
|
not_null_tables_cache= (args[0]->not_null_tables() |
|
|
|
|
(args[1]->not_null_tables() &
|
|
|
|
args[2]->not_null_tables()));
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void Item_func_between::fix_length_and_dec()
|
|
|
|
{
|
2007-04-26 22:40:35 +02:00
|
|
|
max_length= 1;
|
|
|
|
int i;
|
|
|
|
bool datetime_found= FALSE;
|
|
|
|
compare_as_dates= TRUE;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2002-05-04 10:11:00 +02:00
|
|
|
/*
|
|
|
|
As some compare functions are generated after sql_yacc,
|
2005-02-08 23:50:45 +01:00
|
|
|
we have to check for out of memory conditions here
|
2002-05-04 10:11:00 +02:00
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!args[0] || !args[1] || !args[2])
|
|
|
|
return;
|
2007-04-12 00:12:49 +02:00
|
|
|
if ( agg_cmp_type(&cmp_type, args, 3))
|
2007-04-11 20:41:12 +02:00
|
|
|
return;
|
2006-09-12 17:06:26 +02:00
|
|
|
if (cmp_type == STRING_RESULT &&
|
2006-09-15 14:14:38 +02:00
|
|
|
agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1))
|
2006-09-12 17:06:26 +02:00
|
|
|
return;
|
2005-11-07 23:59:52 +01:00
|
|
|
|
2006-09-12 17:06:26 +02:00
|
|
|
/*
|
2007-04-26 22:40:35 +02:00
|
|
|
Detect the comparison of DATE/DATETIME items.
|
|
|
|
At least one of items should be a DATE/DATETIME item and other items
|
|
|
|
should return the STRING result.
|
2006-09-12 17:06:26 +02:00
|
|
|
*/
|
2007-04-26 22:40:35 +02:00
|
|
|
for (i= 0; i < 3; i++)
|
2006-09-12 17:06:26 +02:00
|
|
|
{
|
2007-04-26 22:40:35 +02:00
|
|
|
if (args[i]->is_datetime())
|
2006-09-12 17:06:26 +02:00
|
|
|
{
|
2007-04-26 22:40:35 +02:00
|
|
|
datetime_found= TRUE;
|
|
|
|
continue;
|
2006-09-12 17:06:26 +02:00
|
|
|
}
|
2007-04-26 22:40:35 +02:00
|
|
|
if (args[i]->result_type() == STRING_RESULT)
|
|
|
|
continue;
|
|
|
|
compare_as_dates= FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!datetime_found)
|
|
|
|
compare_as_dates= FALSE;
|
|
|
|
|
|
|
|
if (compare_as_dates)
|
|
|
|
{
|
|
|
|
ge_cmp.set_datetime_cmp_func(args, args + 1);
|
|
|
|
le_cmp.set_datetime_cmp_func(args, args + 2);
|
2006-09-12 17:06:26 +02:00
|
|
|
}
|
2007-06-05 22:25:06 +02:00
|
|
|
else if (args[0]->real_item()->type() == FIELD_ITEM &&
|
|
|
|
thd->lex->sql_command != SQLCOM_CREATE_VIEW &&
|
|
|
|
thd->lex->sql_command != SQLCOM_SHOW_CREATE)
|
|
|
|
{
|
|
|
|
Field *field=((Item_field*) (args[0]->real_item()))->field;
|
|
|
|
if (field->can_be_compared_as_longlong())
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The following can't be recoded with || as convert_constant_item
|
|
|
|
changes the argument
|
|
|
|
*/
|
|
|
|
if (convert_constant_item(thd, field,&args[1]))
|
|
|
|
cmp_type=INT_RESULT; // Works for all types.
|
|
|
|
if (convert_constant_item(thd, field,&args[2]))
|
|
|
|
cmp_type=INT_RESULT; // Works for all types.
|
|
|
|
}
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
longlong Item_func_between::val_int()
|
|
|
|
{ // ANSI BETWEEN
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2007-04-26 22:40:35 +02:00
|
|
|
if (compare_as_dates)
|
|
|
|
{
|
|
|
|
int ge_res, le_res;
|
|
|
|
|
|
|
|
ge_res= ge_cmp.compare();
|
|
|
|
if ((null_value= args[0]->null_value))
|
|
|
|
return 0;
|
|
|
|
le_res= le_cmp.compare();
|
|
|
|
|
|
|
|
if (!args[1]->null_value && !args[2]->null_value)
|
|
|
|
return (longlong) ((ge_res >= 0 && le_res <=0) != negated);
|
|
|
|
else if (args[1]->null_value)
|
|
|
|
{
|
|
|
|
null_value= le_res > 0; // not null if false range.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
null_value= ge_res < 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (cmp_type == STRING_RESULT)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
String *value,*a,*b;
|
|
|
|
value=args[0]->val_str(&value0);
|
|
|
|
if ((null_value=args[0]->null_value))
|
|
|
|
return 0;
|
|
|
|
a=args[1]->val_str(&value1);
|
|
|
|
b=args[2]->val_str(&value2);
|
|
|
|
if (!args[1]->null_value && !args[2]->null_value)
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 &&
|
|
|
|
sortcmp(value,b,cmp_collation.collation) <= 0) !=
|
|
|
|
negated);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (args[1]->null_value && args[2]->null_value)
|
|
|
|
null_value=1;
|
|
|
|
else if (args[1]->null_value)
|
|
|
|
{
|
2004-03-30 01:32:41 +02:00
|
|
|
// Set to not null if false range.
|
|
|
|
null_value= sortcmp(value,b,cmp_collation.collation) <= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-03-30 01:32:41 +02:00
|
|
|
// Set to not null if false range.
|
|
|
|
null_value= sortcmp(value,a,cmp_collation.collation) >= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (cmp_type == INT_RESULT)
|
|
|
|
{
|
2004-11-11 19:39:35 +01:00
|
|
|
longlong value=args[0]->val_int(), a, b;
|
2000-07-31 21:29:14 +02:00
|
|
|
if ((null_value=args[0]->null_value))
|
2002-05-04 10:11:00 +02:00
|
|
|
return 0; /* purecov: inspected */
|
2000-07-31 21:29:14 +02:00
|
|
|
a=args[1]->val_int();
|
|
|
|
b=args[2]->val_int();
|
|
|
|
if (!args[1]->null_value && !args[2]->null_value)
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
return (longlong) ((value >= a && value <= b) != negated);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (args[1]->null_value && args[2]->null_value)
|
|
|
|
null_value=1;
|
|
|
|
else if (args[1]->null_value)
|
|
|
|
{
|
|
|
|
null_value= value <= b; // not null if false range.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
null_value= value >= a;
|
|
|
|
}
|
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
else if (cmp_type == DECIMAL_RESULT)
|
|
|
|
{
|
|
|
|
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))
|
|
|
|
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)
|
2005-09-07 15:42:47 +02:00
|
|
|
return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 &&
|
|
|
|
my_decimal_cmp(dec, b_dec) <= 0) != negated);
|
2005-02-08 23:50:45 +01:00
|
|
|
if (args[1]->null_value && args[2]->null_value)
|
|
|
|
null_value=1;
|
|
|
|
else if (args[1]->null_value)
|
|
|
|
null_value= (my_decimal_cmp(dec, b_dec) <= 0);
|
|
|
|
else
|
|
|
|
null_value= (my_decimal_cmp(dec, a_dec) >= 0);
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
|
|
|
{
|
2004-11-11 19:39:35 +01:00
|
|
|
double value= args[0]->val_real(),a,b;
|
2000-07-31 21:29:14 +02:00
|
|
|
if ((null_value=args[0]->null_value))
|
2002-05-04 10:11:00 +02:00
|
|
|
return 0; /* purecov: inspected */
|
2004-11-11 19:39:35 +01:00
|
|
|
a= args[1]->val_real();
|
|
|
|
b= args[2]->val_real();
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!args[1]->null_value && !args[2]->null_value)
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
return (longlong) ((value >= a && value <= b) != negated);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (args[1]->null_value && args[2]->null_value)
|
|
|
|
null_value=1;
|
|
|
|
else if (args[1]->null_value)
|
|
|
|
{
|
|
|
|
null_value= value <= b; // not null if false range.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
null_value= value >= a;
|
|
|
|
}
|
|
|
|
}
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
return (longlong) (!null_value && negated);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-10-12 16:56:05 +02:00
|
|
|
|
|
|
|
void Item_func_between::print(String *str)
|
|
|
|
{
|
|
|
|
str->append('(');
|
|
|
|
args[0]->print(str);
|
2005-09-09 17:06:15 +02:00
|
|
|
if (negated)
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN(" not"));
|
|
|
|
str->append(STRING_WITH_LEN(" between "));
|
2003-10-12 16:56:05 +02:00
|
|
|
args[1]->print(str);
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN(" and "));
|
2003-10-12 16:56:05 +02:00
|
|
|
args[2]->print(str);
|
|
|
|
str->append(')');
|
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void
|
|
|
|
Item_func_ifnull::fix_length_and_dec()
|
|
|
|
{
|
2005-06-08 17:35:37 +02:00
|
|
|
agg_result_type(&hybrid_type, args, 2);
|
2000-07-31 21:29:14 +02:00
|
|
|
maybe_null=args[1]->maybe_null;
|
2005-02-08 23:50:45 +01:00
|
|
|
decimals= max(args[0]->decimals, args[1]->decimals);
|
2005-06-08 17:35:37 +02:00
|
|
|
max_length= (hybrid_type == DECIMAL_RESULT || hybrid_type == INT_RESULT) ?
|
|
|
|
(max(args[0]->max_length - args[0]->decimals,
|
|
|
|
args[1]->max_length - args[1]->decimals) + decimals) :
|
|
|
|
max(args[0]->max_length, args[1]->max_length);
|
|
|
|
|
2005-06-02 16:27:02 +02:00
|
|
|
switch (hybrid_type) {
|
2005-02-08 23:50:45 +01:00
|
|
|
case STRING_RESULT:
|
2006-06-30 09:26:36 +02:00
|
|
|
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1);
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
|
|
|
case DECIMAL_RESULT:
|
|
|
|
case REAL_RESULT:
|
|
|
|
break;
|
|
|
|
case INT_RESULT:
|
2003-07-18 12:50:40 +02:00
|
|
|
decimals= 0;
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
|
|
|
case ROW_RESULT:
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
}
|
2003-08-28 01:11:54 +02:00
|
|
|
cached_field_type= args[0]->field_type();
|
|
|
|
if (cached_field_type != args[1]->field_type())
|
|
|
|
cached_field_type= Item_func::field_type();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2005-05-05 17:06:49 +02:00
|
|
|
|
|
|
|
uint Item_func_ifnull::decimal_precision() const
|
|
|
|
{
|
|
|
|
int max_int_part=max(args[0]->decimal_int_part(),args[1]->decimal_int_part());
|
|
|
|
return min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-28 01:11:54 +02:00
|
|
|
enum_field_types Item_func_ifnull::field_type() const
|
|
|
|
{
|
|
|
|
return cached_field_type;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-08-28 01:11:54 +02:00
|
|
|
Field *Item_func_ifnull::tmp_table_field(TABLE *table)
|
|
|
|
{
|
2005-11-23 21:45:02 +01:00
|
|
|
return tmp_table_field_from_field_type(table, 0);
|
2003-08-28 01:11:54 +02:00
|
|
|
}
|
2002-12-03 12:08:25 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
double
|
2005-06-02 16:27:02 +02:00
|
|
|
Item_func_ifnull::real_op()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2004-11-11 19:39:35 +01:00
|
|
|
double value= args[0]->val_real();
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!args[0]->null_value)
|
|
|
|
{
|
|
|
|
null_value=0;
|
|
|
|
return value;
|
|
|
|
}
|
2004-11-11 19:39:35 +01:00
|
|
|
value= args[1]->val_real();
|
2000-07-31 21:29:14 +02:00
|
|
|
if ((null_value=args[1]->null_value))
|
|
|
|
return 0.0;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
longlong
|
2005-06-02 16:27:02 +02:00
|
|
|
Item_func_ifnull::int_op()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong value=args[0]->val_int();
|
|
|
|
if (!args[0]->null_value)
|
|
|
|
{
|
|
|
|
null_value=0;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
value=args[1]->val_int();
|
|
|
|
if ((null_value=args[1]->null_value))
|
|
|
|
return 0;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
|
2005-06-02 16:27:02 +02:00
|
|
|
my_decimal *Item_func_ifnull::decimal_op(my_decimal *decimal_value)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
|
|
|
DBUG_ASSERT(fixed == 1);
|
|
|
|
my_decimal *value= args[0]->val_decimal(decimal_value);
|
|
|
|
if (!args[0]->null_value)
|
|
|
|
{
|
|
|
|
null_value= 0;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
value= args[1]->val_decimal(decimal_value);
|
|
|
|
if ((null_value= args[1]->null_value))
|
|
|
|
return 0;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
String *
|
2005-06-02 16:27:02 +02:00
|
|
|
Item_func_ifnull::str_op(String *str)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
String *res =args[0]->val_str(str);
|
|
|
|
if (!args[0]->null_value)
|
|
|
|
{
|
|
|
|
null_value=0;
|
2003-08-05 09:52:37 +02:00
|
|
|
res->set_charset(collation.collation);
|
2000-07-31 21:29:14 +02:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
res=args[1]->val_str(str);
|
|
|
|
if ((null_value=args[1]->null_value))
|
|
|
|
return 0;
|
2003-08-05 09:52:37 +02:00
|
|
|
res->set_charset(collation.collation);
|
2000-07-31 21:29:14 +02:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2002-08-12 02:33:46 +02:00
|
|
|
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
/*
|
|
|
|
Perform context analysis of an IF item tree
|
|
|
|
|
|
|
|
SYNOPSIS:
|
|
|
|
fix_fields()
|
|
|
|
thd reference to the global context of the query thread
|
|
|
|
tables list of all open tables involved in the query
|
|
|
|
ref pointer to Item* variable where pointer to resulting "fixed"
|
|
|
|
item is to be assigned
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
This function performs context analysis (name resolution) and calculates
|
|
|
|
various attributes of the item tree with Item_func_if as its root.
|
|
|
|
The function saves in ref the pointer to the item or to a newly created
|
|
|
|
item that is considered as a replacement for the original one.
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on
|
|
|
|
a predicate/function level. Then it's easy to show that:
|
|
|
|
T0(IF(e,e1,e2) = T1(IF(e,e1,e2))
|
|
|
|
T1(IF(e,e1,e2)) = intersection(T1(e1),T1(e2))
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 ok
|
|
|
|
1 got error
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool
|
2005-09-07 15:42:47 +02:00
|
|
|
Item_func_if::fix_fields(THD *thd, Item **ref)
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
{
|
|
|
|
DBUG_ASSERT(fixed == 0);
|
|
|
|
args[0]->top_level_item();
|
|
|
|
|
2005-09-07 15:42:47 +02:00
|
|
|
if (Item_func::fix_fields(thd, ref))
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
return 1;
|
|
|
|
|
2005-09-12 17:48:17 +02:00
|
|
|
not_null_tables_cache= (args[1]->not_null_tables() &
|
|
|
|
args[2]->not_null_tables());
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void
|
|
|
|
Item_func_if::fix_length_and_dec()
|
|
|
|
{
|
|
|
|
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
|
2005-02-08 23:50:45 +01:00
|
|
|
decimals= max(args[1]->decimals, args[2]->decimals);
|
Bug#24532 (The return data type of IS TRUE is different from similar
operations)
Before this change, the boolean predicates:
- X IS TRUE,
- X IS NOT TRUE,
- X IS FALSE,
- X IS NOT FALSE
were implemented by expanding the Item tree in the parser, by using a
construct like:
Item_func_if(Item_func_ifnull(X, <value>), <value>, <value>)
Each <value> was a constant integer, either 0 or 1.
A bug in the implementation of the function IF(a, b, c), in
Item_func_if::fix_length_and_dec(), would cause the following :
When the arguments b and c are both unsigned, the result type of the
function was signed, instead of unsigned.
When the result of the if function is signed, space for the sign could be
counted twice (in the max() expression for a signed argument, and in the
total), causing the member max_length to be too high.
An effect of this is that the final type of IF(x, int(1), int(1)) would be
int(2) instead of int(1).
With this fix, the problems found in Item_func_if::fix_length_and_dec()
have been fixed.
While it's semantically correct to represent 'X IS TRUE' with
Item_func_if(Item_func_ifnull(X, <value>), <value>, <value>),
there are however more problems with this construct.
a)
Building the parse tree involves :
- creating 5 Item instances (3 ints, 1 ifnull, 1 if),
- creating each Item calls my_pthread_getspecific_ptr() once in the operator
new(size), and a second time in the Item::Item() constructor, resulting
in a total of 10 calls to get the current thread.
Evaluating the expression involves evaluating up to 4 nodes at runtime.
This representation could be greatly simplified and improved.
b)
Transforming the parse tree internally with if(ifnull(...)) is fine as long
as this transformation is internal to the server implementation.
With views however, the result of the parse tree is later exposed by the
::print() functions, and stored as part of the view definition.
Doing this has long term consequences:
1)
The original semantic 'X IS TRUE' is lost, and replaced by the
if(ifnull(...)) expression. As a result, SHOW CREATE VIEW does not restore
the original code.
2)
Should a future version of MySQL implement the SQL BOOLEAN data type for
example, views created today using 'X IS NULL' can be exported using
mysqldump, and imported again. Such views would be converted correctly and
automatically to use a BOOLEAN column in the future version.
With 'X IS TRUE' and the current implementations, views using these
"boolean" predicates would not be converted during the export/import, and
would use integer columns instead.
The difference traces back to how SHOW CREATE VIEW preserves 'X IS NULL' but
does not preserve the 'X IS TRUE' semantic.
With this fix, internal representation of 'X IS TRUE' booleans predicates
has changed, so that:
- dedicated Item classes are created for each predicate,
- only 1 Item is created to represent 1 predicate
- my_pthread_getspecific_ptr() is invoked 1 time instead of 10
- SHOW CREATE VIEW preserves the original semantic, and prints 'X IS TRUE'.
Note that, because of the fix in Item_func_if, views created before this fix
will:
- correctly use a int(1) type instead of int(2) for boolean predicates,
- incorrectly print the if(ifnull(...), ...) expression in SHOW CREATE VIEW,
since the original semantic (X IS TRUE) has been lost.
- except for the syntax used in SHOW CREATE VIEW, these views will operate
properly, no action is needed.
Views created after this fix will operate correctly, and will preserve the
original code semantic in SHOW CREATE VIEW.
2007-02-12 21:59:29 +01:00
|
|
|
unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag;
|
2005-06-08 17:35:37 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
enum Item_result arg1_type=args[1]->result_type();
|
|
|
|
enum Item_result arg2_type=args[2]->result_type();
|
2004-06-07 12:38:35 +02:00
|
|
|
bool null1=args[1]->const_item() && args[1]->null_value;
|
|
|
|
bool null2=args[2]->const_item() && args[2]->null_value;
|
2002-08-12 02:33:46 +02:00
|
|
|
|
|
|
|
if (null1)
|
|
|
|
{
|
|
|
|
cached_result_type= arg2_type;
|
2003-08-05 09:52:37 +02:00
|
|
|
collation.set(args[2]->collation.collation);
|
2002-08-12 02:33:46 +02:00
|
|
|
}
|
|
|
|
else if (null2)
|
|
|
|
{
|
2002-08-12 03:04:43 +02:00
|
|
|
cached_result_type= arg1_type;
|
2003-08-05 09:52:37 +02:00
|
|
|
collation.set(args[1]->collation.collation);
|
2002-08-12 02:33:46 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
2002-08-12 02:33:46 +02:00
|
|
|
{
|
2003-07-18 12:50:40 +02:00
|
|
|
agg_result_type(&cached_result_type, args+1, 2);
|
|
|
|
if (cached_result_type == STRING_RESULT)
|
|
|
|
{
|
2006-06-30 09:26:36 +02:00
|
|
|
if (agg_arg_charsets(collation, args+1, 2, MY_COLL_ALLOW_CONV, 1))
|
2004-11-04 14:06:24 +01:00
|
|
|
return;
|
2003-07-18 12:50:40 +02:00
|
|
|
}
|
2002-08-12 02:33:46 +02:00
|
|
|
else
|
2003-07-18 12:50:40 +02:00
|
|
|
{
|
2003-08-05 09:52:37 +02:00
|
|
|
collation.set(&my_charset_bin); // Number
|
2003-07-18 12:50:40 +02:00
|
|
|
}
|
2002-08-12 02:33:46 +02:00
|
|
|
}
|
Bug#24532 (The return data type of IS TRUE is different from similar
operations)
Before this change, the boolean predicates:
- X IS TRUE,
- X IS NOT TRUE,
- X IS FALSE,
- X IS NOT FALSE
were implemented by expanding the Item tree in the parser, by using a
construct like:
Item_func_if(Item_func_ifnull(X, <value>), <value>, <value>)
Each <value> was a constant integer, either 0 or 1.
A bug in the implementation of the function IF(a, b, c), in
Item_func_if::fix_length_and_dec(), would cause the following :
When the arguments b and c are both unsigned, the result type of the
function was signed, instead of unsigned.
When the result of the if function is signed, space for the sign could be
counted twice (in the max() expression for a signed argument, and in the
total), causing the member max_length to be too high.
An effect of this is that the final type of IF(x, int(1), int(1)) would be
int(2) instead of int(1).
With this fix, the problems found in Item_func_if::fix_length_and_dec()
have been fixed.
While it's semantically correct to represent 'X IS TRUE' with
Item_func_if(Item_func_ifnull(X, <value>), <value>, <value>),
there are however more problems with this construct.
a)
Building the parse tree involves :
- creating 5 Item instances (3 ints, 1 ifnull, 1 if),
- creating each Item calls my_pthread_getspecific_ptr() once in the operator
new(size), and a second time in the Item::Item() constructor, resulting
in a total of 10 calls to get the current thread.
Evaluating the expression involves evaluating up to 4 nodes at runtime.
This representation could be greatly simplified and improved.
b)
Transforming the parse tree internally with if(ifnull(...)) is fine as long
as this transformation is internal to the server implementation.
With views however, the result of the parse tree is later exposed by the
::print() functions, and stored as part of the view definition.
Doing this has long term consequences:
1)
The original semantic 'X IS TRUE' is lost, and replaced by the
if(ifnull(...)) expression. As a result, SHOW CREATE VIEW does not restore
the original code.
2)
Should a future version of MySQL implement the SQL BOOLEAN data type for
example, views created today using 'X IS NULL' can be exported using
mysqldump, and imported again. Such views would be converted correctly and
automatically to use a BOOLEAN column in the future version.
With 'X IS TRUE' and the current implementations, views using these
"boolean" predicates would not be converted during the export/import, and
would use integer columns instead.
The difference traces back to how SHOW CREATE VIEW preserves 'X IS NULL' but
does not preserve the 'X IS TRUE' semantic.
With this fix, internal representation of 'X IS TRUE' booleans predicates
has changed, so that:
- dedicated Item classes are created for each predicate,
- only 1 Item is created to represent 1 predicate
- my_pthread_getspecific_ptr() is invoked 1 time instead of 10
- SHOW CREATE VIEW preserves the original semantic, and prints 'X IS TRUE'.
Note that, because of the fix in Item_func_if, views created before this fix
will:
- correctly use a int(1) type instead of int(2) for boolean predicates,
- incorrectly print the if(ifnull(...), ...) expression in SHOW CREATE VIEW,
since the original semantic (X IS TRUE) has been lost.
- except for the syntax used in SHOW CREATE VIEW, these views will operate
properly, no action is needed.
Views created after this fix will operate correctly, and will preserve the
original code semantic in SHOW CREATE VIEW.
2007-02-12 21:59:29 +01:00
|
|
|
|
|
|
|
if ((cached_result_type == DECIMAL_RESULT )
|
|
|
|
|| (cached_result_type == INT_RESULT))
|
|
|
|
{
|
|
|
|
int len1= args[1]->max_length - args[1]->decimals
|
|
|
|
- (args[1]->unsigned_flag ? 0 : 1);
|
|
|
|
|
|
|
|
int len2= args[2]->max_length - args[2]->decimals
|
|
|
|
- (args[2]->unsigned_flag ? 0 : 1);
|
|
|
|
|
|
|
|
max_length=max(len1, len2) + decimals + (unsigned_flag ? 0 : 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
max_length= max(args[1]->max_length, args[2]->max_length);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-05-05 17:06:49 +02:00
|
|
|
uint Item_func_if::decimal_precision() const
|
|
|
|
{
|
|
|
|
int precision=(max(args[1]->decimal_int_part(),args[2]->decimal_int_part())+
|
|
|
|
decimals);
|
|
|
|
return min(precision, DECIMAL_MAX_PRECISION);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
double
|
2004-11-11 19:39:35 +01:00
|
|
|
Item_func_if::val_real()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2005-02-08 23:50:45 +01:00
|
|
|
Item *arg= args[0]->val_bool() ? args[1] : args[2];
|
2004-11-11 19:39:35 +01:00
|
|
|
double value= arg->val_real();
|
2000-07-31 21:29:14 +02:00
|
|
|
null_value=arg->null_value;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
longlong
|
|
|
|
Item_func_if::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2005-02-08 23:50:45 +01:00
|
|
|
Item *arg= args[0]->val_bool() ? args[1] : args[2];
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong value=arg->val_int();
|
|
|
|
null_value=arg->null_value;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
String *
|
|
|
|
Item_func_if::val_str(String *str)
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2005-02-08 23:50:45 +01:00
|
|
|
Item *arg= args[0]->val_bool() ? args[1] : args[2];
|
2000-07-31 21:29:14 +02:00
|
|
|
String *res=arg->val_str(str);
|
2003-03-28 15:57:03 +01:00
|
|
|
if (res)
|
2003-08-05 09:52:37 +02:00
|
|
|
res->set_charset(collation.collation);
|
2000-07-31 21:29:14 +02:00
|
|
|
null_value=arg->null_value;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
my_decimal *
|
|
|
|
Item_func_if::val_decimal(my_decimal *decimal_value)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(fixed == 1);
|
|
|
|
Item *arg= args[0]->val_bool() ? args[1] : args[2];
|
|
|
|
my_decimal *value= arg->val_decimal(decimal_value);
|
|
|
|
null_value= arg->null_value;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void
|
|
|
|
Item_func_nullif::fix_length_and_dec()
|
|
|
|
{
|
|
|
|
Item_bool_func2::fix_length_and_dec();
|
|
|
|
maybe_null=1;
|
|
|
|
if (args[0]) // Only false if EOM
|
|
|
|
{
|
|
|
|
max_length=args[0]->max_length;
|
|
|
|
decimals=args[0]->decimals;
|
2005-05-05 17:06:49 +02:00
|
|
|
unsigned_flag= args[0]->unsigned_flag;
|
|
|
|
cached_result_type= args[0]->result_type();
|
2005-01-18 14:41:06 +01:00
|
|
|
if (cached_result_type == STRING_RESULT &&
|
2006-06-30 09:26:36 +02:00
|
|
|
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1))
|
2005-01-18 14:41:06 +01:00
|
|
|
return;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*
|
2003-10-30 11:57:26 +01:00
|
|
|
nullif () returns NULL if arguments are equal, else it returns the
|
2000-07-31 21:29:14 +02:00
|
|
|
first argument.
|
|
|
|
Note that we have to evaluate the first argument twice as the compare
|
|
|
|
may have been done with a different type than return value
|
|
|
|
*/
|
|
|
|
|
|
|
|
double
|
2004-11-11 19:39:35 +01:00
|
|
|
Item_func_nullif::val_real()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
double value;
|
2004-03-17 09:36:12 +01:00
|
|
|
if (!cmp.compare())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0.0;
|
|
|
|
}
|
2004-11-11 19:39:35 +01:00
|
|
|
value= args[0]->val_real();
|
2000-07-31 21:29:14 +02:00
|
|
|
null_value=args[0]->null_value;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
longlong
|
|
|
|
Item_func_nullif::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong value;
|
2004-03-17 09:36:12 +01:00
|
|
|
if (!cmp.compare())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
value=args[0]->val_int();
|
|
|
|
null_value=args[0]->null_value;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
String *
|
|
|
|
Item_func_nullif::val_str(String *str)
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
String *res;
|
2004-03-17 09:36:12 +01:00
|
|
|
if (!cmp.compare())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
res=args[0]->val_str(str);
|
|
|
|
null_value=args[0]->null_value;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2004-09-18 11:06:44 +02:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
my_decimal *
|
|
|
|
Item_func_nullif::val_decimal(my_decimal * decimal_value)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(fixed == 1);
|
|
|
|
my_decimal *res;
|
|
|
|
if (!cmp.compare())
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
res= args[0]->val_decimal(decimal_value);
|
|
|
|
null_value= args[0]->null_value;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-09-18 11:06:44 +02:00
|
|
|
bool
|
|
|
|
Item_func_nullif::is_null()
|
|
|
|
{
|
2005-06-13 20:24:26 +02:00
|
|
|
return (null_value= (!cmp.compare() ? 1 : args[0]->null_value));
|
2004-09-18 11:06:44 +02:00
|
|
|
}
|
|
|
|
|
2006-09-26 18:52:54 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*
|
2002-05-04 10:11:00 +02:00
|
|
|
Return the matching ITEM or NULL if all compares (including else) failed
|
2006-09-26 18:52:54 +02:00
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
find_item()
|
|
|
|
str Buffer string
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Find and return matching items for CASE or ELSE item if all compares
|
|
|
|
are failed or NULL if ELSE item isn't defined.
|
|
|
|
|
|
|
|
IMPLEMENTATION
|
|
|
|
In order to do correct comparisons of the CASE expression (the expression
|
|
|
|
between CASE and the first WHEN) with each WHEN expression several
|
|
|
|
comparators are used. One for each result type. CASE expression can be
|
|
|
|
evaluated up to # of different result types are used. To check whether
|
|
|
|
the CASE expression already was evaluated for a particular result type
|
|
|
|
a bit mapped variable value_added_map is used. Result types are mapped
|
|
|
|
to it according to their int values i.e. STRING_RESULT is mapped to bit
|
|
|
|
0, REAL_RESULT to bit 1, so on.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
NULL - Nothing found and there is no ELSE expression defined
|
|
|
|
item - Found item or ELSE item if defined and all comparisons are
|
|
|
|
failed
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
Item *Item_func_case::find_item(String *str)
|
|
|
|
{
|
2006-09-26 18:52:54 +02:00
|
|
|
uint value_added_map= 0;
|
2005-02-08 23:50:45 +01:00
|
|
|
|
2006-09-26 18:52:54 +02:00
|
|
|
if (first_expr_num == -1)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-09-26 18:52:54 +02:00
|
|
|
for (uint i=0 ; i < ncases ; i+=2)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-07-18 10:11:47 +02:00
|
|
|
// No expression between CASE and the first WHEN
|
2005-02-08 23:50:45 +01:00
|
|
|
if (args[i]->val_bool())
|
2000-07-31 21:29:14 +02:00
|
|
|
return args[i+1];
|
|
|
|
continue;
|
|
|
|
}
|
2006-09-26 18:52:54 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Compare every WHEN argument with it and return the first match */
|
|
|
|
for (uint i=0 ; i < ncases ; i+=2)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
2006-09-26 18:52:54 +02:00
|
|
|
cmp_type= item_cmp_type(left_result_type, args[i]->result_type());
|
|
|
|
DBUG_ASSERT(cmp_type != ROW_RESULT);
|
|
|
|
DBUG_ASSERT(cmp_items[(uint)cmp_type]);
|
|
|
|
if (!(value_added_map & (1<<(uint)cmp_type)))
|
|
|
|
{
|
|
|
|
cmp_items[(uint)cmp_type]->store_value(args[first_expr_num]);
|
|
|
|
if ((null_value=args[first_expr_num]->null_value))
|
|
|
|
return else_expr_num != -1 ? args[else_expr_num] : 0;
|
|
|
|
value_added_map|= 1<<(uint)cmp_type;
|
|
|
|
}
|
|
|
|
if (!cmp_items[(uint)cmp_type]->cmp(args[i]) && !args[i]->null_value)
|
|
|
|
return args[i + 1];
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// No, WHEN clauses all missed, return ELSE expression
|
2003-07-17 13:07:56 +02:00
|
|
|
return else_expr_num != -1 ? args[else_expr_num] : 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String *Item_func_case::val_str(String *str)
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
String *res;
|
|
|
|
Item *item=find_item(str);
|
|
|
|
|
|
|
|
if (!item)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
2002-12-21 09:45:06 +01:00
|
|
|
null_value= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!(res=item->val_str(str)))
|
2002-12-21 09:45:06 +01:00
|
|
|
null_value= 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
longlong Item_func_case::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
char buff[MAX_FIELD_WIDTH];
|
2003-03-03 07:53:08 +01:00
|
|
|
String dummy_str(buff,sizeof(buff),default_charset());
|
2000-07-31 21:29:14 +02:00
|
|
|
Item *item=find_item(&dummy_str);
|
|
|
|
longlong res;
|
|
|
|
|
|
|
|
if (!item)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
res=item->val_int();
|
|
|
|
null_value=item->null_value;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2004-11-11 19:39:35 +01:00
|
|
|
double Item_func_case::val_real()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
char buff[MAX_FIELD_WIDTH];
|
2003-03-03 07:53:08 +01:00
|
|
|
String dummy_str(buff,sizeof(buff),default_charset());
|
2000-07-31 21:29:14 +02:00
|
|
|
Item *item=find_item(&dummy_str);
|
|
|
|
double res;
|
|
|
|
|
|
|
|
if (!item)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
2004-11-11 19:39:35 +01:00
|
|
|
res= item->val_real();
|
2000-07-31 21:29:14 +02:00
|
|
|
null_value=item->null_value;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
|
|
|
|
my_decimal *Item_func_case::val_decimal(my_decimal *decimal_value)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(fixed == 1);
|
|
|
|
char buff[MAX_FIELD_WIDTH];
|
|
|
|
String dummy_str(buff, sizeof(buff), default_charset());
|
|
|
|
Item *item= find_item(&dummy_str);
|
|
|
|
my_decimal *res;
|
|
|
|
|
|
|
|
if (!item)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
res= item->val_decimal(decimal_value);
|
|
|
|
null_value= item->null_value;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-04 15:01:04 +02:00
|
|
|
bool Item_func_case::fix_fields(THD *thd, Item **ref)
|
2005-07-04 02:42:33 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
buff should match stack usage from
|
|
|
|
Item_func_case::val_int() -> Item_func_case::find_item()
|
|
|
|
*/
|
2006-12-14 23:51:37 +01:00
|
|
|
#ifndef EMBEDDED_LIBRARY
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2];
|
2006-12-14 23:51:37 +01:00
|
|
|
#endif
|
2005-07-04 15:01:04 +02:00
|
|
|
bool res= Item_func::fix_fields(thd, ref);
|
|
|
|
/*
|
|
|
|
Call check_stack_overrun after fix_fields to be sure that stack variable
|
|
|
|
is not optimized away
|
|
|
|
*/
|
2005-07-04 02:42:33 +02:00
|
|
|
if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
|
|
|
|
return TRUE; // Fatal error flag is set!
|
2005-07-04 15:01:04 +02:00
|
|
|
return res;
|
2005-07-04 02:42:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void Item_func_case::fix_length_and_dec()
|
2001-01-31 03:47:25 +01:00
|
|
|
{
|
2003-07-17 19:58:05 +02:00
|
|
|
Item **agg;
|
|
|
|
uint nagg;
|
2006-09-26 18:52:54 +02:00
|
|
|
uint found_types= 0;
|
2003-07-17 19:58:05 +02:00
|
|
|
if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1))))
|
|
|
|
return;
|
|
|
|
|
2004-11-04 14:06:24 +01:00
|
|
|
/*
|
|
|
|
Aggregate all THEN and ELSE expression types
|
|
|
|
and collations when string result
|
|
|
|
*/
|
2003-07-17 19:58:05 +02:00
|
|
|
|
|
|
|
for (nagg= 0 ; nagg < ncases/2 ; nagg++)
|
|
|
|
agg[nagg]= args[nagg*2+1];
|
|
|
|
|
|
|
|
if (else_expr_num != -1)
|
|
|
|
agg[nagg++]= args[else_expr_num];
|
|
|
|
|
|
|
|
agg_result_type(&cached_result_type, agg, nagg);
|
|
|
|
if ((cached_result_type == STRING_RESULT) &&
|
2006-06-30 09:26:36 +02:00
|
|
|
agg_arg_charsets(collation, agg, nagg, MY_COLL_ALLOW_CONV, 1))
|
2003-07-17 19:58:05 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
2003-11-20 21:06:25 +01:00
|
|
|
/*
|
|
|
|
Aggregate first expression and all THEN expression types
|
|
|
|
and collations when string comparison
|
|
|
|
*/
|
2003-07-17 13:07:56 +02:00
|
|
|
if (first_expr_num != -1)
|
2001-01-31 03:47:25 +01:00
|
|
|
{
|
2006-09-26 18:52:54 +02:00
|
|
|
uint i;
|
2003-07-17 19:58:05 +02:00
|
|
|
agg[0]= args[first_expr_num];
|
2006-09-26 18:52:54 +02:00
|
|
|
left_result_type= agg[0]->result_type();
|
|
|
|
|
2003-07-17 19:58:05 +02:00
|
|
|
for (nagg= 0; nagg < ncases/2 ; nagg++)
|
2003-07-18 09:42:35 +02:00
|
|
|
agg[nagg+1]= args[nagg*2];
|
2003-07-17 19:58:05 +02:00
|
|
|
nagg++;
|
2007-04-12 02:10:44 +02:00
|
|
|
if (!(found_types= collect_cmp_types(agg, nagg)))
|
|
|
|
return;
|
2007-04-12 00:12:49 +02:00
|
|
|
|
|
|
|
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
|
|
|
|
{
|
|
|
|
if (found_types & (1 << i) && !cmp_items[i])
|
|
|
|
{
|
|
|
|
DBUG_ASSERT((Item_result)i != ROW_RESULT);
|
|
|
|
if ((Item_result)i == STRING_RESULT &&
|
|
|
|
agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1))
|
|
|
|
return;
|
|
|
|
if (!(cmp_items[i]=
|
|
|
|
cmp_item::get_comparator((Item_result)i,
|
|
|
|
cmp_collation.collation)))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2001-01-31 03:47:25 +01:00
|
|
|
}
|
2006-09-26 18:52:54 +02:00
|
|
|
|
2003-11-20 21:06:25 +01:00
|
|
|
if (else_expr_num == -1 || args[else_expr_num]->maybe_null)
|
2003-07-17 13:07:56 +02:00
|
|
|
maybe_null=1;
|
2003-07-17 19:58:05 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
max_length=0;
|
|
|
|
decimals=0;
|
2003-07-17 13:07:56 +02:00
|
|
|
for (uint i=0 ; i < ncases ; i+=2)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
set_if_bigger(max_length,args[i+1]->max_length);
|
|
|
|
set_if_bigger(decimals,args[i+1]->decimals);
|
|
|
|
}
|
2003-07-17 13:07:56 +02:00
|
|
|
if (else_expr_num != -1)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-07-17 13:07:56 +02:00
|
|
|
set_if_bigger(max_length,args[else_expr_num]->max_length);
|
|
|
|
set_if_bigger(decimals,args[else_expr_num]->decimals);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-20 21:06:25 +01:00
|
|
|
|
2005-05-05 17:06:49 +02:00
|
|
|
uint Item_func_case::decimal_precision() const
|
|
|
|
{
|
|
|
|
int max_int_part=0;
|
|
|
|
for (uint i=0 ; i < ncases ; i+=2)
|
|
|
|
set_if_bigger(max_int_part, args[i+1]->decimal_int_part());
|
|
|
|
|
|
|
|
if (else_expr_num != -1)
|
|
|
|
set_if_bigger(max_int_part, args[else_expr_num]->decimal_int_part());
|
|
|
|
return min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-01-31 03:47:25 +01:00
|
|
|
/* TODO: Fix this so that it prints the whole CASE expression */
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
void Item_func_case::print(String *str)
|
|
|
|
{
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN("(case "));
|
2003-10-12 16:56:05 +02:00
|
|
|
if (first_expr_num != -1)
|
|
|
|
{
|
|
|
|
args[first_expr_num]->print(str);
|
|
|
|
str->append(' ');
|
|
|
|
}
|
|
|
|
for (uint i=0 ; i < ncases ; i+=2)
|
|
|
|
{
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN("when "));
|
2003-10-12 16:56:05 +02:00
|
|
|
args[i]->print(str);
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN(" then "));
|
2003-10-12 16:56:05 +02:00
|
|
|
args[i+1]->print(str);
|
|
|
|
str->append(' ');
|
|
|
|
}
|
|
|
|
if (else_expr_num != -1)
|
|
|
|
{
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN("else "));
|
2003-10-12 16:56:05 +02:00
|
|
|
args[else_expr_num]->print(str);
|
|
|
|
str->append(' ');
|
|
|
|
}
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN("end)"));
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-05-04 10:11:00 +02:00
|
|
|
Coalesce - return first not NULL argument.
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
|
|
|
|
2005-06-02 16:27:02 +02:00
|
|
|
String *Item_func_coalesce::str_op(String *str)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
null_value=0;
|
|
|
|
for (uint i=0 ; i < arg_count ; i++)
|
|
|
|
{
|
2002-04-02 16:54:57 +02:00
|
|
|
String *res;
|
|
|
|
if ((res=args[i]->val_str(str)))
|
|
|
|
return res;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-06-02 16:27:02 +02:00
|
|
|
longlong Item_func_coalesce::int_op()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
null_value=0;
|
|
|
|
for (uint i=0 ; i < arg_count ; i++)
|
|
|
|
{
|
|
|
|
longlong res=args[i]->val_int();
|
|
|
|
if (!args[i]->null_value)
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-06-02 16:27:02 +02:00
|
|
|
double Item_func_coalesce::real_op()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
null_value=0;
|
|
|
|
for (uint i=0 ; i < arg_count ; i++)
|
|
|
|
{
|
2004-11-11 19:39:35 +01:00
|
|
|
double res= args[i]->val_real();
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!args[i]->null_value)
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-06-02 16:27:02 +02:00
|
|
|
my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
|
|
|
DBUG_ASSERT(fixed == 1);
|
|
|
|
null_value= 0;
|
|
|
|
for (uint i= 0; i < arg_count; i++)
|
|
|
|
{
|
|
|
|
my_decimal *res= args[i]->val_decimal(decimal_value);
|
|
|
|
if (!args[i]->null_value)
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void Item_func_coalesce::fix_length_and_dec()
|
|
|
|
{
|
2005-06-02 16:27:02 +02:00
|
|
|
agg_result_type(&hybrid_type, args, arg_count);
|
|
|
|
switch (hybrid_type) {
|
2005-02-08 23:50:45 +01:00
|
|
|
case STRING_RESULT:
|
|
|
|
count_only_length();
|
|
|
|
decimals= NOT_FIXED_DEC;
|
2006-06-30 09:26:36 +02:00
|
|
|
agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV, 1);
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
|
|
|
case DECIMAL_RESULT:
|
|
|
|
count_decimal_length();
|
|
|
|
break;
|
|
|
|
case REAL_RESULT:
|
|
|
|
count_real_length();
|
|
|
|
break;
|
|
|
|
case INT_RESULT:
|
|
|
|
count_only_length();
|
2003-07-14 16:28:36 +02:00
|
|
|
decimals= 0;
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
|
|
|
case ROW_RESULT:
|
2005-03-17 16:58:23 +01:00
|
|
|
default:
|
2005-02-08 23:50:45 +01:00
|
|
|
DBUG_ASSERT(0);
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2002-05-04 10:11:00 +02:00
|
|
|
Classes and function for the IN operator
|
2000-07-31 21:29:14 +02:00
|
|
|
****************************************************************************/
|
|
|
|
|
2007-03-02 15:25:56 +01:00
|
|
|
/*
|
|
|
|
Determine which of the signed longlong arguments is bigger
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
cmp_longs()
|
|
|
|
a_val left argument
|
|
|
|
b_val right argument
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
This function will compare two signed longlong arguments
|
|
|
|
and will return -1, 0, or 1 if left argument is smaller than,
|
|
|
|
equal to or greater than the right argument.
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
-1 left argument is smaller than the right argument.
|
|
|
|
0 left argument is equal to the right argument.
|
|
|
|
1 left argument is greater than the right argument.
|
|
|
|
*/
|
|
|
|
static inline int cmp_longs (longlong a_val, longlong b_val)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2007-03-02 15:25:56 +01:00
|
|
|
return a_val < b_val ? -1 : a_val == b_val ? 0 : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Determine which of the unsigned longlong arguments is bigger
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
cmp_ulongs()
|
|
|
|
a_val left argument
|
|
|
|
b_val right argument
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
This function will compare two unsigned longlong arguments
|
|
|
|
and will return -1, 0, or 1 if left argument is smaller than,
|
|
|
|
equal to or greater than the right argument.
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
-1 left argument is smaller than the right argument.
|
|
|
|
0 left argument is equal to the right argument.
|
|
|
|
1 left argument is greater than the right argument.
|
|
|
|
*/
|
|
|
|
static inline int cmp_ulongs (ulonglong a_val, ulonglong b_val)
|
|
|
|
{
|
|
|
|
return a_val < b_val ? -1 : a_val == b_val ? 0 : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Compare two integers in IN value list format (packed_longlong)
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
cmp_longlong()
|
|
|
|
cmp_arg an argument passed to the calling function (qsort2)
|
|
|
|
a left argument
|
|
|
|
b right argument
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
This function will compare two integer arguments in the IN value list
|
|
|
|
format and will return -1, 0, or 1 if left argument is smaller than,
|
|
|
|
equal to or greater than the right argument.
|
|
|
|
It's used in sorting the IN values list and finding an element in it.
|
|
|
|
Depending on the signedness of the arguments cmp_longlong() will
|
|
|
|
compare them as either signed (using cmp_longs()) or unsigned (using
|
|
|
|
cmp_ulongs()).
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
-1 left argument is smaller than the right argument.
|
|
|
|
0 left argument is equal to the right argument.
|
|
|
|
1 left argument is greater than the right argument.
|
|
|
|
*/
|
|
|
|
int cmp_longlong(void *cmp_arg,
|
|
|
|
in_longlong::packed_longlong *a,
|
|
|
|
in_longlong::packed_longlong *b)
|
|
|
|
{
|
|
|
|
if (a->unsigned_flag != b->unsigned_flag)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
One of the args is unsigned and is too big to fit into the
|
|
|
|
positive signed range. Report no match.
|
|
|
|
*/
|
2007-03-17 19:45:01 +01:00
|
|
|
if (a->unsigned_flag && ((ulonglong) a->val) > (ulonglong) LONGLONG_MAX ||
|
|
|
|
b->unsigned_flag && ((ulonglong) b->val) > (ulonglong) LONGLONG_MAX)
|
2007-03-02 15:25:56 +01:00
|
|
|
return a->unsigned_flag ? 1 : -1;
|
|
|
|
/*
|
|
|
|
Although the signedness differs both args can fit into the signed
|
|
|
|
positive range. Make them signed and compare as usual.
|
|
|
|
*/
|
|
|
|
return cmp_longs (a->val, b->val);
|
|
|
|
}
|
|
|
|
if (a->unsigned_flag)
|
|
|
|
return cmp_ulongs ((ulonglong) a->val, (ulonglong) b->val);
|
|
|
|
else
|
|
|
|
return cmp_longs (a->val, b->val);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-06-27 10:52:38 +02:00
|
|
|
static int cmp_double(void *cmp_arg, double *a,double *b)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
return *a < *b ? -1 : *a == *b ? 0 : 1;
|
|
|
|
}
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
static int cmp_row(void *cmp_arg, cmp_item_row *a, cmp_item_row *b)
|
2002-12-08 02:19:03 +01:00
|
|
|
{
|
|
|
|
return a->compare(b);
|
|
|
|
}
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
|
|
|
|
static int cmp_decimal(void *cmp_arg, my_decimal *a, my_decimal *b)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We need call of fixing buffer pointer, because fast sort just copy
|
|
|
|
decimal buffers in memory and pointers left pointing on old buffer place
|
|
|
|
*/
|
|
|
|
a->fix_buffer_pointer();
|
|
|
|
b->fix_buffer_pointer();
|
|
|
|
return my_decimal_cmp(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
int in_vector::find(Item *item)
|
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *result=get_value(item);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!result || !used_count)
|
|
|
|
return 0; // Null value
|
|
|
|
|
|
|
|
uint start,end;
|
|
|
|
start=0; end=used_count-1;
|
|
|
|
while (start != end)
|
|
|
|
{
|
|
|
|
uint mid=(start+end+1)/2;
|
|
|
|
int res;
|
2003-06-27 10:52:38 +02:00
|
|
|
if ((res=(*compare)(collation, base+mid*size, result)) == 0)
|
2000-07-31 21:29:14 +02:00
|
|
|
return 1;
|
|
|
|
if (res < 0)
|
|
|
|
start=mid;
|
|
|
|
else
|
|
|
|
end=mid-1;
|
|
|
|
}
|
2003-06-27 10:52:38 +02:00
|
|
|
return (int) ((*compare)(collation, base+start*size, result) == 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-06-27 10:52:38 +02:00
|
|
|
in_string::in_string(uint elements,qsort2_cmp cmp_func, CHARSET_INFO *cs)
|
|
|
|
:in_vector(elements, sizeof(String), cmp_func, cs),
|
2003-03-07 10:39:53 +01:00
|
|
|
tmp(buff, sizeof(buff), &my_charset_bin)
|
2000-07-31 21:29:14 +02:00
|
|
|
{}
|
|
|
|
|
|
|
|
in_string::~in_string()
|
|
|
|
{
|
2003-01-28 21:28:11 +01:00
|
|
|
if (base)
|
2003-01-29 19:44:47 +01:00
|
|
|
{
|
2003-02-02 22:30:01 +01:00
|
|
|
// base was allocated with help of sql_alloc => following is OK
|
2003-01-28 21:28:11 +01:00
|
|
|
for (uint i=0 ; i < count ; i++)
|
|
|
|
((String*) base)[i].free();
|
2003-01-29 19:44:47 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void in_string::set(uint pos,Item *item)
|
|
|
|
{
|
|
|
|
String *str=((String*) base)+pos;
|
|
|
|
String *res=item->val_str(str);
|
|
|
|
if (res && res != str)
|
2005-02-04 07:14:22 +01:00
|
|
|
{
|
|
|
|
if (res->uses_buffer_owned_by(str))
|
|
|
|
res->copy();
|
2000-07-31 21:29:14 +02:00
|
|
|
*str= *res;
|
2005-02-04 07:14:22 +01:00
|
|
|
}
|
2002-03-20 17:52:23 +01:00
|
|
|
if (!str->charset())
|
2003-02-14 10:47:41 +01:00
|
|
|
{
|
|
|
|
CHARSET_INFO *cs;
|
2003-08-05 09:52:37 +02:00
|
|
|
if (!(cs= item->collation.collation))
|
2003-03-07 10:39:53 +01:00
|
|
|
cs= &my_charset_bin; // Should never happen for STR items
|
2003-02-14 10:47:41 +01:00
|
|
|
str->set_charset(cs);
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-02-14 10:47:41 +01:00
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *in_string::get_value(Item *item)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
return (uchar*) item->val_str(&tmp);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-12-08 02:19:03 +01:00
|
|
|
in_row::in_row(uint elements, Item * item)
|
|
|
|
{
|
2003-01-28 21:28:11 +01:00
|
|
|
base= (char*) new cmp_item_row[count= elements];
|
2002-12-08 02:19:03 +01:00
|
|
|
size= sizeof(cmp_item_row);
|
2003-06-27 10:52:38 +02:00
|
|
|
compare= (qsort2_cmp) cmp_row;
|
2005-02-28 10:59:46 +01:00
|
|
|
/*
|
|
|
|
We need to reset these as otherwise we will call sort() with
|
|
|
|
uninitialized (even if not used) elements
|
|
|
|
*/
|
|
|
|
used_count= elements;
|
|
|
|
collation= 0;
|
2003-01-28 21:28:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
in_row::~in_row()
|
|
|
|
{
|
|
|
|
if (base)
|
2003-01-30 17:07:39 +01:00
|
|
|
delete [] (cmp_item_row*) base;
|
2002-12-08 02:19:03 +01:00
|
|
|
}
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *in_row::get_value(Item *item)
|
2002-12-08 02:19:03 +01:00
|
|
|
{
|
|
|
|
tmp.store_value(item);
|
2005-08-09 01:51:12 +02:00
|
|
|
if (item->is_null())
|
|
|
|
return 0;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
return (uchar *)&tmp;
|
2002-12-08 02:19:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void in_row::set(uint pos, Item *item)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("in_row::set");
|
2007-03-22 19:32:07 +01:00
|
|
|
DBUG_PRINT("enter", ("pos: %u item: 0x%lx", pos, (ulong) item));
|
2002-12-08 02:19:03 +01:00
|
|
|
((cmp_item_row*) base)[pos].store_value_by_template(&tmp, item);
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
in_longlong::in_longlong(uint elements)
|
2007-03-02 15:25:56 +01:00
|
|
|
:in_vector(elements,sizeof(packed_longlong),(qsort2_cmp) cmp_longlong, 0)
|
2000-07-31 21:29:14 +02:00
|
|
|
{}
|
|
|
|
|
|
|
|
void in_longlong::set(uint pos,Item *item)
|
|
|
|
{
|
2007-03-02 15:25:56 +01:00
|
|
|
struct packed_longlong *buff= &((packed_longlong*) base)[pos];
|
|
|
|
|
|
|
|
buff->val= item->val_int();
|
|
|
|
buff->unsigned_flag= item->unsigned_flag;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *in_longlong::get_value(Item *item)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2007-03-02 15:25:56 +01:00
|
|
|
tmp.val= item->val_int();
|
2000-07-31 21:29:14 +02:00
|
|
|
if (item->null_value)
|
2002-12-08 02:19:03 +01:00
|
|
|
return 0;
|
2007-03-02 15:25:56 +01:00
|
|
|
tmp.unsigned_flag= item->unsigned_flag;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
return (uchar*) &tmp;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2007-05-07 20:20:43 +02:00
|
|
|
void in_datetime::set(uint pos,Item *item)
|
|
|
|
{
|
|
|
|
Item **tmp= &item;
|
|
|
|
bool is_null;
|
|
|
|
struct packed_longlong *buff= &((packed_longlong*) base)[pos];
|
|
|
|
|
|
|
|
buff->val= get_datetime_value(thd, &tmp, 0, warn_item, &is_null);
|
|
|
|
buff->unsigned_flag= 1L;
|
|
|
|
}
|
|
|
|
|
2007-05-24 18:47:58 +02:00
|
|
|
uchar *in_datetime::get_value(Item *item)
|
2007-05-07 20:20:43 +02:00
|
|
|
{
|
|
|
|
bool is_null;
|
|
|
|
Item **tmp_item= lval_cache ? &lval_cache : &item;
|
|
|
|
tmp.val= get_datetime_value(thd, &tmp_item, &lval_cache, warn_item, &is_null);
|
|
|
|
if (item->null_value)
|
|
|
|
return 0;
|
|
|
|
tmp.unsigned_flag= 1L;
|
2007-05-24 18:47:58 +02:00
|
|
|
return (uchar*) &tmp;
|
2007-05-07 20:20:43 +02:00
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
in_double::in_double(uint elements)
|
2003-06-27 10:52:38 +02:00
|
|
|
:in_vector(elements,sizeof(double),(qsort2_cmp) cmp_double, 0)
|
2000-07-31 21:29:14 +02:00
|
|
|
{}
|
|
|
|
|
|
|
|
void in_double::set(uint pos,Item *item)
|
|
|
|
{
|
2004-11-11 19:39:35 +01:00
|
|
|
((double*) base)[pos]= item->val_real();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *in_double::get_value(Item *item)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-11 19:39:35 +01:00
|
|
|
tmp= item->val_real();
|
2000-07-31 21:29:14 +02:00
|
|
|
if (item->null_value)
|
2002-05-04 10:11:00 +02:00
|
|
|
return 0; /* purecov: inspected */
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
return (uchar*) &tmp;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
|
|
|
|
in_decimal::in_decimal(uint elements)
|
|
|
|
:in_vector(elements, sizeof(my_decimal),(qsort2_cmp) cmp_decimal, 0)
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
void in_decimal::set(uint pos, Item *item)
|
|
|
|
{
|
|
|
|
/* as far as 'item' is constant, we can store reference on my_decimal */
|
|
|
|
my_decimal *dec= ((my_decimal *)base) + pos;
|
|
|
|
dec->len= DECIMAL_BUFF_LENGTH;
|
|
|
|
dec->fix_buffer_pointer();
|
|
|
|
my_decimal *res= item->val_decimal(dec);
|
2007-03-22 08:05:36 +01:00
|
|
|
/* if item->val_decimal() is evaluated to NULL then res == 0 */
|
|
|
|
if (!item->null_value && res != dec)
|
2005-02-08 23:50:45 +01:00
|
|
|
my_decimal2decimal(res, dec);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *in_decimal::get_value(Item *item)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
|
|
|
my_decimal *result= item->val_decimal(&val);
|
|
|
|
if (item->null_value)
|
|
|
|
return 0;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
return (uchar *)result;
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cmp_item* cmp_item::get_comparator(Item_result type,
|
|
|
|
CHARSET_INFO *cs)
|
2002-12-07 18:58:05 +01:00
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
switch (type) {
|
2002-12-07 18:58:05 +01:00
|
|
|
case STRING_RESULT:
|
2005-02-08 23:50:45 +01:00
|
|
|
return new cmp_item_sort_string(cs);
|
2002-12-07 18:58:05 +01:00
|
|
|
case INT_RESULT:
|
|
|
|
return new cmp_item_int;
|
|
|
|
case REAL_RESULT:
|
|
|
|
return new cmp_item_real;
|
|
|
|
case ROW_RESULT:
|
|
|
|
return new cmp_item_row;
|
2005-02-08 23:50:45 +01:00
|
|
|
case DECIMAL_RESULT:
|
|
|
|
return new cmp_item_decimal;
|
2003-01-31 11:07:07 +01:00
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
break;
|
2002-12-07 18:58:05 +01:00
|
|
|
}
|
|
|
|
return 0; // to satisfy compiler :)
|
|
|
|
}
|
|
|
|
|
2003-11-19 16:31:57 +01:00
|
|
|
|
2002-12-08 02:19:03 +01:00
|
|
|
cmp_item* cmp_item_sort_string::make_same()
|
|
|
|
{
|
2003-03-04 15:01:59 +01:00
|
|
|
return new cmp_item_sort_string_in_static(cmp_charset);
|
2002-12-08 02:19:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
cmp_item* cmp_item_int::make_same()
|
|
|
|
{
|
|
|
|
return new cmp_item_int();
|
|
|
|
}
|
|
|
|
|
|
|
|
cmp_item* cmp_item_real::make_same()
|
|
|
|
{
|
|
|
|
return new cmp_item_real();
|
|
|
|
}
|
|
|
|
|
|
|
|
cmp_item* cmp_item_row::make_same()
|
|
|
|
{
|
|
|
|
return new cmp_item_row();
|
|
|
|
}
|
|
|
|
|
2003-11-19 16:31:57 +01:00
|
|
|
|
|
|
|
cmp_item_row::~cmp_item_row()
|
|
|
|
{
|
|
|
|
DBUG_ENTER("~cmp_item_row");
|
2006-11-20 21:42:06 +01:00
|
|
|
DBUG_PRINT("enter",("this: 0x%lx", (long) this));
|
2003-11-19 16:31:57 +01:00
|
|
|
if (comparators)
|
|
|
|
{
|
|
|
|
for (uint i= 0; i < n; i++)
|
|
|
|
{
|
|
|
|
if (comparators[i])
|
|
|
|
delete comparators[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-05-07 20:20:43 +02:00
|
|
|
void cmp_item_row::alloc_comparators()
|
|
|
|
{
|
|
|
|
if (!comparators)
|
|
|
|
comparators= (cmp_item **) current_thd->calloc(sizeof(cmp_item *)*n);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-07 18:58:05 +01:00
|
|
|
void cmp_item_row::store_value(Item *item)
|
|
|
|
{
|
2003-11-19 18:31:19 +01:00
|
|
|
DBUG_ENTER("cmp_item_row::store_value");
|
2002-12-07 18:58:05 +01:00
|
|
|
n= item->cols();
|
2007-05-07 20:20:43 +02:00
|
|
|
alloc_comparators();
|
2003-11-19 18:31:19 +01:00
|
|
|
if (comparators)
|
2002-12-07 18:58:05 +01:00
|
|
|
{
|
2002-12-19 06:38:33 +01:00
|
|
|
item->bring_value();
|
2002-12-08 02:19:03 +01:00
|
|
|
item->null_value= 0;
|
2002-12-07 18:58:05 +01:00
|
|
|
for (uint i=0; i < n; i++)
|
2003-11-19 16:31:57 +01:00
|
|
|
{
|
2003-11-20 13:31:10 +01:00
|
|
|
if (!comparators[i])
|
2005-02-08 23:50:45 +01:00
|
|
|
if (!(comparators[i]=
|
2006-12-14 23:51:37 +01:00
|
|
|
cmp_item::get_comparator(item->element_index(i)->result_type(),
|
|
|
|
item->element_index(i)->collation.collation)))
|
2003-11-20 13:31:10 +01:00
|
|
|
break; // new failed
|
2006-12-14 23:51:37 +01:00
|
|
|
comparators[i]->store_value(item->element_index(i));
|
|
|
|
item->null_value|= item->element_index(i)->null_value;
|
2003-11-19 16:31:57 +01:00
|
|
|
}
|
2002-12-07 18:58:05 +01:00
|
|
|
}
|
2003-11-19 18:31:19 +01:00
|
|
|
DBUG_VOID_RETURN;
|
2002-12-07 18:58:05 +01:00
|
|
|
}
|
|
|
|
|
2003-11-19 16:31:57 +01:00
|
|
|
|
2002-12-08 02:19:03 +01:00
|
|
|
void cmp_item_row::store_value_by_template(cmp_item *t, Item *item)
|
|
|
|
{
|
|
|
|
cmp_item_row *tmpl= (cmp_item_row*) t;
|
|
|
|
if (tmpl->n != item->cols())
|
|
|
|
{
|
2003-10-06 21:35:05 +02:00
|
|
|
my_error(ER_OPERAND_COLUMNS, MYF(0), tmpl->n);
|
2002-12-08 02:19:03 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
n= tmpl->n;
|
|
|
|
if ((comparators= (cmp_item **) sql_alloc(sizeof(cmp_item *)*n)))
|
|
|
|
{
|
2002-12-19 06:38:33 +01:00
|
|
|
item->bring_value();
|
2002-12-08 02:19:03 +01:00
|
|
|
item->null_value= 0;
|
|
|
|
for (uint i=0; i < n; i++)
|
2003-11-19 16:31:57 +01:00
|
|
|
{
|
|
|
|
if (!(comparators[i]= tmpl->comparators[i]->make_same()))
|
|
|
|
break; // new failed
|
|
|
|
comparators[i]->store_value_by_template(tmpl->comparators[i],
|
2006-12-14 23:51:37 +01:00
|
|
|
item->element_index(i));
|
|
|
|
item->null_value|= item->element_index(i)->null_value;
|
2003-11-19 16:31:57 +01:00
|
|
|
}
|
2002-12-08 02:19:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-19 16:31:57 +01:00
|
|
|
|
2002-12-07 18:58:05 +01:00
|
|
|
int cmp_item_row::cmp(Item *arg)
|
|
|
|
{
|
2002-12-08 02:19:03 +01:00
|
|
|
arg->null_value= 0;
|
|
|
|
if (arg->cols() != n)
|
|
|
|
{
|
2003-10-06 21:35:05 +02:00
|
|
|
my_error(ER_OPERAND_COLUMNS, MYF(0), n);
|
2002-12-08 02:19:03 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2002-12-10 17:10:00 +01:00
|
|
|
bool was_null= 0;
|
2002-12-19 06:38:33 +01:00
|
|
|
arg->bring_value();
|
2002-12-10 17:10:00 +01:00
|
|
|
for (uint i=0; i < n; i++)
|
2003-11-19 16:31:57 +01:00
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
if (comparators[i]->cmp(arg->element_index(i)))
|
2002-12-08 02:19:03 +01:00
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
if (!arg->element_index(i)->null_value)
|
2002-12-10 17:10:00 +01:00
|
|
|
return 1;
|
|
|
|
was_null= 1;
|
2002-12-08 02:19:03 +01:00
|
|
|
}
|
2003-11-19 16:31:57 +01:00
|
|
|
}
|
2002-12-12 19:34:16 +01:00
|
|
|
return (arg->null_value= was_null);
|
2002-12-08 02:19:03 +01:00
|
|
|
}
|
|
|
|
|
2003-11-19 16:31:57 +01:00
|
|
|
|
2002-12-08 02:19:03 +01:00
|
|
|
int cmp_item_row::compare(cmp_item *c)
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
cmp_item_row *l_cmp= (cmp_item_row *) c;
|
2002-12-10 17:10:00 +01:00
|
|
|
for (uint i=0; i < n; i++)
|
2003-11-19 16:31:57 +01:00
|
|
|
{
|
|
|
|
int res;
|
2006-12-14 23:51:37 +01:00
|
|
|
if ((res= comparators[i]->compare(l_cmp->comparators[i])))
|
2002-12-08 02:19:03 +01:00
|
|
|
return res;
|
2003-11-19 16:31:57 +01:00
|
|
|
}
|
2002-12-07 18:58:05 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-11-19 16:31:57 +01:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
void cmp_item_decimal::store_value(Item *item)
|
|
|
|
{
|
|
|
|
my_decimal *val= item->val_decimal(&value);
|
2005-02-15 18:35:28 +01:00
|
|
|
/* val may be zero if item is nnull */
|
|
|
|
if (val && val != &value)
|
2005-02-08 23:50:45 +01:00
|
|
|
my_decimal2decimal(val, &value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int cmp_item_decimal::cmp(Item *arg)
|
|
|
|
{
|
|
|
|
my_decimal tmp_buf, *tmp= arg->val_decimal(&tmp_buf);
|
|
|
|
if (arg->null_value)
|
|
|
|
return 1;
|
|
|
|
return my_decimal_cmp(&value, tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-15 18:35:28 +01:00
|
|
|
int cmp_item_decimal::compare(cmp_item *arg)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
cmp_item_decimal *l_cmp= (cmp_item_decimal*) arg;
|
|
|
|
return my_decimal_cmp(&value, &l_cmp->value);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cmp_item* cmp_item_decimal::make_same()
|
|
|
|
{
|
|
|
|
return new cmp_item_decimal();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-05-07 20:20:43 +02:00
|
|
|
void cmp_item_datetime::store_value(Item *item)
|
|
|
|
{
|
|
|
|
bool is_null;
|
|
|
|
Item **tmp_item= lval_cache ? &lval_cache : &item;
|
|
|
|
value= get_datetime_value(thd, &tmp_item, &lval_cache, warn_item, &is_null);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int cmp_item_datetime::cmp(Item *arg)
|
|
|
|
{
|
|
|
|
bool is_null;
|
|
|
|
Item **tmp_item= &arg;
|
|
|
|
return value !=
|
|
|
|
get_datetime_value(thd, &tmp_item, 0, warn_item, &is_null);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int cmp_item_datetime::compare(cmp_item *ci)
|
|
|
|
{
|
|
|
|
cmp_item_datetime *l_cmp= (cmp_item_datetime *)ci;
|
|
|
|
return (value < l_cmp->value) ? -1 : ((value == l_cmp->value) ? 0 : 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cmp_item *cmp_item_datetime::make_same()
|
|
|
|
{
|
|
|
|
return new cmp_item_datetime(warn_item);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-10 17:10:00 +01:00
|
|
|
bool Item_func_in::nulls_in_row()
|
|
|
|
{
|
|
|
|
Item **arg,**arg_end;
|
2003-07-16 08:29:16 +02:00
|
|
|
for (arg= args+1, arg_end= args+arg_count; arg != arg_end ; arg++)
|
2002-12-10 17:10:00 +01:00
|
|
|
{
|
|
|
|
if ((*arg)->null_inside())
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-11-19 16:31:57 +01:00
|
|
|
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
/*
|
|
|
|
Perform context analysis of an IN item tree
|
|
|
|
|
|
|
|
SYNOPSIS:
|
|
|
|
fix_fields()
|
|
|
|
thd reference to the global context of the query thread
|
|
|
|
tables list of all open tables involved in the query
|
|
|
|
ref pointer to Item* variable where pointer to resulting "fixed"
|
|
|
|
item is to be assigned
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
This function performs context analysis (name resolution) and calculates
|
|
|
|
various attributes of the item tree with Item_func_in as its root.
|
|
|
|
The function saves in ref the pointer to the item or to a newly created
|
|
|
|
item that is considered as a replacement for the original one.
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on
|
|
|
|
a predicate/function level. Then it's easy to show that:
|
|
|
|
T0(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei)))
|
|
|
|
T1(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei)))
|
|
|
|
T0(e NOT IN(e1,...,en)) = union(T1(e),union(T1(ei)))
|
|
|
|
T1(e NOT IN(e1,...,en)) = union(T1(e),intersection(T1(ei)))
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 ok
|
|
|
|
1 got error
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool
|
2005-09-07 15:42:47 +02:00
|
|
|
Item_func_in::fix_fields(THD *thd, Item **ref)
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
{
|
|
|
|
Item **arg, **arg_end;
|
|
|
|
|
2005-09-07 15:42:47 +02:00
|
|
|
if (Item_func_opt_neg::fix_fields(thd, ref))
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* not_null_tables_cache == union(T1(e),union(T1(ei))) */
|
|
|
|
if (pred_level && negated)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* not_null_tables_cache = union(T1(e),intersection(T1(ei))) */
|
|
|
|
not_null_tables_cache= ~(table_map) 0;
|
|
|
|
for (arg= args + 1, arg_end= args + arg_count; arg != arg_end; arg++)
|
|
|
|
not_null_tables_cache&= (*arg)->not_null_tables();
|
|
|
|
not_null_tables_cache|= (*args)->not_null_tables();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-06-27 10:52:38 +02:00
|
|
|
static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
|
2003-03-04 15:01:59 +01:00
|
|
|
{
|
2003-05-23 14:45:52 +02:00
|
|
|
return cs->coll->strnncollsp(cs,
|
2004-08-26 17:26:38 +02:00
|
|
|
(uchar *) x->ptr(),x->length(),
|
2004-12-06 01:00:37 +01:00
|
|
|
(uchar *) y->ptr(),y->length(), 0);
|
2003-03-04 15:01:59 +01:00
|
|
|
}
|
|
|
|
|
2003-11-19 16:31:57 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void Item_func_in::fix_length_and_dec()
|
|
|
|
{
|
2003-07-16 08:29:16 +02:00
|
|
|
Item **arg, **arg_end;
|
2006-09-26 18:52:54 +02:00
|
|
|
bool const_itm= 1;
|
2004-10-26 18:30:01 +02:00
|
|
|
THD *thd= current_thd;
|
2007-05-07 20:20:43 +02:00
|
|
|
bool datetime_found= FALSE;
|
|
|
|
/* TRUE <=> arguments values will be compared as DATETIMEs. */
|
|
|
|
bool compare_as_datetime= FALSE;
|
|
|
|
Item *date_arg= 0;
|
2007-05-08 20:28:24 +02:00
|
|
|
uint found_types= 0;
|
|
|
|
uint type_cnt= 0, i;
|
|
|
|
Item_result cmp_type= STRING_RESULT;
|
|
|
|
left_result_type= args[0]->result_type();
|
|
|
|
if (!(found_types= collect_cmp_types(args, arg_count)))
|
|
|
|
return;
|
|
|
|
|
2006-09-26 18:52:54 +02:00
|
|
|
for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++)
|
2005-07-18 14:33:18 +02:00
|
|
|
{
|
|
|
|
if (!arg[0]->const_item())
|
|
|
|
{
|
|
|
|
const_itm= 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-09-26 18:52:54 +02:00
|
|
|
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
|
|
|
|
{
|
|
|
|
if (found_types & 1 << i)
|
2007-02-16 12:56:06 +01:00
|
|
|
{
|
2006-09-26 18:52:54 +02:00
|
|
|
(type_cnt)++;
|
2007-02-16 12:56:06 +01:00
|
|
|
cmp_type= (Item_result) i;
|
|
|
|
}
|
2006-09-26 18:52:54 +02:00
|
|
|
}
|
2007-02-16 12:56:06 +01:00
|
|
|
|
|
|
|
if (type_cnt == 1)
|
|
|
|
{
|
|
|
|
if (cmp_type == STRING_RESULT &&
|
|
|
|
agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
|
|
|
|
return;
|
|
|
|
arg_types_compatible= TRUE;
|
|
|
|
}
|
2007-05-08 20:28:24 +02:00
|
|
|
if (type_cnt == 1)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
When comparing rows create the row comparator object beforehand to ease
|
|
|
|
the DATETIME comparison detection procedure.
|
|
|
|
*/
|
|
|
|
if (cmp_type == ROW_RESULT)
|
|
|
|
{
|
|
|
|
cmp_item_row *cmp= 0;
|
|
|
|
if (const_itm && !nulls_in_row())
|
|
|
|
{
|
|
|
|
array= new in_row(arg_count-1, 0);
|
|
|
|
cmp= &((in_row*)array)->tmp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!(cmp= new cmp_item_row))
|
|
|
|
return;
|
|
|
|
cmp_items[ROW_RESULT]= cmp;
|
|
|
|
}
|
|
|
|
cmp->n= args[0]->cols();
|
|
|
|
cmp->alloc_comparators();
|
|
|
|
}
|
|
|
|
/* All DATE/DATETIME fields/functions has the STRING result type. */
|
|
|
|
if (cmp_type == STRING_RESULT || cmp_type == ROW_RESULT)
|
|
|
|
{
|
|
|
|
uint col, cols= args[0]->cols();
|
2007-02-16 12:56:06 +01:00
|
|
|
|
2007-05-08 20:28:24 +02:00
|
|
|
for (col= 0; col < cols; col++)
|
|
|
|
{
|
|
|
|
bool skip_column= FALSE;
|
|
|
|
/*
|
|
|
|
Check that all items to be compared has the STRING result type and at
|
|
|
|
least one of them is a DATE/DATETIME item.
|
|
|
|
*/
|
|
|
|
for (arg= args, arg_end= args + arg_count; arg != arg_end ; arg++)
|
|
|
|
{
|
|
|
|
Item *itm= ((cmp_type == STRING_RESULT) ? arg[0] :
|
|
|
|
arg[0]->element_index(col));
|
|
|
|
if (itm->result_type() != STRING_RESULT)
|
|
|
|
{
|
|
|
|
skip_column= TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (itm->is_datetime())
|
|
|
|
{
|
|
|
|
datetime_found= TRUE;
|
|
|
|
/*
|
|
|
|
Internally all DATE/DATETIME values are converted to the DATETIME
|
|
|
|
type. So try to find a DATETIME item to issue correct warnings.
|
|
|
|
*/
|
|
|
|
if (!date_arg)
|
|
|
|
date_arg= itm;
|
|
|
|
else if (itm->field_type() == MYSQL_TYPE_DATETIME)
|
|
|
|
{
|
|
|
|
date_arg= itm;
|
|
|
|
/* All arguments are already checked to have the STRING result. */
|
|
|
|
if (cmp_type == STRING_RESULT)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (skip_column)
|
|
|
|
continue;
|
|
|
|
if (datetime_found)
|
|
|
|
{
|
|
|
|
if (cmp_type == ROW_RESULT)
|
|
|
|
{
|
|
|
|
cmp_item **cmp= 0;
|
|
|
|
if (array)
|
|
|
|
cmp= ((in_row*)array)->tmp.comparators + col;
|
|
|
|
else
|
|
|
|
cmp= ((cmp_item_row*)cmp_items[ROW_RESULT])->comparators + col;
|
|
|
|
*cmp= new cmp_item_datetime(date_arg);
|
|
|
|
/* Reset variables for the next column. */
|
|
|
|
date_arg= 0;
|
|
|
|
datetime_found= FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
compare_as_datetime= TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-12-10 17:10:00 +01:00
|
|
|
/*
|
2006-09-26 18:52:54 +02:00
|
|
|
Row item with NULLs inside can return NULL or FALSE =>
|
2002-12-10 17:10:00 +01:00
|
|
|
they can't be processed as static
|
|
|
|
*/
|
2006-09-26 18:52:54 +02:00
|
|
|
if (type_cnt == 1 && const_itm && !nulls_in_row())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2007-05-07 20:20:43 +02:00
|
|
|
if (compare_as_datetime)
|
|
|
|
array= new in_datetime(date_arg, arg_count - 1);
|
|
|
|
else
|
2007-03-02 15:25:56 +01:00
|
|
|
{
|
2007-05-07 20:20:43 +02:00
|
|
|
/*
|
|
|
|
IN must compare INT columns and constants as int values (the same
|
|
|
|
way as equality does).
|
|
|
|
So we must check here if the column on the left and all the constant
|
|
|
|
values on the right can be compared as integers and adjust the
|
|
|
|
comparison type accordingly.
|
|
|
|
*/
|
|
|
|
if (args[0]->real_item()->type() == FIELD_ITEM &&
|
|
|
|
thd->lex->sql_command != SQLCOM_CREATE_VIEW &&
|
|
|
|
thd->lex->sql_command != SQLCOM_SHOW_CREATE &&
|
|
|
|
cmp_type != INT_RESULT)
|
2007-03-02 15:25:56 +01:00
|
|
|
{
|
2007-05-07 20:20:43 +02:00
|
|
|
Field *field= ((Item_field*) (args[0]->real_item()))->field;
|
|
|
|
if (field->can_be_compared_as_longlong())
|
2007-03-02 15:25:56 +01:00
|
|
|
{
|
2007-05-07 20:20:43 +02:00
|
|
|
bool all_converted= TRUE;
|
|
|
|
for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
|
|
|
|
{
|
|
|
|
if (!convert_constant_item (thd, field, &arg[0]))
|
|
|
|
all_converted= FALSE;
|
|
|
|
}
|
|
|
|
if (all_converted)
|
|
|
|
cmp_type= INT_RESULT;
|
2007-03-02 15:25:56 +01:00
|
|
|
}
|
|
|
|
}
|
2007-05-07 20:20:43 +02:00
|
|
|
switch (cmp_type) {
|
|
|
|
case STRING_RESULT:
|
|
|
|
array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in,
|
|
|
|
cmp_collation.collation);
|
|
|
|
break;
|
|
|
|
case INT_RESULT:
|
|
|
|
array= new in_longlong(arg_count-1);
|
|
|
|
break;
|
|
|
|
case REAL_RESULT:
|
|
|
|
array= new in_double(arg_count-1);
|
|
|
|
break;
|
|
|
|
case ROW_RESULT:
|
|
|
|
/*
|
|
|
|
The row comparator was created at the beginning but only DATETIME
|
|
|
|
items comparators were initialized. Call store_value() to setup
|
|
|
|
others.
|
|
|
|
*/
|
|
|
|
((in_row*)array)->tmp.store_value(args[0]);
|
|
|
|
break;
|
|
|
|
case DECIMAL_RESULT:
|
|
|
|
array= new in_decimal(arg_count - 1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
return;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-10-26 18:30:01 +02:00
|
|
|
if (array && !(thd->is_fatal_error)) // If not EOM
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-08-20 15:25:44 +02:00
|
|
|
uint j=0;
|
2003-08-29 12:44:35 +02:00
|
|
|
for (uint i=1 ; i < arg_count ; i++)
|
2003-08-20 15:25:44 +02:00
|
|
|
{
|
|
|
|
array->set(j,args[i]);
|
|
|
|
if (!args[i]->null_value) // Skip NULL values
|
|
|
|
j++;
|
2003-08-29 12:44:35 +02:00
|
|
|
else
|
|
|
|
have_null= 1;
|
2003-08-20 15:25:44 +02:00
|
|
|
}
|
2006-09-26 18:52:54 +02:00
|
|
|
if ((array->used_count= j))
|
2003-08-20 15:25:44 +02:00
|
|
|
array->sort();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-05-08 20:28:24 +02:00
|
|
|
if (compare_as_datetime)
|
|
|
|
cmp_items[STRING_RESULT]= new cmp_item_datetime(date_arg);
|
2007-05-07 20:20:43 +02:00
|
|
|
else
|
2007-05-08 13:54:49 +02:00
|
|
|
{
|
2007-05-08 20:28:24 +02:00
|
|
|
for (i= 0; i <= (uint) DECIMAL_RESULT; i++)
|
2006-09-26 18:52:54 +02:00
|
|
|
{
|
2007-05-08 20:28:24 +02:00
|
|
|
if (found_types & (1 << i) && !cmp_items[i])
|
|
|
|
{
|
|
|
|
if ((Item_result)i == STRING_RESULT &&
|
|
|
|
agg_arg_charsets(cmp_collation, args, arg_count,
|
|
|
|
MY_COLL_CMP_CONV, 1))
|
|
|
|
return;
|
|
|
|
if (!cmp_items[i] && !(cmp_items[i]=
|
|
|
|
cmp_item::get_comparator((Item_result)i,
|
|
|
|
cmp_collation.collation)))
|
|
|
|
return;
|
|
|
|
}
|
2006-09-26 18:52:54 +02:00
|
|
|
}
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-12-10 17:10:00 +01:00
|
|
|
max_length= 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Item_func_in::print(String *str)
|
|
|
|
{
|
|
|
|
str->append('(');
|
2003-10-12 16:56:05 +02:00
|
|
|
args[0]->print(str);
|
2005-09-09 17:06:15 +02:00
|
|
|
if (negated)
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN(" not"));
|
|
|
|
str->append(STRING_WITH_LEN(" in ("));
|
2003-11-03 11:28:36 +01:00
|
|
|
print_args(str, 1);
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN("))"));
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-09-26 18:52:54 +02:00
|
|
|
/*
|
|
|
|
Evaluate the function and return its value.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
val_int()
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Evaluate the function and return its value.
|
|
|
|
|
|
|
|
IMPLEMENTATION
|
|
|
|
If the array object is defined then the value of the function is
|
|
|
|
calculated by means of this array.
|
|
|
|
Otherwise several cmp_item objects are used in order to do correct
|
|
|
|
comparison of left expression and an expression from the values list.
|
|
|
|
One cmp_item object correspond to one used comparison type. Left
|
|
|
|
expression can be evaluated up to number of different used comparison
|
|
|
|
types. A bit mapped variable value_added_map is used to check whether
|
|
|
|
the left expression already was evaluated for a particular result type.
|
|
|
|
Result types are mapped to it according to their integer values i.e.
|
|
|
|
STRING_RESULT is mapped to bit 0, REAL_RESULT to bit 1, so on.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
Value of the function
|
|
|
|
*/
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong Item_func_in::val_int()
|
|
|
|
{
|
2006-09-26 18:52:54 +02:00
|
|
|
cmp_item *in_item;
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2006-09-26 18:52:54 +02:00
|
|
|
uint value_added_map= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
if (array)
|
|
|
|
{
|
2003-07-16 08:29:16 +02:00
|
|
|
int tmp=array->find(args[0]);
|
|
|
|
null_value=args[0]->null_value || (!tmp && have_null);
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
return (longlong) (!null_value && tmp != negated);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2006-09-26 18:52:54 +02:00
|
|
|
|
|
|
|
for (uint i= 1 ; i < arg_count ; i++)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-09-26 18:52:54 +02:00
|
|
|
Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type());
|
|
|
|
in_item= cmp_items[(uint)cmp_type];
|
|
|
|
DBUG_ASSERT(in_item);
|
|
|
|
if (!(value_added_map & (1 << (uint)cmp_type)))
|
|
|
|
{
|
|
|
|
in_item->store_value(args[0]);
|
|
|
|
if ((null_value=args[0]->null_value))
|
|
|
|
return 0;
|
|
|
|
have_null= 0;
|
|
|
|
value_added_map|= 1 << (uint)cmp_type;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!in_item->cmp(args[i]) && !args[i]->null_value)
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
return (longlong) (!negated);
|
2002-12-06 20:55:53 +01:00
|
|
|
have_null|= args[i]->null_value;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2006-09-26 18:52:54 +02:00
|
|
|
|
2002-12-06 20:55:53 +01:00
|
|
|
null_value= have_null;
|
item_cmpfunc.h:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The classes Item_func_between, Item_func_if, Item_func_in are modified.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions.
The class Item_func_opt_neg is added to factor out the functionality
common for the modified classes Item_func_between and Item_func_in.
item_cmpfunc.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Added Item_func_between::fix_fields(), Item_func_if::fix_fields(),
Item_func_in::fix_fields(). They correct generic calculation of
the not_null_tables attribute when it is needed.
Modified Item_func_between::val_int(), Item_func_in::val_int().
opt_range.cc:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
The function get_mm_tree() is modified. There cannot be NOT before
BETWEEN/IN anymore. Rather Item_func_between/in objects can represent
now [NOT]BETWEEN/IN expressions.
sql_yacc.yy:
Fixed bugs #12101, #12102: wrong calculation of not_null_tables()
for some expressions.
Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions.
join_outer.result:
Fixed some testcases results (bugs #12101, #12102)
join_outer.test:
Added testcases for bugs #12101, #12102
2005-09-06 16:03:08 +02:00
|
|
|
return (longlong) (!null_value && negated);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
longlong Item_func_bit_or::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
ulonglong arg1= (ulonglong) args[0]->val_int();
|
|
|
|
if (args[0]->null_value)
|
|
|
|
{
|
|
|
|
null_value=1; /* purecov: inspected */
|
|
|
|
return 0; /* purecov: inspected */
|
|
|
|
}
|
|
|
|
ulonglong arg2= (ulonglong) args[1]->val_int();
|
|
|
|
if (args[1]->null_value)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
null_value=0;
|
|
|
|
return (longlong) (arg1 | arg2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
longlong Item_func_bit_and::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
ulonglong arg1= (ulonglong) args[0]->val_int();
|
|
|
|
if (args[0]->null_value)
|
|
|
|
{
|
|
|
|
null_value=1; /* purecov: inspected */
|
|
|
|
return 0; /* purecov: inspected */
|
|
|
|
}
|
|
|
|
ulonglong arg2= (ulonglong) args[1]->val_int();
|
|
|
|
if (args[1]->null_value)
|
|
|
|
{
|
|
|
|
null_value=1; /* purecov: inspected */
|
|
|
|
return 0; /* purecov: inspected */
|
|
|
|
}
|
|
|
|
null_value=0;
|
|
|
|
return (longlong) (arg1 & arg2);
|
|
|
|
}
|
|
|
|
|
2004-01-19 16:53:25 +01:00
|
|
|
Item_cond::Item_cond(THD *thd, Item_cond *item)
|
2003-09-02 18:56:55 +02:00
|
|
|
:Item_bool_func(thd, item),
|
2004-01-19 16:53:25 +01:00
|
|
|
abort_on_null(item->abort_on_null),
|
|
|
|
and_tables_cache(item->and_tables_cache)
|
2003-09-02 18:56:55 +02:00
|
|
|
{
|
|
|
|
/*
|
2004-01-19 23:51:17 +01:00
|
|
|
item->list will be copied by copy_andor_arguments() call
|
2003-09-02 18:56:55 +02:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2004-01-19 23:51:17 +01:00
|
|
|
|
2003-09-02 18:56:55 +02:00
|
|
|
void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item)
|
|
|
|
{
|
|
|
|
List_iterator_fast<Item> li(item->list);
|
2004-01-19 23:51:17 +01:00
|
|
|
while (Item *it= li++)
|
2003-09-02 18:56:55 +02:00
|
|
|
list.push_back(it->copy_andor_structure(thd));
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-01-19 23:51:17 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
bool
|
2005-07-01 06:05:42 +02:00
|
|
|
Item_cond::fix_fields(THD *thd, Item **ref)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
DBUG_ASSERT(fixed == 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
List_iterator<Item> li(list);
|
|
|
|
Item *item;
|
2003-06-15 22:24:37 +02:00
|
|
|
#ifndef EMBEDDED_LIBRARY
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar buff[sizeof(char*)]; // Max local vars in function
|
2003-06-15 22:24:37 +02:00
|
|
|
#endif
|
2003-06-27 02:04:54 +02:00
|
|
|
not_null_tables_cache= used_tables_cache= 0;
|
2004-10-19 23:12:55 +02:00
|
|
|
const_item_cache= 1;
|
2003-06-26 04:38:19 +02:00
|
|
|
/*
|
|
|
|
and_table_cache is the value that Item_cond_or() returns for
|
|
|
|
not_null_tables()
|
|
|
|
*/
|
|
|
|
and_tables_cache= ~(table_map) 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-05-31 12:06:15 +02:00
|
|
|
if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE; // Fatal error flag is set!
|
2005-03-03 15:38:59 +01:00
|
|
|
/*
|
|
|
|
The following optimization reduces the depth of an AND-OR tree.
|
|
|
|
E.g. a WHERE clause like
|
|
|
|
F1 AND (F2 AND (F2 AND F4))
|
|
|
|
is parsed into a tree with the same nested structure as defined
|
|
|
|
by braces. This optimization will transform such tree into
|
|
|
|
AND (F1, F2, F3, F4).
|
|
|
|
Trees of OR items are flattened as well:
|
|
|
|
((F1 OR F2) OR (F3 OR F4)) => OR (F1, F2, F3, F4)
|
|
|
|
Items for removed AND/OR levels will dangle until the death of the
|
|
|
|
entire statement.
|
|
|
|
The optimization is currently prepared statements and stored procedures
|
|
|
|
friendly as it doesn't allocate any memory and its effects are durable
|
|
|
|
(i.e. do not depend on PS/SP arguments).
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
while ((item=li++))
|
|
|
|
{
|
2003-06-26 04:38:19 +02:00
|
|
|
table_map tmp_table_map;
|
2000-07-31 21:29:14 +02:00
|
|
|
while (item->type() == Item::COND_ITEM &&
|
2006-03-03 14:19:57 +01:00
|
|
|
((Item_cond*) item)->functype() == functype() &&
|
|
|
|
!((Item_cond*) item)->list.is_empty())
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // Identical function
|
|
|
|
li.replace(((Item_cond*) item)->list);
|
|
|
|
((Item_cond*) item)->list.empty();
|
|
|
|
item= *li.ref(); // new current item
|
|
|
|
}
|
2002-11-12 11:42:42 +01:00
|
|
|
if (abort_on_null)
|
|
|
|
item->top_level_item();
|
2004-02-18 00:08:52 +01:00
|
|
|
|
|
|
|
// item can be substituted in fix_fields
|
2003-05-14 20:51:33 +02:00
|
|
|
if ((!item->fixed &&
|
2005-07-01 06:05:42 +02:00
|
|
|
item->fix_fields(thd, li.ref())) ||
|
2004-02-18 00:08:52 +01:00
|
|
|
(item= *li.ref())->check_cols(1))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE; /* purecov: inspected */
|
2003-06-26 04:38:19 +02:00
|
|
|
used_tables_cache|= item->used_tables();
|
2006-05-18 05:48:48 +02:00
|
|
|
if (item->const_item())
|
|
|
|
and_tables_cache= (table_map) 0;
|
|
|
|
else
|
2006-03-24 21:44:54 +01:00
|
|
|
{
|
|
|
|
tmp_table_map= item->not_null_tables();
|
|
|
|
not_null_tables_cache|= tmp_table_map;
|
|
|
|
and_tables_cache&= tmp_table_map;
|
|
|
|
const_item_cache= FALSE;
|
|
|
|
}
|
2003-06-26 04:38:19 +02:00
|
|
|
with_sum_func= with_sum_func || item->with_sum_func;
|
2006-05-17 22:55:28 +02:00
|
|
|
with_subselect|= item->with_subselect;
|
2002-09-03 14:44:25 +02:00
|
|
|
if (item->maybe_null)
|
|
|
|
maybe_null=1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2003-12-19 18:52:13 +01:00
|
|
|
thd->lex->current_select->cond_count+= list.elements;
|
2000-07-31 21:29:14 +02:00
|
|
|
fix_length_and_dec();
|
2002-11-21 10:01:33 +01:00
|
|
|
fixed= 1;
|
2004-10-20 03:04:37 +02:00
|
|
|
return FALSE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
bool Item_cond::walk(Item_processor processor, bool walk_subquery, uchar *arg)
|
2003-07-02 12:12:18 +02:00
|
|
|
{
|
|
|
|
List_iterator_fast<Item> li(list);
|
|
|
|
Item *item;
|
|
|
|
while ((item= li++))
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
if (item->walk(processor, walk_subquery, arg))
|
2003-07-02 12:12:18 +02:00
|
|
|
return 1;
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
return Item_func::walk(processor, walk_subquery, arg);
|
2003-07-02 12:12:18 +02:00
|
|
|
}
|
|
|
|
|
2004-02-19 07:21:37 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Transform an Item_cond object with a transformer callback function
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
transform()
|
2006-09-07 20:06:37 +02:00
|
|
|
transformer the transformer callback function to be applied to the nodes
|
|
|
|
of the tree of the object
|
|
|
|
arg parameter to be passed to the transformer
|
2004-02-19 07:21:37 +01:00
|
|
|
|
|
|
|
DESCRIPTION
|
2006-09-07 20:06:37 +02:00
|
|
|
The function recursively applies the transform method to each
|
|
|
|
member item of the condition list.
|
2004-02-19 07:21:37 +01:00
|
|
|
If the call of the method for a member item returns a new item
|
|
|
|
the old item is substituted for a new one.
|
2006-09-07 20:06:37 +02:00
|
|
|
After this the transformer is applied to the root node
|
2004-02-19 07:21:37 +01:00
|
|
|
of the Item_cond object.
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
Item returned as the result of transformation of the root node
|
|
|
|
*/
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
Item *Item_cond::transform(Item_transformer transformer, uchar *arg)
|
2003-11-27 02:23:52 +01:00
|
|
|
{
|
2006-08-24 13:49:12 +02:00
|
|
|
DBUG_ASSERT(!current_thd->is_stmt_prepare());
|
|
|
|
|
2003-11-27 02:23:52 +01:00
|
|
|
List_iterator<Item> li(list);
|
|
|
|
Item *item;
|
|
|
|
while ((item= li++))
|
|
|
|
{
|
2004-02-19 07:21:37 +01:00
|
|
|
Item *new_item= item->transform(transformer, arg);
|
2003-11-27 02:23:52 +01:00
|
|
|
if (!new_item)
|
|
|
|
return 0;
|
2006-08-24 13:49:12 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
THD::change_item_tree() should be called only if the tree was
|
|
|
|
really transformed, i.e. when a new item has been created.
|
|
|
|
Otherwise we'll be allocating a lot of unnecessary memory for
|
|
|
|
change records at each execution.
|
|
|
|
*/
|
2003-11-27 02:23:52 +01:00
|
|
|
if (new_item != item)
|
2006-08-24 13:49:12 +02:00
|
|
|
current_thd->change_item_tree(li.ref(), new_item);
|
2003-11-27 02:23:52 +01:00
|
|
|
}
|
2004-02-19 07:21:37 +01:00
|
|
|
return Item_func::transform(transformer, arg);
|
2003-11-27 02:23:52 +01:00
|
|
|
}
|
|
|
|
|
2006-09-07 20:06:37 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Compile Item_cond object with a processor and a transformer callback functions
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
compile()
|
|
|
|
analyzer the analyzer callback function to be applied to the nodes
|
|
|
|
of the tree of the object
|
|
|
|
arg_p in/out parameter to be passed to the analyzer
|
|
|
|
transformer the transformer callback function to be applied to the nodes
|
|
|
|
of the tree of the object
|
|
|
|
arg_t parameter to be passed to the transformer
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
First the function applies the analyzer to the root node of
|
|
|
|
the Item_func object. Then if the analyzer succeeeds (returns TRUE)
|
|
|
|
the function recursively applies the compile method to member
|
|
|
|
item of the condition list.
|
|
|
|
If the call of the method for a member item returns a new item
|
|
|
|
the old item is substituted for a new one.
|
|
|
|
After this the transformer is applied to the root node
|
|
|
|
of the Item_cond object.
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
Item returned as the result of transformation of the root node
|
|
|
|
*/
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
Item *Item_cond::compile(Item_analyzer analyzer, uchar **arg_p,
|
|
|
|
Item_transformer transformer, uchar *arg_t)
|
2006-09-07 20:06:37 +02:00
|
|
|
{
|
|
|
|
if (!(this->*analyzer)(arg_p))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
List_iterator<Item> li(list);
|
|
|
|
Item *item;
|
|
|
|
while ((item= li++))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The same parameter value of arg_p must be passed
|
|
|
|
to analyze any argument of the condition formula.
|
|
|
|
*/
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *arg_v= *arg_p;
|
2006-09-07 20:06:37 +02:00
|
|
|
Item *new_item= item->compile(analyzer, &arg_v, transformer, arg_t);
|
|
|
|
if (new_item && new_item != item)
|
|
|
|
li.replace(new_item);
|
|
|
|
}
|
|
|
|
return Item_func::transform(transformer, arg_t);
|
|
|
|
}
|
|
|
|
|
2005-03-02 10:38:25 +01:00
|
|
|
void Item_cond::traverse_cond(Cond_traverser traverser,
|
|
|
|
void *arg, traverse_order order)
|
2004-12-17 21:13:22 +01:00
|
|
|
{
|
|
|
|
List_iterator<Item> li(list);
|
|
|
|
Item *item;
|
|
|
|
|
2004-12-20 10:58:00 +01:00
|
|
|
switch(order) {
|
|
|
|
case(PREFIX):
|
|
|
|
(*traverser)(this, arg);
|
|
|
|
while ((item= li++))
|
|
|
|
{
|
|
|
|
item->traverse_cond(traverser, arg, order);
|
|
|
|
}
|
2005-01-07 15:33:24 +01:00
|
|
|
(*traverser)(NULL, arg);
|
2004-12-20 10:58:00 +01:00
|
|
|
break;
|
|
|
|
case(POSTFIX):
|
|
|
|
while ((item= li++))
|
|
|
|
{
|
|
|
|
item->traverse_cond(traverser, arg, order);
|
|
|
|
}
|
|
|
|
(*traverser)(this, arg);
|
2004-12-17 21:13:22 +01:00
|
|
|
}
|
|
|
|
}
|
2004-02-19 07:21:37 +01:00
|
|
|
|
2005-02-07 17:13:57 +01:00
|
|
|
/*
|
|
|
|
Move SUM items out from item tree and replace with reference
|
|
|
|
|
|
|
|
SYNOPSIS
|
2005-02-08 13:41:09 +01:00
|
|
|
split_sum_func()
|
|
|
|
thd Thread handler
|
|
|
|
ref_pointer_array Pointer to array of reference fields
|
|
|
|
fields All fields in select
|
2005-02-07 17:13:57 +01:00
|
|
|
|
|
|
|
NOTES
|
|
|
|
This function is run on all expression (SELECT list, WHERE, HAVING etc)
|
|
|
|
that have or refer (HAVING) to a SUM expression.
|
|
|
|
|
|
|
|
The split is done to get an unique item for each SUM function
|
|
|
|
so that we can easily find and calculate them.
|
|
|
|
(Calculation done by update_sum_func() and copy_sum_funcs() in
|
|
|
|
sql_select.cc)
|
|
|
|
*/
|
|
|
|
|
2004-10-08 17:13:09 +02:00
|
|
|
void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array,
|
|
|
|
List<Item> &fields)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
List_iterator<Item> li(list);
|
|
|
|
Item *item;
|
2005-02-08 13:41:09 +01:00
|
|
|
while ((item= li++))
|
2005-10-15 23:32:37 +02:00
|
|
|
item->split_sum_func2(thd, ref_pointer_array, fields, li.ref(), TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
table_map
|
|
|
|
Item_cond::used_tables() const
|
|
|
|
{ // This caches used_tables
|
|
|
|
return used_tables_cache;
|
|
|
|
}
|
|
|
|
|
2003-06-26 04:38:19 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void Item_cond::update_used_tables()
|
|
|
|
{
|
2001-08-02 05:29:50 +02:00
|
|
|
List_iterator_fast<Item> li(list);
|
2000-07-31 21:29:14 +02:00
|
|
|
Item *item;
|
2003-06-26 04:38:19 +02:00
|
|
|
|
|
|
|
used_tables_cache=0;
|
|
|
|
const_item_cache=1;
|
2000-07-31 21:29:14 +02:00
|
|
|
while ((item=li++))
|
|
|
|
{
|
|
|
|
item->update_used_tables();
|
2003-06-26 04:38:19 +02:00
|
|
|
used_tables_cache|= item->used_tables();
|
2004-10-19 23:12:55 +02:00
|
|
|
const_item_cache&= item->const_item();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Item_cond::print(String *str)
|
|
|
|
{
|
|
|
|
str->append('(');
|
2001-08-02 05:29:50 +02:00
|
|
|
List_iterator_fast<Item> li(list);
|
2000-07-31 21:29:14 +02:00
|
|
|
Item *item;
|
|
|
|
if ((item=li++))
|
|
|
|
item->print(str);
|
|
|
|
while ((item=li++))
|
|
|
|
{
|
|
|
|
str->append(' ');
|
|
|
|
str->append(func_name());
|
|
|
|
str->append(' ');
|
|
|
|
item->print(str);
|
|
|
|
}
|
|
|
|
str->append(')');
|
|
|
|
}
|
|
|
|
|
2003-10-31 10:02:16 +01:00
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
void Item_cond::neg_arguments(THD *thd)
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
|
|
|
List_iterator<Item> li(list);
|
|
|
|
Item *item;
|
|
|
|
while ((item= li++)) /* Apply not transformation to the arguments */
|
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
Item *new_item= item->neg_transformer(thd);
|
|
|
|
if (!new_item)
|
|
|
|
{
|
2004-03-25 21:11:22 +01:00
|
|
|
if (!(new_item= new Item_func_not(item)))
|
|
|
|
return; // Fatal OEM error
|
2004-03-17 13:26:26 +01:00
|
|
|
}
|
|
|
|
VOID(li.replace(new_item));
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-11 14:57:35 +01:00
|
|
|
/*
|
2005-02-08 23:50:45 +01:00
|
|
|
Evaluation of AND(expr, expr, expr ...)
|
2002-11-11 14:57:35 +01:00
|
|
|
|
|
|
|
NOTES:
|
|
|
|
abort_if_null is set for AND expressions for which we don't care if the
|
|
|
|
result is NULL or 0. This is set for:
|
|
|
|
- WHERE clause
|
|
|
|
- HAVING clause
|
|
|
|
- IF(expression)
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
1 If all expressions are true
|
|
|
|
0 If all expressions are false or if we find a NULL expression and
|
|
|
|
'abort_on_null' is set.
|
|
|
|
NULL if all expression are either 1 or NULL
|
|
|
|
*/
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
longlong Item_cond_and::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2001-08-02 05:29:50 +02:00
|
|
|
List_iterator_fast<Item> li(list);
|
2000-07-31 21:29:14 +02:00
|
|
|
Item *item;
|
2002-11-11 14:57:35 +01:00
|
|
|
null_value= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
while ((item=li++))
|
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
if (!item->val_bool())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-11-11 14:57:35 +01:00
|
|
|
if (abort_on_null || !(null_value= item->null_value))
|
|
|
|
return 0; // return FALSE
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
2002-11-11 14:57:35 +01:00
|
|
|
return null_value ? 0 : 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-11-11 14:57:35 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong Item_cond_or::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2001-08-02 05:29:50 +02:00
|
|
|
List_iterator_fast<Item> li(list);
|
2000-07-31 21:29:14 +02:00
|
|
|
Item *item;
|
|
|
|
null_value=0;
|
|
|
|
while ((item=li++))
|
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
if (item->val_bool())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
null_value=0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (item->null_value)
|
|
|
|
null_value=1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-11-09 08:51:03 +01:00
|
|
|
/*
|
|
|
|
Create an AND expression from two expressions
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
and_expressions()
|
|
|
|
a expression or NULL
|
|
|
|
b expression.
|
|
|
|
org_item Don't modify a if a == *org_item
|
|
|
|
If a == NULL, org_item is set to point at b,
|
|
|
|
to ensure that future calls will not modify b.
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
This will not modify item pointed to by org_item or b
|
|
|
|
The idea is that one can call this in a loop and create and
|
|
|
|
'and' over all items without modifying any of the original items.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
NULL Error
|
|
|
|
Item
|
|
|
|
*/
|
|
|
|
|
|
|
|
Item *and_expressions(Item *a, Item *b, Item **org_item)
|
|
|
|
{
|
|
|
|
if (!a)
|
2002-12-02 12:41:08 +01:00
|
|
|
return (*org_item= (Item*) b);
|
2002-11-09 08:51:03 +01:00
|
|
|
if (a == *org_item)
|
|
|
|
{
|
|
|
|
Item_cond *res;
|
2002-12-02 12:41:08 +01:00
|
|
|
if ((res= new Item_cond_and(a, (Item*) b)))
|
2003-06-26 04:38:19 +02:00
|
|
|
{
|
2002-11-09 08:51:03 +01:00
|
|
|
res->used_tables_cache= a->used_tables() | b->used_tables();
|
2003-06-26 04:38:19 +02:00
|
|
|
res->not_null_tables_cache= a->not_null_tables() | b->not_null_tables();
|
|
|
|
}
|
2002-11-09 08:51:03 +01:00
|
|
|
return res;
|
|
|
|
}
|
2002-12-02 12:41:08 +01:00
|
|
|
if (((Item_cond_and*) a)->add((Item*) b))
|
2002-11-09 08:51:03 +01:00
|
|
|
return 0;
|
|
|
|
((Item_cond_and*) a)->used_tables_cache|= b->used_tables();
|
2003-06-26 04:38:19 +02:00
|
|
|
((Item_cond_and*) a)->not_null_tables_cache|= b->not_null_tables();
|
2002-11-09 08:51:03 +01:00
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong Item_func_isnull::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2002-05-04 10:11:00 +02:00
|
|
|
/*
|
|
|
|
Handle optimization if the argument can't be null
|
|
|
|
This has to be here because of the test in update_used_tables().
|
|
|
|
*/
|
2006-12-14 06:08:25 +01:00
|
|
|
if (!used_tables_cache && !with_subselect)
|
2002-05-07 18:08:56 +02:00
|
|
|
return cached_value;
|
2001-10-04 01:44:18 +02:00
|
|
|
return args[0]->is_null() ? 1: 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-04-22 23:01:19 +02:00
|
|
|
longlong Item_is_not_null_test::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2003-04-22 23:01:19 +02:00
|
|
|
DBUG_ENTER("Item_is_not_null_test::val_int");
|
2006-12-14 06:08:25 +01:00
|
|
|
if (!used_tables_cache && !with_subselect)
|
2003-04-22 23:01:19 +02:00
|
|
|
{
|
|
|
|
owner->was_null|= (!cached_value);
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("info", ("cached: %ld", (long) cached_value));
|
2003-04-22 23:01:19 +02:00
|
|
|
DBUG_RETURN(cached_value);
|
|
|
|
}
|
|
|
|
if (args[0]->is_null())
|
|
|
|
{
|
2006-02-14 22:36:11 +01:00
|
|
|
DBUG_PRINT("info", ("null"));
|
2003-04-22 23:01:19 +02:00
|
|
|
owner->was_null|= 1;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Optimize case of not_null_column IS NULL */
|
|
|
|
void Item_is_not_null_test::update_used_tables()
|
|
|
|
{
|
|
|
|
if (!args[0]->maybe_null)
|
|
|
|
{
|
|
|
|
used_tables_cache= 0; /* is always true */
|
|
|
|
cached_value= (longlong) 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
args[0]->update_used_tables();
|
2006-12-14 06:08:25 +01:00
|
|
|
if (!(used_tables_cache=args[0]->used_tables()) && !with_subselect)
|
2003-04-22 23:01:19 +02:00
|
|
|
{
|
|
|
|
/* Remember if the value is always NULL or never NULL */
|
|
|
|
cached_value= (longlong) !args[0]->is_null();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-02-14 10:47:41 +01:00
|
|
|
|
2003-10-12 16:56:05 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong Item_func_isnotnull::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2001-10-04 01:44:18 +02:00
|
|
|
return args[0]->is_null() ? 0 : 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-12 16:56:05 +02:00
|
|
|
void Item_func_isnotnull::print(String *str)
|
|
|
|
{
|
|
|
|
str->append('(');
|
|
|
|
args[0]->print(str);
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN(" is not null)"));
|
2003-10-12 16:56:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong Item_func_like::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2002-05-17 15:45:00 +02:00
|
|
|
String* res = args[0]->val_str(&tmp_value1);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (args[0]->null_value)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
2002-05-17 15:45:00 +02:00
|
|
|
String* res2 = args[1]->val_str(&tmp_value2);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (args[1]->null_value)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
null_value=0;
|
2002-05-17 15:45:00 +02:00
|
|
|
if (canDoTurboBM)
|
|
|
|
return turboBM_matches(res->ptr(), res->length()) ? 1 : 0;
|
2003-07-03 14:00:01 +02:00
|
|
|
return my_wildcmp(cmp.cmp_collation.collation,
|
2002-11-14 14:25:34 +01:00
|
|
|
res->ptr(),res->ptr()+res->length(),
|
|
|
|
res2->ptr(),res2->ptr()+res2->length(),
|
|
|
|
escape,wild_one,wild_many) ? 0 : 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* We can optimize a where if first character isn't a wildcard */
|
|
|
|
|
|
|
|
Item_func::optimize_type Item_func_like::select_optimize() const
|
|
|
|
{
|
2003-03-02 14:07:32 +01:00
|
|
|
if (args[1]->const_item())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-03-02 14:07:32 +01:00
|
|
|
String* res2= args[1]->val_str((String *)&tmp_value2);
|
|
|
|
|
|
|
|
if (!res2)
|
|
|
|
return OPTIMIZE_NONE;
|
|
|
|
|
|
|
|
if (*res2->ptr() != wild_many)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-03-02 14:07:32 +01:00
|
|
|
if (args[0]->result_type() != STRING_RESULT || *res2->ptr() != wild_one)
|
2000-07-31 21:29:14 +02:00
|
|
|
return OPTIMIZE_OP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return OPTIMIZE_NONE;
|
|
|
|
}
|
|
|
|
|
2003-02-12 20:55:37 +01:00
|
|
|
|
2005-07-01 06:05:42 +02:00
|
|
|
bool Item_func_like::fix_fields(THD *thd, Item **ref)
|
2002-05-17 15:45:00 +02:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
DBUG_ASSERT(fixed == 0);
|
2005-07-01 06:05:42 +02:00
|
|
|
if (Item_bool_func2::fix_fields(thd, ref) ||
|
|
|
|
escape_item->fix_fields(thd, &escape_item))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2002-05-17 15:45:00 +02:00
|
|
|
|
2004-06-22 17:27:16 +02:00
|
|
|
if (!escape_item->const_during_execution())
|
2002-05-17 15:45:00 +02:00
|
|
|
{
|
2004-06-22 17:27:16 +02:00
|
|
|
my_error(ER_WRONG_ARGUMENTS,MYF(0),"ESCAPE");
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2004-06-22 17:27:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (escape_item->const_item())
|
|
|
|
{
|
|
|
|
/* If we are on execution stage */
|
|
|
|
String *escape_str= escape_item->val_str(&tmp_value1);
|
2005-08-31 11:04:54 +02:00
|
|
|
if (escape_str)
|
|
|
|
{
|
2005-10-21 03:01:52 +02:00
|
|
|
if (escape_used_in_parsing && (
|
|
|
|
(((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) &&
|
|
|
|
escape_str->numchars() != 1) ||
|
|
|
|
escape_str->numchars() > 1)))
|
|
|
|
{
|
|
|
|
my_error(ER_WRONG_ARGUMENTS,MYF(0),"ESCAPE");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2005-10-05 14:33:39 +02:00
|
|
|
if (use_mb(cmp.cmp_collation.collation))
|
2005-08-31 11:04:54 +02:00
|
|
|
{
|
2005-09-21 20:10:51 +02:00
|
|
|
CHARSET_INFO *cs= escape_str->charset();
|
2005-08-31 11:04:54 +02:00
|
|
|
my_wc_t wc;
|
|
|
|
int rc= cs->cset->mb_wc(cs, &wc,
|
|
|
|
(const uchar*) escape_str->ptr(),
|
|
|
|
(const uchar*) escape_str->ptr() +
|
|
|
|
escape_str->length());
|
|
|
|
escape= (int) (rc > 0 ? wc : '\\');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-09-06 13:16:10 +02:00
|
|
|
/*
|
|
|
|
In the case of 8bit character set, we pass native
|
|
|
|
code instead of Unicode code as "escape" argument.
|
|
|
|
Convert to "cs" if charset of escape differs.
|
|
|
|
*/
|
2005-10-06 12:26:59 +02:00
|
|
|
CHARSET_INFO *cs= cmp.cmp_collation.collation;
|
2005-09-06 13:16:10 +02:00
|
|
|
uint32 unused;
|
|
|
|
if (escape_str->needs_conversion(escape_str->length(),
|
|
|
|
escape_str->charset(), cs, &unused))
|
|
|
|
{
|
|
|
|
char ch;
|
|
|
|
uint errors;
|
|
|
|
uint32 cnvlen= copy_and_convert(&ch, 1, cs, escape_str->ptr(),
|
|
|
|
escape_str->length(),
|
|
|
|
escape_str->charset(), &errors);
|
|
|
|
escape= cnvlen ? ch : '\\';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
escape= *(escape_str->ptr());
|
2005-08-31 11:04:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
escape= '\\';
|
2005-08-16 20:54:53 +02:00
|
|
|
|
2002-05-17 15:45:00 +02:00
|
|
|
/*
|
2004-06-22 17:27:16 +02:00
|
|
|
We could also do boyer-more for non-const items, but as we would have to
|
|
|
|
recompute the tables for each row it's not worth it.
|
2002-05-17 15:45:00 +02:00
|
|
|
*/
|
2004-06-22 17:27:16 +02:00
|
|
|
if (args[1]->const_item() && !use_strnxfrm(collation.collation) &&
|
|
|
|
!(specialflag & SPECIAL_NO_NEW_FUNC))
|
2002-05-17 15:45:00 +02:00
|
|
|
{
|
2004-06-22 17:27:16 +02:00
|
|
|
String* res2 = args[1]->val_str(&tmp_value2);
|
|
|
|
if (!res2)
|
2004-10-20 03:04:37 +02:00
|
|
|
return FALSE; // Null argument
|
2004-06-22 17:27:16 +02:00
|
|
|
|
|
|
|
const size_t len = res2->length();
|
|
|
|
const char* first = res2->ptr();
|
|
|
|
const char* last = first + len - 1;
|
|
|
|
/*
|
|
|
|
len must be > 2 ('%pattern%')
|
|
|
|
heuristic: only do TurboBM for pattern_len > 2
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (len > MIN_TURBOBM_PATTERN_LEN + 2 &&
|
|
|
|
*first == wild_many &&
|
|
|
|
*last == wild_many)
|
|
|
|
{
|
|
|
|
const char* tmp = first + 1;
|
|
|
|
for (; *tmp != wild_many && *tmp != wild_one && *tmp != escape; tmp++) ;
|
|
|
|
canDoTurboBM = (tmp == last) && !use_mb(args[0]->collation.collation);
|
|
|
|
}
|
|
|
|
if (canDoTurboBM)
|
|
|
|
{
|
|
|
|
pattern = first + 1;
|
2005-06-13 12:41:15 +02:00
|
|
|
pattern_len = (int) len - 2;
|
2004-06-22 17:27:16 +02:00
|
|
|
DBUG_PRINT("info", ("Initializing pattern: '%s'", first));
|
2005-06-13 12:41:15 +02:00
|
|
|
int *suff = (int*) thd->alloc((int) (sizeof(int)*
|
|
|
|
((pattern_len + 1)*2+
|
|
|
|
alphabet_size)));
|
2004-06-22 17:27:16 +02:00
|
|
|
bmGs = suff + pattern_len + 1;
|
|
|
|
bmBc = bmGs + pattern_len + 1;
|
|
|
|
turboBM_compute_good_suffix_shifts(suff);
|
|
|
|
turboBM_compute_bad_character_shifts();
|
|
|
|
DBUG_PRINT("info",("done"));
|
|
|
|
}
|
2002-05-17 15:45:00 +02:00
|
|
|
}
|
|
|
|
}
|
2004-10-20 03:04:37 +02:00
|
|
|
return FALSE;
|
2002-05-17 15:45:00 +02:00
|
|
|
}
|
|
|
|
|
2006-01-14 02:55:07 +01:00
|
|
|
void Item_func_like::cleanup()
|
|
|
|
{
|
|
|
|
canDoTurboBM= FALSE;
|
|
|
|
Item_bool_func2::cleanup();
|
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
#ifdef USE_REGEX
|
|
|
|
|
|
|
|
bool
|
2005-07-01 06:05:42 +02:00
|
|
|
Item_func_regex::fix_fields(THD *thd, Item **ref)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
DBUG_ASSERT(fixed == 0);
|
2004-12-14 01:36:19 +01:00
|
|
|
if ((!args[0]->fixed &&
|
2005-07-01 06:05:42 +02:00
|
|
|
args[0]->fix_fields(thd, args)) || args[0]->check_cols(1) ||
|
2005-02-08 23:50:45 +01:00
|
|
|
(!args[1]->fixed &&
|
2005-07-01 06:05:42 +02:00
|
|
|
args[1]->fix_fields(thd, args + 1)) || args[1]->check_cols(1))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE; /* purecov: inspected */
|
2000-07-31 21:29:14 +02:00
|
|
|
with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func;
|
2002-12-10 17:10:00 +01:00
|
|
|
max_length= 1;
|
|
|
|
decimals= 0;
|
2003-06-26 12:45:04 +02:00
|
|
|
|
2006-06-30 09:26:36 +02:00
|
|
|
if (agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2002-10-25 10:58:32 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
used_tables_cache=args[0]->used_tables() | args[1]->used_tables();
|
2003-06-26 04:38:19 +02:00
|
|
|
not_null_tables_cache= (args[0]->not_null_tables() |
|
|
|
|
args[1]->not_null_tables());
|
2000-07-31 21:29:14 +02:00
|
|
|
const_item_cache=args[0]->const_item() && args[1]->const_item();
|
|
|
|
if (!regex_compiled && args[1]->const_item())
|
|
|
|
{
|
|
|
|
char buff[MAX_FIELD_WIDTH];
|
2003-03-07 10:39:53 +01:00
|
|
|
String tmp(buff,sizeof(buff),&my_charset_bin);
|
2000-07-31 21:29:14 +02:00
|
|
|
String *res=args[1]->val_str(&tmp);
|
|
|
|
if (args[1]->null_value)
|
|
|
|
{ // Will always return NULL
|
|
|
|
maybe_null=1;
|
2004-10-20 03:04:37 +02:00
|
|
|
return FALSE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
int error;
|
2005-09-29 02:08:24 +02:00
|
|
|
if ((error= my_regcomp(&preg,res->c_ptr(),
|
|
|
|
((cmp_collation.collation->state &
|
|
|
|
(MY_CS_BINSORT | MY_CS_CSSORT)) ?
|
|
|
|
REG_EXTENDED | REG_NOSUB :
|
|
|
|
REG_EXTENDED | REG_NOSUB | REG_ICASE),
|
|
|
|
cmp_collation.collation)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-09-29 02:08:24 +02:00
|
|
|
(void) my_regerror(error,&preg,buff,sizeof(buff));
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_REGEXP_ERROR, MYF(0), buff);
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
regex_compiled=regex_is_const=1;
|
|
|
|
maybe_null=args[0]->maybe_null;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
maybe_null=1;
|
2002-11-21 10:01:33 +01:00
|
|
|
fixed= 1;
|
2004-10-20 03:04:37 +02:00
|
|
|
return FALSE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-02-12 20:55:37 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong Item_func_regex::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
char buff[MAX_FIELD_WIDTH];
|
2003-03-07 10:39:53 +01:00
|
|
|
String *res, tmp(buff,sizeof(buff),&my_charset_bin);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
res=args[0]->val_str(&tmp);
|
|
|
|
if (args[0]->null_value)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!regex_is_const)
|
|
|
|
{
|
|
|
|
char buff2[MAX_FIELD_WIDTH];
|
2003-03-07 10:39:53 +01:00
|
|
|
String *res2, tmp2(buff2,sizeof(buff2),&my_charset_bin);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
res2= args[1]->val_str(&tmp2);
|
|
|
|
if (args[1]->null_value)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
2004-02-16 09:03:25 +01:00
|
|
|
if (!regex_compiled || stringcmp(res2,&prev_regexp))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
prev_regexp.copy(*res2);
|
|
|
|
if (regex_compiled)
|
|
|
|
{
|
2005-09-29 02:08:24 +02:00
|
|
|
my_regfree(&preg);
|
2000-07-31 21:29:14 +02:00
|
|
|
regex_compiled=0;
|
|
|
|
}
|
2005-09-29 03:20:31 +02:00
|
|
|
if (my_regcomp(&preg,res2->c_ptr_safe(),
|
2005-09-29 02:08:24 +02:00
|
|
|
((cmp_collation.collation->state &
|
|
|
|
(MY_CS_BINSORT | MY_CS_CSSORT)) ?
|
|
|
|
REG_EXTENDED | REG_NOSUB :
|
|
|
|
REG_EXTENDED | REG_NOSUB | REG_ICASE),
|
|
|
|
cmp_collation.collation))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
regex_compiled=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
null_value=0;
|
2006-07-03 21:41:15 +02:00
|
|
|
return my_regexec(&preg,res->c_ptr_safe(),0,(my_regmatch_t*) 0,0) ? 0 : 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-19 12:26:39 +02:00
|
|
|
void Item_func_regex::cleanup()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-06-19 12:26:39 +02:00
|
|
|
DBUG_ENTER("Item_func_regex::cleanup");
|
|
|
|
Item_bool_func::cleanup();
|
2000-07-31 21:29:14 +02:00
|
|
|
if (regex_compiled)
|
|
|
|
{
|
2005-09-29 02:08:24 +02:00
|
|
|
my_regfree(&preg);
|
2000-07-31 21:29:14 +02:00
|
|
|
regex_compiled=0;
|
|
|
|
}
|
2004-06-19 12:26:39 +02:00
|
|
|
DBUG_VOID_RETURN;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2004-06-19 12:26:39 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
#endif /* USE_REGEX */
|
2002-05-17 15:45:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef LIKE_CMP_TOUPPER
|
2002-06-04 07:23:57 +02:00
|
|
|
#define likeconv(cs,A) (uchar) (cs)->toupper(A)
|
2002-05-17 15:45:00 +02:00
|
|
|
#else
|
2002-06-04 07:23:57 +02:00
|
|
|
#define likeconv(cs,A) (uchar) (cs)->sort_order[(uchar) (A)]
|
2002-05-17 15:45:00 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
turboBM_compute_suffixes()
|
|
|
|
Precomputation dependent only on pattern_len.
|
|
|
|
**********************************************************************/
|
|
|
|
|
2003-01-10 00:55:05 +01:00
|
|
|
void Item_func_like::turboBM_compute_suffixes(int *suff)
|
2002-05-17 15:45:00 +02:00
|
|
|
{
|
|
|
|
const int plm1 = pattern_len - 1;
|
|
|
|
int f = 0;
|
|
|
|
int g = plm1;
|
2002-06-04 07:23:57 +02:00
|
|
|
int *const splm1 = suff + plm1;
|
2004-02-03 15:14:23 +01:00
|
|
|
CHARSET_INFO *cs= cmp.cmp_collation.collation;
|
2002-05-17 15:45:00 +02:00
|
|
|
|
|
|
|
*splm1 = pattern_len;
|
|
|
|
|
2004-08-18 09:07:54 +02:00
|
|
|
if (!cs->sort_order)
|
2002-05-17 15:45:00 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = pattern_len - 2; i >= 0; i--)
|
|
|
|
{
|
|
|
|
int tmp = *(splm1 + i - f);
|
|
|
|
if (g < i && tmp < i - g)
|
|
|
|
suff[i] = tmp;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (i < g)
|
|
|
|
g = i; // g = min(i, g)
|
|
|
|
f = i;
|
|
|
|
while (g >= 0 && pattern[g] == pattern[g + plm1 - f])
|
|
|
|
g--;
|
|
|
|
suff[i] = f - g;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = pattern_len - 2; 0 <= i; --i)
|
|
|
|
{
|
|
|
|
int tmp = *(splm1 + i - f);
|
|
|
|
if (g < i && tmp < i - g)
|
|
|
|
suff[i] = tmp;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (i < g)
|
|
|
|
g = i; // g = min(i, g)
|
|
|
|
f = i;
|
2003-01-10 00:55:05 +01:00
|
|
|
while (g >= 0 &&
|
2003-01-18 02:13:37 +01:00
|
|
|
likeconv(cs, pattern[g]) == likeconv(cs, pattern[g + plm1 - f]))
|
2002-05-17 15:45:00 +02:00
|
|
|
g--;
|
|
|
|
suff[i] = f - g;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
turboBM_compute_good_suffix_shifts()
|
|
|
|
Precomputation dependent only on pattern_len.
|
|
|
|
**********************************************************************/
|
|
|
|
|
2003-01-10 00:55:05 +01:00
|
|
|
void Item_func_like::turboBM_compute_good_suffix_shifts(int *suff)
|
2002-05-17 15:45:00 +02:00
|
|
|
{
|
|
|
|
turboBM_compute_suffixes(suff);
|
|
|
|
|
2003-01-10 00:55:05 +01:00
|
|
|
int *end = bmGs + pattern_len;
|
|
|
|
int *k;
|
2002-05-17 15:45:00 +02:00
|
|
|
for (k = bmGs; k < end; k++)
|
|
|
|
*k = pattern_len;
|
|
|
|
|
|
|
|
int tmp;
|
|
|
|
int i;
|
|
|
|
int j = 0;
|
|
|
|
const int plm1 = pattern_len - 1;
|
|
|
|
for (i = plm1; i > -1; i--)
|
|
|
|
{
|
|
|
|
if (suff[i] == i + 1)
|
|
|
|
{
|
|
|
|
for (tmp = plm1 - i; j < tmp; j++)
|
|
|
|
{
|
2003-01-10 00:55:05 +01:00
|
|
|
int *tmp2 = bmGs + j;
|
2002-05-17 15:45:00 +02:00
|
|
|
if (*tmp2 == pattern_len)
|
|
|
|
*tmp2 = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-10 00:55:05 +01:00
|
|
|
int *tmp2;
|
2002-05-17 15:45:00 +02:00
|
|
|
for (tmp = plm1 - i; j < tmp; j++)
|
|
|
|
{
|
|
|
|
tmp2 = bmGs + j;
|
|
|
|
if (*tmp2 == pattern_len)
|
|
|
|
*tmp2 = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp2 = bmGs + plm1;
|
|
|
|
for (i = 0; i <= pattern_len - 2; i++)
|
|
|
|
*(tmp2 - suff[i]) = plm1 - i;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
turboBM_compute_bad_character_shifts()
|
|
|
|
Precomputation dependent on pattern_len.
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
void Item_func_like::turboBM_compute_bad_character_shifts()
|
|
|
|
{
|
2002-06-04 07:23:57 +02:00
|
|
|
int *i;
|
|
|
|
int *end = bmBc + alphabet_size;
|
|
|
|
int j;
|
|
|
|
const int plm1 = pattern_len - 1;
|
2004-02-03 15:14:23 +01:00
|
|
|
CHARSET_INFO *cs= cmp.cmp_collation.collation;
|
2002-06-04 07:23:57 +02:00
|
|
|
|
2002-05-17 15:45:00 +02:00
|
|
|
for (i = bmBc; i < end; i++)
|
|
|
|
*i = pattern_len;
|
|
|
|
|
2004-08-18 09:07:54 +02:00
|
|
|
if (!cs->sort_order)
|
2002-06-04 07:23:57 +02:00
|
|
|
{
|
2002-05-17 15:45:00 +02:00
|
|
|
for (j = 0; j < plm1; j++)
|
2003-01-10 00:55:05 +01:00
|
|
|
bmBc[(uint) (uchar) pattern[j]] = plm1 - j;
|
2002-06-04 07:23:57 +02:00
|
|
|
}
|
2002-05-17 15:45:00 +02:00
|
|
|
else
|
2002-06-04 07:23:57 +02:00
|
|
|
{
|
2002-05-17 15:45:00 +02:00
|
|
|
for (j = 0; j < plm1; j++)
|
2003-01-18 02:13:37 +01:00
|
|
|
bmBc[(uint) likeconv(cs,pattern[j])] = plm1 - j;
|
2002-06-04 07:23:57 +02:00
|
|
|
}
|
2002-05-17 15:45:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
turboBM_matches()
|
|
|
|
Search for pattern in text, returns true/false for match/no match
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
bool Item_func_like::turboBM_matches(const char* text, int text_len) const
|
|
|
|
{
|
|
|
|
register int bcShift;
|
|
|
|
register int turboShift;
|
|
|
|
int shift = pattern_len;
|
|
|
|
int j = 0;
|
|
|
|
int u = 0;
|
2004-02-03 15:14:23 +01:00
|
|
|
CHARSET_INFO *cs= cmp.cmp_collation.collation;
|
2002-05-17 15:45:00 +02:00
|
|
|
|
2003-01-10 00:55:05 +01:00
|
|
|
const int plm1= pattern_len - 1;
|
|
|
|
const int tlmpl= text_len - pattern_len;
|
2002-05-17 15:45:00 +02:00
|
|
|
|
|
|
|
/* Searching */
|
2004-08-18 09:07:54 +02:00
|
|
|
if (!cs->sort_order)
|
2002-05-17 15:45:00 +02:00
|
|
|
{
|
|
|
|
while (j <= tlmpl)
|
|
|
|
{
|
2003-01-10 00:55:05 +01:00
|
|
|
register int i= plm1;
|
2002-05-17 15:45:00 +02:00
|
|
|
while (i >= 0 && pattern[i] == text[i + j])
|
|
|
|
{
|
|
|
|
i--;
|
|
|
|
if (i == plm1 - shift)
|
2003-01-10 00:55:05 +01:00
|
|
|
i-= u;
|
2002-05-17 15:45:00 +02:00
|
|
|
}
|
|
|
|
if (i < 0)
|
2002-11-29 15:40:18 +01:00
|
|
|
return 1;
|
2002-05-17 15:45:00 +02:00
|
|
|
|
|
|
|
register const int v = plm1 - i;
|
|
|
|
turboShift = u - v;
|
2003-01-10 00:55:05 +01:00
|
|
|
bcShift = bmBc[(uint) (uchar) text[i + j]] - plm1 + i;
|
2002-05-17 15:45:00 +02:00
|
|
|
shift = max(turboShift, bcShift);
|
|
|
|
shift = max(shift, bmGs[i]);
|
|
|
|
if (shift == bmGs[i])
|
|
|
|
u = min(pattern_len - shift, v);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (turboShift < bcShift)
|
|
|
|
shift = max(shift, u + 1);
|
|
|
|
u = 0;
|
|
|
|
}
|
2003-01-10 00:55:05 +01:00
|
|
|
j+= shift;
|
2002-05-17 15:45:00 +02:00
|
|
|
}
|
2002-11-29 15:40:18 +01:00
|
|
|
return 0;
|
2002-05-17 15:45:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (j <= tlmpl)
|
|
|
|
{
|
|
|
|
register int i = plm1;
|
2002-06-04 07:23:57 +02:00
|
|
|
while (i >= 0 && likeconv(cs,pattern[i]) == likeconv(cs,text[i + j]))
|
2002-05-17 15:45:00 +02:00
|
|
|
{
|
|
|
|
i--;
|
|
|
|
if (i == plm1 - shift)
|
2003-01-10 00:55:05 +01:00
|
|
|
i-= u;
|
2002-05-17 15:45:00 +02:00
|
|
|
}
|
|
|
|
if (i < 0)
|
2002-11-29 15:40:18 +01:00
|
|
|
return 1;
|
2002-05-17 15:45:00 +02:00
|
|
|
|
|
|
|
register const int v = plm1 - i;
|
|
|
|
turboShift = u - v;
|
2003-01-18 02:13:37 +01:00
|
|
|
bcShift = bmBc[(uint) likeconv(cs, text[i + j])] - plm1 + i;
|
2002-05-17 15:45:00 +02:00
|
|
|
shift = max(turboShift, bcShift);
|
|
|
|
shift = max(shift, bmGs[i]);
|
|
|
|
if (shift == bmGs[i])
|
|
|
|
u = min(pattern_len - shift, v);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (turboShift < bcShift)
|
|
|
|
shift = max(shift, u + 1);
|
|
|
|
u = 0;
|
|
|
|
}
|
2003-01-10 00:55:05 +01:00
|
|
|
j+= shift;
|
2002-05-17 15:45:00 +02:00
|
|
|
}
|
2002-11-29 15:40:18 +01:00
|
|
|
return 0;
|
2002-05-17 15:45:00 +02:00
|
|
|
}
|
|
|
|
}
|
2002-06-29 15:25:09 +02:00
|
|
|
|
2002-06-30 17:57:21 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Make a logical XOR of the arguments.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
val_int()
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
If either operator is NULL, return NULL.
|
|
|
|
|
|
|
|
NOTE
|
|
|
|
As we don't do any index optimization on XOR this is not going to be
|
|
|
|
very fast to use.
|
|
|
|
|
|
|
|
TODO (low priority)
|
|
|
|
Change this to be optimized as:
|
|
|
|
A XOR B -> (A) == 1 AND (B) <> 1) OR (A <> 1 AND (B) == 1)
|
|
|
|
To be able to do this, we would however first have to extend the MySQL
|
|
|
|
range optimizer to handle OR better.
|
|
|
|
*/
|
|
|
|
|
2002-06-29 15:25:09 +02:00
|
|
|
longlong Item_cond_xor::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2002-06-29 15:25:09 +02:00
|
|
|
List_iterator<Item> li(list);
|
|
|
|
Item *item;
|
|
|
|
int result=0;
|
2002-06-30 17:57:21 +02:00
|
|
|
null_value=0;
|
2002-06-29 15:25:09 +02:00
|
|
|
while ((item=li++))
|
|
|
|
{
|
2002-06-30 17:57:21 +02:00
|
|
|
result^= (item->val_int() != 0);
|
|
|
|
if (item->null_value)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0;
|
|
|
|
}
|
2002-06-29 15:25:09 +02:00
|
|
|
}
|
2002-06-30 17:57:21 +02:00
|
|
|
return (longlong) result;
|
2002-06-29 15:25:09 +02:00
|
|
|
}
|
2003-10-31 10:02:16 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Apply NOT transformation to the item and return a new one.
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
SYNOPSIS
|
2003-10-31 10:02:16 +01:00
|
|
|
neg_transformer()
|
2004-03-17 13:26:26 +01:00
|
|
|
thd thread handler
|
2003-10-31 10:02:16 +01:00
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Transform the item using next rules:
|
|
|
|
a AND b AND ... -> NOT(a) OR NOT(b) OR ...
|
|
|
|
a OR b OR ... -> NOT(a) AND NOT(b) AND ...
|
|
|
|
NOT(a) -> a
|
|
|
|
a = b -> a != b
|
|
|
|
a != b -> a = b
|
|
|
|
a < b -> a >= b
|
|
|
|
a >= b -> a < b
|
|
|
|
a > b -> a <= b
|
|
|
|
a <= b -> a > b
|
|
|
|
IS NULL(a) -> IS NOT NULL(a)
|
|
|
|
IS NOT NULL(a) -> IS NULL(a)
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
New item or
|
|
|
|
NULL if we cannot apply NOT transformation (see Item::neg_transformer()).
|
|
|
|
*/
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
Item *Item_func_not::neg_transformer(THD *thd) /* NOT(x) -> x */
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-08-31 20:10:57 +02:00
|
|
|
return args[0];
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
|
|
|
|
Item *Item_bool_rowready_func2::neg_transformer(THD *thd)
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
Item *item= negated_item();
|
|
|
|
return item;
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
|
|
|
|
/* a IS NULL -> a IS NOT NULL */
|
|
|
|
Item *Item_func_isnull::neg_transformer(THD *thd)
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
Item *item= new Item_func_isnotnull(args[0]);
|
|
|
|
return item;
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
|
|
|
|
/* a IS NOT NULL -> a IS NULL */
|
|
|
|
Item *Item_func_isnotnull::neg_transformer(THD *thd)
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
Item *item= new Item_func_isnull(args[0]);
|
|
|
|
return item;
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
|
|
|
|
Item *Item_cond_and::neg_transformer(THD *thd) /* NOT(a AND b AND ...) -> */
|
|
|
|
/* NOT a OR NOT b OR ... */
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
neg_arguments(thd);
|
|
|
|
Item *item= new Item_cond_or(list);
|
|
|
|
return item;
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
|
|
|
|
Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */
|
|
|
|
/* NOT a AND NOT b AND ... */
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
neg_arguments(thd);
|
|
|
|
Item *item= new Item_cond_and(list);
|
|
|
|
return item;
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
|
2006-07-21 01:04:04 +02:00
|
|
|
Item *Item_func_nop_all::neg_transformer(THD *thd)
|
|
|
|
{
|
|
|
|
/* "NOT (e $cmp$ ANY (SELECT ...)) -> e $rev_cmp$" ALL (SELECT ...) */
|
|
|
|
Item_func_not_all *new_item= new Item_func_not_all(args[0]);
|
|
|
|
Item_allany_subselect *allany= (Item_allany_subselect*)args[0];
|
|
|
|
allany->func= allany->func_creator(FALSE);
|
|
|
|
allany->all= !allany->all;
|
|
|
|
allany->upper_item= new_item;
|
|
|
|
return new_item;
|
|
|
|
}
|
|
|
|
|
|
|
|
Item *Item_func_not_all::neg_transformer(THD *thd)
|
|
|
|
{
|
|
|
|
/* "NOT (e $cmp$ ALL (SELECT ...)) -> e $rev_cmp$" ANY (SELECT ...) */
|
|
|
|
Item_func_nop_all *new_item= new Item_func_nop_all(args[0]);
|
|
|
|
Item_allany_subselect *allany= (Item_allany_subselect*)args[0];
|
|
|
|
allany->all= !allany->all;
|
|
|
|
allany->func= allany->func_creator(TRUE);
|
|
|
|
allany->upper_item= new_item;
|
|
|
|
return new_item;
|
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
Item *Item_func_eq::negated_item() /* a = b -> a != b */
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
return new Item_func_ne(args[0], args[1]);
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
|
|
|
|
Item *Item_func_ne::negated_item() /* a != b -> a = b */
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
return new Item_func_eq(args[0], args[1]);
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
|
|
|
|
Item *Item_func_lt::negated_item() /* a < b -> a >= b */
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
return new Item_func_ge(args[0], args[1]);
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
|
|
|
|
Item *Item_func_ge::negated_item() /* a >= b -> a < b */
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
return new Item_func_lt(args[0], args[1]);
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
|
|
|
|
Item *Item_func_gt::negated_item() /* a > b -> a <= b */
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
return new Item_func_le(args[0], args[1]);
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
|
|
|
|
Item *Item_func_le::negated_item() /* a <= b -> a > b */
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
return new Item_func_gt(args[0], args[1]);
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
|
|
|
|
2004-03-17 13:26:26 +01:00
|
|
|
// just fake method, should never be called
|
|
|
|
Item *Item_bool_rowready_func2::negated_item()
|
2003-10-31 10:02:16 +01:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
DBUG_ASSERT(0);
|
|
|
|
return 0;
|
2003-10-31 10:02:16 +01:00
|
|
|
}
|
2003-11-27 02:23:52 +01:00
|
|
|
|
|
|
|
Item_equal::Item_equal(Item_field *f1, Item_field *f2)
|
|
|
|
: Item_bool_func(), const_item(0), eval_item(0), cond_false(0)
|
|
|
|
{
|
|
|
|
const_item_cache= 0;
|
|
|
|
fields.push_back(f1);
|
|
|
|
fields.push_back(f2);
|
|
|
|
}
|
|
|
|
|
|
|
|
Item_equal::Item_equal(Item *c, Item_field *f)
|
|
|
|
: Item_bool_func(), eval_item(0), cond_false(0)
|
|
|
|
{
|
|
|
|
const_item_cache= 0;
|
|
|
|
fields.push_back(f);
|
|
|
|
const_item= c;
|
|
|
|
}
|
|
|
|
|
2005-03-03 15:38:59 +01:00
|
|
|
|
2003-11-27 02:23:52 +01:00
|
|
|
Item_equal::Item_equal(Item_equal *item_equal)
|
|
|
|
: Item_bool_func(), eval_item(0), cond_false(0)
|
|
|
|
{
|
|
|
|
const_item_cache= 0;
|
|
|
|
List_iterator_fast<Item_field> li(item_equal->fields);
|
|
|
|
Item_field *item;
|
|
|
|
while ((item= li++))
|
|
|
|
{
|
|
|
|
fields.push_back(item);
|
|
|
|
}
|
|
|
|
const_item= item_equal->const_item;
|
|
|
|
cond_false= item_equal->cond_false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item_equal::add(Item *c)
|
|
|
|
{
|
|
|
|
if (cond_false)
|
|
|
|
return;
|
|
|
|
if (!const_item)
|
|
|
|
{
|
|
|
|
const_item= c;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Item_func_eq *func= new Item_func_eq(c, const_item);
|
|
|
|
func->set_cmp_func();
|
2004-10-19 23:12:55 +02:00
|
|
|
func->quick_fix_field();
|
2006-04-01 07:26:17 +02:00
|
|
|
if ((cond_false= !func->val_int()))
|
|
|
|
const_item_cache= 1;
|
2003-11-27 02:23:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Item_equal::add(Item_field *f)
|
|
|
|
{
|
|
|
|
fields.push_back(f);
|
|
|
|
}
|
|
|
|
|
2004-02-19 07:21:37 +01:00
|
|
|
uint Item_equal::members()
|
|
|
|
{
|
2005-03-03 15:38:59 +01:00
|
|
|
return fields.elements;
|
2004-02-19 07:21:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Check whether a field is referred in the multiple equality
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
contains()
|
2005-02-08 23:50:45 +01:00
|
|
|
field field whose occurrence is to be checked
|
2004-02-19 07:21:37 +01:00
|
|
|
|
|
|
|
DESCRIPTION
|
2005-02-08 23:50:45 +01:00
|
|
|
The function checks whether field is occurred in the Item_equal object
|
2004-02-19 07:21:37 +01:00
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
1 if nultiple equality contains a reference to field
|
|
|
|
0 otherwise
|
|
|
|
*/
|
|
|
|
|
2003-11-27 02:23:52 +01:00
|
|
|
bool Item_equal::contains(Field *field)
|
|
|
|
{
|
|
|
|
List_iterator_fast<Item_field> it(fields);
|
|
|
|
Item_field *item;
|
|
|
|
while ((item= it++))
|
|
|
|
{
|
|
|
|
if (field->eq(item->field))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-02-19 07:21:37 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Join members of another Item_equal object
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
merge()
|
|
|
|
item multiple equality whose members are to be joined
|
|
|
|
|
|
|
|
DESCRIPTION
|
2005-02-08 23:50:45 +01:00
|
|
|
The function actually merges two multiple equalities.
|
2004-02-19 07:21:37 +01:00
|
|
|
After this operation the Item_equal object additionally contains
|
|
|
|
the field items of another item of the type Item_equal.
|
|
|
|
If the optional constant items are not equal the cond_false flag is
|
|
|
|
set to 1.
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
none
|
|
|
|
*/
|
|
|
|
|
2003-11-27 02:23:52 +01:00
|
|
|
void Item_equal::merge(Item_equal *item)
|
|
|
|
{
|
|
|
|
fields.concat(&item->fields);
|
|
|
|
Item *c= item->const_item;
|
|
|
|
if (c)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The flag cond_false will be set to 1 after this, if
|
|
|
|
the multiple equality already contains a constant and its
|
|
|
|
value is not equal to the value of c.
|
|
|
|
*/
|
2005-11-26 03:51:44 +01:00
|
|
|
add(c);
|
2003-11-27 02:23:52 +01:00
|
|
|
}
|
|
|
|
cond_false|= item->cond_false;
|
|
|
|
}
|
|
|
|
|
2004-02-19 07:21:37 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Order field items in multiple equality according to a sorting criteria
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
sort()
|
|
|
|
cmp function to compare field item
|
|
|
|
arg context extra parameter for the cmp function
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
The function perform ordering of the field items in the Item_equal
|
|
|
|
object according to the criteria determined by the cmp callback parameter.
|
|
|
|
If cmp(item_field1,item_field2,arg)<0 than item_field1 must be
|
|
|
|
placed after item_fiel2.
|
|
|
|
|
|
|
|
IMPLEMENTATION
|
|
|
|
The function sorts field items by the exchange sort algorithm.
|
|
|
|
The list of field items is looked through and whenever two neighboring
|
|
|
|
members follow in a wrong order they are swapped. This is performed
|
|
|
|
again and again until we get all members in a right order.
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
None
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Item_equal::sort(Item_field_cmpfunc cmp, void *arg)
|
2003-11-27 02:23:52 +01:00
|
|
|
{
|
|
|
|
bool swap;
|
|
|
|
List_iterator<Item_field> it(fields);
|
|
|
|
do
|
|
|
|
{
|
|
|
|
Item_field *item1= it++;
|
|
|
|
Item_field **ref1= it.ref();
|
|
|
|
Item_field *item2;
|
|
|
|
|
|
|
|
swap= FALSE;
|
|
|
|
while ((item2= it++))
|
|
|
|
{
|
2004-02-19 07:21:37 +01:00
|
|
|
Item_field **ref2= it.ref();
|
|
|
|
if (cmp(item1, item2, arg) < 0)
|
2003-11-27 02:23:52 +01:00
|
|
|
{
|
|
|
|
Item_field *item= *ref1;
|
|
|
|
*ref1= *ref2;
|
|
|
|
*ref2= item;
|
|
|
|
swap= TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
item1= item2;
|
|
|
|
ref1= ref2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
it.rewind();
|
|
|
|
} while (swap);
|
|
|
|
}
|
|
|
|
|
2006-04-01 07:26:17 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Check appearance of new constant items in the multiple equality object
|
|
|
|
|
|
|
|
SYNOPSIS
|
2006-04-04 06:02:40 +02:00
|
|
|
update_const()
|
2006-04-01 07:26:17 +02:00
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
The function checks appearance of new constant items among
|
|
|
|
the members of multiple equalities. Each new constant item is
|
|
|
|
compared with the designated constant item if there is any in the
|
|
|
|
multiple equality. If there is none the first new constant item
|
|
|
|
becomes designated.
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
none
|
|
|
|
*/
|
|
|
|
|
2006-04-04 06:02:40 +02:00
|
|
|
void Item_equal::update_const()
|
2006-04-01 07:26:17 +02:00
|
|
|
{
|
|
|
|
List_iterator<Item_field> it(fields);
|
|
|
|
Item *item;
|
|
|
|
while ((item= it++))
|
|
|
|
{
|
|
|
|
if (item->const_item())
|
|
|
|
{
|
|
|
|
it.remove();
|
|
|
|
add(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-01 06:05:42 +02:00
|
|
|
bool Item_equal::fix_fields(THD *thd, Item **ref)
|
2003-11-27 02:23:52 +01:00
|
|
|
{
|
|
|
|
List_iterator_fast<Item_field> li(fields);
|
|
|
|
Item *item;
|
|
|
|
not_null_tables_cache= used_tables_cache= 0;
|
|
|
|
const_item_cache= 0;
|
2006-04-01 07:26:17 +02:00
|
|
|
while ((item= li++))
|
2003-11-27 02:23:52 +01:00
|
|
|
{
|
|
|
|
table_map tmp_table_map;
|
|
|
|
used_tables_cache|= item->used_tables();
|
|
|
|
tmp_table_map= item->not_null_tables();
|
|
|
|
not_null_tables_cache|= tmp_table_map;
|
|
|
|
if (item->maybe_null)
|
|
|
|
maybe_null=1;
|
|
|
|
}
|
|
|
|
fix_length_and_dec();
|
|
|
|
fixed= 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item_equal::update_used_tables()
|
|
|
|
{
|
|
|
|
List_iterator_fast<Item_field> li(fields);
|
|
|
|
Item *item;
|
|
|
|
not_null_tables_cache= used_tables_cache= 0;
|
2004-02-19 07:21:37 +01:00
|
|
|
if ((const_item_cache= cond_false))
|
|
|
|
return;
|
2003-11-27 02:23:52 +01:00
|
|
|
while ((item=li++))
|
|
|
|
{
|
|
|
|
item->update_used_tables();
|
|
|
|
used_tables_cache|= item->used_tables();
|
|
|
|
const_item_cache&= item->const_item();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
longlong Item_equal::val_int()
|
|
|
|
{
|
2006-01-11 20:49:43 +01:00
|
|
|
Item_field *item_field;
|
2003-11-27 02:23:52 +01:00
|
|
|
if (cond_false)
|
|
|
|
return 0;
|
|
|
|
List_iterator_fast<Item_field> it(fields);
|
|
|
|
Item *item= const_item ? const_item : it++;
|
|
|
|
if ((null_value= item->null_value))
|
|
|
|
return 0;
|
|
|
|
eval_item->store_value(item);
|
2006-01-11 20:49:43 +01:00
|
|
|
while ((item_field= it++))
|
2003-11-27 02:23:52 +01:00
|
|
|
{
|
2006-01-11 20:49:43 +01:00
|
|
|
/* Skip fields of non-const tables. They haven't been read yet */
|
|
|
|
if (item_field->field->table->const_table)
|
|
|
|
{
|
|
|
|
if ((null_value= item_field->null_value) || eval_item->cmp(item_field))
|
|
|
|
return 0;
|
|
|
|
}
|
2003-11-27 02:23:52 +01:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item_equal::fix_length_and_dec()
|
|
|
|
{
|
2007-02-09 21:54:50 +01:00
|
|
|
Item *item= get_first();
|
2005-02-08 23:50:45 +01:00
|
|
|
eval_item= cmp_item::get_comparator(item->result_type(),
|
|
|
|
item->collation.collation);
|
2003-11-27 02:23:52 +01:00
|
|
|
}
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
bool Item_equal::walk(Item_processor processor, bool walk_subquery, uchar *arg)
|
2003-11-27 02:23:52 +01:00
|
|
|
{
|
|
|
|
List_iterator_fast<Item_field> it(fields);
|
|
|
|
Item *item;
|
|
|
|
while ((item= it++))
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
{
|
|
|
|
if (item->walk(processor, walk_subquery, arg))
|
2003-11-27 02:23:52 +01:00
|
|
|
return 1;
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
}
|
|
|
|
return Item_func::walk(processor, walk_subquery, arg);
|
2003-11-27 02:23:52 +01:00
|
|
|
}
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
Item *Item_equal::transform(Item_transformer transformer, uchar *arg)
|
2003-11-27 02:23:52 +01:00
|
|
|
{
|
2006-08-24 13:49:12 +02:00
|
|
|
DBUG_ASSERT(!current_thd->is_stmt_prepare());
|
|
|
|
|
2003-11-27 02:23:52 +01:00
|
|
|
List_iterator<Item_field> it(fields);
|
|
|
|
Item *item;
|
|
|
|
while ((item= it++))
|
|
|
|
{
|
2004-02-19 07:21:37 +01:00
|
|
|
Item *new_item= item->transform(transformer, arg);
|
2003-11-27 02:23:52 +01:00
|
|
|
if (!new_item)
|
|
|
|
return 0;
|
2006-08-24 13:49:12 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
THD::change_item_tree() should be called only if the tree was
|
|
|
|
really transformed, i.e. when a new item has been created.
|
|
|
|
Otherwise we'll be allocating a lot of unnecessary memory for
|
|
|
|
change records at each execution.
|
|
|
|
*/
|
2003-11-27 02:23:52 +01:00
|
|
|
if (new_item != item)
|
2006-08-24 13:49:12 +02:00
|
|
|
current_thd->change_item_tree((Item **) it.ref(), new_item);
|
2003-11-27 02:23:52 +01:00
|
|
|
}
|
2004-02-19 07:21:37 +01:00
|
|
|
return Item_func::transform(transformer, arg);
|
2003-11-27 02:23:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Item_equal::print(String *str)
|
|
|
|
{
|
|
|
|
str->append(func_name());
|
|
|
|
str->append('(');
|
|
|
|
List_iterator_fast<Item_field> it(fields);
|
|
|
|
Item *item;
|
2004-02-19 07:21:37 +01:00
|
|
|
if (const_item)
|
|
|
|
const_item->print(str);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
item= it++;
|
2003-11-27 02:23:52 +01:00
|
|
|
item->print(str);
|
2004-02-19 07:21:37 +01:00
|
|
|
}
|
2003-11-27 02:23:52 +01:00
|
|
|
while ((item= it++))
|
|
|
|
{
|
|
|
|
str->append(',');
|
|
|
|
str->append(' ');
|
|
|
|
item->print(str);
|
|
|
|
}
|
|
|
|
str->append(')');
|
|
|
|
}
|
|
|
|
|