Several problems here :
1. The conversion to double of an hex string const item
was not taking into account the unsigned flag.
2. IN was not behaving in the same was way as comparisons
when performed over an INT/DATE/DATETIME/TIMESTAMP column
and a constant. The ordinary comparisons in that case
convert the constant to an INTEGER value and do int
comparisons. Fixed the IN to do the same.
3. IN is not taking into account the unsigned flag when
calculating <expr> IN (<int_const1>, <int_const2>, ...).
Extended the implementation of IN to store and process
the unsigned flag for its arguments.
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.
Objects of the class Item_equal contain an auxiliary member
eval_item of the type cmp_item that is used only for direct
evaluation of multiple equalities. Currently a multiple equality
is evaluated directly only in the cases when the equality holds
at most for one row in the result set.
The compare collation of eval_item was determined incorectly.
It could lead to returning incorrect results for some queries.
Depending on the queries we use different data processing methods
and can lose some data in case of double (and decimal in 4.1) fields.
The fix consists of two parts:
1. double comparison changed, now double a is equal to double b
if (a-b) is less than 5*0.1^(1 + max(a->decimals, b->decimals)).
For example, if a->decimals==1, b->decimals==2, a==b if (a-b)<0.005
2. if we use a temporary table, store double values there as is
to avoid any data conversion (rounding).
when they contain the '!' operator.
Added an implementation for the method Item_func_not::print.
The method encloses any NOT expression into extra parentheses to avoid
incorrect stored representations of views that use the '!' operators.
Without this change when a view was created that contained
the expression !0*5 its stored representation contained not this
expression but rather the expression not(0)*5 .
The operator '!' is of a higher precedence than '*', while NOT is
of a lower precedence than '*'. That's why the expression !0*5
is interpreted as not(0)*5, while the expression not(0)*5 is interpreted
as not((0)*5) unless sql_mode is set to HIGH_NOT_PRECEDENCE.
Now we translate !0*5 into (not(0))*5.
The optimizer needs to evaluate whether predicates are better
evaluated using an index. IN is one such predicate.
To qualify an IN predicate must involve a field of the index
on the left and constant arguments on the right.
However whether an expression is a constant can be determined only
by knowing the preceding tables in the join order.
Assuming that only IN predicates with expressions on the right that
are constant for the whole query qualify limits the scope of
possible optimizations of the IN predicate (more specifically it
doesn't allow the "Range checked for each record" optimization for
such an IN predicate.
Fixed by not pre-determining the optimizability of the IN predicate
in the case when all right IN operands are not SQL constant expressions
- Make the code produce correct result: use an array of triggers to turn on/off equalities for each
compared column. Also turn on/off optimizations based on those equalities.
- Make EXPLAIN output show "Full scan on NULL key" for tables for which we switch between
ref/unique_subquery/index_subquery and ALL access.
- index_subquery engine now has HAVING clause when it is needed, and it is
displayed in EXPLAIN EXTENDED
- Fix incorrect presense of "Using index" for index/unique-based subqueries (BUG#22930)
// bk trigger note: this commit refers to BUG#24127
- Removed not used variables and functions
- Added #ifdef around code that is not used
- Renamed variables and functions to avoid conflicts
- Removed some not used arguments
Fixed some class/struct warnings in ndb
Added define IS_LONGDATA() to simplify code in libmysql.c
I did run gcov on the changes and added 'purecov' comments on almost all lines that was not just variable name changes
Blocked evaluation of constant objects of the classes
Item_func_is_null and Item_is_not_null_test at the
prepare phase in the cases when the objects used subqueries.
Evaluate "NULL IN (SELECT ...)" in a special way: Disable pushed-down
conditions and their "consequences":
= Do full table scans instead of unique_[index_subquery] lookups.
= Change appropriate "ref_or_null" accesses to full table scans in
subquery's joins.
Also cache value of NULL IN (SELECT ...) if the SELECT is not correlated
wrt any upper select.
After the patch for big 21698 equality propagation stopped
working for BETWEEN and IN predicates with STRING arguments.
This changeset completes the solution of the above patch.
equal constant under any circumstances.
In fact this substitution can be allowed if the field is
not of a type string or if the field reference serves as
an argument of a comparison predicate.
can lead to a wrong result.
All date/time functions has the STRING result type thus their results are
compared as strings. The string date representation allows a user to skip
some of leading zeros. This can lead to wrong comparison result if a date/time
function result is compared to such a string constant.
The idea behind this bug fix is to compare results of date/time functions
and data/time constants as ints, because that date/time representation is
more exact. To achieve this the agg_cmp_type() is changed to take in the
account that a date/time field or an date/time item should be compared
as ints.
This bug fix is partially back ported from 5.0.
The agg_cmp_type() function now accepts THD as one of parameters.
In addition, it now checks if a date/time field/function is present in the
list. If so, it tries to coerce all constants to INT to make date/time
comparison return correct result. The field for the constant coercion is
taken from the Item_field or constructed from the Item_func. In latter case
the constructed field will be freed after conversion of all constant items.
Otherwise the result is same as before - aggregated with help of the
item_cmp_type() function.
From the Item_func_between::fix_length_and_dec() function removed the part
which was converting date/time constants to int if possible. Now this is
done by the agg_cmp_type() function.
The new function result_as_longlong() is added to the Item class.
It indicates that the item is a date/time item and result of it can be
compared as int. Such items are date/time fields/functions.
Correct val_int() methods are implemented for classes Item_date_typecast,
Item_func_makedate, Item_time_typecast, Item_datetime_typecast. All these
classes are derived from Item_str_func and Item_str_func::val_int() converts
its string value to int without regard to the date/time type of these items.
Arg_comparator::set_compare_func() and Arg_comparator::set_cmp_func()
functions are changed to substitute result type of an item with the INT_RESULT
if the item is a date/time item and another item is a constant. This is done
to get a correct result of comparisons like date_time_function() = string_constant.
too much memory. Instead, either create the equvalent SEL_TREE manually, or create only two ranges that
strictly include the area to scan
(Note: just to re-iterate: increasing NOT_IN_IGNORE_THRESHOLD will make optimization run slower for big
IN-lists, but the server will not run out of memory. O(N^2) memory use has been eliminated)
Multiple equalities were not adjusted after reading constant tables.
It resulted in neglecting good index based methods that could be
used to access of other tables.
- Added empty constructors and virtual destructors to many classes and structs
- Removed some usage of the offsetof() macro to instead use C++ class pointers
select result
Item equal objects are employed only at the optimize phase. Usually they are not
supposed to be evaluated. Yet in some cases we call the method val_int() for
them. Here we have to take care of restricting the predicate such an object
represents f1=f2= ...=fn to the projection of known fields fi1=...=fik.
Added a check for field's table being const in Item_equal::val_int().
If the field's table is not const val_int() just skips that field when
evaluating Item_equal.
cmp_item_sort_string::cmp() wasn't checking values_res variable for null.
Later called function was dereferenced it and crashed server.
Added null check to cmp_item_sort_string::cmp().
ESCAPE has length of 1 if specified and sql_mode is NO_BACKSLASH_ESCAPES
or has length of 0 or 1 in every other situation.
(approved patch applied on a up-to-date tree re-commit)