From 5cde0ca744b72dfd36f4ed0a13269b1d3f48de54 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 10 Aug 2010 18:36:04 +0400 Subject: [PATCH 01/17] created *-all build scripts that build with ndb (as -max scripts don't) --- BUILD/SETUP.sh | 7 +++---- BUILD/compile-amd64-debug-all | 7 +++++++ BUILD/compile-pentium-debug-all | 10 ++++++++++ BUILD/compile-pentium64-debug-all | 12 ++++++++++++ mysql-test/mysql-test-run.pl | 1 + 5 files changed, 33 insertions(+), 4 deletions(-) create mode 100755 BUILD/compile-amd64-debug-all create mode 100755 BUILD/compile-pentium-debug-all create mode 100755 BUILD/compile-pentium64-debug-all diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index fe572562750..b888ac03ef3 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -91,8 +91,8 @@ path=`dirname $0` get_make_parallel_flag # SSL library to use.--with-ssl will select our bundled yaSSL -# implementation of SSL. To use openSSl you will nee too point out -# the location of openSSL headers and lbs on your system. +# implementation of SSL. To use OpenSSL you will need to specify +# the location of OpenSSL headers and libs on your system. # Ex --with-ssl=/usr SSL_LIBRARY=--with-ssl @@ -182,8 +182,7 @@ max_no_embedded_configs="$SSL_LIBRARY --with-plugins=max" max_no_qc_configs="$SSL_LIBRARY --with-plugins=max --without-query-cache" max_no_ndb_configs="$SSL_LIBRARY --with-plugins=max-no-ndb --with-embedded-server --with-libevent" max_configs="$SSL_LIBRARY --with-plugins=max --with-embedded-server --with-libevent" -# Disable NDB in maria max builds -max_configs=$max_no_ndb_configs +all_configs="$SSL_LIBRARY --with-plugins=max --with-plugin-ndbcluster --with-embedded-server --with-libevent" # # CPU and platform specific compilation flags. diff --git a/BUILD/compile-amd64-debug-all b/BUILD/compile-amd64-debug-all new file mode 100755 index 00000000000..b8b2ed05402 --- /dev/null +++ b/BUILD/compile-amd64-debug-all @@ -0,0 +1,7 @@ +#! /bin/sh +path=`dirname $0` +. "$path/SETUP.sh" +extra_flags="$amd64_cflags $debug_cflags" +extra_configs="$amd64_configs $debug_configs $all_configs" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-debug-all b/BUILD/compile-pentium-debug-all new file mode 100755 index 00000000000..710ce8af63c --- /dev/null +++ b/BUILD/compile-pentium-debug-all @@ -0,0 +1,10 @@ +#! /bin/sh + +path=`dirname $0` +set -- "$@" --with-debug=full +. "$path/SETUP.sh" + +extra_flags="$pentium_cflags $debug_cflags" +extra_configs="$pentium_configs $debug_configs $all_configs $error_inject --with-experimental-collations" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium64-debug-all b/BUILD/compile-pentium64-debug-all new file mode 100755 index 00000000000..7824f7ad47f --- /dev/null +++ b/BUILD/compile-pentium64-debug-all @@ -0,0 +1,12 @@ +#! /bin/sh + +path=`dirname $0` +set -- "$@" --with-debug=full +. "$path/SETUP.sh" + +extra_flags="$pentium64_cflags $debug_cflags" +extra_configs="$pentium_configs $debug_configs $all_configs" + +extra_configs="$extra_configs " +CC="$CC --pipe" +. "$path/FINISH.sh" diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 190020a817c..e0af128cd04 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -4039,6 +4039,7 @@ sub extract_warning_lines ($) { qr/Now setting lower_case_table_names to [02]/, qr/Setting lower_case_table_names=2/, qr/You have forced lower_case_table_names to 0/, + qr/Plugin 'ndbcluster' will be forced to shutdow/, qr/deprecated/, qr/Slave SQL thread retried transaction/, qr/Slave \(additional info\)/, From 236478cef7f826a2cc019febedc6854861243169 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 11 Aug 2010 13:55:54 +0300 Subject: [PATCH 02/17] Fixed compiler warnings from Windows compiler client/mysqlcheck.c: Added missing casts client/mysqldump.c: Added missing casts client/mysqlimport.c: Added missing casts extra/my_print_defaults.c: Added missing casts mysql-test/mysql-test-run.pl: Added suppression for non-critical warning on windows storage/maria/maria_pack.c: Added missing casts storage/xtradb/buf/buf0lru.c: Added missing casts storage/xtradb/fil/fil0fil.c: Added missing casts storage/xtradb/handler/i_s.cc: Added extra argument to call store() function for longlong. storage/xtradb/srv/srv0srv.c: Added cast to suppress compiler warning support-files/compiler_warnings.supp: Added suppression for some non critical compiler warnings on Windows unittest/mytap/tap.h: Fixed prototypes to be same as the actual functions --- client/mysqlcheck.c | 4 ++-- client/mysqldump.c | 8 ++++---- client/mysqlimport.c | 4 ++-- extra/my_print_defaults.c | 4 ++-- mysql-test/mysql-test-run.pl | 1 + storage/maria/maria_pack.c | 4 ++-- storage/xtradb/buf/buf0lru.c | 8 ++++---- storage/xtradb/fil/fil0fil.c | 4 ++-- storage/xtradb/handler/i_s.cc | 2 +- storage/xtradb/srv/srv0srv.c | 2 +- support-files/compiler_warnings.supp | 2 ++ unittest/mytap/tap.h | 4 ++-- 12 files changed, 25 insertions(+), 22 deletions(-) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index fd067e8a8ad..62eab5bf6e4 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -71,8 +71,8 @@ static struct my_option my_long_options[] = &opt_auto_repair, &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory for character set files.", &charsets_dir, - &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Directory for character set files.", (char**) &charsets_dir, + (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"check", 'c', "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"check-only-changed", 'C', diff --git a/client/mysqldump.c b/client/mysqldump.c index 0045faa2229..bb09af4a3c2 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -211,8 +211,8 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory for character set files.", &charsets_dir, - &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Directory for character set files.", (char**) &charsets_dir, + (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"comments", 'i', "Write additional information.", &opt_comments, &opt_comments, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, @@ -242,8 +242,8 @@ static struct my_option my_long_options[] = {"debug", '#', "This is a non-debug version. Catch this and exit.", 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, #else - {"debug", '#', "Output debug log.", &default_dbug_option, - &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug", '#', "Output debug log.", (char**) &default_dbug_option, + (char**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.", &debug_check_flag, &debug_check_flag, 0, diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 404106560c1..43994a4f514 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -73,8 +73,8 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory for character set files.", &charsets_dir, - &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Directory for character set files.", (char**) &charsets_dir, + (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"default-character-set", OPT_DEFAULT_CHARSET, "Set the default character set.", &default_charset, &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c index da7061471fa..847738951dd 100644 --- a/extra/my_print_defaults.c +++ b/extra/my_print_defaults.c @@ -55,8 +55,8 @@ static struct my_option my_long_options[] = {"debug", '#', "This is a non-debug version. Catch this and exit", 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, #else - {"debug", '#', "Output debug log", &default_dbug_option, - &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug", '#', "Output debug log", (char**) &default_dbug_option, + (char**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif {"defaults-file", 'c', "Like --config-file, except: if first option, " "then read this file only, do not read global or per-user config " diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index eb51d385f77..190020a817c 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -4038,6 +4038,7 @@ sub extract_warning_lines ($) { qr/unknown variable 'loose-/, qr/Now setting lower_case_table_names to [02]/, qr/Setting lower_case_table_names=2/, + qr/You have forced lower_case_table_names to 0/, qr/deprecated/, qr/Slave SQL thread retried transaction/, qr/Slave \(additional info\)/, diff --git a/storage/maria/maria_pack.c b/storage/maria/maria_pack.c index 0673f571a6b..167d0af3078 100644 --- a/storage/maria/maria_pack.c +++ b/storage/maria/maria_pack.c @@ -261,8 +261,8 @@ static struct my_option my_long_options[] = {"backup", 'b', "Make a backup of the table as table_name.OLD.", &backup, &backup, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR_MP, - "Directory where character sets are.", &charsets_dir, - &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Directory where character sets are.", (char**) &charsets_dir, + (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"force", 'f', diff --git a/storage/xtradb/buf/buf0lru.c b/storage/xtradb/buf/buf0lru.c index 65fdf342e4f..7b01c4aec50 100644 --- a/storage/xtradb/buf/buf0lru.c +++ b/storage/xtradb/buf/buf0lru.c @@ -2131,7 +2131,7 @@ ibool buf_LRU_file_dump(void) /*===================*/ { - os_file_t dump_file = -1; + os_file_t dump_file = (os_file_t) -1; ibool success; byte* buffer_base = NULL; byte* buffer = NULL; @@ -2221,7 +2221,7 @@ buf_LRU_file_dump(void) ret = TRUE; end: - if (dump_file != -1) + if (dump_file != (os_file_t) -1) os_file_close(dump_file); if (buffer_base) ut_free(buffer_base); @@ -2235,7 +2235,7 @@ ibool buf_LRU_file_restore(void) /*======================*/ { - os_file_t dump_file = -1; + os_file_t dump_file = (os_file_t) -1; ibool success; byte* buffer_base = NULL; byte* buffer = NULL; @@ -2326,7 +2326,7 @@ buf_LRU_file_restore(void) " (requested: %lu, read: %lu)\n", req, reads); ret = TRUE; end: - if (dump_file != -1) + if (dump_file != (os_file_t) -1) os_file_close(dump_file); if (buffer_base) ut_free(buffer_base); diff --git a/storage/xtradb/fil/fil0fil.c b/storage/xtradb/fil/fil0fil.c index bb1eed2a1e3..d69e5859d99 100644 --- a/storage/xtradb/fil/fil0fil.c +++ b/storage/xtradb/fil/fil0fil.c @@ -3044,7 +3044,7 @@ fil_open_single_table_tablespace( dulint new_id[31]; ulint root_page[31]; ulint n_index; - os_file_t info_file = -1; + os_file_t info_file = (os_file_t) -1; char* info_file_path; ulint i; int len; @@ -3130,7 +3130,7 @@ fil_open_single_table_tablespace( } skip_info: - if (info_file != -1) + if (info_file != (os_file_t) -1) os_file_close(info_file); /* diff --git a/storage/xtradb/handler/i_s.cc b/storage/xtradb/handler/i_s.cc index c48676c2892..5b5d5ef7186 100644 --- a/storage/xtradb/handler/i_s.cc +++ b/storage/xtradb/handler/i_s.cc @@ -2821,7 +2821,7 @@ i_s_innodb_table_stats_fill( field_store_string(i_s_table->field[0], buf); field_store_string(i_s_table->field[1], ptr); - i_s_table->field[2]->store(table->stat_n_rows); + i_s_table->field[2]->store(table->stat_n_rows, 1); i_s_table->field[3]->store(table->stat_clustered_index_size); i_s_table->field[4]->store(table->stat_sum_of_other_index_sizes); i_s_table->field[5]->store(table->stat_modified_counter); diff --git a/storage/xtradb/srv/srv0srv.c b/storage/xtradb/srv/srv0srv.c index 86bf309bac1..bc2dd562697 100644 --- a/storage/xtradb/srv/srv0srv.c +++ b/storage/xtradb/srv/srv0srv.c @@ -2897,7 +2897,7 @@ loop: if (bpl) { retry_flush_batch: n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, - bpl, + (ulint) bpl, oldest_lsn + (lsn - lsn_old)); if (n_pages_flushed == ULINT_UNDEFINED) { os_thread_sleep(5000); diff --git a/support-files/compiler_warnings.supp b/support-files/compiler_warnings.supp index 94e5b54d6fa..5039c28aab0 100644 --- a/support-files/compiler_warnings.supp +++ b/support-files/compiler_warnings.supp @@ -44,6 +44,7 @@ buf/buf0buf\.c: .*block_mutex.* might be used uninitialized btr/btr0cur\.c: null argument where non-null required: 1800-3000 btr/btr0btr\.c: null argument where non-null required: 2500-3000 ibuf/ibuf0ibuf.c: null argument where non-null required: 700-1000 +fsp/fsp0fsp\.c: result of 32-bit shift implicitly converted to 64 bits # # bdb is not critical to keep up to date @@ -108,6 +109,7 @@ signal\.c : .*unused parameter.* .* : conversion from '.*size_t' to 'UINT'.* .* : conversion from '.*size_t' to 'uInt'.* .* : conversion from '.*size_t' to 'uint16'.* +.* : The following environment variables were not found.* # # The following should be fixed by the ndb team diff --git a/unittest/mytap/tap.h b/unittest/mytap/tap.h index 206a939e43b..a75d0a4932b 100644 --- a/unittest/mytap/tap.h +++ b/unittest/mytap/tap.h @@ -106,7 +106,7 @@ extern int skip_big_tests; @param count The planned number of tests to run. */ -void plan(int const count); +void plan(int count); /** @@ -125,7 +125,7 @@ void plan(int const count); which case nothing is printed. */ -void ok(int const pass, char const *fmt, ...) +void ok(int pass, char const *fmt, ...) __attribute__((format(printf,2,3))); From 2d7b9ac75c18537c5dfd67660b42619249f11a34 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 12 Aug 2010 00:33:15 +0300 Subject: [PATCH 03/17] Disable events_time_zone.test as test is not predictable --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index cede26f555a..1de9d1c9847 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -14,3 +14,4 @@ query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails spo partition_innodb_plugin : Bug#53307 2010-04-30 VasilDimov valgrind warnings main.mysqlhotcopy_myisam : bug#54129 2010-06-04 Horst main.mysqlhotcopy_archive: bug#54129 2010-06-04 Horst +main.events_time_zone : Test is not predictable as it depends on precise timing. From 6bbb0b573983320d136522d207f282e8506862da Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 12 Aug 2010 19:46:36 +0300 Subject: [PATCH 04/17] Added option --start-from-checkpoint to maria_read_log Print out checked file names in maria_check -s (unless you use a second -s) Some trivial optimizations storage/maria/ma_bitmap.c: Trivial optimizations: - Combine common code (to be able to remove duplicate mutex_lock call) - Move setting of thread specific variables outside of mutex storage/maria/ma_check.c: Fixed wrong argument to printf storage/maria/maria_chk.c: Print out checked table names unless -s -s storage/maria/maria_read_log.c: Added option --start-from-checkpoint (to help find bugs in checkpoints) --- storage/maria/ma_bitmap.c | 10 ++++++---- storage/maria/ma_check.c | 2 +- storage/maria/maria_chk.c | 2 +- storage/maria/maria_read_log.c | 20 +++++++++++++++----- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/storage/maria/ma_bitmap.c b/storage/maria/ma_bitmap.c index 70617160d03..f75df06cadc 100644 --- a/storage/maria/ma_bitmap.c +++ b/storage/maria/ma_bitmap.c @@ -2142,12 +2142,12 @@ void _ma_bitmap_flushable(MARIA_HA *info, int non_flushable_inc) DBUG_VOID_RETURN; bitmap= &share->bitmap; + pthread_mutex_lock(&bitmap->bitmap_lock); + if (non_flushable_inc == -1) { - pthread_mutex_lock(&bitmap->bitmap_lock); DBUG_ASSERT((int) bitmap->non_flushable > 0); DBUG_ASSERT(info->non_flushable_state == 1); - info->non_flushable_state= 0; if (--bitmap->non_flushable == 0) { /* @@ -2164,11 +2164,11 @@ void _ma_bitmap_flushable(MARIA_HA *info, int non_flushable_inc) } DBUG_PRINT("info", ("bitmap->non_flushable: %u", bitmap->non_flushable)); pthread_mutex_unlock(&bitmap->bitmap_lock); + info->non_flushable_state= 0; DBUG_VOID_RETURN; } DBUG_ASSERT(non_flushable_inc == 1); DBUG_ASSERT(info->non_flushable_state == 0); - pthread_mutex_lock(&bitmap->bitmap_lock); while (unlikely(bitmap->flush_all_requested)) { /* @@ -2186,9 +2186,9 @@ void _ma_bitmap_flushable(MARIA_HA *info, int non_flushable_inc) pthread_cond_wait(&bitmap->bitmap_cond, &bitmap->bitmap_lock); } bitmap->non_flushable++; - info->non_flushable_state= 1; DBUG_PRINT("info", ("bitmap->non_flushable: %u", bitmap->non_flushable)); pthread_mutex_unlock(&bitmap->bitmap_lock); + info->non_flushable_state= 1; DBUG_VOID_RETURN; } @@ -2217,6 +2217,8 @@ void _ma_bitmap_flushable(MARIA_HA *info, int non_flushable_inc) Note that we may have 'filler blocks' that are used to split a block in half; These can be recognized by that they have page_count == 0. + This code also reverse the effect of ma_bitmap_flushable(.., 1); + RETURN 0 ok 1 error (Couldn't write or read bitmap page) diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index 28b808cf27e..086cff67dab 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -1930,7 +1930,7 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend, _ma_check_print_error(param, "Page %9s: Wrong data in bitmap. Page_type: " "%d full: %d empty_space: %u Bitmap-bits: %d", - llstr(page, llbuff), full_dir, page_type, + llstr(page, llbuff), page_type, full_dir, empty_space, bitmap_pattern); if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE)) goto err; diff --git a/storage/maria/maria_chk.c b/storage/maria/maria_chk.c index 6b194eee96f..ae840467894 100644 --- a/storage/maria/maria_chk.c +++ b/storage/maria/maria_chk.c @@ -1252,7 +1252,7 @@ static int maria_chk(HA_CHECK *param, char *filename) } else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC)) { - if (!(param->testflag & T_SILENT) || param->testflag & T_INFO) + if (!(param->testflag & T_VERY_SILENT) || param->testflag & T_INFO) printf("Checking MARIA file: %s\n",filename); if (!(param->testflag & T_SILENT)) printf("Data records: %7s Deleted blocks: %7s\n", diff --git a/storage/maria/maria_read_log.c b/storage/maria/maria_read_log.c index 1002260afe5..c964e47eafd 100644 --- a/storage/maria/maria_read_log.c +++ b/storage/maria/maria_read_log.c @@ -33,7 +33,7 @@ static my_bool opt_display_only, opt_apply, opt_apply_undo, opt_silent; static my_bool opt_check; static const char *opt_tmpdir; static ulong opt_page_buffer_size; -static ulonglong opt_start_from_lsn, opt_end_lsn; +static ulonglong opt_start_from_lsn, opt_end_lsn, opt_start_from_checkpoint; static MY_TMPDIR maria_chk_tmpdir; @@ -94,7 +94,6 @@ int main(int argc, char **argv) if (opt_display_only) printf("You are using --display-only, NOTHING will be written to disk\n"); - /* LSN could be also --start-from-lsn=# */ lsn= translog_first_lsn_in_log(); if (lsn == LSN_ERROR) { @@ -105,8 +104,16 @@ int main(int argc, char **argv) { fprintf(stdout, "The transaction log is empty\n"); } - fprintf(stdout, "The transaction log starts from lsn (%lu,0x%lx)\n", - LSN_IN_PARTS(lsn)); + if (opt_start_from_checkpoint && !opt_start_from_lsn && + last_checkpoint_lsn != LSN_IMPOSSIBLE) + { + lsn= LSN_IMPOSSIBLE; /* LSN set in maria_apply_log() */ + fprintf(stdout, "Starting from checkpoint (%lu,0x%lx)\n", + LSN_IN_PARTS(last_checkpoint_lsn)); + } + else + fprintf(stdout, "The transaction log starts from lsn (%lu,0x%lx)\n", + LSN_IN_PARTS(lsn)); if (opt_start_from_lsn) { @@ -183,7 +190,7 @@ static struct my_option my_long_options[] = {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"display-only", 'd', "display brief info read from records' header", - (uchar **) &opt_display_only, (uchar **) &opt_display_only, 0, GET_BOOL, + &opt_display_only, &opt_display_only, 0, GET_BOOL, NO_ARG,0, 0, 0, 0, 0, 0}, {"maria-log-dir-path", 'l', "Path to the directory where to store transactional log", @@ -197,6 +204,9 @@ static struct my_option my_long_options[] = { "start-from-lsn", 'o', "Start reading log from this lsn", &opt_start_from_lsn, &opt_start_from_lsn, 0, GET_ULL, REQUIRED_ARG, 0, 0, ~(longlong) 0, 0, 0, 0 }, + {"start-from-checkpoint", 'C', "Start applying from last checkpoint", + &opt_start_from_checkpoint, &opt_start_from_checkpoint, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, { "end-lsn", 'e', "Stop applying at this lsn. If end-lsn is used, UNDO:s " "will not be applied", &opt_end_lsn, &opt_end_lsn, 0, GET_ULL, REQUIRED_ARG, 0, 0, ~(longlong) 0, 0, 0, 0 }, From ae6c5d0de310f75551586b440824ffb5a13270e3 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 12 Aug 2010 20:52:52 +0300 Subject: [PATCH 05/17] Fix for LP#571200 MySQL Bug#32426: FederatedX corrupt ORDER BY with TEXT Patch taken from lp:~capttofu/maria/bug_571200 (originally for MariaDB 5.3, but adapted for 5.1) --- .../suite/federated/federated_server.result | 2 +- storage/federatedx/federatedx_io_mysql.cc | 69 +++++- storage/federatedx/federatedx_io_null.cc | 22 ++ storage/federatedx/ha_federatedx.cc | 198 ++++++++++++------ storage/federatedx/ha_federatedx.h | 51 +++-- 5 files changed, 248 insertions(+), 94 deletions(-) diff --git a/mysql-test/suite/federated/federated_server.result b/mysql-test/suite/federated/federated_server.result index 753b9286287..05782c6ef81 100644 --- a/mysql-test/suite/federated/federated_server.result +++ b/mysql-test/suite/federated/federated_server.result @@ -213,7 +213,7 @@ id name alter server s1 options (database 'db_bogus'); flush tables; select * from federated.t1; -ERROR 42000: Got error: 1044 : Access denied for user 'test_fed'@'localhost' to database 'db_bogus' +ERROR 42000: Received error: 1044 : Access denied for user 'test_fed'@'localhost' to database 'db_bogus' drop server if exists 's1'; ERROR 42000: Access denied; you need the SUPER privilege for this operation create server 's1' foreign data wrapper 'mysql' options diff --git a/storage/federatedx/federatedx_io_mysql.cc b/storage/federatedx/federatedx_io_mysql.cc index 5245395b060..d6844fab2c6 100644 --- a/storage/federatedx/federatedx_io_mysql.cc +++ b/storage/federatedx/federatedx_io_mysql.cc @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2007, Antony T Curtis All rights reserved. @@ -51,6 +51,12 @@ typedef struct federatedx_savepoint uint flags; } SAVEPT; +struct mysql_position +{ + MYSQL_RES* result; + MYSQL_ROW_OFFSET offset; +}; + class federatedx_io_mysql :public federatedx_io { @@ -76,16 +82,16 @@ public: virtual int error_code(); virtual const char *error_str(); - + void reset(); int commit(); int rollback(); - + int savepoint_set(ulong sp); ulong savepoint_release(ulong sp); ulong savepoint_rollback(ulong sp); void savepoint_restrict(ulong sp); - + ulong last_savepoint() const; ulong actual_savepoint() const; bool is_autocommit() const; @@ -94,7 +100,7 @@ public: uint table_name_length, uint flag); /* resultset operations */ - + virtual void free_result(FEDERATEDX_IO_RESULT *io_result); virtual unsigned int get_num_fields(FEDERATEDX_IO_RESULT *io_result); virtual my_ulonglong get_num_rows(FEDERATEDX_IO_RESULT *io_result); @@ -104,6 +110,12 @@ public: unsigned int column); virtual bool is_column_null(const FEDERATEDX_IO_ROW *row, unsigned int column) const; + + virtual size_t get_ref_length() const; + virtual void mark_position(FEDERATEDX_IO_RESULT *io_result, + void *ref); + virtual int seek_position(FEDERATEDX_IO_RESULT **io_result, + const void *ref); }; @@ -466,14 +478,13 @@ const char *federatedx_io_mysql::error_str() return mysql_error(&mysql); } - FEDERATEDX_IO_RESULT *federatedx_io_mysql::store_result() { FEDERATEDX_IO_RESULT *result; DBUG_ENTER("federatedx_io_mysql::store_result"); - + result= (FEDERATEDX_IO_RESULT *) mysql_store_result(&mysql); - + DBUG_RETURN(result); } @@ -590,3 +601,45 @@ error: free_result(result); return 1; } + + + +size_t federatedx_io_mysql::get_ref_length() const +{ + return sizeof(mysql_position); +} + + +void federatedx_io_mysql::mark_position(FEDERATEDX_IO_RESULT *io_result, + void *ref) +{ + MYSQL_ROWS *tmp= 0; + mysql_position& pos= *reinterpret_cast(ref); + pos.result= (MYSQL_RES *) io_result; + + if (pos.result && pos.result->data) + { + for (tmp= pos.result->data->data; + tmp && (tmp->next != pos.result->data_cursor); + tmp= tmp->next) + {} + } + + pos.offset= tmp; +} + +int federatedx_io_mysql::seek_position(FEDERATEDX_IO_RESULT **io_result, + const void *ref) +{ + const mysql_position& pos= *reinterpret_cast(ref); + + if (!pos.result || !pos.offset) + return HA_ERR_END_OF_FILE; + + pos.result->current_row= 0; + pos.result->data_cursor= pos.offset; + *io_result= (FEDERATEDX_IO_RESULT*) pos.result; + + return 0; +} + diff --git a/storage/federatedx/federatedx_io_null.cc b/storage/federatedx/federatedx_io_null.cc index cd8fc3eaf85..49f93ab6546 100644 --- a/storage/federatedx/federatedx_io_null.cc +++ b/storage/federatedx/federatedx_io_null.cc @@ -96,6 +96,11 @@ public: unsigned int column); virtual bool is_column_null(const FEDERATEDX_IO_ROW *row, unsigned int column) const; + virtual size_t get_ref_length() const; + virtual void mark_position(FEDERATEDX_IO_RESULT *io_result, + void *ref); + virtual int seek_position(FEDERATEDX_IO_RESULT **io_result, + const void *ref); }; @@ -275,3 +280,20 @@ bool federatedx_io_null::table_metadata(ha_statistics *stats, return 0; } + +size_t federatedx_io_null::get_ref_length() const +{ + return sizeof(int); +} + + +void federatedx_io_null::mark_position(FEDERATEDX_IO_RESULT *io_result, + void *ref) +{ +} + +int federatedx_io_null::seek_position(FEDERATEDX_IO_RESULT **io_result, + const void *ref) +{ + return 0; +} diff --git a/storage/federatedx/ha_federatedx.cc b/storage/federatedx/ha_federatedx.cc index a88c60efb74..8296fbcd2e9 100644 --- a/storage/federatedx/ha_federatedx.cc +++ b/storage/federatedx/ha_federatedx.cc @@ -1717,14 +1717,14 @@ federatedx_txn *ha_federatedx::get_txn(THD *thd, bool no_create) return *txnp; } - + int ha_federatedx::disconnect(handlerton *hton, MYSQL_THD thd) { federatedx_txn *txn= (federatedx_txn *) thd_get_ha_data(thd, hton); delete txn; return 0; } - + /* Used for opening tables. The name will be the name of the file. @@ -1756,14 +1756,15 @@ int ha_federatedx::open(const char *name, int mode, uint test_if_locked) free_share(txn, share); DBUG_RETURN(error); } - + + ref_length= io->get_ref_length(); + txn->release(&io); - - ref_length= (table->s->primary_key != MAX_KEY ? - table->key_info[table->s->primary_key].key_length : - table->s->reclength); + DBUG_PRINT("info", ("ref_length: %u", ref_length)); + my_init_dynamic_array(&results, sizeof(FEDERATEDX_IO_RESULT*), 4, 4); + reset(); DBUG_RETURN(0); @@ -1788,8 +1789,7 @@ int ha_federatedx::close(void) DBUG_ENTER("ha_federatedx::close"); /* free the result set */ - if (stored_result) - retval= free_result(); + reset(); /* Disconnect from mysql */ if (!thd || !(txn= get_txn(thd, true))) @@ -1799,7 +1799,7 @@ int ha_federatedx::close(void) tmp_txn.release(&io); DBUG_ASSERT(io == NULL); - + if ((error= free_share(&tmp_txn, share))) retval= error; } @@ -2525,7 +2525,7 @@ int ha_federatedx::index_read_idx(uchar *buf, uint index, const uchar *key, uint key_len, enum ha_rkey_function find_flag) { int retval; - FEDERATEDX_IO_RESULT *io_result; + FEDERATEDX_IO_RESULT *io_result= 0; DBUG_ENTER("ha_federatedx::index_read_idx"); if ((retval= index_read_idx_with_result_set(buf, index, key, @@ -2601,7 +2601,7 @@ int ha_federatedx::index_read_idx_with_result_set(uchar *buf, uint index, if (!(retval= read_next(buf, *result))) DBUG_RETURN(retval); - io->free_result(*result); + insert_dynamic(&results, (uchar*) result); *result= 0; table->status= STATUS_NOT_FOUND; DBUG_RETURN(retval); @@ -2669,10 +2669,7 @@ int ha_federatedx::read_range_first(const key_range *start_key, DBUG_RETURN(retval); if (stored_result) - { - io->free_result(stored_result); - stored_result= 0; - } + (void) free_result(); if (io->query(sql_query.ptr(), sql_query.length())) { @@ -2773,10 +2770,7 @@ int ha_federatedx::rnd_init(bool scan) DBUG_RETURN(error); if (stored_result) - { - io->free_result(stored_result); - stored_result= 0; - } + (void) free_result(); if (io->query(share->select_query, strlen(share->select_query))) @@ -2803,17 +2797,35 @@ int ha_federatedx::rnd_end() int ha_federatedx::free_result() { int error; - federatedx_io *tmp_io= 0, **iop; + DBUG_ENTER("ha_federatedx::free_result"); DBUG_ASSERT(stored_result); - if (!*(iop= &io) && (error= txn->acquire(share, TRUE, (iop= &tmp_io)))) + for (uint i= 0; i < results.elements; ++i) { - DBUG_ASSERT(0); // Fail when testing - return error; + FEDERATEDX_IO_RESULT *result= 0; + get_dynamic(&results, (uchar*) &result, i); + if (result == stored_result) + goto end; } - (*iop)->free_result(stored_result); + if (position_called) + { + insert_dynamic(&results, (uchar*) &stored_result); + } + else + { + federatedx_io *tmp_io= 0, **iop; + if (!*(iop= &io) && (error= txn->acquire(share, TRUE, (iop= &tmp_io)))) + { + DBUG_ASSERT(0); // Fail when testing + insert_dynamic(&results, (uchar*) &stored_result); + goto end; + } + (*iop)->free_result(stored_result); + txn->release(&tmp_io); + } +end: stored_result= 0; - txn->release(&tmp_io); - return 0; + position_called= FALSE; + DBUG_RETURN(0); } int ha_federatedx::index_end(void) @@ -2862,8 +2874,8 @@ int ha_federatedx::rnd_next(uchar *buf) SYNOPSIS field_in_record_is_null() - buf byte pointer to record - result mysql result set + buf byte pointer to record + result mysql result set DESCRIPTION This method is a wrapper method that reads one record from a result @@ -2896,24 +2908,43 @@ int ha_federatedx::read_next(uchar *buf, FEDERATEDX_IO_RESULT *result) } -/* - store reference to current row so that we can later find it for - a re-read, update or delete. +/** + @brief Store a reference to current row. - In case of federatedx, a reference is either a primary key or - the whole record. + @details During a query execution we may have different result sets (RS), + e.g. for different ranges. All the RS's used are stored in + memory and placed in @c results dynamic array. At the end of + execution all stored RS's are freed at once in the + @c ha_federated::reset(). + So, in case of federated, a reference to current row is a + stored result address and current data cursor position. + As we keep all RS in memory during a query execution, + we can get any record using the reference any time until + @c ha_federated::reset() is called. + TODO: we don't have to store all RS's rows but only those + we call @c ha_federated::position() for, so we can free memory + where we store other rows in the @c ha_federated::index_end(). + + @param[in] record record data (unused) - Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc. */ -void ha_federatedx::position(const uchar *record) +void ha_federatedx::position(const uchar *record __attribute__ ((unused))) { DBUG_ENTER("ha_federatedx::position"); - if (table->s->primary_key != MAX_KEY) - key_copy(ref, (uchar *)record, table->key_info + table->s->primary_key, - ref_length); - else - memcpy(ref, record, ref_length); + + bzero(ref, ref_length); + + if (!stored_result) + DBUG_VOID_RETURN; + + if (txn->acquire(share, TRUE, &io)) + DBUG_VOID_RETURN; + + io->mark_position(stored_result, ref); + + position_called= TRUE; + DBUG_VOID_RETURN; } @@ -2929,23 +2960,23 @@ void ha_federatedx::position(const uchar *record) int ha_federatedx::rnd_pos(uchar *buf, uchar *pos) { - int result; + int retval; + FEDERATEDX_IO_RESULT *result= stored_result; DBUG_ENTER("ha_federatedx::rnd_pos"); ha_statistic_increment(&SSV::ha_read_rnd_count); - if (table->s->primary_key != MAX_KEY) - { - /* We have a primary key, so use index_read_idx to find row */ - result= index_read_idx(buf, table->s->primary_key, pos, - ref_length, HA_READ_KEY_EXACT); - } - else - { - /* otherwise, get the old record ref as obtained in ::position */ - memcpy(buf, pos, ref_length); - result= 0; - } - table->status= result ? STATUS_NOT_FOUND : 0; - DBUG_RETURN(result); + + if ((retval= txn->acquire(share, TRUE, &io))) + goto error; + + if ((retval= io->seek_position(&result, pos))) + goto error; + + retval= read_next(buf, result); + DBUG_RETURN(retval); + +error: + table->status= STATUS_NOT_FOUND; + DBUG_RETURN(retval); } @@ -2996,15 +3027,20 @@ int ha_federatedx::rnd_pos(uchar *buf, uchar *pos) int ha_federatedx::info(uint flag) { uint error_code; + THD *thd= current_thd; + federatedx_txn *tmp_txn; federatedx_io *tmp_io= 0, **iop= 0; DBUG_ENTER("ha_federatedx::info"); error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE; + // external_lock may not have been called so txn may not be set + tmp_txn= get_txn(thd); + /* we want not to show table status if not needed to do so */ if (flag & (HA_STATUS_VARIABLE | HA_STATUS_CONST | HA_STATUS_AUTO)) { - if (!*(iop= &io) && (error_code= txn->acquire(share, TRUE, (iop= &tmp_io)))) + if (!*(iop= &io) && (error_code= tmp_txn->acquire(share, TRUE, (iop= &tmp_io)))) goto fail; } @@ -3029,14 +3065,14 @@ int ha_federatedx::info(uint flag) If ::info created it's own transaction, close it. This happens in case of show table status; */ - txn->release(&tmp_io); + tmp_txn->release(&tmp_io); DBUG_RETURN(0); error: if (iop && *iop) { - my_printf_error((*iop)->error_code(), "Got error: %d : %s", MYF(0), + my_printf_error((*iop)->error_code(), "Received error: %d : %s", MYF(0), (*iop)->error_code(), (*iop)->error_str()); } else if (remote_error_number != -1 /* error already reported */) @@ -3045,7 +3081,7 @@ error: my_error(error_code, MYF(0), ER(error_code)); } fail: - txn->release(&tmp_io); + tmp_txn->release(&tmp_io); DBUG_RETURN(error_code); } @@ -3105,12 +3141,44 @@ int ha_federatedx::extra(ha_extra_function operation) int ha_federatedx::reset(void) { + int error = 0; + insert_dup_update= FALSE; ignore_duplicates= FALSE; replace_duplicates= FALSE; - return 0; -} + position_called= FALSE; + if (stored_result) + insert_dynamic(&results, (uchar*) &stored_result); + stored_result= 0; + + if (results.elements) + { + federatedx_txn *tmp_txn; + federatedx_io *tmp_io= 0, **iop; + + // external_lock may not have been called so txn may not be set + tmp_txn= get_txn(current_thd); + + if (!*(iop= &io) && (error= tmp_txn->acquire(share, TRUE, (iop= &tmp_io)))) + { + DBUG_ASSERT(0); // Fail when testing + return error; + } + + for (uint i= 0; i < results.elements; ++i) + { + FEDERATEDX_IO_RESULT *result= 0; + get_dynamic(&results, (uchar*) &result, i); + (*iop)->free_result(result); + } + tmp_txn->release(&tmp_io); + reset_dynamic(&results); + } + + return error; + +} /* Used to delete all rows in a table. Both for cases of truncate and @@ -3237,7 +3305,7 @@ static int test_connection(MYSQL_THD thd, federatedx_io *io, str.length(0); str.append(STRING_WITH_LEN("SELECT * FROM ")); - append_identifier(thd, &str, share->table_name, + append_identifier(thd, &str, share->table_name, share->table_name_length); str.append(STRING_WITH_LEN(" WHERE 1=0")); @@ -3288,14 +3356,14 @@ int ha_federatedx::create(const char *name, TABLE *table_arg, pthread_mutex_lock(&federatedx_mutex); tmp_share.s= get_server(&tmp_share, NULL); pthread_mutex_unlock(&federatedx_mutex); - + if (tmp_share.s) { tmp_txn= get_txn(thd); if (!(retval= tmp_txn->acquire(&tmp_share, TRUE, &tmp_io))) { retval= test_connection(thd, tmp_io, &tmp_share); - tmp_txn->release(&tmp_io); + tmp_txn->release(&tmp_io); } free_server(tmp_txn, tmp_share.s); } diff --git a/storage/federatedx/ha_federatedx.h b/storage/federatedx/ha_federatedx.h index 2fd3c559321..2820f8a6c29 100644 --- a/storage/federatedx/ha_federatedx.h +++ b/storage/federatedx/ha_federatedx.h @@ -1,5 +1,5 @@ -/* -Copyright (c) 2008, Patrick Galbraith +/* +Copyright (c) 2008, Patrick Galbraith All rights reserved. Redistribution and use in source and binary forms, with or without @@ -43,7 +43,7 @@ class federatedx_io; typedef struct st_fedrated_server { MEM_ROOT mem_root; uint use_count, io_count; - + uchar *key; uint key_length; @@ -74,10 +74,10 @@ typedef struct st_fedrated_server { #include -/* +/* handler::print_error has a case statement for error numbers. - This value is (10000) is far out of range and will envoke the - default: case. + This value is (10000) is far out of range and will envoke the + default: case. (Current error range is 120-159 from include/my_base.h) */ #define HA_FEDERATEDX_ERROR_WITH_REMOTE_SYSTEM 10000 @@ -158,7 +158,7 @@ public: const char * get_database() const { return server->database; } ushort get_port() const { return server->port; } const char * get_socket() const { return server->socket; } - + static bool handles_scheme(const char *scheme); static federatedx_io *construct(MEM_ROOT *server_root, FEDERATEDX_SERVER *server); @@ -167,7 +167,7 @@ public: { return alloc_root(mem_root, size); } static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); } - + virtual int query(const char *buffer, uint length)=0; virtual FEDERATEDX_IO_RESULT *store_result()=0; @@ -178,25 +178,25 @@ public: virtual int error_code()=0; virtual const char *error_str()=0; - + virtual void reset()=0; virtual int commit()=0; virtual int rollback()=0; - + virtual int savepoint_set(ulong sp)=0; virtual ulong savepoint_release(ulong sp)=0; virtual ulong savepoint_rollback(ulong sp)=0; virtual void savepoint_restrict(ulong sp)=0; - + virtual ulong last_savepoint() const=0; virtual ulong actual_savepoint() const=0; virtual bool is_autocommit() const=0; virtual bool table_metadata(ha_statistics *stats, const char *table_name, uint table_name_length, uint flag) = 0; - + /* resultset operations */ - + virtual void free_result(FEDERATEDX_IO_RESULT *io_result)=0; virtual unsigned int get_num_fields(FEDERATEDX_IO_RESULT *io_result)=0; virtual my_ulonglong get_num_rows(FEDERATEDX_IO_RESULT *io_result)=0; @@ -206,6 +206,13 @@ public: unsigned int column)=0; virtual bool is_column_null(const FEDERATEDX_IO_ROW *row, unsigned int column) const=0; + + virtual size_t get_ref_length() const=0; + virtual void mark_position(FEDERATEDX_IO_RESULT *io_result, + void *ref)=0; + virtual int seek_position(FEDERATEDX_IO_RESULT **io_result, + const void *ref)=0; + }; @@ -215,12 +222,12 @@ class federatedx_txn ulong savepoint_level; ulong savepoint_stmt; ulong savepoint_next; - + void release_scan(); public: federatedx_txn(); ~federatedx_txn(); - + bool has_connections() const { return txn_list != NULL; } bool in_transaction() const { return savepoint_next != 0; } int acquire(FEDERATEDX_SHARE *share, bool readonly, federatedx_io **io); @@ -254,8 +261,12 @@ class ha_federatedx: public handler federatedx_txn *txn; federatedx_io *io; FEDERATEDX_IO_RESULT *stored_result; + /** + Array of all stored results we get during a query execution. + */ + DYNAMIC_ARRAY results; + bool position_called; uint fetch_num; // stores the fetch num - FEDERATEDX_IO_OFFSET current_position; // Current position used by ::position() int remote_error_number; char remote_error_buf[FEDERATEDX_QUERY_BUFFER_SIZE]; bool ignore_duplicates, replace_duplicates; @@ -269,7 +280,7 @@ private: */ uint convert_row_to_internal_format(uchar *buf, FEDERATEDX_IO_ROW *row, FEDERATEDX_IO_RESULT *result); - bool create_where_from_key(String *to, KEY *key_info, + bool create_where_from_key(String *to, KEY *key_info, const key_range *start_key, const key_range *end_key, bool records_in_range, bool eq_range); @@ -348,18 +359,18 @@ public: Talk to Kostja about this - how to get the number of rows * ... disk scan time on other side (block size, size of the row) + network time ... - The reason for "records * 1000" is that such a large number forces + The reason for "records * 1000" is that such a large number forces this to use indexes " */ double scan_time() { DBUG_PRINT("info", ("records %lu", (ulong) stats.records)); - return (double)(stats.records*1000); + return (double)(stats.records*1000); } /* The next method will never be called if you do not implement indexes. */ - double read_time(uint index, uint ranges, ha_rows rows) + double read_time(uint index, uint ranges, ha_rows rows) { /* Per Brian, this number is bugus, but this method must be implemented, From 6795a545e382a2de7104cdc57e0a2834e4aa9b67 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 12 Aug 2010 20:55:00 +0300 Subject: [PATCH 06/17] Trivial optimizations and cleanups --- storage/maria/ma_bitmap.c | 2 +- storage/maria/ma_checkpoint.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/storage/maria/ma_bitmap.c b/storage/maria/ma_bitmap.c index f75df06cadc..cec7cd782be 100644 --- a/storage/maria/ma_bitmap.c +++ b/storage/maria/ma_bitmap.c @@ -365,8 +365,8 @@ my_bool _ma_bitmap_flush_all(MARIA_SHARE *share) */ if (bitmap->changed) { - res= write_changed_bitmap(share, bitmap); bitmap->changed= FALSE; + res= write_changed_bitmap(share, bitmap); } /* We do NOT use FLUSH_KEEP_LAZY because we must be sure that bitmap diff --git a/storage/maria/ma_checkpoint.c b/storage/maria/ma_checkpoint.c index 6d1a6332c54..8a6e2b5d960 100644 --- a/storage/maria/ma_checkpoint.c +++ b/storage/maria/ma_checkpoint.c @@ -827,7 +827,6 @@ static int collect_tables(LEX_STRING *str, LSN checkpoint_start_log_horizon) not seen again in the loop. */ share->in_checkpoint= MARIA_CHECKPOINT_LOOKS_AT_ME; - /** @todo avoid strlen() */ total_names_length+= share->open_file_name.length; } } From b87a73773913ebdcfdacb2d8b8704958bc0e93f2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 14 Aug 2010 18:44:45 +0400 Subject: [PATCH 07/17] missing DBUG_RETURNs --- mysys/my_getwd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mysys/my_getwd.c b/mysys/my_getwd.c index e6b867e2753..a18c296a7e1 100644 --- a/mysys/my_getwd.c +++ b/mysys/my_getwd.c @@ -51,7 +51,7 @@ int my_getwd(char * buf, size_t size, myf MyFlags) (long) buf, (uint) size, MyFlags)); if (size < 1) - return(-1); + DBUG_RETURN(-1); if (curr_dir[0]) /* Current pos is saved here */ VOID(strmake(buf,&curr_dir[0],size-1)); @@ -59,12 +59,12 @@ int my_getwd(char * buf, size_t size, myf MyFlags) { #if defined(HAVE_GETCWD) if (size < 2) - return(-1); + DBUG_RETURN(-1); if (!getcwd(buf,(uint) (size-2)) && MyFlags & MY_WME) { my_errno=errno; my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno); - return(-1); + DBUG_RETURN(-1); } #elif defined(HAVE_GETWD) { @@ -74,12 +74,12 @@ int my_getwd(char * buf, size_t size, myf MyFlags) } #elif defined(VMS) if (size < 2) - return(-1); + DBUG_RETURN(-1); if (!getcwd(buf,size-2,1) && MyFlags & MY_WME) { my_errno=errno; my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno); - return(-1); + DBUG_RETURN(-1); } intern_filename(buf,buf); #else From 8da7be63027403c5b82eda378842142cdcbad95c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 17 Aug 2010 11:14:46 +0400 Subject: [PATCH 08/17] generalization of mtr to support suite.pm extensions: * no automatic --loose-skip-innodb added by mtr based on the test name. instead loose-skip-innodb is now in the default_mysqld.cnf * have_innodb_plugin.inc is changed to give a verbose "skip" message (instead of "require: true") * My::Suite class. It's support in mtr, and everywhere * support for suite.pm * when sorting tests, take combinations into account * support for SUITENAME_COMBINATIONS * no special treatment for innodb_plugin in mtr_cases.pm * two special pre-created config groups: ENV and OPT * allow option names to start from # * allow magic option to have an argument * remove dead code * fix @-substitution to works as expected * new processes take the value of $opt_verbose automatically, no need to pass it to a constructor * innodb_plugin suite uses suite.pm and combinations file to test as much as possible (innodb plugin, xtradb plugin, xtradb static - whatever available) * besides test-master.opt and test-slave.opt a test.opt file is also loaded, both for master and slave * .opt files for all included files are loaded too * progress report in the xterm titlebar --- mysql-test/Makefile.am | 5 +- mysql-test/README.suites | 136 +++++ mysql-test/include/default_my.cnf | 3 - mysql-test/include/default_mysqld.cnf | 5 +- .../include/have_binlog_format_mixed.opt | 1 + mysql-test/include/have_binlog_format_row.opt | 1 + .../include/have_binlog_format_statement.opt | 2 + mysql-test/include/have_exampledb.inc | 4 - mysql-test/include/have_innodb.inc | 9 +- mysql-test/include/have_innodb.opt | 1 + mysql-test/include/have_innodb_plugin.inc | 9 +- mysql-test/include/have_log_bin-master.opt | 1 + mysql-test/include/have_log_bin-slave.opt | 1 + mysql-test/include/have_log_bin.inc | 2 + mysql-test/include/have_pbxt.opt | 1 + mysql-test/lib/My/Config.pm | 131 +++-- mysql-test/lib/My/ConfigFactory.pm | 54 +- mysql-test/lib/My/Handles.pm | 0 mysql-test/lib/My/SafeProcess.pm | 2 +- mysql-test/lib/My/Suite.pm | 10 + mysql-test/lib/My/Test.pm | 6 + mysql-test/lib/mtr_cases.pm | 214 ++------ mysql-test/lib/mtr_report.pm | 6 +- mysql-test/mysql-test-run.pl | 512 +++++++++--------- mysql-test/r/exampledb.result | 8 - mysql-test/r/warnings_engine_disabled.result | 17 +- .../suite/binlog/t/binlog_base64_flag.test | 1 + .../suite/binlog/t/binlog_old_versions.test | 1 + .../t/binlog_row_mix_innodb_myisam-master.opt | 2 +- .../t/binlog_stm_mix_innodb_myisam-master.opt | 2 +- .../federated/federated_innodb-slave.opt | 2 +- mysql-test/suite/federated/my.cnf | 3 +- mysql-test/suite/funcs_1/t/is_columns_is.test | 1 + mysql-test/suite/innodb/t/innodb-master.opt | 2 +- .../t/innodb-semi-consistent-master.opt | 2 +- .../innodb_autoinc_lock_mode_zero-master.opt | 2 +- .../suite/innodb/t/innodb_bug30919-master.opt | 2 +- .../suite/innodb/t/innodb_bug39438-master.opt | 2 +- .../suite/innodb/t/innodb_bug52663-master.opt | 2 +- .../suite/innodb/t/innodb_bug53674-master.opt | 2 +- .../suite/innodb/t/innodb_bug53674.test | 1 + .../t/innodb_lock_wait_timeout_1-master.opt | 2 +- .../suite/innodb/t/innodb_misc1-master.opt | 2 +- .../suite/innodb/t/innodb_mysql-master.opt | 2 +- .../innodb/t/innodb_mysql_rbk-master.opt | 2 +- .../t/innodb_timeout_rollback-master.opt | 2 +- mysql-test/suite/innodb_plugin/combinations | 12 + mysql-test/suite/innodb_plugin/suite.pm | 17 + .../t/innodb-consistent-master.opt | 2 +- .../suite/innodb_plugin/t/innodb-master.opt | 2 +- .../t/innodb-semi-consistent-master.opt | 2 +- .../t/innodb-use-sys-malloc-master.opt | 2 +- .../innodb_autoinc_lock_mode_zero-master.opt | 2 +- .../t/innodb_bug30919-master.opt | 2 +- .../t/innodb_bug39438-master.opt | 2 +- .../t/innodb_bug42101-nonzero-master.opt | 2 +- .../t/innodb_bug53674-master.opt | 2 +- .../t/innodb_lock_wait_timeout_1-master.opt | 2 +- .../innodb_plugin/t/innodb_mysql-master.opt | 2 +- .../t/innodb_mysql_rbk-master.opt | 2 +- .../t/innodb_timeout_rollback-master.opt | 2 +- .../ndb_team/t/rpl_ndb_mix_innodb-master.opt | 2 +- .../t/partition_debug_sync_innodb-master.opt | 2 +- .../t/partition_special_innodb-master.opt | 2 +- mysql-test/suite/pbxt/my.cnf | 1 + mysql-test/suite/pbxt/t/suite.opt | 1 - ...percona_innodb_doublewrite_file-master.opt | 2 +- .../rpl/r/rpl_row_basic_11bugs-master.opt | 2 +- .../rpl/r/rpl_row_basic_11bugs-slave.opt | 2 +- mysql-test/suite/rpl/rpl_1slave_base.cnf | 3 - .../t/rpl_begin_commit_rollback-master.opt | 2 +- .../rpl/t/rpl_begin_commit_rollback-slave.opt | 2 +- .../suite/rpl/t/rpl_circular_for_4_hosts.cnf | 8 +- .../rpl/t/rpl_concurrency_error-master.opt | 2 +- mysql-test/suite/rpl/t/rpl_ddl-slave.opt | 1 + .../suite/rpl/t/rpl_deadlock_innodb-slave.opt | 2 +- mysql-test/suite/rpl/t/rpl_innodb-master.opt | 2 +- .../rpl/t/rpl_innodb_bug28430-master.opt | 2 +- .../suite/rpl/t/rpl_innodb_bug28430-slave.opt | 2 +- .../rpl/t/rpl_start_stop_slave-slave.opt | 2 +- mysql-test/suite/rpl/t/rpl_trigger.test | 9 +- mysql-test/suite/rpl/t/rpl_typeconv-slave.opt | 2 +- .../suite/rpl_ndb/t/rpl_ndb_2innodb-slave.opt | 2 +- .../suite/rpl_ndb/t/rpl_ndb_2other-slave.opt | 2 +- .../suite/rpl_ndb/t/rpl_ndb_circular_2ch.cnf | 4 - .../rpl_ndb/t/rpl_ndb_innodb2ndb-master.opt | 2 +- .../rpl_ndb/t/rpl_ndb_innodb_trans-slave.opt | 2 +- ..._ndb_mixed_engines_transactions-master.opt | 2 +- ...l_ndb_mixed_engines_transactions-slave.opt | 2 +- .../rpl_ndb/t/rpl_ndb_mixed_tables-master.opt | 2 +- .../rpl_ndb/t/rpl_ndb_mixed_tables-slave.opt | 2 +- .../rpl_ndb/t/rpl_ndb_stm_innodb-master.opt | 2 +- .../sys_vars/t/autocommit_func-master.opt | 2 +- .../character_set_filesystem_func-master.opt | 2 +- .../suite/sys_vars/t/identity_func-master.opt | 2 +- .../innodb_autoinc_lock_mode_func-master.opt | 2 +- .../sys_vars/t/last_insert_id_func-master.opt | 2 +- .../t/max_binlog_cache_size_func-master.opt | 2 +- .../t/storage_engine_basic-master.opt | 2 +- .../sys_vars/t/tx_isolation_func-master.opt | 4 +- mysql-test/t/bug46760-master.opt | 4 +- .../t/concurrent_innodb_safelog-master.opt | 2 +- .../t/concurrent_innodb_unsafelog-master.opt | 4 +- mysql-test/t/connect.cnf | 2 +- mysql-test/t/exampledb.test | 22 - mysql-test/t/partition_innodb-master.opt | 2 +- ...artition_innodb_semi_consistent-master.opt | 2 +- mysql-test/t/pool_of_threads.cnf | 2 +- mysql-test/t/sp_trans_log.test | 2 +- mysql-test/t/unsafe_binlog_innodb-master.opt | 2 +- mysql-test/t/warnings_engine_disabled.test | 19 +- 111 files changed, 708 insertions(+), 681 deletions(-) create mode 100644 mysql-test/README.suites create mode 100644 mysql-test/include/have_binlog_format_mixed.opt create mode 100644 mysql-test/include/have_binlog_format_row.opt create mode 100644 mysql-test/include/have_binlog_format_statement.opt delete mode 100644 mysql-test/include/have_exampledb.inc create mode 100644 mysql-test/include/have_innodb.opt create mode 100644 mysql-test/include/have_log_bin-master.opt create mode 100644 mysql-test/include/have_log_bin-slave.opt create mode 100644 mysql-test/include/have_pbxt.opt mode change 100755 => 100644 mysql-test/lib/My/Handles.pm create mode 100644 mysql-test/lib/My/Suite.pm delete mode 100644 mysql-test/r/exampledb.result create mode 100644 mysql-test/suite/innodb_plugin/combinations create mode 100644 mysql-test/suite/innodb_plugin/suite.pm delete mode 100644 mysql-test/suite/pbxt/t/suite.opt create mode 100644 mysql-test/suite/rpl/t/rpl_ddl-slave.opt delete mode 100644 mysql-test/t/exampledb.test diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index 4ea634688fe..7a0d4c2d6fc 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -63,13 +63,14 @@ nobase_test_DATA = \ lib/My/SafeProcess.pm \ lib/My/File/Path.pm \ lib/My/SysInfo.pm \ + lib/My/Suite.pm \ lib/My/CoreDump.pm \ lib/My/SafeProcess/Base.pm \ lib/My/SafeProcess/safe_process.pl SUBDIRS = lib/My/SafeProcess -EXTRA_DIST = README \ +EXTRA_DIST = README README.suites \ $(test_SCRIPTS) \ $(nobase_test_DATA) @@ -101,7 +102,7 @@ TEST_DIRS = t r include std_data std_data/parts collections \ suite/ndb suite/ndb/t suite/ndb/r \ suite/rpl_ndb suite/rpl_ndb/t suite/rpl_ndb/r \ suite/parts suite/parts/t suite/parts/r suite/parts/inc \ - suite/pbxt/t suite/pbxt/r \ + suite/pbxt/t suite/pbxt/r suite/pbxt \ suite/innodb suite/innodb/t suite/innodb/r suite/innodb/include \ suite/innodb_plugin suite/innodb_plugin/t suite/innodb_plugin/r suite/innodb_plugin/include \ suite/percona \ diff --git a/mysql-test/README.suites b/mysql-test/README.suites new file mode 100644 index 00000000000..d8f39cbc39f --- /dev/null +++ b/mysql-test/README.suites @@ -0,0 +1,136 @@ +These are the assorted notes that will be turned into a manual eventually. + +========================== +Tests are organized in suites. +A "suite" is a subdirectory inside, one of, + + /mysql-test/suite + /mysql-test + /share/mysql-test/suite + /share/mysql-test + /share/mysql/mysql-test/suite + /share/mysql/mysql-test + /storage/*/mysql-test-suites + +This is supposed to cover running mtr from a source directory and installed. + +========================== +A suite contains *.test and *.result files. They can be in the t/ and r/ +subdirectories under the suitedir or directly in the suitedir +(that is suitedir/t/*.test or suitedir/*.test, same for *.result)) + +========================== +A suite can contain a suite.opt file - at the same location where .test +files are. As usual, the .opt file can use $-substitutions for the +environment variables. + +Usually, using my.cnf template (see below) is preferrable. +========================== +A suite can have suite.pm file in the suitedir. It must declare a +package that inherits from My::Suite. + +The suite.pm needs to have @ISA=qw(My::Suite) and it must end +with bless {}; - that is it must return an object of that class. + +A suite class can define config_files() and servers() methods. + +A config_files method returns a list of additional config files (besides +my.cnf), that this suite needs to be created. For every file it specifies +a function that will create it, when given a My::Config object. For example: + + sub config_files { ( 'config.ini' => \&write_ini, + 'new.conf' => \&do_new_conf ) } + +A servers method returns a list of processes that needs to be started for +this suite. A process is specified as a pair (regex, hash). A regex must +match a section in the my.cnf template (for example, qr/mysqld\./ corresponds +to all mysqld processes), a hash contains these options: + + SORT => a number, processes are started in the order of increasing SORT + values (and stopped in the reverse order). mysqld has number 300. + START => a function to start a process. It takes two arguments, + My::Config::Group and My::Test. If START is undefined the process + will not be started. + WAIT => a function waits for the process to be started. It takes + My::Config::Group as an argument. Internallys mtr first invokes + START for all processes, then WAIT for all started processes. + +example: sub servers { ( qr/^foo$/ => { SORT => 200, + START => \&start_foo, + WAIT => \&wait_foo } ) } + +See sphinx suite for an example. + +========================== +A suite can have my.cnf template file in the suitedir. +A my.cnf template uses a normal my.cnf syntax - groups, options, +and values - with templating extensions. They are + +* There can be groups with non-standard names, not used by mysqld. + These groups may be used by the suite.pm file somehow. + For example, they can be written to the additional config files. + See sphinx suite for an example. + +* There can be ENV group. It sets values for the environment variables. + +* Values can refer to each other - they will be expanded as needed. + A reference to a value of an option looks like @groupname.optionname. + For example + + [mysqld.2] + master-port= @mysqld.1.port + + it sets the master-port in the mysqld.2 group to the value of + port in the mysqld.1 group. + +* An option name may start from '#'. In the resulting my.cnf it will look + like a comment, but it still can be referred to. For example: + + [example] + #foo = localhost:@mysqld.1.port + bar = http://@example.#foo/index.html + +* There are two special - in this regard - groups. + + Via the ENV group one can refer to any environment variable, not only + to values in the [ENV] group of my.cnf file. + + Via the OPT group one can refer to special values: + @OPT.vardir - a path to vardir + @OPT.port - a new port number is reserved out of the pool. It will not + match any other port number used by this test run. + See sphinx suite for an example. + +Most probably a suite my.cnf will need to start from + + !include include/default_my.cnf + +and then modify the configuration as necessary. +========================== + +A suite can have combinations file in the suitedir. It uses my.cnf syntax +but it cannot use @-substitutions. Instead, it can use $-substitutions for +the environment variables. Because the combination options will not be +merged to a my.cnf, but will be added to the command line. Example: + + [conf1] + opt1=val1 + + [conf2] + opt1=val2 + opt2=$HAVE_SOMETHING + +Such a file will cause every test from the suite to be run twice - once +with mysqld using --opt1=val1 and the other one with mysqld using +--opt1=val2 --opt2=$HAVE_SOMETHING + +One can limit mtr run to a subset of combinations by setting environment +variable SUITENAME_COMBINATIONS to the ':'-separated set of combination +names. E.g. + + RPL_COMBINATIONS=mix:row ./mtr --suite rpl + +See innodb_plugin suite for an example of how suite.pm may set this variable +to exclude unsupported configurations. +========================== + diff --git a/mysql-test/include/default_my.cnf b/mysql-test/include/default_my.cnf index d77fee0e200..17a418ff7b5 100644 --- a/mysql-test/include/default_my.cnf +++ b/mysql-test/include/default_my.cnf @@ -6,9 +6,6 @@ # Run the master.sh script before starting this process #!run-master-sh -log-bin= master-bin - - [mysqlbinlog] disable-force-if-open diff --git a/mysql-test/include/default_mysqld.cnf b/mysql-test/include/default_mysqld.cnf index c93762f6c25..e46c3bc3c17 100644 --- a/mysql-test/include/default_mysqld.cnf +++ b/mysql-test/include/default_mysqld.cnf @@ -13,9 +13,10 @@ key_buffer_size= 1M sort_buffer= 256K max_heap_table_size= 1M +loose-skip-innodb +loose-skip-pbxt + loose-innodb_data_file_path= ibdata1:10M:autoextend slave-net-timeout=120 -log-bin=mysqld-bin - diff --git a/mysql-test/include/have_binlog_format_mixed.opt b/mysql-test/include/have_binlog_format_mixed.opt new file mode 100644 index 00000000000..01cf3e0520f --- /dev/null +++ b/mysql-test/include/have_binlog_format_mixed.opt @@ -0,0 +1 @@ +--binlog-format=mixed diff --git a/mysql-test/include/have_binlog_format_row.opt b/mysql-test/include/have_binlog_format_row.opt new file mode 100644 index 00000000000..83ed8522e72 --- /dev/null +++ b/mysql-test/include/have_binlog_format_row.opt @@ -0,0 +1 @@ +--binlog-format=row diff --git a/mysql-test/include/have_binlog_format_statement.opt b/mysql-test/include/have_binlog_format_statement.opt new file mode 100644 index 00000000000..0dac5e9fb9c --- /dev/null +++ b/mysql-test/include/have_binlog_format_statement.opt @@ -0,0 +1,2 @@ +--binlog-format=statement + diff --git a/mysql-test/include/have_exampledb.inc b/mysql-test/include/have_exampledb.inc deleted file mode 100644 index db3985e3c7c..00000000000 --- a/mysql-test/include/have_exampledb.inc +++ /dev/null @@ -1,4 +0,0 @@ -disable_query_log; ---require r/true.require -select (support = 'YES' or support = 'DEFAULT') as `TRUE` from information_schema.engines where engine = 'example'; -enable_query_log; diff --git a/mysql-test/include/have_innodb.inc b/mysql-test/include/have_innodb.inc index 8944cc46f3e..c3c8b5cc4f2 100644 --- a/mysql-test/include/have_innodb.inc +++ b/mysql-test/include/have_innodb.inc @@ -1,4 +1,5 @@ -disable_query_log; ---require r/true.require -select (support = 'YES' or support = 'DEFAULT' or support = 'ENABLED') as `TRUE` from information_schema.engines where engine = 'innodb'; -enable_query_log; +if (!`SELECT count(*) FROM information_schema.engines WHERE + (support = 'YES' OR support = 'DEFAULT') AND + engine = 'innodb'`){ + skip Needs innodb engine; +} diff --git a/mysql-test/include/have_innodb.opt b/mysql-test/include/have_innodb.opt new file mode 100644 index 00000000000..48457b17309 --- /dev/null +++ b/mysql-test/include/have_innodb.opt @@ -0,0 +1 @@ +--loose-innodb diff --git a/mysql-test/include/have_innodb_plugin.inc b/mysql-test/include/have_innodb_plugin.inc index 6b5fc29d459..5f67fb1f97d 100644 --- a/mysql-test/include/have_innodb_plugin.inc +++ b/mysql-test/include/have_innodb_plugin.inc @@ -1,4 +1,5 @@ -disable_query_log; ---require r/true.require -SELECT (plugin_library LIKE 'ha_innodb_plugin%' OR plugin_description LIKE '%xtradb%') AS `TRUE` FROM information_schema.plugins WHERE LOWER(plugin_name) = 'innodb' AND LOWER(plugin_status) = 'active'; -enable_query_log; +if (!`SELECT COUNT(*) FROM INFORMATION_SCHEMA.PLUGINS + WHERE PLUGIN_NAME = 'innodb' AND PLUGIN_STATUS = 'active' AND + (PLUGIN_LIBRARY LIKE 'ha_innodb_plugin%' OR PLUGIN_DESCRIPTION LIKE '%xtradb%')`) { + skip Need InnoDB plugin or XtraDB; +} diff --git a/mysql-test/include/have_log_bin-master.opt b/mysql-test/include/have_log_bin-master.opt new file mode 100644 index 00000000000..9ce5d80d7e8 --- /dev/null +++ b/mysql-test/include/have_log_bin-master.opt @@ -0,0 +1 @@ +--log-bin=master-bin diff --git a/mysql-test/include/have_log_bin-slave.opt b/mysql-test/include/have_log_bin-slave.opt new file mode 100644 index 00000000000..92012982830 --- /dev/null +++ b/mysql-test/include/have_log_bin-slave.opt @@ -0,0 +1 @@ +--log-bin=slave-bin diff --git a/mysql-test/include/have_log_bin.inc b/mysql-test/include/have_log_bin.inc index 369af9b8e1d..e51205d25ad 100644 --- a/mysql-test/include/have_log_bin.inc +++ b/mysql-test/include/have_log_bin.inc @@ -6,6 +6,8 @@ # # source include/have_log_bin.inc; +source include/not_embedded.inc; + -- require r/have_log_bin.require disable_query_log; show variables like 'log_bin'; diff --git a/mysql-test/include/have_pbxt.opt b/mysql-test/include/have_pbxt.opt new file mode 100644 index 00000000000..54ba9495053 --- /dev/null +++ b/mysql-test/include/have_pbxt.opt @@ -0,0 +1 @@ +--loose-pbxt diff --git a/mysql-test/lib/My/Config.pm b/mysql-test/lib/My/Config.pm index f8416e3df3a..0955c1bb190 100644 --- a/mysql-test/lib/My/Config.pm +++ b/mysql-test/lib/My/Config.pm @@ -6,7 +6,6 @@ use strict; use warnings; use Carp; - sub new { my ($class, $option_name, $option_value)= @_; my $self= bless { name => $option_name, @@ -61,7 +60,7 @@ sub insert { $option->{value}= $value; } else { - my $option= My::Config::Option->new($option_name, $value); + $option= My::Config::Option->new($option_name, $value); # Insert option in list push(@{$self->{options}}, $option); # Insert option in hash @@ -163,6 +162,62 @@ sub if_exist { return $option->value(); } +package My::Config::Group::ENV; +our @ISA=qw(My::Config::Group); + +use strict; +use warnings; +use Carp; + +sub new { + my ($class, $group_name)= @_; + bless My::Config::Group->new($group_name), $class; +} + +# +# Return value for an option in the group, fail if it does not exist +# +sub value { + my ($self, $option_name)= @_; + my $option= $self->option($option_name); + + if (! defined($option) and defined $ENV{$option_name}) { + my $value= $ENV{$option_name}; + $option= My::Config::Option->new($option_name, $value); + } + + croak "No option named '$option_name' in group '$self->{name}'" + if ! defined($option); + + return $option->value(); +} + +package My::Config::Group::OPT; +our @ISA=qw(My::Config::Group); + +use strict; +use warnings; +use Carp; + +sub new { + my ($class, $group_name)= @_; + bless My::Config::Group->new($group_name), $class; +} + +sub options { + my ($self)= @_; + () +} + +sub value { + my ($self, $option_name)= @_; + my $option= $self->option($option_name); + + croak "No option named '$option_name' in group '$self->{name}'" + if ! defined($option); + + return $option->value()->(); +} package My::Config; @@ -182,7 +237,10 @@ sub new { my ($class, $path)= @_; my $group_name= undef; - my $self= bless { groups => [] }, $class; + my $self= bless { groups => [ + My::Config::Group::ENV->new('ENV'), + My::Config::Group::OPT->new('OPT'), + ] }, $class; my $F= IO::File->new($path, "<") or croak "Could not open '$path': $!"; @@ -199,19 +257,13 @@ sub new { } # Magic #! comments - elsif ( $line =~ /^#\!/) { - my $magic= $line; + elsif ( $line =~ /^(#\!\S+)(?:\s*(.*?)\s*)?$/) { + my ($magic, $arg)= ($1, $2); croak "Found magic comment '$magic' outside of group" unless $group_name; #print "$magic\n"; - $self->insert($group_name, $magic, undef); - } - - # Comments - elsif ( $line =~ /^#/ || $line =~ /^;/) { - # Skip comment - next; + $self->insert($group_name, $magic, $arg); } # Empty lines @@ -236,7 +288,7 @@ sub new { } #