From a134f1ebb129bdd0f312ec0204b9dba38fa24359 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Thu, 24 Jan 2019 03:06:56 -0800 Subject: [PATCH 1/5] PR #1127 and PR #1150 PR#1127: Fix is_check_constraints.result to be compatibile with 10.3 The patch is done according to the original patch for MDEV-14474 1edd09c325525cba33152 and not one which is merged on server d526679efd108478cc2af07578. This patch includes: - Rename from `is_check_constraint` to `is_check_constraints` to tests and results - Per review, change the order of fields in IS check_constraints table by adding the column `table_name` before `constraint_name`. According to the standard 2006 there is no `table_name` column. - Original patch and one in `10.3` supports embedded server this patch doesn't support. After the merge `10.3` will not support also. - Don't use patch c8b8b01b61 to change the length of `CHECK_CLAUSE` field PR#1150: MDEV-18440: Information_schema.check_constraints possible data leak This patch is extension of PR 1127 and includes: - Check for table grants - Additional test according to the MDEV specification --- ...int.result => is_check_constraints.result} | 26 +++++++++++++ ...straint.test => is_check_constraints.test} | 33 +++++++++++++++-- sql/sql_show.cc | 37 ++++++++++++++----- 3 files changed, 83 insertions(+), 13 deletions(-) rename mysql-test/suite/funcs_1/r/{is_check_constraint.result => is_check_constraints.result} (84%) rename mysql-test/suite/funcs_1/t/{is_check_constraint.test => is_check_constraints.test} (78%) diff --git a/mysql-test/suite/funcs_1/r/is_check_constraint.result b/mysql-test/suite/funcs_1/r/is_check_constraints.result similarity index 84% rename from mysql-test/suite/funcs_1/r/is_check_constraint.result rename to mysql-test/suite/funcs_1/r/is_check_constraints.result index e36db395eb9..4d7c7b446e6 100644 --- a/mysql-test/suite/funcs_1/r/is_check_constraint.result +++ b/mysql-test/suite/funcs_1/r/is_check_constraints.result @@ -119,3 +119,29 @@ disconnect con1; connection default; DROP USER boo1; DROP USER boo2; +# +# MDEV-18440: Information_schema.check_constraints possible data leak +# +CREATE USER foo; +CREATE DATABASE db; +USE db; +CREATE TABLE t1 (a int, b int, CONSTRAINT CHECK (b > 0)); +INSERT INTO t1 VALUES (1, 2), (2, 3); +GRANT SELECT (a) ON t1 TO foo; +SHOW GRANTS FOR foo; +Grants for foo@% +GRANT USAGE ON *.* TO 'foo'@'%' +GRANT SELECT (a) ON `db`.`t1` TO 'foo'@'%' +SELECT * FROM information_schema.check_constraints; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA TABLE_NAME CONSTRAINT_NAME CHECK_CLAUSE +def db t1 CONSTRAINT_1 `b` > 0 +CONNECT con1,localhost, foo,, db; +SELECT a FROM t1; +a +1 +2 +SELECT * FROM information_schema.check_constraints; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA TABLE_NAME CONSTRAINT_NAME CHECK_CLAUSE +connection default; +DROP USER foo; +DROP DATABASE db; diff --git a/mysql-test/suite/funcs_1/t/is_check_constraint.test b/mysql-test/suite/funcs_1/t/is_check_constraints.test similarity index 78% rename from mysql-test/suite/funcs_1/t/is_check_constraint.test rename to mysql-test/suite/funcs_1/t/is_check_constraints.test index 30a72d02b34..eadfd817832 100644 --- a/mysql-test/suite/funcs_1/t/is_check_constraint.test +++ b/mysql-test/suite/funcs_1/t/is_check_constraints.test @@ -40,7 +40,7 @@ CREATE TABLE t1 CONSTRAINT CHECK (tt > 32), CONSTRAINT CHECK (tt <50),# autogenerated names table constraints CONSTRAINT CHK_tt CHECK(tt<100) # named table constraint ) ENGINE=InnoDB; - --sorted_result +--sorted_result SELECT * from information_schema.check_constraints; ALTER TABLE t1 @@ -55,7 +55,7 @@ start_date DATE, end_date DATE, CONSTRAINT CHK_dates CHECK(start_date IS NULL) #table constraint )ENGINE=Innodb; - --sorted_result +--sorted_result SELECT * from information_schema.check_constraints; ALTER TABLE t1 @@ -70,12 +70,12 @@ a int, b int check (b>0), # field constraint named 'b' CONSTRAINT b check (b>10) # table constraint ) ENGINE=InnoDB; - --sorted_result +--sorted_result SELECT * from information_schema.check_constraints; DISCONNECT con1; CONNECT(con2, localhost, boo2,, test); - --sorted_result +--sorted_result SELECT * from information_schema.check_constraints; DISCONNECT con2; @@ -90,3 +90,28 @@ DISCONNECT con1; --CONNECTION default DROP USER boo1; DROP USER boo2; + +--echo # +--echo # MDEV-18440: Information_schema.check_constraints possible data leak +--echo # + +CREATE USER foo; +CREATE DATABASE db; +USE db; +CREATE TABLE t1 (a int, b int, CONSTRAINT CHECK (b > 0)); +INSERT INTO t1 VALUES (1, 2), (2, 3); +GRANT SELECT (a) ON t1 TO foo; + +SHOW GRANTS FOR foo; +--sorted_result +SELECT * FROM information_schema.check_constraints; + +CONNECT(con1,localhost, foo,, db); +SELECT a FROM t1; +--sorted_result +SELECT * FROM information_schema.check_constraints; + +--CONNECTION default + +DROP USER foo; +DROP DATABASE db; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f54a9af5441..fcf97fc8fee 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -6526,7 +6526,7 @@ static int get_check_constraints_record(THD *thd, TABLE_LIST *tables, LEX_STRING *table_name) { DBUG_ENTER("get_check_constraints_record"); - if(res) + if (res) { if (thd->is_error()) push_warning(thd, Sql_condition::WARN_LEVEL_WARN, @@ -6535,15 +6535,32 @@ static int get_check_constraints_record(THD *thd, TABLE_LIST *tables, thd->clear_error(); DBUG_RETURN(0); } - if(!tables->view) + if (!tables->view) { StringBuffer str(system_charset_info); +#ifndef NO_EMBEDDED_ACCESS_CHECKS + TABLE_LIST table_acl_check; + bzero((char*) &table_acl_check, sizeof(table_acl_check)); +#endif for (uint i= 0; i < tables->table->s->table_check_constraints; i++) { +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (!(thd->col_access & TABLE_ACLS)) + { + table_acl_check.db= db_name->str; + table_acl_check.db_length= db_name->length; + table_acl_check.table_name= table_name->str; + table_acl_check.table_name_length= table_name->length; + table_acl_check.grant.privilege= thd->col_access; + if (check_grant(thd, TABLE_ACLS, &table_acl_check, FALSE, 1, TRUE)) + continue; + } +#endif Virtual_column_info *check= tables->table->check_constraints[i]; table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info); table->field[3]->store(check->name.str, check->name.length, system_charset_info); + /* Make sure the string is empty between each print. */ str.length(0); check->print(&str); table->field[4]->store(str.ptr(), str.length(), system_charset_info); @@ -6551,8 +6568,7 @@ static int get_check_constraints_record(THD *thd, TABLE_LIST *tables, DBUG_RETURN(1); } } - - DBUG_RETURN(0); + DBUG_RETURN(res); } static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, @@ -9370,11 +9386,14 @@ ST_FIELD_INFO spatial_ref_sys_fields_info[]= ST_FIELD_INFO check_constraints_fields_info[]= { {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, + {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, + OPEN_FULL_TABLE}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"CHECK_CLAUSE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE } + {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, + OPEN_FULL_TABLE}, + {"CHECK_CLAUSE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, + OPEN_FULL_TABLE}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} }; /* @@ -9393,7 +9412,7 @@ ST_SCHEMA_TABLE schema_tables[]= {"CHARACTER_SETS", charsets_fields_info, 0, fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0}, {"CHECK_CONSTRAINTS", check_constraints_fields_info, 0, get_all_tables, 0, - get_check_constraints_record, 1, 2, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY}, + get_check_constraints_record, 1, 2, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY}, {"COLLATIONS", collation_fields_info, 0, fill_schema_collation, make_old_format, 0, -1, -1, 0, 0}, {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info, From cf0823f9b582ae815607ebc0855003db78a53969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Fri, 13 Dec 2019 20:52:44 +0200 Subject: [PATCH 2/5] Update test result post merge Columns order is now according to standard SQL --- mysql-test/suite/funcs_1/r/is_columns_is.result | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/funcs_1/r/is_columns_is.result b/mysql-test/suite/funcs_1/r/is_columns_is.result index dfaa5d75137..808836ab119 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_is.result +++ b/mysql-test/suite/funcs_1/r/is_columns_is.result @@ -26,9 +26,9 @@ def information_schema CHARACTER_SETS DESCRIPTION 3 '' NO varchar 60 180 NULL NU def information_schema CHARACTER_SETS MAXLEN 4 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(3) select NEVER NULL def information_schema CHECK_CONSTRAINTS CHECK_CLAUSE 5 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL def information_schema CHECK_CONSTRAINTS CONSTRAINT_CATALOG 1 '' NO varchar 512 1536 NULL NULL NULL utf8 utf8_general_ci varchar(512) select NEVER NULL -def information_schema CHECK_CONSTRAINTS CONSTRAINT_NAME 3 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL +def information_schema CHECK_CONSTRAINTS CONSTRAINT_NAME 4 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL def information_schema CHECK_CONSTRAINTS CONSTRAINT_SCHEMA 2 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL -def information_schema CHECK_CONSTRAINTS TABLE_NAME 4 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL +def information_schema CHECK_CONSTRAINTS TABLE_NAME 3 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL def information_schema CLIENT_STATISTICS ACCESS_DENIED 22 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select NEVER NULL def information_schema CLIENT_STATISTICS BINLOG_BYTES_WRITTEN 9 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select NEVER NULL def information_schema CLIENT_STATISTICS BUSY_TIME 5 0 NO double NULL NULL 21 NULL NULL NULL NULL double select NEVER NULL @@ -564,8 +564,8 @@ COL_CML TABLE_SCHEMA TABLE_NAME COLUMN_NAME DATA_TYPE CHARACTER_MAXIMUM_LENGTH C NULL information_schema CHARACTER_SETS MAXLEN bigint NULL NULL NULL NULL bigint(3) 3.0000 information_schema CHECK_CONSTRAINTS CONSTRAINT_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512) 3.0000 information_schema CHECK_CONSTRAINTS CONSTRAINT_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64) -3.0000 information_schema CHECK_CONSTRAINTS CONSTRAINT_NAME varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema CHECK_CONSTRAINTS TABLE_NAME varchar 64 192 utf8 utf8_general_ci varchar(64) +3.0000 information_schema CHECK_CONSTRAINTS CONSTRAINT_NAME varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema CHECK_CONSTRAINTS CHECK_CLAUSE varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema CLIENT_STATISTICS CLIENT varchar 64 192 utf8 utf8_general_ci varchar(64) NULL information_schema CLIENT_STATISTICS TOTAL_CONNECTIONS bigint NULL NULL NULL NULL bigint(21) From 59a088744def823e5940757237b15fb00ae06f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 16 Dec 2019 13:40:00 +0200 Subject: [PATCH 3/5] Remove unused mlog_catenate_ulint_compressed() The function was only used by trx_undo_page_init_log() (writing the MLOG_UNDO_INIT record), which was removed in commit ccb3550221497e7e652883b79e4a01451a55c4d7. --- storage/innobase/include/mtr0log.h | 8 -------- storage/innobase/include/mtr0log.ic | 24 ------------------------ 2 files changed, 32 deletions(-) diff --git a/storage/innobase/include/mtr0log.h b/storage/innobase/include/mtr0log.h index eaf2fad9e7f..dc76b40a3db 100644 --- a/storage/innobase/include/mtr0log.h +++ b/storage/innobase/include/mtr0log.h @@ -109,14 +109,6 @@ mlog_catenate_string( const byte* str, /*!< in: string to write */ ulint len); /*!< in: string length */ /********************************************************//** -Catenates a compressed ulint to mlog. */ -UNIV_INLINE -void -mlog_catenate_ulint_compressed( -/*===========================*/ - mtr_t* mtr, /*!< in: mtr */ - ulint val); /*!< in: value to write */ -/********************************************************//** Catenates a compressed 64-bit integer to mlog. */ UNIV_INLINE void diff --git a/storage/innobase/include/mtr0log.ic b/storage/innobase/include/mtr0log.ic index 23a840d95a6..70bcaf43b9e 100644 --- a/storage/innobase/include/mtr0log.ic +++ b/storage/innobase/include/mtr0log.ic @@ -117,30 +117,6 @@ mlog_catenate_ulint( mlog_catenate_ulint(mtr->get_log(), val, type); } -/********************************************************//** -Catenates a compressed ulint to mlog. */ -UNIV_INLINE -void -mlog_catenate_ulint_compressed( -/*===========================*/ - mtr_t* mtr, /*!< in: mtr */ - ulint val) /*!< in: value to write */ -{ - byte* log_ptr; - - log_ptr = mlog_open(mtr, 10); - - /* If no logging is requested, we may return now */ - if (log_ptr == NULL) { - - return; - } - - log_ptr += mach_write_compressed(log_ptr, val); - - mlog_close(mtr, log_ptr); -} - /********************************************************//** Catenates a compressed 64-bit integer to mlog. */ UNIV_INLINE From b21dc119865993916abc736081e8ceed1e165961 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 24 Dec 2019 18:10:18 +0400 Subject: [PATCH 4/5] MDEV-21389 Derive Item_func_month from Item_long_func --- sql/item_timefunc.h | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 46f0da2ed2a..6373aa517ba 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -170,28 +170,13 @@ public: }; -class Item_func_month :public Item_func +class Item_func_month :public Item_long_func { public: - Item_func_month(THD *thd, Item *a): Item_func(thd, a) - { collation.set_numeric(); } + Item_func_month(THD *thd, Item *a): Item_long_func(thd, a) + { } longlong val_int(); - double val_real() - { DBUG_ASSERT(fixed == 1); return (double) Item_func_month::val_int(); } - String *val_str(String *str) - { - longlong nr= val_int(); - if (null_value) - return 0; - str->set(nr, collation.collation); - return str; - } - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) - { - return get_date_from_int(ltime, fuzzydate); - } const char *func_name() const { return "month"; } - const Type_handler *type_handler() const { return &type_handler_long; } bool fix_length_and_dec() { decimals= 0; From ee9a19fb054085fcea006a25ec957e0d5cb01ce8 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 25 Dec 2019 12:23:24 +0400 Subject: [PATCH 5/5] MDEV-21392 Cleanup redundant overriding in Item_sum_num --- sql/item_sum.cc | 22 +----- sql/item_sum.h | 97 +++++++++++++++---------- sql/item_windowfunc.h | 164 ++++++++++++++++++++++++------------------ sql/sql_window.cc | 6 +- 4 files changed, 156 insertions(+), 133 deletions(-) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 08ee190e96c..91b75b776e2 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1093,19 +1093,6 @@ void Aggregator_distinct::endup() } -String * -Item_sum_num::val_str(String *str) -{ - return val_string_from_real(str); -} - - -my_decimal *Item_sum_num::val_decimal(my_decimal *decimal_value) -{ - return val_decimal_from_real(decimal_value); -} - - String * Item_sum_int::val_str(String *str) { @@ -2188,7 +2175,7 @@ static double variance_fp_recurrence_result(double s, ulonglong count, bool is_s Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item): - Item_sum_num(thd, item), + Item_sum_double(thd, item), count(item->count), sample(item->sample), prec_increment(item->prec_increment) { @@ -2314,13 +2301,6 @@ double Item_sum_variance::val_real() } -my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf) -{ - DBUG_ASSERT(fixed == 1); - return val_decimal_from_real(dec_buf); -} - - void Item_sum_variance::reset_field() { double nr; diff --git a/sql/item_sum.h b/sql/item_sum.h index a3e10c25763..243b6f28944 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -578,6 +578,7 @@ public: void mark_as_window_func_sum_expr() { window_func_sum_expr_flag= true; } bool is_window_func_sum_expr() { return window_func_sum_expr_flag; } virtual void setup_caches(THD *thd) {}; + virtual void set_partition_row_count(ulonglong count) { DBUG_ASSERT(0); } }; @@ -713,33 +714,45 @@ public: class Item_sum_num :public Item_sum { -protected: - /* - val_xxx() functions may be called several times during the execution of a - query. Derived classes that require extensive calculation in val_xxx() - maintain cache of aggregate value. This variable governs the validity of - that cache. - */ - bool is_evaluated; public: - Item_sum_num(THD *thd): Item_sum(thd), is_evaluated(FALSE) {} + Item_sum_num(THD *thd): Item_sum(thd) {} Item_sum_num(THD *thd, Item *item_par): - Item_sum(thd, item_par), is_evaluated(FALSE) {} + Item_sum(thd, item_par) {} Item_sum_num(THD *thd, Item *a, Item* b): - Item_sum(thd, a, b), is_evaluated(FALSE) {} + Item_sum(thd, a, b) {} Item_sum_num(THD *thd, List &list): - Item_sum(thd, list), is_evaluated(FALSE) {} + Item_sum(thd, list) {} Item_sum_num(THD *thd, Item_sum_num *item): - Item_sum(thd, item),is_evaluated(item->is_evaluated) {} + Item_sum(thd, item) {} bool fix_fields(THD *, Item **); - longlong val_int() { return val_int_from_real(); /* Real as default */ } - String *val_str(String*str); - my_decimal *val_decimal(my_decimal *); + void reset_field(); +}; + + +class Item_sum_double :public Item_sum_num +{ +public: + Item_sum_double(THD *thd): Item_sum_num(thd) {} + Item_sum_double(THD *thd, Item *item_par): Item_sum_num(thd, item_par) {} + Item_sum_double(THD *thd, List &list): Item_sum_num(thd, list) {} + Item_sum_double(THD *thd, Item_sum_double *item) :Item_sum_num(thd, item) {} + longlong val_int() + { + return val_int_from_real(); + } + String *val_str(String*str) + { + return val_string_from_real(str); + } + my_decimal *val_decimal(my_decimal *to) + { + return val_decimal_from_real(to); + } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) { - return type_handler()->Item_get_date(this, ltime, fuzzydate); + return get_date_from_real(ltime, fuzzydate); } - void reset_field(); + const Type_handler *type_handler() const { return &type_handler_double; } }; @@ -753,6 +766,10 @@ public: double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } String *val_str(String*str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_int(ltime, fuzzydate); + } const Type_handler *type_handler() const { return &type_handler_longlong; } bool fix_length_and_dec() { decimals=0; max_length=21; maybe_null=null_value=0; return FALSE; } @@ -794,6 +811,10 @@ public: longlong val_int(); String *val_str(String*str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } void fix_length_and_dec_double(); @@ -964,7 +985,7 @@ But, this falls prey to catastrophic cancellation. Instead, use the recurrence */ -class Item_sum_variance : public Item_sum_num +class Item_sum_variance : public Item_sum_double { bool fix_length_and_dec(); @@ -975,7 +996,7 @@ public: uint prec_increment; Item_sum_variance(THD *thd, Item *item_par, uint sample_arg): - Item_sum_num(thd, item_par), count(0), + Item_sum_double(thd, item_par), count(0), sample(sample_arg) {} Item_sum_variance(THD *thd, Item_sum_variance *item); @@ -985,7 +1006,6 @@ public: void clear(); bool add(); double val_real(); - my_decimal *val_decimal(my_decimal *); void reset_field(); void update_field(); Item *result_item(THD *thd, Field *field); @@ -994,11 +1014,10 @@ public: { return sample ? "var_samp(" : "variance("; } Item *copy_or_same(THD* thd); Field *create_tmp_field(bool group, TABLE *table); - const Type_handler *type_handler() const { return &type_handler_double; } void cleanup() { count= 0; - Item_sum_num::cleanup(); + Item_sum_double::cleanup(); } Item *get_copy(THD *thd) { return get_item_copy(thd, this); } @@ -1679,15 +1698,15 @@ public: #else /* Dummy functions to get sql_yacc.cc compiled */ -class Item_sum_udf_float :public Item_sum_num +class Item_sum_udf_float :public Item_sum_double { public: Item_sum_udf_float(THD *thd, udf_func *udf_arg): - Item_sum_num(thd) {} + Item_sum_double(thd) {} Item_sum_udf_float(THD *thd, udf_func *udf_arg, List &list): - Item_sum_num(thd) {} + Item_sum_double(thd) {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) - :Item_sum_num(thd, item) {} + :Item_sum_double(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } void clear() {} @@ -1696,15 +1715,15 @@ class Item_sum_udf_float :public Item_sum_num }; -class Item_sum_udf_int :public Item_sum_num +class Item_sum_udf_int :public Item_sum_double { public: Item_sum_udf_int(THD *thd, udf_func *udf_arg): - Item_sum_num(thd) {} + Item_sum_double(thd) {} Item_sum_udf_int(THD *thd, udf_func *udf_arg, List &list): - Item_sum_num(thd) {} + Item_sum_double(thd) {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) - :Item_sum_num(thd, item) {} + :Item_sum_double(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; } double val_real() { DBUG_ASSERT(fixed == 1); return 0; } @@ -1714,15 +1733,15 @@ public: }; -class Item_sum_udf_decimal :public Item_sum_num +class Item_sum_udf_decimal :public Item_sum_double { public: Item_sum_udf_decimal(THD *thd, udf_func *udf_arg): - Item_sum_num(thd) {} + Item_sum_double(thd) {} Item_sum_udf_decimal(THD *thd, udf_func *udf_arg, List &list): - Item_sum_num(thd) {} + Item_sum_double(thd) {} Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item) - :Item_sum_num(thd, item) {} + :Item_sum_double(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } @@ -1732,15 +1751,15 @@ class Item_sum_udf_decimal :public Item_sum_num }; -class Item_sum_udf_str :public Item_sum_num +class Item_sum_udf_str :public Item_sum_double { public: Item_sum_udf_str(THD *thd, udf_func *udf_arg): - Item_sum_num(thd) {} + Item_sum_double(thd) {} Item_sum_udf_str(THD *thd, udf_func *udf_arg, List &list): - Item_sum_num(thd) {} + Item_sum_double(thd) {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) - :Item_sum_num(thd, item) {} + :Item_sum_double(thd, item) {} String *val_str(String *) { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } double val_real() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; } diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index cc67c02f1ee..971b316ca99 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -438,27 +438,38 @@ class Item_sum_lag : public Item_sum_hybrid_simple { return get_item_copy(thd, this); } }; -/* - A base window function (aggregate) that also holds a counter for the number - of rows. -*/ -class Item_sum_window_with_row_count : public Item_sum_num + +class Partition_row_count { - public: - Item_sum_window_with_row_count(THD *thd) : Item_sum_num(thd), - partition_row_count_(0) {} - - Item_sum_window_with_row_count(THD *thd, Item *arg) : - Item_sum_num(thd, arg), partition_row_count_(0) {}; - - void set_row_count(ulonglong count) { partition_row_count_ = count; } - - protected: +public: + Partition_row_count() :partition_row_count_(0) { } + void set_partition_row_count(ulonglong count) + { + partition_row_count_ = count; + } + double calc_val_real(bool *null_value, + ulonglong current_row_count) + { + if ((*null_value= (partition_row_count_ == 0))) + return 0; + return static_cast(current_row_count) / partition_row_count_; + } +protected: longlong get_row_count() { return partition_row_count_; } - private: ulonglong partition_row_count_; }; + +class Current_row_count +{ +public: + Current_row_count() :current_row_count_(0) { } +protected: + ulonglong get_row_number() { return current_row_count_ ; } + ulonglong current_row_count_; +}; + + /* @detail "The relative rank of a row R is defined as (RK-1)/(NR-1), where RK is @@ -470,11 +481,12 @@ class Item_sum_window_with_row_count : public Item_sum_num This is held within the row_count context. - Second pass to compute rank of current row and the value of the function */ -class Item_sum_percent_rank: public Item_sum_window_with_row_count +class Item_sum_percent_rank: public Item_sum_double, + public Partition_row_count { public: Item_sum_percent_rank(THD *thd) - : Item_sum_window_with_row_count(thd), cur_rank(1), peer_tracker(NULL) {} + : Item_sum_double(thd), cur_rank(1), peer_tracker(NULL) {} longlong val_int() { @@ -527,6 +539,12 @@ class Item_sum_percent_rank: public Item_sum_window_with_row_count } void setup_window_func(THD *thd, Window_spec *window_spec); + + void set_partition_row_count(ulonglong count) + { + Partition_row_count::set_partition_row_count(count); + } + Item *get_copy(THD *thd) { return get_item_copy(thd, this); } @@ -561,25 +579,17 @@ class Item_sum_percent_rank: public Item_sum_window_with_row_count two passes. */ -class Item_sum_cume_dist: public Item_sum_window_with_row_count +class Item_sum_cume_dist: public Item_sum_double, + public Partition_row_count, + public Current_row_count { public: - Item_sum_cume_dist(THD *thd) : Item_sum_window_with_row_count(thd), - current_row_count_(0) {} - - Item_sum_cume_dist(THD *thd, Item *arg) : Item_sum_window_with_row_count(thd,arg), - current_row_count_(0) {} + Item_sum_cume_dist(THD *thd) :Item_sum_double(thd) { } + Item_sum_cume_dist(THD *thd, Item *arg) :Item_sum_double(thd, arg) { } double val_real() { - if (get_row_count() == 0) - { - null_value= true; - return 0; - } - ulonglong partition_row_count= get_row_count(); - null_value= false; - return static_cast(current_row_count_) / partition_row_count; + return calc_val_real(&null_value, current_row_count_); } bool add() @@ -596,7 +606,7 @@ class Item_sum_cume_dist: public Item_sum_window_with_row_count void clear() { current_row_count_= 0; - set_row_count(0); + partition_row_count_= 0; } const char*func_name() const @@ -614,29 +624,24 @@ class Item_sum_cume_dist: public Item_sum_window_with_row_count return FALSE; } + void set_partition_row_count(ulonglong count) + { + Partition_row_count::set_partition_row_count(count); + } + Item *get_copy(THD *thd) { return get_item_copy(thd, this); } - ulonglong get_row_number() - { - return current_row_count_ ; - } - - private: - ulonglong current_row_count_; }; -class Item_sum_ntile : public Item_sum_window_with_row_count +class Item_sum_ntile : public Item_sum_int, + public Partition_row_count, + public Current_row_count { public: Item_sum_ntile(THD* thd, Item* num_quantiles_expr) : - Item_sum_window_with_row_count(thd, num_quantiles_expr), - current_row_count_(0) {}; - - double val_real() - { - return (double) val_int(); - } + Item_sum_int(thd, num_quantiles_expr) + { } longlong val_int() { @@ -677,7 +682,7 @@ class Item_sum_ntile : public Item_sum_window_with_row_count void clear() { current_row_count_= 0; - set_row_count(0); + partition_row_count_= 0; } const char*func_name() const @@ -687,21 +692,25 @@ class Item_sum_ntile : public Item_sum_window_with_row_count void update_field() {} - const Type_handler *type_handler() const { return &type_handler_longlong; } - + void set_partition_row_count(ulonglong count) + { + Partition_row_count::set_partition_row_count(count); + } + Item *get_copy(THD *thd) { return get_item_copy(thd, this); } private: longlong get_num_quantiles() { return args[0]->val_int(); } - ulong current_row_count_; }; -class Item_sum_percentile_disc : public Item_sum_cume_dist, - public Type_handler_hybrid_field_type +class Item_sum_percentile_disc : public Item_sum_num, + public Type_handler_hybrid_field_type, + public Partition_row_count, + public Current_row_count { public: - Item_sum_percentile_disc(THD *thd, Item* arg) : Item_sum_cume_dist(thd, arg), + Item_sum_percentile_disc(THD *thd, Item* arg) : Item_sum_num(thd, arg), Type_handler_hybrid_field_type(&type_handler_longlong), value(NULL), val_calculated(FALSE), first_call(TRUE), prev_value(0), order_item(NULL){} @@ -750,6 +759,17 @@ public: return value->val_str(str); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + if (get_row_count() == 0 || get_arg(0)->is_null()) + { + null_value= true; + return 0; + } + null_value= false; + return value->get_date(ltime, fuzzydate); + } + bool add() { Item *arg= get_arg(0); @@ -783,8 +803,8 @@ public: if (value->null_value) return false; - Item_sum_cume_dist::add(); - double val= Item_sum_cume_dist::val_real(); + current_row_count_++; + double val= calc_val_real(&null_value, current_row_count_); if (val >= prev_value && !val_calculated) val_calculated= true; @@ -801,7 +821,8 @@ public: val_calculated= false; first_call= true; value->clear(); - Item_sum_cume_dist::clear(); + partition_row_count_= 0; + current_row_count_= 0; } const char*func_name() const @@ -810,7 +831,6 @@ public: } void update_field() {} - void set_type_handler(Window_spec *window_spec); const Type_handler *type_handler() const {return Type_handler_hybrid_field_type::type_handler();} @@ -821,6 +841,11 @@ public: return FALSE; } + void set_partition_row_count(ulonglong count) + { + Partition_row_count::set_partition_row_count(count); + } + Item *get_copy(THD *thd) { return get_item_copy(thd, this); } void setup_window_func(THD *thd, Window_spec *window_spec); @@ -835,12 +860,12 @@ private: Item *order_item; }; -class Item_sum_percentile_cont : public Item_sum_cume_dist, - public Type_handler_hybrid_field_type +class Item_sum_percentile_cont : public Item_sum_double, + public Partition_row_count, + public Current_row_count { public: - Item_sum_percentile_cont(THD *thd, Item* arg) : Item_sum_cume_dist(thd, arg), - Type_handler_hybrid_field_type(&type_handler_double), + Item_sum_percentile_cont(THD *thd, Item* arg) : Item_sum_double(thd, arg), floor_value(NULL), ceil_value(NULL), first_call(TRUE),prev_value(0), ceil_val_calculated(FALSE), floor_val_calculated(FALSE), order_item(NULL){} @@ -910,7 +935,7 @@ public: return false; } - Item_sum_cume_dist::add(); + current_row_count_++; double val= 1 + prev_value * (get_row_count()-1); if (!floor_val_calculated && get_row_number() == floor(val)) @@ -933,7 +958,8 @@ public: ceil_value->clear(); floor_val_calculated= false; ceil_val_calculated= false; - Item_sum_cume_dist::clear(); + partition_row_count_= 0; + current_row_count_= 0; } const char*func_name() const @@ -941,9 +967,6 @@ public: return "percentile_cont"; } void update_field() {} - void set_type_handler(Window_spec *window_spec); - const Type_handler *type_handler() const - {return Type_handler_hybrid_field_type::type_handler();} bool fix_length_and_dec() { @@ -952,6 +975,11 @@ public: return FALSE; } + void set_partition_row_count(ulonglong count) + { + Partition_row_count::set_partition_row_count(count); + } + Item *get_copy(THD *thd) { return get_item_copy(thd, this); } void setup_window_func(THD *thd, Window_spec *window_spec); diff --git a/sql/sql_window.cc b/sql/sql_window.cc index a6c9dd3fea7..7e319c96000 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -1779,11 +1779,7 @@ protected: List_iterator_fast it(sum_functions); Item_sum* item; while ((item= it++)) - { - Item_sum_window_with_row_count* item_with_row_count = - static_cast(item); - item_with_row_count->set_row_count(num_rows_in_partition); - } + item->set_partition_row_count(num_rows_in_partition); } };