Commit cc9cfeca authored by Alexander Barkov's avatar Alexander Barkov

MDEV-8865 Wrong field type or metadata for COALESCE(signed_int_column, unsigned_int_column)

Item_func_hybrid_field_type did not return correct field_type(), cmp_type()
and result_type() in some cases, because cached_result_type and
cached_field_type were set in independent pieces of the code and
did not properly match to each other.
Fix:
- Removing Item_func_hybrid_result_type
- Deriving Item_func_hybrid_field_type directly from Item_func
- Introducing a new class Type_handler which guarantees that
  field_type(), cmp_type() and result_type() are always properly synchronized
  and using the new class in Item_func_hybrid_field_type.
parent 09b87d62
...@@ -104,6 +104,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ...@@ -104,6 +104,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/sql_explain.cc ../sql/sql_explain.h ../sql/sql_explain.cc ../sql/sql_explain.h
../sql/sql_analyze_stmt.cc ../sql/sql_analyze_stmt.h ../sql/sql_analyze_stmt.cc ../sql/sql_analyze_stmt.h
../sql/compat56.cc ../sql/compat56.cc
../sql/sql_type.cc ../sql/sql_type.h
../sql/table_cache.cc ../sql/mf_iocache_encr.cc ../sql/table_cache.cc ../sql/mf_iocache_encr.cc
../sql/item_inetfunc.cc ../sql/item_inetfunc.cc
../sql/wsrep_dummy.cc ../sql/encryption.cc ../sql/wsrep_dummy.cc ../sql/encryption.cc
......
# "mtr --ps" returns different values in "Max length"
--disable_ps_protocol
--enable_metadata
--vertical_results
SELECT
a AS ___________a,
CASE WHEN a IS NOT NULL THEN a END AS case_______a,
CASE WHEN a IS NOT NULL THEN a ELSE a END AS case_____a_a,
COALESCE(a) AS coalesce___a,
COALESCE(a, a) AS coalesce_a_a,
IF(a IS NULL, a, a) AS if_______a_a,
IFNULL(a, a) AS ifnull___a_a,
LEAST(a, a) AS least____a_a,
GREATEST(a, a) AS greatest_a_a,
b AS ___________b,
CASE WHEN a IS NOT NULL THEN b END AS case_______b,
CASE WHEN a IS NOT NULL THEN b ELSE b END AS case_____b_b,
COALESCE(b) AS coalesce___b,
COALESCE(b, b) AS coalesce_b_b,
IF(a IS NULL, b, b) AS if_______b_b,
IFNULL(b, b) AS ifnull___b_b,
LEAST(b, b) AS least____b_b,
GREATEST(b, b) AS greatest_b_b
FROM t1;
SELECT
CASE WHEN a IS NOT NULL THEN a ELSE b END AS case_____a_b,
CASE WHEN a IS NOT NULL THEN b ELSE a END AS case_____b_a,
COALESCE(a, b) AS coalesce_a_b,
COALESCE(b, a) AS coalesce_b_a,
IF(a IS NULL, a, b) AS if_______a_b,
IF(a IS NULL, b, a) AS if_______b_a,
IFNULL(a, b) AS ifnull___a_b,
IFNULL(b, a) AS ifnull___b_a,
LEAST(a, b) AS least____a_b,
LEAST(b, a) AS least____b_a,
GREATEST(a, b) AS greatest_a_b,
GREATEST(b, a) AS greatest_b_a
FROM t1;
--horizontal_results
--disable_metadata
--enable_ps_protocol
CREATE TABLE t2 AS
SELECT
a AS ___________a,
CASE WHEN a IS NOT NULL THEN a END AS case_______a,
CASE WHEN a IS NOT NULL THEN a ELSE a END AS case_____a_a,
COALESCE(a) AS coalesce___a,
COALESCE(a, a) AS coalesce_a_a,
IF(a IS NULL, a, a) AS if_______a_a,
IFNULL(a, a) AS ifnull___a_a,
LEAST(a, a) AS least____a_a,
GREATEST(a, a) AS greatest_a_a,
b AS ___________b,
CASE WHEN a IS NOT NULL THEN b END AS case_______b,
CASE WHEN a IS NOT NULL THEN b ELSE b END AS case_____b_b,
COALESCE(b) AS coalesce___b,
COALESCE(b, b) AS coalesce_b_b,
IF(a IS NULL, b, b) AS if_______b_b,
IFNULL(b, b) AS ifnull___b_b,
LEAST(b, b) AS least____b_b,
GREATEST(b, b) AS greatest_b_b
FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
CREATE TABLE t2 AS
SELECT
CASE WHEN a IS NOT NULL THEN a ELSE b END AS case_____a_b,
CASE WHEN a IS NOT NULL THEN b ELSE a END AS case_____b_a,
COALESCE(a, b) AS coalesce_a_b,
COALESCE(b, a) AS coalesce_b_a,
IF(a IS NULL, a, b) AS if_______a_b,
IF(a IS NULL, b, a) AS if_______b_a,
IFNULL(a, b) AS ifnull___a_b,
IFNULL(b, a) AS ifnull___b_a,
LEAST(a, b) AS least____a_b,
LEAST(b, a) AS least____b_a,
GREATEST(a, b) AS greatest_a_b,
GREATEST(b, a) AS greatest_b_a
FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
This diff is collapsed.
--echo #
--echo # Start of 10.1 tests
--echo #
--echo #
--echo # MDEV-8865 Wrong field type or metadata for COALESCE(signed_int_column, unsigned_int_column)
--echo #
--echo #
CREATE TABLE t1 (a INT, b INT UNSIGNED);
INSERT INTO t1 VALUES (1,1);
INSERT INTO t1 VALUES (-1,1);
INSERT INTO t1 VALUES (-2147483648,4294967295);
--source include/func_hybrid_type.inc
DROP TABLE t1;
--echo #
CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (1,1);
INSERT INTO t1 VALUES (-2147483648,2147483647);
--source include/func_hybrid_type.inc
DROP TABLE t1;
--echo #
CREATE TABLE t1 (a BIGINT, b BIGINT UNSIGNED);
INSERT INTO t1 VALUES (1,1);
INSERT INTO t1 VALUES (-9223372036854775808,0xFFFFFFFFFFFFFFFF);
--source include/func_hybrid_type.inc
DROP TABLE t1;
--echo #
CREATE TABLE t1 (a BIGINT, b BIGINT);
INSERT INTO t1 VALUES (1,1);
INSERT INTO t1 VALUES (-9223372036854775808,9223372036854775807);
--source include/func_hybrid_type.inc
DROP TABLE t1;
# Testing BIT(N) types.
# Using safe BIT(N) type and value to make sure
# that "file func_hybrid_type.test" tells "ASCII text".
--echo #
CREATE TABLE t1 (a INT, b BIT(8));
INSERT INTO t1 VALUES (-2147483648,0x32);
--source include/func_hybrid_type.inc
DROP TABLE t1;
--echo #
CREATE TABLE t1 (a INT UNSIGNED, b BIT(8));
INSERT INTO t1 VALUES (4294967295,0x32);
--source include/func_hybrid_type.inc
DROP TABLE t1;
--echo #
CREATE TABLE t1 (a BIT(7), b BIT(8));
INSERT INTO t1 VALUES (0x32,0x32);
--source include/func_hybrid_type.inc
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests
--echo #
...@@ -135,6 +135,7 @@ SET (SQL_SOURCE ...@@ -135,6 +135,7 @@ SET (SQL_SOURCE
my_apc.cc my_apc.h mf_iocache_encr.cc my_apc.cc my_apc.h mf_iocache_encr.cc
my_json_writer.cc my_json_writer.h my_json_writer.cc my_json_writer.h
rpl_gtid.cc rpl_parallel.cc rpl_gtid.cc rpl_parallel.cc
sql_type.cc sql_type.h
${WSREP_SOURCES} ${WSREP_SOURCES}
table_cache.cc encryption.cc table_cache.cc encryption.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "unireg.h" // REQUIRED: for other includes #include "unireg.h" // REQUIRED: for other includes
#include "thr_malloc.h" /* sql_calloc */ #include "thr_malloc.h" /* sql_calloc */
#include "field.h" /* Derivation */ #include "field.h" /* Derivation */
#include "sql_type.h"
C_MODE_START C_MODE_START
#include <ma_dyncol.h> #include <ma_dyncol.h>
...@@ -602,7 +603,9 @@ class Type_std_attributes ...@@ -602,7 +603,9 @@ class Type_std_attributes
}; };
class Item: public Value_source, public Type_std_attributes class Item: public Value_source,
public Type_std_attributes,
public Type_handler
{ {
Item(const Item &); /* Prevent use of these */ Item(const Item &); /* Prevent use of these */
void operator=(Item &); void operator=(Item &);
...@@ -752,12 +755,12 @@ class Item: public Value_source, public Type_std_attributes ...@@ -752,12 +755,12 @@ class Item: public Value_source, public Type_std_attributes
virtual bool send(Protocol *protocol, String *str); virtual bool send(Protocol *protocol, String *str);
virtual bool eq(const Item *, bool binary_cmp) const; virtual bool eq(const Item *, bool binary_cmp) const;
/* result_type() of an item specifies how the value should be returned */ /* result_type() of an item specifies how the value should be returned */
virtual Item_result result_type() const { return REAL_RESULT; } Item_result result_type() const { return REAL_RESULT; }
/* ... while cmp_type() specifies how it should be compared */ /* ... while cmp_type() specifies how it should be compared */
virtual Item_result cmp_type() const; Item_result cmp_type() const;
virtual Item_result cast_to_int_type() const { return cmp_type(); } virtual Item_result cast_to_int_type() const { return cmp_type(); }
virtual enum_field_types string_field_type() const; virtual enum_field_types string_field_type() const;
virtual enum_field_types field_type() const; enum_field_types field_type() const;
virtual enum Type type() const =0; virtual enum Type type() const =0;
/* /*
real_type() is the type of base item. This is same as type() for real_type() is the type of base item. This is same as type() for
......
...@@ -34,47 +34,6 @@ ...@@ -34,47 +34,6 @@
#include "sql_time.h" // make_truncated_value_warning #include "sql_time.h" // make_truncated_value_warning
#include "sql_base.h" // dynamic_column_error_message #include "sql_base.h" // dynamic_column_error_message
static Item_result item_store_type(Item_result a, Item *item,
my_bool unsigned_flag)
{
Item_result b= item->result_type();
if (a == STRING_RESULT || b == STRING_RESULT)
return STRING_RESULT;
else if (a == REAL_RESULT || b == REAL_RESULT)
return REAL_RESULT;
else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT ||
unsigned_flag != item->unsigned_flag)
return DECIMAL_RESULT;
else
return INT_RESULT;
}
static void agg_result_type(Item_result *type, Item **items, uint nitems)
{
Item **item, **item_end;
my_bool unsigned_flag= 0;
*type= STRING_RESULT;
/* Skip beginning NULL items */
for (item= items, item_end= item + nitems; item < item_end; item++)
{
if ((*item)->type() != Item::NULL_ITEM)
{
*type= (*item)->result_type();
unsigned_flag= (*item)->unsigned_flag;
item++;
break;
}
}
/* Combine result types. Note: NULL items don't affect the result */
for (; item < item_end; item++)
{
if ((*item)->type() != Item::NULL_ITEM)
*type= item_store_type(*type, *item, unsigned_flag);
}
}
/** /**
find an temporal type (item) that others will be converted to find an temporal type (item) that others will be converted to
...@@ -185,6 +144,22 @@ static int agg_cmp_type(Item_result *type, Item **items, uint nitems) ...@@ -185,6 +144,22 @@ static int agg_cmp_type(Item_result *type, Item **items, uint nitems)
@param[in] items array of items to aggregate the type from @param[in] items array of items to aggregate the type from
@paran[in] nitems number of items in the array @paran[in] nitems number of items in the array
@param[in] treat_bit_as_number - if BIT should be aggregated to a non-BIT
counterpart as a LONGLONG number or as a VARBINARY string.
Currently behaviour depends on the function:
- LEAST/GREATEST treat BIT as VARBINARY when
aggregating with a non-BIT counterpart.
Note, UNION also works this way.
- CASE, COALESCE, IF, IFNULL treat BIT as LONGLONG when
aggregating with a non-BIT counterpart;
This inconsistency may be changed in the future. See MDEV-8867.
Note, independently from "treat_bit_as_number":
- a single BIT argument gives BIT as a result
- two BIT couterparts give BIT as a result
@details This function aggregates field types from the array of items. @details This function aggregates field types from the array of items.
Found type is supposed to be used later as the result field type Found type is supposed to be used later as the result field type
...@@ -198,14 +173,50 @@ static int agg_cmp_type(Item_result *type, Item **items, uint nitems) ...@@ -198,14 +173,50 @@ static int agg_cmp_type(Item_result *type, Item **items, uint nitems)
@return aggregated field type. @return aggregated field type.
*/ */
enum_field_types agg_field_type(Item **items, uint nitems) enum_field_types agg_field_type(Item **items, uint nitems,
bool treat_bit_as_number)
{ {
uint i; uint i;
if (!nitems || items[0]->result_type() == ROW_RESULT ) if (!nitems || items[0]->result_type() == ROW_RESULT)
return (enum_field_types)-1; {
DBUG_ASSERT(0);
return MYSQL_TYPE_NULL;
}
enum_field_types res= items[0]->field_type(); enum_field_types res= items[0]->field_type();
uint unsigned_count= items[0]->unsigned_flag;
for (i= 1 ; i < nitems ; i++) for (i= 1 ; i < nitems ; i++)
res= Field::field_type_merge(res, items[i]->field_type()); {
enum_field_types cur= items[i]->field_type();
if (treat_bit_as_number &&
((res == MYSQL_TYPE_BIT) ^ (cur == MYSQL_TYPE_BIT)))
{
if (res == MYSQL_TYPE_BIT)
res= MYSQL_TYPE_LONGLONG; // BIT + non-BIT
else
cur= MYSQL_TYPE_LONGLONG; // non-BIT + BIT
}
res= Field::field_type_merge(res, cur);
unsigned_count+= items[i]->unsigned_flag;
}
switch (res) {
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_BIT:
if (unsigned_count != 0 && unsigned_count != nitems)
{
/*
If all arguments are of INT-alike type but have different
unsigned_flag, then convert to DECIMAL.
*/
return MYSQL_TYPE_NEWDECIMAL;
}
default:
break;
}
return res; return res;
} }
...@@ -2261,13 +2272,13 @@ void ...@@ -2261,13 +2272,13 @@ void
Item_func_case_abbreviation2::fix_length_and_dec2(Item **args) Item_func_case_abbreviation2::fix_length_and_dec2(Item **args)
{ {
uint32 char_length; uint32 char_length;
agg_result_type(&cached_result_type, args, 2); set_handler_by_field_type(agg_field_type(args, 2, true));
cached_field_type= agg_field_type(args, 2);
maybe_null=args[0]->maybe_null || args[1]->maybe_null; maybe_null=args[0]->maybe_null || args[1]->maybe_null;
decimals= MY_MAX(args[0]->decimals, args[1]->decimals); decimals= MY_MAX(args[0]->decimals, args[1]->decimals);
unsigned_flag= args[0]->unsigned_flag && args[1]->unsigned_flag; unsigned_flag= args[0]->unsigned_flag && args[1]->unsigned_flag;
if (cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) if (Item_func_case_abbreviation2::result_type() == DECIMAL_RESULT ||
Item_func_case_abbreviation2::result_type() == INT_RESULT)
{ {
int len0= args[0]->max_char_length() - args[0]->decimals int len0= args[0]->max_char_length() - args[0]->decimals
- (args[0]->unsigned_flag ? 0 : 1); - (args[0]->unsigned_flag ? 0 : 1);
...@@ -2280,9 +2291,10 @@ Item_func_case_abbreviation2::fix_length_and_dec2(Item **args) ...@@ -2280,9 +2291,10 @@ Item_func_case_abbreviation2::fix_length_and_dec2(Item **args)
else else
char_length= MY_MAX(args[0]->max_char_length(), args[1]->max_char_length()); char_length= MY_MAX(args[0]->max_char_length(), args[1]->max_char_length());
switch (cached_result_type) { switch (Item_func_case_abbreviation2::result_type()) {
case STRING_RESULT: case STRING_RESULT:
if (count_string_result_length(cached_field_type, args, 2)) if (count_string_result_length(Item_func_case_abbreviation2::field_type(),
args, 2))
return; return;
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
...@@ -2459,8 +2471,7 @@ void Item_func_if::fix_after_pullout(st_select_lex *new_parent, Item **ref) ...@@ -2459,8 +2471,7 @@ void Item_func_if::fix_after_pullout(st_select_lex *new_parent, Item **ref)
void Item_func_if::cache_type_info(Item *source) void Item_func_if::cache_type_info(Item *source)
{ {
Type_std_attributes::set(source); Type_std_attributes::set(source);
cached_field_type= source->field_type(); set_handler_by_field_type(source->field_type());
cached_result_type= source->result_type();
maybe_null= source->maybe_null; maybe_null= source->maybe_null;
} }
...@@ -2475,7 +2486,7 @@ Item_func_if::fix_length_and_dec() ...@@ -2475,7 +2486,7 @@ Item_func_if::fix_length_and_dec()
maybe_null= true; maybe_null= true;
// If both arguments are NULL, make resulting type BINARY(0). // If both arguments are NULL, make resulting type BINARY(0).
if (args[2]->type() == NULL_ITEM) if (args[2]->type() == NULL_ITEM)
cached_field_type= MYSQL_TYPE_STRING; set_handler_by_field_type(MYSQL_TYPE_STRING);
return; return;
} }
if (args[2]->type() == NULL_ITEM) if (args[2]->type() == NULL_ITEM)
...@@ -2546,8 +2557,7 @@ Item_func_nullif::fix_length_and_dec() ...@@ -2546,8 +2557,7 @@ Item_func_nullif::fix_length_and_dec()
if (!args[2]) // Only false if EOM if (!args[2]) // Only false if EOM
return; return;
cached_result_type= args[2]->result_type(); set_handler_by_field_type(args[2]->field_type());
cached_field_type= args[2]->field_type();
collation.set(args[2]->collation); collation.set(args[2]->collation);
decimals= args[2]->decimals; decimals= args[2]->decimals;
unsigned_flag= args[2]->unsigned_flag; unsigned_flag= args[2]->unsigned_flag;
...@@ -2961,12 +2971,11 @@ void Item_func_case::fix_length_and_dec() ...@@ -2961,12 +2971,11 @@ void Item_func_case::fix_length_and_dec()
if (else_expr_num != -1) if (else_expr_num != -1)
agg[nagg++]= args[else_expr_num]; agg[nagg++]= args[else_expr_num];
agg_result_type(&cached_result_type, agg, nagg); set_handler_by_field_type(agg_field_type(agg, nagg, true));
cached_field_type= agg_field_type(agg, nagg);
if (cached_result_type == STRING_RESULT) if (Item_func_case::result_type() == STRING_RESULT)
{ {
if (count_string_result_length(cached_field_type, agg, nagg)) if (count_string_result_length(Item_func_case::field_type(), agg, nagg))
return; return;
/* /*
Copy all THEN and ELSE items back to args[] array. Copy all THEN and ELSE items back to args[] array.
...@@ -3295,11 +3304,11 @@ my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value) ...@@ -3295,11 +3304,11 @@ my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value)
void Item_func_coalesce::fix_length_and_dec() void Item_func_coalesce::fix_length_and_dec()
{ {
cached_field_type= agg_field_type(args, arg_count); set_handler_by_field_type(agg_field_type(args, arg_count, true));
agg_result_type(&cached_result_type, args, arg_count); switch (Item_func_coalesce::result_type()) {
switch (cached_result_type) {
case STRING_RESULT: case STRING_RESULT:
if (count_string_result_length(cached_field_type, args, arg_count)) if (count_string_result_length(Item_func_coalesce::field_type(),
args, arg_count))
return; return;
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
......
...@@ -800,28 +800,28 @@ void Item_num_op::fix_length_and_dec(void) ...@@ -800,28 +800,28 @@ void Item_num_op::fix_length_and_dec(void)
{ {
count_real_length(); count_real_length();
max_length= float_length(decimals); max_length= float_length(decimals);
cached_result_type= REAL_RESULT; set_handler_by_result_type(REAL_RESULT);
} }
else if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT || else if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT ||
r0 == TIME_RESULT || r1 == TIME_RESULT) r0 == TIME_RESULT || r1 == TIME_RESULT)
{ {
cached_result_type= DECIMAL_RESULT; set_handler_by_result_type(DECIMAL_RESULT);
result_precision(); result_precision();
fix_decimals(); fix_decimals();
if ((r0 == TIME_RESULT || r1 == TIME_RESULT) && decimals == 0) if ((r0 == TIME_RESULT || r1 == TIME_RESULT) && decimals == 0)
cached_result_type= INT_RESULT; set_handler_by_result_type(INT_RESULT);
} }
else else
{ {
DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT); DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT);
cached_result_type=INT_RESULT; set_handler_by_result_type(INT_RESULT);
result_precision(); result_precision();
decimals= 0; decimals= 0;
} }
DBUG_PRINT("info", ("Type: %s", DBUG_PRINT("info", ("Type: %s",
(cached_result_type == REAL_RESULT ? "REAL_RESULT" : (result_type() == REAL_RESULT ? "REAL_RESULT" :
cached_result_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : result_type() == DECIMAL_RESULT ? "DECIMAL_RESULT" :
cached_result_type == INT_RESULT ? "INT_RESULT" : result_type() == INT_RESULT ? "INT_RESULT" :
"--ILLEGAL!!!--"))); "--ILLEGAL!!!--")));
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -837,20 +837,22 @@ void Item_func_num1::fix_length_and_dec() ...@@ -837,20 +837,22 @@ void Item_func_num1::fix_length_and_dec()
{ {
DBUG_ENTER("Item_func_num1::fix_length_and_dec"); DBUG_ENTER("Item_func_num1::fix_length_and_dec");
DBUG_PRINT("info", ("name %s", func_name())); DBUG_PRINT("info", ("name %s", func_name()));
switch (cached_result_type= args[0]->cast_to_int_type()) { // Note, cast_to_int_type() can return TIME_RESULT
switch (args[0]->cast_to_int_type()) {
case INT_RESULT: case INT_RESULT:
set_handler_by_result_type(INT_RESULT);
max_length= args[0]->max_length; max_length= args[0]->max_length;
unsigned_flag= args[0]->unsigned_flag; unsigned_flag= args[0]->unsigned_flag;
break; break;
case STRING_RESULT: case STRING_RESULT:
case REAL_RESULT: case REAL_RESULT:
cached_result_type= REAL_RESULT; set_handler_by_result_type(REAL_RESULT);
decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC
max_length= float_length(decimals); max_length= float_length(decimals);
break; break;
case TIME_RESULT: case TIME_RESULT:
cached_result_type= DECIMAL_RESULT;
case DECIMAL_RESULT: case DECIMAL_RESULT:
set_handler_by_result_type(DECIMAL_RESULT);
decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC
max_length= args[0]->max_length; max_length= args[0]->max_length;
break; break;
...@@ -858,18 +860,18 @@ void Item_func_num1::fix_length_and_dec() ...@@ -858,18 +860,18 @@ void Item_func_num1::fix_length_and_dec()
DBUG_ASSERT(0); DBUG_ASSERT(0);
} }
DBUG_PRINT("info", ("Type: %s", DBUG_PRINT("info", ("Type: %s",
(cached_result_type == REAL_RESULT ? "REAL_RESULT" : (result_type() == REAL_RESULT ? "REAL_RESULT" :
cached_result_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : result_type() == DECIMAL_RESULT ? "DECIMAL_RESULT" :
cached_result_type == INT_RESULT ? "INT_RESULT" : result_type() == INT_RESULT ? "INT_RESULT" :
"--ILLEGAL!!!--"))); "--ILLEGAL!!!--")));
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
String *Item_func_hybrid_result_type::val_str(String *str) String *Item_func_hybrid_field_type::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
switch (cached_result_type) { switch (Item_func_hybrid_field_type::result_type()) {
case DECIMAL_RESULT: case DECIMAL_RESULT:
{ {
my_decimal decimal_value, *val; my_decimal decimal_value, *val;
...@@ -921,10 +923,10 @@ String *Item_func_hybrid_result_type::val_str(String *str) ...@@ -921,10 +923,10 @@ String *Item_func_hybrid_result_type::val_str(String *str)
} }
double Item_func_hybrid_result_type::val_real() double Item_func_hybrid_field_type::val_real()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
switch (cached_result_type) { switch (Item_func_hybrid_field_type::result_type()) {
case DECIMAL_RESULT: case DECIMAL_RESULT:
{ {
my_decimal decimal_value, *val; my_decimal decimal_value, *val;
...@@ -966,10 +968,10 @@ double Item_func_hybrid_result_type::val_real() ...@@ -966,10 +968,10 @@ double Item_func_hybrid_result_type::val_real()
} }
longlong Item_func_hybrid_result_type::val_int() longlong Item_func_hybrid_field_type::val_int()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
switch (cached_result_type) { switch (Item_func_hybrid_field_type::result_type()) {
case DECIMAL_RESULT: case DECIMAL_RESULT:
{ {
my_decimal decimal_value, *val; my_decimal decimal_value, *val;
...@@ -1008,11 +1010,11 @@ longlong Item_func_hybrid_result_type::val_int() ...@@ -1008,11 +1010,11 @@ longlong Item_func_hybrid_result_type::val_int()
} }
my_decimal *Item_func_hybrid_result_type::val_decimal(my_decimal *decimal_value) my_decimal *Item_func_hybrid_field_type::val_decimal(my_decimal *decimal_value)
{ {
my_decimal *val= decimal_value; my_decimal *val= decimal_value;
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
switch (cached_result_type) { switch (Item_func_hybrid_field_type::result_type()) {
case DECIMAL_RESULT: case DECIMAL_RESULT:
val= decimal_op(decimal_value); val= decimal_op(decimal_value);
break; break;
...@@ -1054,11 +1056,11 @@ my_decimal *Item_func_hybrid_result_type::val_decimal(my_decimal *decimal_value) ...@@ -1054,11 +1056,11 @@ my_decimal *Item_func_hybrid_result_type::val_decimal(my_decimal *decimal_value)
} }
bool Item_func_hybrid_result_type::get_date(MYSQL_TIME *ltime, bool Item_func_hybrid_field_type::get_date(MYSQL_TIME *ltime,
ulonglong fuzzydate) ulonglong fuzzydate)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
switch (cached_result_type) { switch (Item_func_hybrid_field_type::result_type()) {
case DECIMAL_RESULT: case DECIMAL_RESULT:
{ {
my_decimal value, *res; my_decimal value, *res;
...@@ -1812,7 +1814,7 @@ void Item_func_div::fix_length_and_dec() ...@@ -1812,7 +1814,7 @@ void Item_func_div::fix_length_and_dec()
DBUG_ENTER("Item_func_div::fix_length_and_dec"); DBUG_ENTER("Item_func_div::fix_length_and_dec");
prec_increment= current_thd->variables.div_precincrement; prec_increment= current_thd->variables.div_precincrement;
Item_num_op::fix_length_and_dec(); Item_num_op::fix_length_and_dec();
switch (cached_result_type) { switch (Item_func_div::result_type()) {
case REAL_RESULT: case REAL_RESULT:
{ {
decimals=MY_MAX(args[0]->decimals,args[1]->decimals)+prec_increment; decimals=MY_MAX(args[0]->decimals,args[1]->decimals)+prec_increment;
...@@ -1828,7 +1830,7 @@ void Item_func_div::fix_length_and_dec() ...@@ -1828,7 +1830,7 @@ void Item_func_div::fix_length_and_dec()
break; break;
} }
case INT_RESULT: case INT_RESULT:
cached_result_type= DECIMAL_RESULT; set_handler_by_result_type(DECIMAL_RESULT);
DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
result_precision(); result_precision();
break; break;
...@@ -2075,7 +2077,7 @@ void Item_func_neg::fix_length_and_dec() ...@@ -2075,7 +2077,7 @@ void Item_func_neg::fix_length_and_dec()
Use val() to get value as arg_type doesn't mean that item is Use val() to get value as arg_type doesn't mean that item is
Item_int or Item_float due to existence of Item_param. Item_int or Item_float due to existence of Item_param.
*/ */
if (cached_result_type == INT_RESULT && args[0]->const_item()) if (Item_func_neg::result_type() == INT_RESULT && args[0]->const_item())
{ {
longlong val= args[0]->val_int(); longlong val= args[0]->val_int();
if ((ulonglong) val >= (ulonglong) LONGLONG_MIN && if ((ulonglong) val >= (ulonglong) LONGLONG_MIN &&
...@@ -2086,7 +2088,7 @@ void Item_func_neg::fix_length_and_dec() ...@@ -2086,7 +2088,7 @@ void Item_func_neg::fix_length_and_dec()
Ensure that result is converted to DECIMAL, as longlong can't hold Ensure that result is converted to DECIMAL, as longlong can't hold
the negated number the negated number
*/ */
cached_result_type= DECIMAL_RESULT; set_handler_by_result_type(DECIMAL_RESULT);
DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
} }
} }
...@@ -2388,11 +2390,12 @@ void Item_func_int_val::fix_length_and_dec() ...@@ -2388,11 +2390,12 @@ void Item_func_int_val::fix_length_and_dec()
set_if_smaller(max_length,tmp); set_if_smaller(max_length,tmp);
decimals= 0; decimals= 0;
switch (cached_result_type= args[0]->cast_to_int_type()) // Note, cast_to_int_type() can return TIME_RESULT
switch (args[0]->cast_to_int_type())
{ {
case STRING_RESULT: case STRING_RESULT:
case REAL_RESULT: case REAL_RESULT:
cached_result_type= REAL_RESULT; set_handler_by_result_type(REAL_RESULT);
max_length= float_length(decimals); max_length= float_length(decimals);
break; break;
case INT_RESULT: case INT_RESULT:
...@@ -2405,21 +2408,21 @@ void Item_func_int_val::fix_length_and_dec() ...@@ -2405,21 +2408,21 @@ void Item_func_int_val::fix_length_and_dec()
if ((args[0]->max_length - args[0]->decimals) >= if ((args[0]->max_length - args[0]->decimals) >=
(DECIMAL_LONGLONG_DIGITS - 2)) (DECIMAL_LONGLONG_DIGITS - 2))
{ {
cached_result_type= DECIMAL_RESULT; set_handler_by_result_type(DECIMAL_RESULT);
} }
else else
{ {
unsigned_flag= args[0]->unsigned_flag; unsigned_flag= args[0]->unsigned_flag;
cached_result_type= INT_RESULT; set_handler_by_result_type(INT_RESULT);
} }
break; break;
case ROW_RESULT: case ROW_RESULT:
DBUG_ASSERT(0); DBUG_ASSERT(0);
} }
DBUG_PRINT("info", ("Type: %s", DBUG_PRINT("info", ("Type: %s",
(cached_result_type == REAL_RESULT ? "REAL_RESULT" : (result_type() == REAL_RESULT ? "REAL_RESULT" :
cached_result_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : result_type() == DECIMAL_RESULT ? "DECIMAL_RESULT" :
cached_result_type == INT_RESULT ? "INT_RESULT" : result_type() == INT_RESULT ? "INT_RESULT" :
"--ILLEGAL!!!--"))); "--ILLEGAL!!!--")));
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -2534,10 +2537,10 @@ void Item_func_round::fix_length_and_dec() ...@@ -2534,10 +2537,10 @@ void Item_func_round::fix_length_and_dec()
if (args[0]->result_type() == DECIMAL_RESULT) if (args[0]->result_type() == DECIMAL_RESULT)
{ {
max_length++; max_length++;
cached_result_type= DECIMAL_RESULT; set_handler_by_result_type(DECIMAL_RESULT);
} }
else else
cached_result_type= REAL_RESULT; set_handler_by_result_type(REAL_RESULT);
return; return;
} }
...@@ -2555,14 +2558,14 @@ void Item_func_round::fix_length_and_dec() ...@@ -2555,14 +2558,14 @@ void Item_func_round::fix_length_and_dec()
{ {
decimals= MY_MIN(decimals_to_set, NOT_FIXED_DEC); decimals= MY_MIN(decimals_to_set, NOT_FIXED_DEC);
max_length= float_length(decimals); max_length= float_length(decimals);
cached_result_type= REAL_RESULT; set_handler_by_result_type(REAL_RESULT);
return; return;
} }
switch (args[0]->result_type()) { switch (args[0]->result_type()) {
case REAL_RESULT: case REAL_RESULT:
case STRING_RESULT: case STRING_RESULT:
cached_result_type= REAL_RESULT; set_handler_by_result_type(REAL_RESULT);
decimals= MY_MIN(decimals_to_set, NOT_FIXED_DEC); decimals= MY_MIN(decimals_to_set, NOT_FIXED_DEC);
max_length= float_length(decimals); max_length= float_length(decimals);
break; break;
...@@ -2573,14 +2576,14 @@ void Item_func_round::fix_length_and_dec() ...@@ -2573,14 +2576,14 @@ void Item_func_round::fix_length_and_dec()
!val1_unsigned); !val1_unsigned);
max_length= args[0]->max_length + length_can_increase; max_length= args[0]->max_length + length_can_increase;
/* Here we can keep INT_RESULT */ /* Here we can keep INT_RESULT */
cached_result_type= INT_RESULT; set_handler_by_result_type(INT_RESULT);
decimals= 0; decimals= 0;
break; break;
} }
/* fall through */ /* fall through */
case DECIMAL_RESULT: case DECIMAL_RESULT:
{ {
cached_result_type= DECIMAL_RESULT; set_handler_by_result_type(DECIMAL_RESULT);
decimals_to_set= MY_MIN(DECIMAL_MAX_SCALE, decimals_to_set); decimals_to_set= MY_MIN(DECIMAL_MAX_SCALE, decimals_to_set);
int decimals_delta= args[0]->decimals - decimals_to_set; int decimals_delta= args[0]->decimals - decimals_to_set;
int precision= args[0]->decimal_precision(); int precision= args[0]->decimal_precision();
...@@ -2884,7 +2887,7 @@ void Item_func_min_max::fix_length_and_dec() ...@@ -2884,7 +2887,7 @@ void Item_func_min_max::fix_length_and_dec()
set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
} }
else else
cached_field_type= agg_field_type(args, arg_count); cached_field_type= agg_field_type(args, arg_count, false);
} }
......
...@@ -373,29 +373,32 @@ class Item_real_func :public Item_func ...@@ -373,29 +373,32 @@ class Item_real_func :public Item_func
}; };
class Item_func_hybrid_result_type: public Item_func class Item_func_hybrid_field_type: public Item_func,
public Type_handler_hybrid_field_type
{ {
protected:
Item_result cached_result_type;
public: public:
Item_func_hybrid_result_type(THD *thd): Item_func_hybrid_field_type(THD *thd):
Item_func(thd), cached_result_type(REAL_RESULT) Item_func(thd)
{ collation.set_numeric(); } { collation.set_numeric(); }
Item_func_hybrid_result_type(THD *thd, Item *a): Item_func_hybrid_field_type(THD *thd, Item *a):
Item_func(thd, a), cached_result_type(REAL_RESULT) Item_func(thd, a)
{ collation.set_numeric(); } { collation.set_numeric(); }
Item_func_hybrid_result_type(THD *thd, Item *a, Item *b): Item_func_hybrid_field_type(THD *thd, Item *a, Item *b):
Item_func(thd, a, b), cached_result_type(REAL_RESULT) Item_func(thd, a, b)
{ collation.set_numeric(); } { collation.set_numeric(); }
Item_func_hybrid_result_type(THD *thd, Item *a, Item *b, Item *c): Item_func_hybrid_field_type(THD *thd, Item *a, Item *b, Item *c):
Item_func(thd, a, b, c), cached_result_type(REAL_RESULT) Item_func(thd, a, b, c)
{ collation.set_numeric(); } { collation.set_numeric(); }
Item_func_hybrid_result_type(THD *thd, List<Item> &list): Item_func_hybrid_field_type(THD *thd, List<Item> &list):
Item_func(thd, list), cached_result_type(REAL_RESULT) Item_func(thd, list)
{ collation.set_numeric(); } { collation.set_numeric(); }
enum Item_result result_type () const { return cached_result_type; } enum_field_types field_type() const
{ return Type_handler_hybrid_field_type::field_type(); }
enum Item_result result_type () const
{ return Type_handler_hybrid_field_type::result_type(); }
enum Item_result cmp_type () const
{ return Type_handler_hybrid_field_type::cmp_type(); }
double val_real(); double val_real();
longlong val_int(); longlong val_int();
...@@ -449,33 +452,7 @@ class Item_func_hybrid_result_type: public Item_func ...@@ -449,33 +452,7 @@ class Item_func_hybrid_result_type: public Item_func
}; };
class Item_func_numhybrid: public Item_func_hybrid_field_type
class Item_func_hybrid_field_type :public Item_func_hybrid_result_type
{
protected:
enum_field_types cached_field_type;
public:
Item_func_hybrid_field_type(THD *thd):
Item_func_hybrid_result_type(thd), cached_field_type(MYSQL_TYPE_DOUBLE)
{}
Item_func_hybrid_field_type(THD *thd, Item *a, Item *b):
Item_func_hybrid_result_type(thd, a, b),
cached_field_type(MYSQL_TYPE_DOUBLE)
{}
Item_func_hybrid_field_type(THD *thd, Item *a, Item *b, Item *c):
Item_func_hybrid_result_type(thd, a, b, c),
cached_field_type(MYSQL_TYPE_DOUBLE)
{}
Item_func_hybrid_field_type(THD *thd, List<Item> &list):
Item_func_hybrid_result_type(thd, list),
cached_field_type(MYSQL_TYPE_DOUBLE)
{}
enum_field_types field_type() const { return cached_field_type; }
};
class Item_func_numhybrid: public Item_func_hybrid_result_type
{ {
protected: protected:
...@@ -487,18 +464,18 @@ class Item_func_numhybrid: public Item_func_hybrid_result_type ...@@ -487,18 +464,18 @@ class Item_func_numhybrid: public Item_func_hybrid_result_type
} }
public: public:
Item_func_numhybrid(THD *thd): Item_func_hybrid_result_type(thd) Item_func_numhybrid(THD *thd): Item_func_hybrid_field_type(thd)
{ } { }
Item_func_numhybrid(THD *thd, Item *a): Item_func_hybrid_result_type(thd, a) Item_func_numhybrid(THD *thd, Item *a): Item_func_hybrid_field_type(thd, a)
{ } { }
Item_func_numhybrid(THD *thd, Item *a, Item *b): Item_func_numhybrid(THD *thd, Item *a, Item *b):
Item_func_hybrid_result_type(thd, a, b) Item_func_hybrid_field_type(thd, a, b)
{ } { }
Item_func_numhybrid(THD *thd, Item *a, Item *b, Item *c): Item_func_numhybrid(THD *thd, Item *a, Item *b, Item *c):
Item_func_hybrid_result_type(thd, a, b, c) Item_func_hybrid_field_type(thd, a, b, c)
{ } { }
Item_func_numhybrid(THD *thd, List<Item> &list): Item_func_numhybrid(THD *thd, List<Item> &list):
Item_func_hybrid_result_type(thd, list) Item_func_hybrid_field_type(thd, list)
{ } { }
String *str_op(String *str) { DBUG_ASSERT(0); return 0; } String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
bool date_op(MYSQL_TIME *ltime, uint fuzzydate) { DBUG_ASSERT(0); return true; } bool date_op(MYSQL_TIME *ltime, uint fuzzydate) { DBUG_ASSERT(0); return true; }
...@@ -2169,7 +2146,8 @@ class Item_func_last_value :public Item_func ...@@ -2169,7 +2146,8 @@ class Item_func_last_value :public Item_func
Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name, Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
LEX_STRING component); LEX_STRING component);
extern bool check_reserved_words(LEX_STRING *name); extern bool check_reserved_words(LEX_STRING *name);
extern enum_field_types agg_field_type(Item **items, uint nitems); extern enum_field_types agg_field_type(Item **items, uint nitems,
bool treat_bit_as_number);
Item *find_date_time_item(Item **args, uint nargs, uint col); Item *find_date_time_item(Item **args, uint nargs, uint col);
double my_double_round(double value, longlong dec, bool dec_unsigned, double my_double_round(double value, longlong dec, bool dec_unsigned,
bool truncate); bool truncate);
......
...@@ -421,7 +421,7 @@ class Item_func_seconds_hybrid: public Item_func_numhybrid ...@@ -421,7 +421,7 @@ class Item_func_seconds_hybrid: public Item_func_numhybrid
set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
max_length=17 + (decimals ? decimals + 1 : 0); max_length=17 + (decimals ? decimals + 1 : 0);
maybe_null= true; maybe_null= true;
cached_result_type= decimals ? DECIMAL_RESULT : INT_RESULT; set_handler_by_result_type(decimals ? DECIMAL_RESULT : INT_RESULT);
} }
double real_op() { DBUG_ASSERT(0); return 0; } double real_op() { DBUG_ASSERT(0); return 0; }
String *str_op(String *str) { DBUG_ASSERT(0); return 0; } String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
......
/*
Copyright (c) 2015 MariaDB Foundation.
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
the Free Software Foundation; version 2 of the License.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "sql_type.h"
static Type_handler_tiny type_handler_tiny;
static Type_handler_short type_handler_short;
static Type_handler_long type_handler_long;
static Type_handler_longlong type_handler_longlong;
static Type_handler_int24 type_handler_int24;
static Type_handler_year type_handler_year;
static Type_handler_bit type_handler_bit;
static Type_handler_float type_handler_float;
static Type_handler_double type_handler_double;
static Type_handler_time type_handler_time;
static Type_handler_date type_handler_date;
static Type_handler_datetime type_handler_datetime;
static Type_handler_timestamp type_handler_timestamp;
static Type_handler_olddecimal type_handler_olddecimal;
static Type_handler_newdecimal type_handler_newdecimal;
static Type_handler_null type_handler_null;
static Type_handler_string type_handler_string;
static Type_handler_varchar type_handler_varchar;
static Type_handler_tiny_blob type_handler_tiny_blob;
static Type_handler_medium_blob type_handler_medium_blob;
static Type_handler_long_blob type_handler_long_blob;
static Type_handler_blob type_handler_blob;
static Type_handler_geometry type_handler_geometry;
Type_handler_hybrid_field_type::Type_handler_hybrid_field_type()
:m_type_handler(&type_handler_double)
{
}
const Type_handler *
Type_handler_hybrid_field_type::get_handler_by_result_type(Item_result type)
const
{
switch (type) {
case REAL_RESULT: return &type_handler_double;
case INT_RESULT: return &type_handler_longlong;
case DECIMAL_RESULT: return &type_handler_newdecimal;
case STRING_RESULT: return &type_handler_string;
case TIME_RESULT:
case ROW_RESULT:
DBUG_ASSERT(0);
}
return &type_handler_string;
}
const Type_handler *
Type_handler_hybrid_field_type::get_handler_by_field_type(enum_field_types type)
const
{
switch (type) {
case MYSQL_TYPE_DECIMAL: return &type_handler_olddecimal;
case MYSQL_TYPE_NEWDECIMAL: return &type_handler_newdecimal;
case MYSQL_TYPE_TINY: return &type_handler_tiny;
case MYSQL_TYPE_SHORT: return &type_handler_short;
case MYSQL_TYPE_LONG: return &type_handler_long;
case MYSQL_TYPE_LONGLONG: return &type_handler_longlong;
case MYSQL_TYPE_INT24: return &type_handler_int24;
case MYSQL_TYPE_YEAR: return &type_handler_year;
case MYSQL_TYPE_BIT: return &type_handler_bit;
case MYSQL_TYPE_FLOAT: return &type_handler_float;
case MYSQL_TYPE_DOUBLE: return &type_handler_double;
case MYSQL_TYPE_NULL: return &type_handler_null;
case MYSQL_TYPE_VARCHAR: return &type_handler_varchar;
case MYSQL_TYPE_TINY_BLOB: return &type_handler_tiny_blob;
case MYSQL_TYPE_MEDIUM_BLOB: return &type_handler_medium_blob;
case MYSQL_TYPE_LONG_BLOB: return &type_handler_long_blob;
case MYSQL_TYPE_BLOB: return &type_handler_blob;
case MYSQL_TYPE_VAR_STRING: return &type_handler_varchar; // Map to VARCHAR
case MYSQL_TYPE_STRING: return &type_handler_string;
case MYSQL_TYPE_ENUM: return &type_handler_varchar; // Map to VARCHAR
case MYSQL_TYPE_SET: return &type_handler_varchar; // Map to VARCHAR
case MYSQL_TYPE_GEOMETRY: return &type_handler_geometry;
case MYSQL_TYPE_TIMESTAMP: return &type_handler_timestamp;
case MYSQL_TYPE_TIMESTAMP2: return &type_handler_timestamp;
case MYSQL_TYPE_DATE: return &type_handler_date;
case MYSQL_TYPE_TIME: return &type_handler_time;
case MYSQL_TYPE_TIME2: return &type_handler_time;
case MYSQL_TYPE_DATETIME: return &type_handler_datetime;
case MYSQL_TYPE_DATETIME2: return &type_handler_datetime;
case MYSQL_TYPE_NEWDATE: return &type_handler_date;
};
DBUG_ASSERT(0);
return &type_handler_string;
}
#ifndef SQL_TYPE_H_INCLUDED
#define SQL_TYPE_H_INCLUDED
/*
Copyright (c) 2015 MariaDB Foundation.
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
the Free Software Foundation; version 2 of the License.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
#include "mysqld.h"
class Type_handler
{
public:
virtual enum_field_types field_type() const= 0;
virtual Item_result result_type() const= 0;
virtual Item_result cmp_type() const= 0;
};
/*** Abstract classes for every XXX_RESULT */
class Type_handler_real_result: public Type_handler
{
public:
Item_result result_type() const { return REAL_RESULT; }
Item_result cmp_type() const { return REAL_RESULT; }
};
class Type_handler_decimal_result: public Type_handler
{
public:
Item_result result_type() const { return DECIMAL_RESULT; }
Item_result cmp_type() const { return DECIMAL_RESULT; }
};
class Type_handler_int_result: public Type_handler
{
public:
Item_result result_type() const { return INT_RESULT; }
Item_result cmp_type() const { return INT_RESULT; }
};
class Type_handler_temporal_result: public Type_handler
{
public:
Item_result result_type() const { return STRING_RESULT; }
Item_result cmp_type() const { return TIME_RESULT; }
};
class Type_handler_string_result: public Type_handler
{
public:
Item_result result_type() const { return STRING_RESULT; }
Item_result cmp_type() const { return STRING_RESULT; }
};
/***
Instantiable classes for every MYSQL_TYPE_XXX
There are no Type_handler_xxx for the following types:
- MYSQL_TYPE_VAR_STRING (old VARCHAR) - mapped to MYSQL_TYPE_VARSTRING
- MYSQL_TYPE_ENUM - mapped to MYSQL_TYPE_VARSTRING
- MYSQL_TYPE_SET: - mapped to MYSQL_TYPE_VARSTRING
because the functionality that currently uses Type_handler
(e.g. hybrid type functions) does not need to distinguish between
these types and VARCHAR.
For example:
CREATE TABLE t2 AS SELECT COALESCE(enum_column) FROM t1;
creates a VARCHAR column.
There most likely be Type_handler_enum and Type_handler_set later,
when the Type_handler infrastructure gets used in more pieces of the code.
*/
class Type_handler_tiny: public Type_handler_int_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_TINY; }
};
class Type_handler_short: public Type_handler_int_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_SHORT; }
};
class Type_handler_long: public Type_handler_int_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_LONG; }
};
class Type_handler_longlong: public Type_handler_int_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
};
class Type_handler_int24: public Type_handler_int_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_INT24; }
};
class Type_handler_year: public Type_handler_int_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_YEAR; }
};
class Type_handler_bit: public Type_handler_int_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_BIT; }
};
class Type_handler_float: public Type_handler_real_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_FLOAT; }
};
class Type_handler_double: public Type_handler_real_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
};
class Type_handler_time: public Type_handler_temporal_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
};
class Type_handler_date: public Type_handler_temporal_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
};
class Type_handler_datetime: public Type_handler_temporal_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
};
class Type_handler_timestamp: public Type_handler_temporal_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_TIMESTAMP; }
};
class Type_handler_olddecimal: public Type_handler_decimal_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; }
};
class Type_handler_newdecimal: public Type_handler_decimal_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
};
class Type_handler_null: public Type_handler_string_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
};
class Type_handler_string: public Type_handler_string_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
};
class Type_handler_varchar: public Type_handler_string_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
};
class Type_handler_tiny_blob: public Type_handler_string_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_TINY_BLOB; }
};
class Type_handler_medium_blob: public Type_handler_string_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_MEDIUM_BLOB; }
};
class Type_handler_long_blob: public Type_handler_string_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_LONG_BLOB; }
};
class Type_handler_blob: public Type_handler_string_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_BLOB; }
};
class Type_handler_geometry: public Type_handler_string_result
{
public:
enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; }
};
/**
A handler for hybrid type functions, e.g.
COALESCE(), IF(), IFNULL(), NULLIF(), CASE,
numeric operators,
UNIX_TIMESTAMP(), TIME_TO_SEC().
Makes sure that field_type(), cmp_type() and result_type()
are always in sync to each other for hybrid functions.
*/
class Type_handler_hybrid_field_type: public Type_handler
{
const Type_handler *m_type_handler;
const Type_handler *get_handler_by_result_type(Item_result type) const;
const Type_handler *get_handler_by_field_type(enum_field_types type) const;
public:
Type_handler_hybrid_field_type();
enum_field_types field_type() const { return m_type_handler->field_type(); }
Item_result result_type() const { return m_type_handler->result_type(); }
Item_result cmp_type() const { return m_type_handler->cmp_type(); }
const Type_handler *set_handler_by_result_type(Item_result type)
{
return (m_type_handler= get_handler_by_result_type(type));
}
const Type_handler *set_handler_by_field_type(enum_field_types type)
{
return (m_type_handler= get_handler_by_field_type(type));
}
};
#endif /* SQL_TYPE_H_INCLUDED */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment