From 380b5819a20d93f0e0430bc9225e55a54cb52dcf Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Mar 2005 14:29:22 +0100 Subject: [PATCH 1/9] Fix for Bug #8897 Test ndb_autodiscover: Spurious warning in --ps-protocol on NDB --- sql/mysql_priv.h | 2 +- sql/sql_base.cc | 3 ++- sql/sql_error.cc | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7e58f7bf728..de1cbf5d9cd 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -817,7 +817,7 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint const char *msg); void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code, const char *format, ...); -void mysql_reset_errors(THD *thd); +void mysql_reset_errors(THD *thd, bool force= false); bool mysqld_show_warnings(THD *thd, ulong levels_to_show); /* sql_handler.cc */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4fd943c08f4..09640eb3f57 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1606,7 +1606,8 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, if (ha_create_table_from_engine(thd, db, name, TRUE) != 0) goto err; - thd->clear_error(); // Clear error message + mysql_reset_errors(thd, true); // Clear warnings + thd->clear_error(); // Clear error message continue; } diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 4d254b95514..4420f2d16ad 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -64,6 +64,7 @@ void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg) SYNOPSIS mysql_reset_errors() thd Thread handle + force Reset warnings even if it has been done before IMPLEMENTATION Don't reset warnings if this has already been called for this query. @@ -71,14 +72,15 @@ void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg) in which case push_warnings() has already called this function. */ -void mysql_reset_errors(THD *thd) +void mysql_reset_errors(THD *thd, bool force) { DBUG_ENTER("mysql_reset_errors"); - if (thd->query_id != thd->warn_id) + if (thd->query_id != thd->warn_id || force) { thd->warn_id= thd->query_id; free_root(&thd->warn_root,MYF(0)); bzero((char*) thd->warn_count, sizeof(thd->warn_count)); + if (force) thd->total_warn_count= 0; thd->warn_list.empty(); thd->row_count= 1; // by default point to row 1 } From 7cecea527d5fcfa7c12c55ee3c95347ee8f43b15 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 12 Mar 2005 23:31:52 -0800 Subject: [PATCH 2/9] join_outer.result, join_outer.test: Added a test case for bug #9017. item_cmpfunc.h: A wrong not_null_tables method for Item_cond_xor caused a conversion of a left join into an inner join that was not valid. sql/item_cmpfunc.h: A wrong not_null_tables method for Item_cond_xor caused a conversion of a left join into an inner join that was not valid. mysql-test/t/join_outer.test: Added a test case for bug #9017. mysql-test/r/join_outer.result: Added a test case for bug #9017. --- mysql-test/r/join_outer.result | 22 ++++++++++++++++++++++ mysql-test/t/join_outer.test | 19 +++++++++++++++++++ sql/item_cmpfunc.h | 1 + 3 files changed, 42 insertions(+) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 09a55ba2054..7981fc9c733 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -836,3 +836,25 @@ id text_id text_data 1 0 0-SV 2 10 10-SV DROP TABLE invoice, text_table; +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); +INSERT INTO t1 VALUES (1,1), (2,1), (3,1), (4,2); +INSERT INTO t2 VALUES (1,2), (2,2); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a; +a b a b +1 1 1 2 +2 1 2 2 +3 1 NULL NULL +4 2 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a WHERE t1.b=1; +a b a b +1 1 1 2 +2 1 2 2 +3 1 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a +WHERE t1.b=1 XOR (NOT ISNULL(t2.a) AND t2.b=1); +a b a b +1 1 1 2 +2 1 2 2 +3 1 NULL NULL +DROP TABLE t1,t2; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 8096176a744..2ed7086746f 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -595,3 +595,22 @@ SELECT invoice.id, invoice.text_id, text_table.text_data WHERE (invoice.id LIKE '%' OR text_table.text_data LIKE '%'); DROP TABLE invoice, text_table; + +# +# Test for bug #9017: left join mistakingly converted to inner join +# + +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); + +INSERT INTO t1 VALUES (1,1), (2,1), (3,1), (4,2); +INSERT INTO t2 VALUES (1,2), (2,2); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a WHERE t1.b=1; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a + WHERE t1.b=1 XOR (NOT ISNULL(t2.a) AND t2.b=1); + +DROP TABLE t1,t2; + + diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8e8e4e922c0..7c48854850e 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1013,6 +1013,7 @@ public: enum Type type() const { return FUNC_ITEM; } longlong val_int(); const char *func_name() const { return "xor"; } + table_map not_null_tables() const { return and_tables_cache; } }; From dad8e1f59a30e6bdc45bf57d6b3404313d8b2b25 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 13 Mar 2005 01:07:01 -0800 Subject: [PATCH 3/9] join_outer.test: Correction after manual merge. mysql-test/t/join_outer.test: Correction after manual merge. --- mysql-test/t/join_outer.test | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 87e31d7affc..f87233bff12 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -588,6 +588,12 @@ INSERT INTO t2 VALUES("0", "SV", "0-SV"); INSERT INTO t2 VALUES("10", "EN", "10-EN"); INSERT INTO t2 VALUES("10", "SV", "10-SV"); +SELECT t1.id, t1.text_id, t2.text_data + FROM t1 LEFT JOIN t2 + ON t1.text_id = t2.text_id + AND t2.language_id = 'SV' + WHERE (t1.id LIKE '%' OR t2.text_data LIKE '%'); + DROP TABLE t1, t2; # Test for bug #5896 From a569b08375672b561bd1d15a66fc1dafa69c72a5 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 13 Mar 2005 12:49:39 +0200 Subject: [PATCH 4/9] set_var.cc, mysqld.cc, ha_innodb.cc, sql_class.h: Add a settable session variable innodb_support_xa; setting it to 0 can save up to 10 % of CPU time and 150 bytes of space in each undo log trx0trx.h, trx0undo.c, trx0trx.c, trx0roll.c: Enable XA if innodb_support_xa is not set to 0; make prepare to do log fsync's according to innodb_flush_log_at_trx_commit innobase/trx/trx0roll.c: Enable XA if innodb_support_xa is not set to 0; make prepare to do log fsync's according to innodb_flush_log_at_trx_commit innobase/trx/trx0trx.c: Enable XA if innodb_support_xa is not set to 0; make prepare to do log fsync's according to innodb_flush_log_at_trx_commit innobase/trx/trx0undo.c: Enable XA if innodb_support_xa is not set to 0; make prepare to do log fsync's according to innodb_flush_log_at_trx_commit innobase/include/trx0trx.h: Enable XA if innodb_support_xa is not set to 0; make prepare to do log fsync's according to innodb_flush_log_at_trx_commit sql/sql_class.h: Add a settable session variable innodb_support_xa; setting it to 0 can save up to 10 % of CPU time and 150 bytes of space in each undo log sql/ha_innodb.cc: Add a settable session variable innodb_support_xa; setting it to 0 can save up to 10 % of CPU time and 150 bytes of space in each undo log sql/mysqld.cc: Add a settable session variable innodb_support_xa; setting it to 0 can save up to 10 % of CPU time and 150 bytes of space in each undo log sql/set_var.cc: Add a settable session variable innodb_support_xa; setting it to 0 can save up to 10 % of CPU time and 150 bytes of space in each undo log --- innobase/include/trx0trx.h | 5 ++ innobase/trx/trx0roll.c | 14 ++--- innobase/trx/trx0trx.c | 104 +++++++++++++++++++++++++------------ innobase/trx/trx0undo.c | 31 +++++++---- sql/ha_innodb.cc | 15 ++++++ sql/mysqld.cc | 6 +++ sql/set_var.cc | 4 ++ sql/sql_class.h | 1 + 8 files changed, 127 insertions(+), 53 deletions(-) diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 61d372a824a..9db69261468 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -369,6 +369,11 @@ struct trx_struct{ XID xid; /* X/Open XA transaction identification to identify a transaction branch */ + ibool support_xa; /* normally we do the XA two-phase + commit steps, but by setting this to + FALSE, one can save CPU time and about + 150 bytes in the undo log size as then + we skip XA steps */ dulint no; /* transaction serialization number == max trx id when the transaction is moved to COMMITTED_IN_MEMORY state */ diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c index 4c68e0a0dd3..69f7a99187f 100644 --- a/innobase/trx/trx0roll.c +++ b/innobase/trx/trx0roll.c @@ -441,16 +441,8 @@ loop: trx = UT_LIST_GET_NEXT(trx_list, trx); } else if (trx->conc_state == TRX_PREPARED) { - /* Roll back all prepared transactions if - innobase_force_recovery > 0 in my.cnf */ - - if (srv_force_recovery > 0) { - trx->conc_state = TRX_ACTIVE; - break; - } else { - trx->sess = trx_dummy_sess; - trx = UT_LIST_GET_NEXT(trx_list, trx); - } + trx->sess = trx_dummy_sess; + trx = UT_LIST_GET_NEXT(trx_list, trx); } else { break; } @@ -461,7 +453,7 @@ loop: if (trx == NULL) { ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB: Rollback of uncommitted transactions completed\n"); + " InnoDB: Rollback of non-prepared transactions completed\n"); mem_heap_free(heap); diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index ad82560e26c..614058e6860 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -93,6 +93,8 @@ trx_create( trx->id = ut_dulint_zero; trx->no = ut_dulint_max; + trx->support_xa = TRUE; + trx->check_foreigns = TRUE; trx->check_unique_secondary = TRUE; @@ -453,9 +455,15 @@ trx_lists_init_at_db_start(void) ut_dulint_get_high(trx->id), ut_dulint_get_low(trx->id)); - trx->conc_state = TRX_ACTIVE; + if (srv_force_recovery == 0) { - /* trx->conc_state = TRX_PREPARED;*/ + trx->conc_state = TRX_PREPARED; + } else { + fprintf(stderr, +"InnoDB: Since innodb_force_recovery > 0, we will rollback it anyway.\n"); + + trx->conc_state = TRX_ACTIVE; + } } else { trx->conc_state = TRX_COMMITTED_IN_MEMORY; @@ -511,15 +519,20 @@ trx_lists_init_at_db_start(void) commit or abort decision from MySQL */ if (undo->state == TRX_UNDO_PREPARED) { - fprintf(stderr, + fprintf(stderr, "InnoDB: Transaction %lu %lu was in the XA prepared state.\n", - ut_dulint_get_high(trx->id), - ut_dulint_get_low(trx->id)); + ut_dulint_get_high(trx->id), + ut_dulint_get_low(trx->id)); + + if (srv_force_recovery == 0) { + + trx->conc_state = TRX_PREPARED; + } else { + fprintf(stderr, +"InnoDB: Since innodb_force_recovery > 0, we will rollback it anyway.\n"); trx->conc_state = TRX_ACTIVE; - - /* trx->conc_state = - TRX_PREPARED; */ + } } else { trx->conc_state = TRX_COMMITTED_IN_MEMORY; @@ -823,9 +836,6 @@ trx_commit_off_kernel( trx->read_view = NULL; } -/* fprintf(stderr, "Trx %lu commit finished\n", - ut_dulint_get_low(trx->id)); */ - if (must_flush_log) { mutex_exit(&kernel_mutex); @@ -869,14 +879,15 @@ trx_commit_off_kernel( /* Do nothing */ } else if (srv_flush_log_at_trx_commit == 1) { if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { - /* Write the log but do not flush it to disk */ + /* Write the log but do not flush it to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, + FALSE); } else { - /* Write the log to the log files AND flush - them to disk */ + /* Write the log to the log files AND flush + them to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); } } else if (srv_flush_log_at_trx_commit == 2) { @@ -1747,12 +1758,11 @@ Prepares a transaction. */ void trx_prepare_off_kernel( -/*==================*/ +/*===================*/ trx_t* trx) /* in: transaction */ { page_t* update_hdr_page; trx_rseg_t* rseg; - trx_undo_t* undo; ibool must_flush_log = FALSE; dulint lsn; mtr_t mtr; @@ -1779,19 +1789,18 @@ trx_prepare_off_kernel( mutex_enter(&(rseg->mutex)); if (trx->insert_undo != NULL) { + + /* It is not necessary to obtain trx->undo_mutex here + because only a single OS thread is allowed to do the + transaction prepare for this transaction. */ + trx_undo_set_state_at_prepare(trx, trx->insert_undo, &mtr); } - undo = trx->update_undo; - - if (undo) { - /* It is not necessary to obtain trx->undo_mutex here - because only a single OS thread is allowed to do the - transaction prepare for this transaction. */ - + if (trx->update_undo) { update_hdr_page = trx_undo_set_state_at_prepare(trx, - undo, &mtr); + trx->update_undo, &mtr); } mutex_exit(&(rseg->mutex)); @@ -1815,17 +1824,48 @@ trx_prepare_off_kernel( /*--------------------------------------*/ if (must_flush_log) { + /* Depending on the my.cnf options, we may now write the log + buffer to the log files, making the prepared state of the + transaction durable if the OS does not crash. We may also + flush the log files to disk, making the prepared state of the + transaction durable also at an OS crash or a power outage. + + The idea in InnoDB's group prepare is that a group of + transactions gather behind a trx doing a physical disk write + to log files, and when that physical write has been completed, + one of those transactions does a write which prepares the whole + group. Note that this group prepare will only bring benefit if + there are > 2 users in the database. Then at least 2 users can + gather behind one doing the physical log write to disk. + + TODO: find out if MySQL holds some mutex when calling this. + That would spoil our group prepare algorithm. */ mutex_exit(&kernel_mutex); - - /* Write the log to the log files AND flush them to disk */ - /*-------------------------------------*/ + if (srv_flush_log_at_trx_commit == 0) { + /* Do nothing */ + } else if (srv_flush_log_at_trx_commit == 1) { + if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { + /* Write the log but do not flush it to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, + FALSE); + } else { + /* Write the log to the log files AND flush + them to disk */ + + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); + } + } else if (srv_flush_log_at_trx_commit == 2) { + + /* Write the log but do not flush it to disk */ + + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); + } else { + ut_error; + } - /*-------------------------------------*/ - mutex_enter(&kernel_mutex); } } diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c index 88185973dfc..bb314dd35e9 100644 --- a/innobase/trx/trx0undo.c +++ b/innobase/trx/trx0undo.c @@ -596,7 +596,7 @@ trx_undo_read_xid( } /******************************************************************* -Adds the XA XID after an undo log old-style header. */ +Adds space for the XA XID after an undo log old-style header. */ static void trx_undo_header_add_space_for_xid( @@ -1488,6 +1488,7 @@ trx_undo_create( /*============*/ /* out: undo log object, NULL if did not succeed: out of space */ + trx_t* trx, /* in: transaction */ trx_rseg_t* rseg, /* in: rollback segment memory copy */ ulint type, /* in: type of the log: TRX_UNDO_INSERT or TRX_UNDO_UPDATE */ @@ -1530,7 +1531,10 @@ trx_undo_create( offset = trx_undo_header_create(undo_page, trx_id, mtr); - trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, mtr); + if (trx->support_xa) { + trx_undo_header_add_space_for_xid(undo_page, + undo_page + offset, mtr); + } undo = trx_undo_mem_create(rseg, id, type, trx_id, xid, page_no, offset); @@ -1547,6 +1551,7 @@ trx_undo_reuse_cached( /*==================*/ /* out: the undo log memory object, NULL if none cached */ + trx_t* trx, /* in: transaction */ trx_rseg_t* rseg, /* in: rollback segment memory object */ ulint type, /* in: type of the log: TRX_UNDO_INSERT or TRX_UNDO_UPDATE */ @@ -1597,16 +1602,22 @@ trx_undo_reuse_cached( if (type == TRX_UNDO_INSERT) { offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr); - trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, - mtr); + + if (trx->support_xa) { + trx_undo_header_add_space_for_xid(undo_page, + undo_page + offset, mtr); + } } else { ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_UPDATE); offset = trx_undo_header_create(undo_page, trx_id, mtr); - trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, - mtr); + + if (trx->support_xa) { + trx_undo_header_add_space_for_xid(undo_page, + undo_page + offset, mtr); + } } trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset); @@ -1674,11 +1685,11 @@ trx_undo_assign_undo( #endif /* UNIV_SYNC_DEBUG */ mutex_enter(&(rseg->mutex)); - undo = trx_undo_reuse_cached(rseg, type, trx->id, &trx->xid, &mtr); - + undo = trx_undo_reuse_cached(trx, rseg, type, trx->id, &trx->xid, + &mtr); if (undo == NULL) { - undo = trx_undo_create(rseg, type, trx->id, &trx->xid, &mtr); - + undo = trx_undo_create(trx, rseg, type, trx->id, &trx->xid, + &mtr); if (undo == NULL) { /* Did not succeed */ diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 4dee14c27b4..f3ca1de0bba 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -690,6 +690,10 @@ check_trx_exists( trx->mysql_query_str = &(thd->query); trx->active_trans = 0; + /* Update the info whether we should skip XA steps that eat + CPU time */ + trx->support_xa = (ibool)(thd->variables.innodb_support_xa); + thd->ha_data[innobase_hton.slot] = trx; } else { if (trx->magic_n != TRX_MAGIC_N) { @@ -1434,6 +1438,9 @@ innobase_commit( trx = check_trx_exists(thd); + /* Update the info whether we should skip XA steps that eat CPU time */ + trx->support_xa = (ibool)(thd->variables.innodb_support_xa); + /* Release a possible FIFO ticket and search latch. Since we will reserve the kernel mutex, we have to release the search system latch first to obey the latching order. */ @@ -1620,6 +1627,9 @@ innobase_rollback( trx = check_trx_exists(thd); + /* Update the info whether we should skip XA steps that eat CPU time */ + trx->support_xa = (ibool)(thd->variables.innodb_support_xa); + /* Release a possible FIFO ticket and search latch. Since we will reserve the kernel mutex, we have to release the search system latch first to obey the latching order. */ @@ -6308,6 +6318,11 @@ innobase_xa_prepare( int error = 0; trx_t* trx; + if (!thd->variables.innodb_support_xa) { + + return(0); + } + trx = check_trx_exists(thd); trx->xid=thd->transaction.xid; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8271f8fa473..2913b930f89 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4211,6 +4211,7 @@ enum options_mysqld OPT_INNODB_STATUS_FILE, OPT_INNODB_MAX_DIRTY_PAGES_PCT, OPT_INNODB_TABLE_LOCKS, + OPT_INNODB_SUPPORT_XA, OPT_INNODB_OPEN_FILES, OPT_INNODB_AUTOEXTEND_INCREMENT, OPT_INNODB_SYNC_SPIN_LOOPS, @@ -4514,6 +4515,11 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, (gptr*) &global_system_variables.innodb_table_locks, (gptr*) &global_system_variables.innodb_table_locks, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, + {"innodb_support_xa", OPT_INNODB_SUPPORT_XA, + "Enable InnoDB support for the XA two-phase commit", + (gptr*) &global_system_variables.innodb_support_xa, + (gptr*) &global_system_variables.innodb_support_xa, + 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, #endif /* End HAVE_INNOBASE_DB */ {"isam", OPT_ISAM, "Enable ISAM (if this version of MySQL supports it). \ Disable with --skip-isam.", diff --git a/sql/set_var.cc b/sql/set_var.cc index ad8eaee10f2..bb5d386934d 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -392,6 +392,8 @@ sys_var_long_ptr sys_innodb_max_purge_lag("innodb_max_purge_lag", &srv_max_purge_lag); sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks", &SV::innodb_table_locks); +sys_var_thd_bool sys_innodb_support_xa("innodb_support_xa", + &SV::innodb_support_xa); sys_var_long_ptr sys_innodb_autoextend_increment("innodb_autoextend_increment", &srv_auto_extend_increment); sys_var_long_ptr sys_innodb_sync_spin_loops("innodb_sync_spin_loops", @@ -689,6 +691,7 @@ sys_var *sys_variables[]= &sys_innodb_max_dirty_pages_pct, &sys_innodb_max_purge_lag, &sys_innodb_table_locks, + &sys_innodb_support_xa, &sys_innodb_max_purge_lag, &sys_innodb_autoextend_increment, &sys_innodb_sync_spin_loops, @@ -810,6 +813,7 @@ struct show_var_st init_vars[]= { {"innodb_open_files", (char*) &innobase_open_files, SHOW_LONG }, {sys_innodb_sync_spin_loops.name, (char*) &sys_innodb_sync_spin_loops, SHOW_SYS}, {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS}, + {sys_innodb_support_xa.name, (char*) &sys_innodb_support_xa, SHOW_SYS}, {sys_innodb_thread_concurrency.name, (char*) &sys_innodb_thread_concurrency, SHOW_SYS}, {sys_innodb_thread_sleep_delay.name, (char*) &sys_innodb_thread_sleep_delay, SHOW_SYS}, #endif diff --git a/sql/sql_class.h b/sql/sql_class.h index e185631f5d6..2335ff54bfd 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -578,6 +578,7 @@ struct system_variables #endif /* HAVE_REPLICATION */ #ifdef HAVE_INNOBASE_DB my_bool innodb_table_locks; + my_bool innodb_support_xa; #endif /* HAVE_INNOBASE_DB */ #ifdef HAVE_NDBCLUSTER_DB ulong ndb_autoincrement_prefetch_sz; From 53ffcff7beaa3f9d655bfadf00a28f29946098fd Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 13 Mar 2005 22:46:57 +0200 Subject: [PATCH 5/9] row0mysql.c: Correct web links fil0fil.c: Correct (?) English grammar innobase/fil/fil0fil.c: Correct (?) English grammar innobase/row/row0mysql.c: Correct web links --- innobase/fil/fil0fil.c | 14 +++++++------- innobase/row/row0mysql.c | 10 ++++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 3ff70aece5e..74970648c1a 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -2621,12 +2621,12 @@ fil_open_single_table_tablespace( fputs("!\n" "InnoDB: Have you moved InnoDB .ibd files around without using the\n" "InnoDB: commands DISCARD TABLESPACE and IMPORT TABLESPACE?\n" -"InnoDB: It is also possible that this is a table created with\n" -"InnoDB: CREATE TEMPORARY TABLE, and MySQL removed the .ibd file for this.\n" +"InnoDB: It is also possible that this is a temporary table #sql...,\n" +"InnoDB: and MySQL removed the .ibd file for this.\n" "InnoDB: Please refer to\n" "InnoDB:" " http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n" -"InnoDB: how to resolve the issue.\n", stderr); +"InnoDB: for how to resolve the issue.\n", stderr); mem_free(filepath); @@ -2666,7 +2666,7 @@ fil_open_single_table_tablespace( "InnoDB: Please refer to\n" "InnoDB:" " http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n" -"InnoDB: how to resolve the issue.\n", (ulong) space_id, (ulong) id); +"InnoDB: for how to resolve the issue.\n", (ulong) space_id, (ulong) id); ret = FALSE; @@ -3261,7 +3261,7 @@ fil_space_for_table_exists_in_mem( ut_print_filename(stderr, name); fprintf(stderr, "\n" "InnoDB: in InnoDB data dictionary has tablespace id %lu,\n" -"InnoDB: but tablespace with that id does not exist. There is\n" +"InnoDB: but a tablespace with that id does not exist. There is\n" "InnoDB: a tablespace of name %s and id %lu, though. Have\n" "InnoDB: you deleted or moved .ibd files?\n", (ulong) id, namespace->name, @@ -3272,7 +3272,7 @@ fil_space_for_table_exists_in_mem( "InnoDB: Please refer to\n" "InnoDB:" " http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n" -"InnoDB: how to resolve the issue.\n", stderr); +"InnoDB: for how to resolve the issue.\n", stderr); mem_free(path); mutex_exit(&(system->mutex)); @@ -3286,7 +3286,7 @@ fil_space_for_table_exists_in_mem( ut_print_filename(stderr, name); fprintf(stderr, "\n" "InnoDB: in InnoDB data dictionary has tablespace id %lu,\n" -"InnoDB: but tablespace with that id has name %s.\n" +"InnoDB: but the tablespace with that id has name %s.\n" "InnoDB: Have you deleted or moved .ibd files?\n", (ulong) id, space->name); if (namespace != NULL) { diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 5009f017053..2b2b2d83002 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -3382,8 +3382,9 @@ row_rename_table_for_mysql( "InnoDB: data dictionary though MySQL is trying to rename the table.\n" "InnoDB: Have you copied the .frm file of the table to the\n" "InnoDB: MySQL database directory from another database?\n" - "InnoDB: You can look for further help from section 15.1 of\n" - "InnoDB: http://www.innodb.com/ibman.php\n", stderr); + "InnoDB: You can look for further help from\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/" + "InnoDB_troubleshooting_datadict.html\n", stderr); goto funct_exit; } @@ -3395,8 +3396,9 @@ row_rename_table_for_mysql( ut_print_name(stderr, trx, old_name); fputs( " does not have an .ibd file in the database directory.\n" - "InnoDB: You can look for further help from section 15.1 of\n" - "InnoDB: http://www.innodb.com/ibman.php\n", stderr); + "InnoDB: You can look for further help from\n" + "InnoDB: http://dev.mysql.com/doc/mysql/en/" + "InnoDB_troubleshooting_datadict.html\n", stderr); goto funct_exit; } From 1534ed8e1553eb3105bc06d963038a82d548b8d9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 13 Mar 2005 23:50:43 +0300 Subject: [PATCH 6/9] WL#926 "SUM(DISTINCT) and AVG(DISTINCT)": improvement of SUM(DISTINCT) and implementation of AVG(DISTINCT) which utilizes the approach with Fields. The patch implemented in October is portede to the up-to-date tree containing DECIMAL type. Tests for AVG(DISTINCT) (although there is not much to test provided that SUM(DISTINCT) works), cleanups for COUNT(DISTINCT) and GROUP_CONCAT() will follow in another changeset. sql/field.cc: A handy way to init create_field used for use with virtual tmp tables. Feel free to extend it for your own needs. sql/field.h: Declaration for create_field::init_for_tmp_table() sql/item.cc: Implementation for a framework used to easily handle different result types of SQL expressions. Instead of having instances of each possible result type (integer, decimal, double) in every item, variables of all used types are moved to struct Hybrid_type. Hybrid_type can change its dynamic type in runtime, and become, for instance, DECIMAL from INTEGER. All type-specific Item operations are moved to the class hierarchy Hybrid_type_traits. Item::decimals and Item::max_length can be moved to Hybrid_type as well. sql/item.h: Declaration for Hybrid_type framework. See also comments for item.cc in this changeset. sql/item_sum.cc: Rewritten implementation for Item_sum_sum_distinct (SUM(DISTINCT)) and added implementation for Item_sum_avg_distinct (AVG(DISTINCT)). The classes utilize Hybrid_type class hierarchy and Fields to convert SUM/AVG arguments to binary representation and store in a RB-tree. sql/item_sum.h: Declarations for Item_sum_distinct (the new intermediate class used for SUM and AVG distinct), Item_sum_sum_distinct, Item_sum_avg_distinct. sql/sql_select.cc: Implementatio of create_virtual_tmp_table(). sql/sql_select.h: Declaration for create_virtual_tmp_table. sql/sql_yacc.yy: Grammar support for Item_sum_avg_distinct. --- sql/field.cc | 18 +++ sql/field.h | 8 +- sql/item.cc | 125 ++++++++++++++++ sql/item.h | 114 +++++++++++++++ sql/item_sum.cc | 366 ++++++++++++++++++++++++---------------------- sql/item_sum.h | 82 ++++++++--- sql/sql_select.cc | 111 ++++++++++++++ sql/sql_select.h | 1 + sql/sql_yacc.yy | 2 + 9 files changed, 635 insertions(+), 192 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index fd4d83a8b1c..7d17431b4a1 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7150,6 +7150,24 @@ void create_field::create_length_to_internal_length(void) } +void create_field::init_for_tmp_table(enum_field_types sql_type_arg, + uint32 length_arg, uint32 decimals, + bool maybe_null, bool is_unsigned) +{ + field_name= ""; + sql_type= sql_type_arg; + length= length_arg;; + unireg_check= Field::NONE; + interval= 0; + charset= &my_charset_bin; + geom_type= Field::GEOM_GEOMETRY; + pack_flag= (FIELDFLAG_NUMBER | + ((decimals & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) | + (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) | + (is_unsigned ? 0 : FIELDFLAG_DECIMAL)); +} + + enum_field_types get_blob_type_from_length(ulong length) { enum_field_types type; diff --git a/sql/field.h b/sql/field.h index a92ef1db297..083af27d6d9 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1340,7 +1340,8 @@ public: Create field class for CREATE TABLE */ -class create_field :public Sql_alloc { +class create_field :public Sql_alloc +{ public: const char *field_name; const char *change; // If done with alter table @@ -1362,6 +1363,11 @@ public: create_field() :after(0) {} create_field(Field *field, Field *orig_field); void create_length_to_internal_length(void); + + /* Init for a tmp table field. To be extended if need be. */ + void init_for_tmp_table(enum_field_types sql_type_arg, + uint32 max_length, uint32 decimals, + bool maybe_null, bool is_unsigned); }; diff --git a/sql/item.cc b/sql/item.cc index 1096114021e..994bdc86413 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -33,6 +33,131 @@ static void mark_as_dependent(THD *thd, const String my_null_string("NULL", 4, default_charset_info); +/****************************************************************************/ + +/* Hybrid_type_traits {_real} */ + +void Hybrid_type_traits::fix_length_and_dec(Item *item, Item *arg) const +{ + item->decimals= NOT_FIXED_DEC; + item->max_length= item->float_length(arg->decimals); +} + + +const Hybrid_type_traits *Hybrid_type_traits::instance() +{ + const static Hybrid_type_traits real_traits; + return &real_traits; +} + + +my_decimal * +Hybrid_type_traits::val_decimal(Hybrid_type *val, my_decimal *to) const +{ + double2my_decimal(E_DEC_FATAL_ERROR, val->real, val->dec_buf); + return val->dec_buf; +} + + +String * +Hybrid_type_traits::val_str(Hybrid_type *val, String *to, uint8 decimals) const +{ + to->set(val->real, decimals, &my_charset_bin); + return to; +} + +/* Hybrid_type_traits_decimal */ + +const Hybrid_type_traits_decimal *Hybrid_type_traits_decimal::instance() +{ + const static Hybrid_type_traits_decimal decimal_traits; + return &decimal_traits; +} + + +void +Hybrid_type_traits_decimal::fix_length_and_dec(Item *item, Item *arg) const +{ + item->decimals= arg->decimals; + item->max_length= min(arg->max_length + DECIMAL_LONGLONG_DIGITS, + DECIMAL_MAX_LENGTH); +} + + +void Hybrid_type_traits_decimal::set_zero(Hybrid_type *val) const +{ + my_decimal_set_zero(&val->dec_buf[0]); + val->used_dec_buf_no= 0; +} + + +void Hybrid_type_traits_decimal::add(Hybrid_type *val, Field *f) const +{ + my_decimal_add(E_DEC_FATAL_ERROR, + &val->dec_buf[val->used_dec_buf_no ^ 1], + &val->dec_buf[val->used_dec_buf_no], + f->val_decimal(&val->dec_buf[2])); + val->used_dec_buf_no^= 1; +} + + +void Hybrid_type_traits_decimal::div(Hybrid_type *val, ulonglong u) const +{ + int2my_decimal(E_DEC_FATAL_ERROR, u, TRUE, &val->dec_buf[2]); + /* XXX: what is '4' for scale? */ + my_decimal_div(E_DEC_FATAL_ERROR, + &val->dec_buf[val->used_dec_buf_no ^ 1], + &val->dec_buf[val->used_dec_buf_no], + &val->dec_buf[2], 4); + val->used_dec_buf_no^= 1; +} + + +longlong +Hybrid_type_traits_decimal::val_int(Hybrid_type *val, bool unsigned_flag) const +{ + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no], + unsigned_flag, &result); + return result; +} + + +double +Hybrid_type_traits_decimal::val_real(Hybrid_type *val) const +{ + my_decimal2double(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no], + &val->real); + return val->real; +} + + +String * +Hybrid_type_traits_decimal::val_str(Hybrid_type *val, String *to, + uint8 decimals) const +{ + my_decimal_round(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no], + decimals, FALSE, &val->dec_buf[2]); + my_decimal2string(E_DEC_FATAL_ERROR, &val->dec_buf[2], 0, 0, 0, to); + return to; +} + +/* Hybrid_type_traits_integer */ + +const Hybrid_type_traits_integer *Hybrid_type_traits_integer::instance() +{ + const static Hybrid_type_traits_integer integer_traits; + return &integer_traits; +} + +void +Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const +{ + item->decimals= 0; + item->max_length= 21; + item->unsigned_flag= 0; +} + /***************************************************************************** ** Item functions *****************************************************************************/ diff --git a/sql/item.h b/sql/item.h index 97913e40916..a2bf33398cc 100644 --- a/sql/item.h +++ b/sql/item.h @@ -106,6 +106,120 @@ public: } }; + +/*************************************************************************/ +/* + A framework to easily handle different return types for hybrid items + (hybrid item is an item whose operand can be of any type, e.g. integer, + real, decimal). +*/ + +struct Hybrid_type_traits; + +struct Hybrid_type +{ + longlong integer; + + double real; + /* + Use two decimal buffers interchangeably to speed up += operation + which has no native support in decimal library. + Hybrid_type+= arg is implemented as dec_buf[1]= dec_buf[0] + arg. + The third decimal is used as a handy temporary storage. + */ + my_decimal dec_buf[3]; + int used_dec_buf_no; + + /* + Traits moved to a separate class to + a) be able to easily change object traits in runtime + b) they work as a differentiator for the union above + */ + const Hybrid_type_traits *traits; + + Hybrid_type() {} + /* XXX: add traits->copy() when needed */ + Hybrid_type(const Hybrid_type &rhs) :traits(rhs.traits) {} +}; + + +/* Hybryd_type_traits interface + default implementation for REAL_RESULT */ + +struct Hybrid_type_traits +{ + virtual Item_result type() const { return REAL_RESULT; } + + virtual void + fix_length_and_dec(Item *item, Item *arg) const; + + /* Hybrid_type operations. */ + virtual void set_zero(Hybrid_type *val) const { val->real= 0.0; } + virtual void add(Hybrid_type *val, Field *f) const + { val->real+= f->val_real(); } + virtual void div(Hybrid_type *val, ulonglong u) const + { val->real/= ulonglong2double(u); } + + virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const + { return (longlong) val->real; } + virtual double val_real(Hybrid_type *val) const { return val->real; } + virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const; + virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const; + static const Hybrid_type_traits *instance(); +}; + + +struct Hybrid_type_traits_decimal: public Hybrid_type_traits +{ + virtual Item_result type() const { return DECIMAL_RESULT; } + + virtual void + fix_length_and_dec(Item *arg, Item *item) const; + + /* Hybrid_type operations. */ + virtual void set_zero(Hybrid_type *val) const; + virtual void add(Hybrid_type *val, Field *f) const; + virtual void div(Hybrid_type *val, ulonglong u) const; + + virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const; + virtual double val_real(Hybrid_type *val) const; + virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const + { return &val->dec_buf[val->used_dec_buf_no]; } + virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const; + static const Hybrid_type_traits_decimal *instance(); +}; + + +struct Hybrid_type_traits_integer: public Hybrid_type_traits +{ + virtual Item_result type() const { return INT_RESULT; } + + virtual void + fix_length_and_dec(Item *arg, Item *item) const; + + /* Hybrid_type operations. */ + virtual void set_zero(Hybrid_type *val) const + { val->integer= 0; } + virtual void add(Hybrid_type *val, Field *f) const + { val->integer+= f->val_int(); } + virtual void div(Hybrid_type *val, ulonglong u) const + { val->integer/= (longlong) u; } + + virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const + { return val->integer; } + virtual double val_real(Hybrid_type *val) const + { return (double) val->integer; } + virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const + { + int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, &val->dec_buf[2]); + return &val->dec_buf[2]; + } + virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const + { buf->set(val->integer, &my_charset_bin); return buf;} + static const Hybrid_type_traits_integer *instance(); +}; + +/*************************************************************************/ + typedef bool (Item::*Item_processor)(byte *arg); typedef Item* (Item::*Item_transformer) (byte *arg); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index dbba02c3cf7..b3a7332fe52 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -456,11 +456,30 @@ my_decimal *Item_sum_sum::val_decimal(my_decimal *val) return val_decimal_from_real(val); } +/***************************************************************************/ -/* Item_sum_sum_distinct */ +C_MODE_START -Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item) - :Item_sum_sum(item), tree(0) +/* Declarations for auxilary C-callbacks */ + +static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2) +{ + return memcmp(key1, key2, *(uint *) arg); +} + + +static int item_sum_distinct_walk(void *element, element_count num_of_dups, + void *item) +{ + return ((Item_sum_distinct*) (item))->unique_walk_function(element); +} + +C_MODE_END + +/* Item_sum_distinct */ + +Item_sum_distinct::Item_sum_distinct(Item *item_arg) + :Item_sum_num(item_arg), tree(0) { /* quick_group is an optimizer hint, which means that GROUP BY can be @@ -472,239 +491,242 @@ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item) } -Item_sum_sum_distinct::Item_sum_sum_distinct(THD *thd, - Item_sum_sum_distinct *original) - :Item_sum_sum(thd, original), tree(0), dec_bin_buff(original->dec_bin_buff) +Item_sum_distinct::Item_sum_distinct(THD *thd, Item_sum_distinct *original) + :Item_sum_num(thd, original), val(original->val), tree(0), + table_field_type(original->table_field_type) { quick_group= 0; } -void Item_sum_sum_distinct::fix_length_and_dec() +/* + Behaves like an Integer except to fix_length_and_dec(). + Additionally div() converts val with this traits to a val with true + decimal traits along with conversion of integer value to decimal value. + This is to speedup SUM/AVG(DISTINCT) evaluation for 8-32 bit integer + values. +*/ + +struct Hybrid_type_traits_fast_decimal: public + Hybrid_type_traits_integer { - Item_sum_sum::fix_length_and_dec(); - if (hybrid_type == DECIMAL_RESULT) + virtual Item_result type() const { return DECIMAL_RESULT; } + virtual void fix_length_and_dec(Item *item, Item *arg) const + { Hybrid_type_traits_decimal::instance()->fix_length_and_dec(item, arg); } + + virtual void div(Hybrid_type *val, ulonglong u) const { - dec_bin_buff= (byte *) - sql_alloc(my_decimal_get_binary_size(args[0]->max_length, - args[0]->decimals)); + int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, val->dec_buf); + val->used_dec_buf_no= 0; + val->traits= Hybrid_type_traits_decimal::instance(); + val->traits->div(val, u); } + static const Hybrid_type_traits_fast_decimal *instance() + { + static const Hybrid_type_traits_fast_decimal fast_decimal_traits; + return &fast_decimal_traits; + } +}; + + +void Item_sum_distinct::fix_length_and_dec() +{ + DBUG_ASSERT(args[0]->fixed); + + table_field_type= args[0]->field_type(); + + /* Adjust tmp table type according to the chosen aggregation type */ + switch (args[0]->result_type()) { + case STRING_RESULT: + case REAL_RESULT: + val.traits= Hybrid_type_traits::instance(); + if (table_field_type != MYSQL_TYPE_FLOAT) + table_field_type= MYSQL_TYPE_DOUBLE; + break; + case INT_RESULT: + /* + Preserving int8, int16, int32 field types gives ~10% performance boost + as the size of result tree becomes significantly smaller. + Another speed up we gain by using longlong for intermediate + calculations. The range of int64 is enough to hold sum 2^32 distinct + integers each <= 2^32. + */ + if (table_field_type == MYSQL_TYPE_INT24 || + table_field_type >= MYSQL_TYPE_TINY && + table_field_type <= MYSQL_TYPE_LONG) + { + val.traits= Hybrid_type_traits_fast_decimal::instance(); + break; + } + table_field_type= MYSQL_TYPE_LONGLONG; + /* fallthrough */ + case DECIMAL_RESULT: + val.traits= Hybrid_type_traits_decimal::instance(); + if (table_field_type != MYSQL_TYPE_LONGLONG) + table_field_type= MYSQL_TYPE_NEWDECIMAL; + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + val.traits->fix_length_and_dec(this, args[0]); } -Item * -Item_sum_sum_distinct::copy_or_same(THD *thd) +bool Item_sum_distinct::setup(THD *thd) { - return new (thd->mem_root) Item_sum_sum_distinct(thd, this); -} + List field_list; + create_field field_def; /* field definition */ -C_MODE_START - -static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2) -{ - return memcmp(key1, key2, *(uint *) arg); -} - -C_MODE_END - - -bool Item_sum_sum_distinct::setup(THD *thd) -{ - DBUG_ENTER("Item_sum_sum_distinct::setup"); - SELECT_LEX *select_lex= thd->lex->current_select; - /* what does it mean??? */ - if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) - DBUG_RETURN(1); + DBUG_ENTER("Item_sum_distinct::setup"); DBUG_ASSERT(tree == 0); /* setup can not be called twice */ /* - Uniques handles all unique elements in a tree until they can't fit in. - Then thee tree is dumped to the temporary file. - See class Unique for details. + Virtual table and the tree are created anew on each re-execution of + PS/SP. Hence all further allocations are performed in the runtime + mem_root. */ + if (field_list.push_back(&field_def)) + return TRUE; + null_value= maybe_null= 1; - /* - TODO: if underlying item result fits in 4 bytes we can take advantage - of it and have tree of long/ulong. It gives 10% performance boost - */ + quick_group= 0; + + DBUG_ASSERT(args[0]->fixed); + + field_def.init_for_tmp_table(table_field_type, args[0]->max_length, + args[0]->decimals, args[0]->maybe_null, + args[0]->unsigned_flag); + + if (! (table= create_virtual_tmp_table(thd, field_list))) + return TRUE; + + /* XXX: check that the case of CHAR(0) works OK */ + tree_key_length= table->s->reclength - table->s->null_bytes; /* - It's safe to use key_length here as even if we do copy_or_same() - the new item will just share the old items key_length, which will not - change or disappear during the life time of this item. + Unique handles all unique elements in a tree until they can't fit + in. Then the tree is dumped to the temporary file. We can use + simple_raw_key_cmp because the table contains numbers only; decimals + are converted to binary representation as well. */ - key_length= ((hybrid_type == DECIMAL_RESULT) ? - my_decimal_get_binary_size(args[0]->max_length, - args[0]->decimals) : - sizeof(double)); - tree= new Unique(simple_raw_key_cmp, &key_length, key_length, + tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length, thd->variables.max_heap_table_size); - DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree, - key_length)); + DBUG_RETURN(tree == 0); } -void Item_sum_sum_distinct::clear() + +bool Item_sum_distinct::add() { - DBUG_ENTER("Item_sum_sum_distinct::clear"); + args[0]->save_in_field(table->field[0], FALSE); + if (!table->field[0]->is_null()) + { + DBUG_ASSERT(tree); + null_value= 0; + /* + '0' values are also stored in the tree. This doesn't matter + for SUM(DISTINCT), but is important for AVG(DISTINCT) + */ + return tree->unique_add(table->field[0]->ptr); + } + return 0; +} + + +bool Item_sum_distinct::unique_walk_function(void *element) +{ + memcpy(table->field[0]->ptr, element, tree_key_length); + ++count; + val.traits->add(&val, table->field[0]); + return 0; +} + + +void Item_sum_distinct::clear() +{ + DBUG_ENTER("Item_sum_distinct::clear"); DBUG_ASSERT(tree != 0); /* we always have a tree */ - null_value= 1; + null_value= 1; tree->reset(); DBUG_VOID_RETURN; } -void Item_sum_sum_distinct::cleanup() +void Item_sum_distinct::cleanup() { Item_sum_num::cleanup(); delete tree; tree= 0; + table= 0; } - -bool Item_sum_sum_distinct::add() +Item_sum_distinct::~Item_sum_distinct() { - DBUG_ENTER("Item_sum_sum_distinct::add"); - if (hybrid_type == DECIMAL_RESULT) - { - my_decimal value, *val= args[0]->val_decimal(&value); - if (!args[0]->null_value) - { - DBUG_ASSERT(tree != 0); - null_value= 0; - my_decimal2binary(E_DEC_FATAL_ERROR, val, (char *) dec_bin_buff, - args[0]->max_length, args[0]->decimals); - DBUG_RETURN(tree->unique_add(dec_bin_buff)); - } - } - else - { - /* args[0]->val() may reset args[0]->null_value */ - double val= args[0]->val_real(); - if (!args[0]->null_value) - { - DBUG_ASSERT(tree != 0); - null_value= 0; - DBUG_PRINT("info", ("real: %lg, tree 0x%lx", val, (ulong)tree)); - if (val) - DBUG_RETURN(tree->unique_add(&val)); - } - else - DBUG_PRINT("info", ("real: NULL")); - } - DBUG_RETURN(0); + delete tree; + /* no need to free the table */ } -void Item_sum_sum_distinct::add_real(double val) +void Item_sum_distinct::calculate_val_and_count() { - DBUG_ENTER("Item_sum_sum_distinct::add_real"); - sum+= val; - DBUG_PRINT("info", ("sum %lg, val %lg", sum, val)); - DBUG_VOID_RETURN; -} - - -void Item_sum_sum_distinct::add_decimal(byte *val) -{ - binary2my_decimal(E_DEC_FATAL_ERROR, (char *) val, &tmp_dec, - args[0]->max_length, args[0]->decimals); - my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1), - &tmp_dec, dec_buffs + curr_dec_buff); - curr_dec_buff^= 1; -} - -C_MODE_START - -static int sum_sum_distinct_real(void *element, element_count num_of_dups, - void *item_sum_sum_distinct) -{ - ((Item_sum_sum_distinct *) - (item_sum_sum_distinct))->add_real(* (double *) element); - return 0; -} - -static int sum_sum_distinct_decimal(void *element, element_count num_of_dups, - void *item_sum_sum_distinct) -{ - ((Item_sum_sum_distinct *) - (item_sum_sum_distinct))->add_decimal((byte *)element); - return 0; -} - -C_MODE_END - - -double Item_sum_sum_distinct::val_real() -{ - DBUG_ENTER("Item_sum_sum_distinct::val"); + count= 0; + val.traits->set_zero(&val); /* We don't have a tree only if 'setup()' hasn't been called; this is the case of sql_select.cc:return_zero_rows. */ - if (hybrid_type == DECIMAL_RESULT) + if (tree) { - /* Item_sum_sum_distinct::val_decimal do not use argument */ - my_decimal *val= val_decimal(0); - if (!null_value) - my_decimal2double(E_DEC_FATAL_ERROR, val, &sum); + table->field[0]->set_notnull(); + tree->walk(item_sum_distinct_walk, (void*) this); } - else - { - sum= 0.0; - DBUG_PRINT("info", ("tree 0x%lx", (ulong)tree)); - if (tree) - tree->walk(sum_sum_distinct_real, (void *) this); - } - DBUG_RETURN(sum); } -my_decimal *Item_sum_sum_distinct::val_decimal(my_decimal *fake) +double Item_sum_distinct::val_real() { - if (hybrid_type == DECIMAL_RESULT) - { - my_decimal_set_zero(dec_buffs); - curr_dec_buff= 0; - if (tree) - tree->walk(sum_sum_distinct_decimal, (void *)this); - } - else - { - double real= val_real(); - curr_dec_buff= 0; - double2my_decimal(E_DEC_FATAL_ERROR, real, dec_buffs); - } - return(dec_buffs + curr_dec_buff); + calculate_val_and_count(); + return val.traits->val_real(&val); } -longlong Item_sum_sum_distinct::val_int() +my_decimal *Item_sum_distinct::val_decimal(my_decimal *to) { - longlong result; - if (hybrid_type == DECIMAL_RESULT) - { - /* Item_sum_sum_distinct::val_decimal do not use argument */ - my_decimal *val= val_decimal(0); - if (!null_value) - my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result); - } - else - result= (longlong) val_real(); - return result; + calculate_val_and_count(); + if (null_value) + return 0; + return val.traits->val_decimal(&val, to); } -String *Item_sum_sum_distinct::val_str(String *str) +longlong Item_sum_distinct::val_int() { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == DECIMAL_RESULT) - return val_string_from_decimal(str); - return val_string_from_real(str); + calculate_val_and_count(); + return val.traits->val_int(&val, unsigned_flag); } -/* end of Item_sum_sum_distinct */ +String *Item_sum_distinct::val_str(String *str) +{ + calculate_val_and_count(); + if (null_value) + return 0; + return val.traits->val_str(&val, str, decimals); +} + +/* end of Item_sum_distinct */ + +/* Item_sum_avg_distinct */ + +void +Item_sum_avg_distinct::calculate_val_and_count() +{ + Item_sum_distinct::calculate_val_and_count(); + if (count) + val.traits->div(&val, count); +} + Item *Item_sum_count::copy_or_same(THD* thd) { diff --git a/sql/item_sum.h b/sql/item_sum.h index af2710d7800..641acb0efd9 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -30,8 +30,8 @@ class Item_sum :public Item_result_field public: enum Sumfunctype { COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC, - MIN_FUNC, MAX_FUNC, UNIQUE_USERS_FUNC, STD_FUNC, VARIANCE_FUNC, - SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC + AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, UNIQUE_USERS_FUNC, STD_FUNC, + VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC }; Item **args, *tmp_args[2]; @@ -68,6 +68,9 @@ public: a temporary table. Similar to reset(), but must also store value in result_field. Like reset() it is supposed to reset start value to default. + This set of methods (reult_field(), reset_field, update_field()) of + Item_sum is used only if quick_group is not null. Otherwise + copy_or_same() is used to obtain a copy of this item. */ virtual void reset_field()=0; /* @@ -161,26 +164,28 @@ public: }; -/* - Item_sum_sum_distinct - SELECT SUM(DISTINCT expr) FROM ... - support. See also: MySQL manual, chapter 'Adding New Functions To MySQL' - and comments in item_sum.cc. -*/ + +/* Common class for SUM(DISTINCT), AVG(DISTINCT) */ class Unique; -class Item_sum_sum_distinct :public Item_sum_sum +class Item_sum_distinct :public Item_sum_num { +protected: + /* storage for the summation result */ + ulonglong count; + Hybrid_type val; + /* storage for unique elements */ Unique *tree; - byte *dec_bin_buff; - my_decimal tmp_dec; - uint key_length; -private: - Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item); + TABLE *table; + enum enum_field_types table_field_type; + uint tree_key_length; +protected: + Item_sum_distinct(THD *thd, Item_sum_distinct *item); public: - Item_sum_sum_distinct(Item *item_par); - ~Item_sum_sum_distinct() {} - + Item_sum_distinct(Item *item_par); + ~Item_sum_distinct(); + bool setup(THD *thd); void clear(); void cleanup(); @@ -190,15 +195,54 @@ public: longlong val_int(); String *val_str(String *str); - void add_real(double val); - void add_decimal(byte *val); + /* XXX: does it need make_unique? */ + enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } void reset_field() {} // not used void update_field() {} // not used const char *func_name() const { return "sum_distinct"; } - Item *copy_or_same(THD* thd); virtual void no_rows_in_result() {} void fix_length_and_dec(); + enum Item_result result_type () const { return val.traits->type(); } + virtual void calculate_val_and_count(); + virtual bool unique_walk_function(void *elem); +}; + + +/* + Item_sum_sum_distinct - implementation of SUM(DISTINCT expr). + See also: MySQL manual, chapter 'Adding New Functions To MySQL' + and comments in item_sum.cc. +*/ + +class Item_sum_sum_distinct :public Item_sum_distinct +{ +private: + Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item) + :Item_sum_distinct(thd, item) {} +public: + Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {} + + enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } + const char *func_name() const { return "sum_distinct"; } + Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); } +}; + + +/* Item_sum_avg_distinct - SELECT AVG(DISTINCT expr) FROM ... */ + +class Item_sum_avg_distinct: public Item_sum_distinct +{ +private: + Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original) + :Item_sum_distinct(thd, original) {} +public: + Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {} + + virtual void calculate_val_and_count(); + enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; } + const char *func_name() const { return "avg_distinct"; } + Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); } }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 76d8ec1740a..cb906931b2b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8359,6 +8359,117 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, } +/****************************************************************************/ + +/* + Create a reduced TABLE object with properly set up Field list from a + list of field definitions. + + SYNOPSIS + create_virtual_tmp_table() + thd connection handle + field_list list of column definitions + + DESCRIPTION + The created table doesn't have a table handler assotiated with + it, has no keys, no group/distinct, no copy_funcs array. + The sole purpose of this TABLE object is to use the power of Field + class to read/write data to/from table->record[0]. Then one can store + the record in any container (RB tree, hash, etc). + The table is created in THD mem_root, so are the table's fields. + Consequently, if you don't BLOB fields, you don't need to free it. + + RETURN + 0 if out of memory, TABLE object in case of success +*/ + +TABLE *create_virtual_tmp_table(THD *thd, List &field_list) +{ + uint field_count= field_list.elements; + Field **field; + create_field *cdef; /* column definition */ + uint record_length= 0; + uint null_count= 0; /* number of columns which may be null */ + uint null_pack_length; /* NULL representation array length */ + TABLE_SHARE *s; + /* Create the table and list of all fields */ + TABLE *table= (TABLE*) thd->calloc(sizeof(*table)); + field= (Field**) thd->alloc((field_count + 1) * sizeof(Field*)); + if (!table || !field) + return 0; + + table->field= field; + table->s= s= &table->share_not_to_be_used; + s->fields= field_count; + + /* Create all fields and calculate the total length of record */ + List_iterator_fast it(field_list); + while ((cdef= it++)) + { + *field= make_field(0, cdef->length, + (uchar*) (f_maybe_null(cdef->pack_flag) ? "" : 0), + f_maybe_null(cdef->pack_flag) ? 1 : 0, + cdef->pack_flag, cdef->sql_type, cdef->charset, + cdef->geom_type, cdef->unireg_check, + cdef->interval, cdef->field_name, table); + if (!*field) + goto error; + record_length+= (**field).pack_length(); + if (! ((**field).flags & NOT_NULL_FLAG)) + ++null_count; + ++field; + } + *field= NULL; /* mark the end of the list */ + + null_pack_length= (null_count + 7)/8; + s->reclength= record_length + null_pack_length; + s->rec_buff_length= ALIGN_SIZE(s->reclength + 1); + table->record[0]= (byte*) thd->alloc(s->rec_buff_length); + if (!table->record[0]) + goto error; + + if (null_pack_length) + { + table->null_flags= (uchar*) table->record[0]; + s->null_fields= null_count; + s->null_bytes= null_pack_length; + } + + table->in_use= thd; /* field->reset() may access table->in_use */ + { + /* Set up field pointers */ + byte *null_pos= table->record[0]; + byte *field_pos= null_pos + s->null_bytes; + uint null_bit= 1; + + for (field= table->field; *field; ++field) + { + Field *cur_field= *field; + if ((cur_field->flags & NOT_NULL_FLAG)) + cur_field->move_field((char*) field_pos); + else + { + cur_field->move_field((char*) field_pos, (uchar*) null_pos, null_bit); + null_bit<<= 1; + if (null_bit == (1 << 8)) + { + ++null_pos; + null_bit= 1; + } + } + cur_field->reset(); + + field_pos+= cur_field->pack_length(); + } + } + return table; +error: + for (field= table->field; *field; ++field) + delete *field; /* just invokes field destructor */ + return 0; +} + + static bool open_tmp_table(TABLE *table) { int error; diff --git a/sql/sql_select.h b/sql/sql_select.h index 1b7893dbc7c..f00fd476edd 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -387,6 +387,7 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, ORDER *group, bool distinct, bool save_sum_fields, ulong select_options, ha_rows rows_limit, char* alias); +TABLE *create_virtual_tmp_table(THD *thd, List &field_list); void free_tmp_table(THD *thd, TABLE *entry); void count_field_types(TMP_TABLE_PARAM *param, List &fields, bool reset_with_sum_func); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 212f004e3bf..56dd6409eba 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4754,6 +4754,8 @@ udf_expr: sum_expr: AVG_SYM '(' in_sum_expr ')' { $$=new Item_sum_avg($3); } + | AVG_SYM '(' DISTINCT in_sum_expr ')' + { $$=new Item_sum_avg_distinct($4); } | BIT_AND '(' in_sum_expr ')' { $$=new Item_sum_and($3); } | BIT_OR '(' in_sum_expr ')' From 6c256bb2fa22d48cfe9ffd8f52356c72be10ed7a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Mar 2005 11:12:54 +0100 Subject: [PATCH 7/9] Removed --- BitKeeper/etc/gone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BitKeeper/etc/gone b/BitKeeper/etc/gone index 126bd4e38d3..ead6fb9e939 100644 --- a/BitKeeper/etc/gone +++ b/BitKeeper/etc/gone @@ -457,7 +457,7 @@ ccarkner@nslinuxw10.bedford.progress.com|mysql-test/r/isolation.result|200103271 ccarkner@nslinuxw10.bedford.progress.com|mysql-test/t/isolation.test|20010327145543|39049|6a39e4138dd4a456 jani@hynda.mysql.fi|client/mysqlcheck|20010419221207|26716|363e3278166d84ec jcole@tetra.bedford.progress.com|BitKeeper/etc/logging_ok|20001004201211|30554 -magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2 +jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aajimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6djimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27ajimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2 magnus@neptunus.(none)|ndb/src/client/odbc/Extra.mk|20040414082358|47442|eabbb28986ca817d magnus@neptunus.(none)|ndb/src/client/odbc/Makefile|20040414084435|33394|9bc928a18aa88d66 magnus@neptunus.(none)|ndb/src/client/odbc/NdbOdbc.cpp|20040414082358|49599|aa491b06c9172d11 From 096a7d63583791ab4515c3832647664c1aad086f Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Mar 2005 11:37:26 +0100 Subject: [PATCH 8/9] Marked missing file gone --- BitKeeper/etc/gone | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BitKeeper/etc/gone b/BitKeeper/etc/gone index ead6fb9e939..7f84ec8a46f 100644 --- a/BitKeeper/etc/gone +++ b/BitKeeper/etc/gone @@ -458,6 +458,7 @@ ccarkner@nslinuxw10.bedford.progress.com|mysql-test/t/isolation.test|20010327145 jani@hynda.mysql.fi|client/mysqlcheck|20010419221207|26716|363e3278166d84ec jcole@tetra.bedford.progress.com|BitKeeper/etc/logging_ok|20001004201211|30554 jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aajimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6djimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27ajimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2 +magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2 magnus@neptunus.(none)|ndb/src/client/odbc/Extra.mk|20040414082358|47442|eabbb28986ca817d magnus@neptunus.(none)|ndb/src/client/odbc/Makefile|20040414084435|33394|9bc928a18aa88d66 magnus@neptunus.(none)|ndb/src/client/odbc/NdbOdbc.cpp|20040414082358|49599|aa491b06c9172d11 @@ -1174,6 +1175,7 @@ mwagner@evoq.home.mwagner.org|mysql-test/xml/xsl/README|20001013051514|26509|cd4 mwagner@evoq.home.mwagner.org|mysql-test/xml/xsl/mysqltest.xsl|20001013051514|27425|1b8f6ec4f1b5f634 mwagner@work.mysql.com|mysql-test/r/3.23/sel000001.result|20001010091454|28284|383913ae4505ec86 mwagner@work.mysql.com|mysql-test/r/3.23/sel000002.result|20001010091454|29230|d1787e6fd5dbc1cc +ndb/src/client/Makefile nick@nick.leippe.com|mysql-test/r/rpl_empty_master_crash.result|20020531235552|47718|615f521be2132141 nick@nick.leippe.com|mysql-test/t/rpl_empty_master_crash.test|20020531235552|52328|99464e737639ccc6 sasha@mysql.sashanet.com|BitKeeper/etc/logging_ok|20000801000905|12967|5b7d847a2158554 From 87b40f2013a108ed3caaf6912772354d0b0dc842 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Mar 2005 12:27:02 +0100 Subject: [PATCH 9/9] Removed files that disabled ndb tests --- BitKeeper/etc/gone | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/BitKeeper/etc/gone b/BitKeeper/etc/gone index 7f84ec8a46f..776d469ee41 100644 --- a/BitKeeper/etc/gone +++ b/BitKeeper/etc/gone @@ -457,7 +457,14 @@ ccarkner@nslinuxw10.bedford.progress.com|mysql-test/r/isolation.result|200103271 ccarkner@nslinuxw10.bedford.progress.com|mysql-test/t/isolation.test|20010327145543|39049|6a39e4138dd4a456 jani@hynda.mysql.fi|client/mysqlcheck|20010419221207|26716|363e3278166d84ec jcole@tetra.bedford.progress.com|BitKeeper/etc/logging_ok|20001004201211|30554 -jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aajimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6djimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27ajimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2 +jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aa +jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aajimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6djimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27ajimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aajimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6djimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27ajimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2 +jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06 +jimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1 +jimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27a +jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6d +jimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6 +jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30 magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2 magnus@neptunus.(none)|ndb/src/client/odbc/Extra.mk|20040414082358|47442|eabbb28986ca817d magnus@neptunus.(none)|ndb/src/client/odbc/Makefile|20040414084435|33394|9bc928a18aa88d66