summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xBitKeeper/triggers/post-commit.innodb.pl22
-rwxr-xr-xBitKeeper/triggers/post-incoming.innodb.pl30
-rwxr-xr-xBitKeeper/triggers/pre-commit.innodb.pl21
-rw-r--r--BitKeeper/triggers/triggers-lib.pl360
-rw-r--r--client/mysql.cc749
-rw-r--r--cmd-line-utils/readline/bind.c2
-rw-r--r--cmd-line-utils/readline/callback.c2
-rw-r--r--cmd-line-utils/readline/compat.c2
-rw-r--r--cmd-line-utils/readline/complete.c2
-rw-r--r--cmd-line-utils/readline/display.c2
-rw-r--r--cmd-line-utils/readline/funmap.c2
-rw-r--r--cmd-line-utils/readline/histexpand.c2
-rw-r--r--cmd-line-utils/readline/histfile.c2
-rw-r--r--cmd-line-utils/readline/history.c2
-rw-r--r--cmd-line-utils/readline/histsearch.c2
-rw-r--r--cmd-line-utils/readline/input.c2
-rw-r--r--cmd-line-utils/readline/isearch.c2
-rw-r--r--cmd-line-utils/readline/keymaps.c2
-rw-r--r--cmd-line-utils/readline/kill.c2
-rw-r--r--cmd-line-utils/readline/macro.c2
-rw-r--r--cmd-line-utils/readline/mbutil.c2
-rw-r--r--cmd-line-utils/readline/misc.c2
-rw-r--r--cmd-line-utils/readline/nls.c2
-rw-r--r--cmd-line-utils/readline/parens.c2
-rw-r--r--cmd-line-utils/readline/readline.c2
-rw-r--r--cmd-line-utils/readline/rldefs.h2
-rw-r--r--cmd-line-utils/readline/rltty.c2
-rw-r--r--cmd-line-utils/readline/rlwinsize.h2
-rw-r--r--cmd-line-utils/readline/savestring.c2
-rw-r--r--cmd-line-utils/readline/search.c2
-rw-r--r--cmd-line-utils/readline/shell.c2
-rw-r--r--cmd-line-utils/readline/signals.c2
-rw-r--r--cmd-line-utils/readline/tcap.h2
-rw-r--r--cmd-line-utils/readline/terminal.c2
-rw-r--r--cmd-line-utils/readline/text.c2
-rw-r--r--cmd-line-utils/readline/tilde.c2
-rw-r--r--cmd-line-utils/readline/undo.c2
-rw-r--r--cmd-line-utils/readline/util.c2
-rw-r--r--cmd-line-utils/readline/vi_mode.c2
-rw-r--r--cmd-line-utils/readline/xmalloc.c2
-rw-r--r--configure.in4
-rwxr-xr-xextra/CMakeLists.txt3
-rw-r--r--extra/resolveip.c22
-rw-r--r--extra/yassl/src/handshake.cpp5
-rw-r--r--extra/yassl/src/template_instnt.cpp1
-rw-r--r--extra/yassl/src/yassl_imp.cpp11
-rw-r--r--mysql-test/include/ndb_wait_connected.inc26
-rwxr-xr-xmysql-test/mysql-test-run.pl5
-rw-r--r--mysql-test/r/limit.result9
-rw-r--r--mysql-test/r/ndb_alter_table2.result19
-rw-r--r--mysql-test/r/ndb_auto_increment.result6
-rw-r--r--mysql-test/r/ndb_bug31477.result98
-rw-r--r--mysql-test/r/ndb_condition_pushdown.result6
-rw-r--r--mysql-test/r/ndb_restore.result50
-rw-r--r--mysql-test/r/ps.result182
-rw-r--r--mysql-test/r/rpl_user_variables.result16
-rw-r--r--mysql-test/r/view.result21
-rw-r--r--mysql-test/r/view_grant.result1
-rw-r--r--mysql-test/t/limit.test17
-rw-r--r--mysql-test/t/ndb_alter_table2.test31
-rw-r--r--mysql-test/t/ndb_autodiscover.test1
-rw-r--r--mysql-test/t/ndb_autodiscover3.test9
-rw-r--r--mysql-test/t/ndb_bug31477.test109
-rw-r--r--mysql-test/t/ndb_condition_pushdown.test751
-rw-r--r--mysql-test/t/ndb_restore.test25
-rw-r--r--mysql-test/t/ps.test142
-rw-r--r--mysql-test/t/rpl_user_variables.test17
-rw-r--r--mysql-test/t/view.test35
-rw-r--r--mysql-test/t/view_grant.test1
-rw-r--r--ndb/include/kernel/ndb_limits.h11
-rw-r--r--ndb/include/mgmapi/ndb_logevent.h8
-rw-r--r--ndb/include/ndbapi/Ndb.hpp18
-rw-r--r--ndb/include/ndbapi/ndbapi_limits.h3
-rw-r--r--ndb/include/util/Bitmask.hpp10
-rw-r--r--ndb/src/common/debugger/SignalLoggerManager.cpp2
-rw-r--r--ndb/src/common/debugger/signaldata/ScanTab.cpp2
-rw-r--r--ndb/src/common/transporter/TCP_Transporter.cpp22
-rw-r--r--ndb/src/common/util/Bitmask.cpp353
-rw-r--r--ndb/src/common/util/NdbOut.cpp2
-rw-r--r--ndb/src/kernel/blocks/backup/Backup.cpp14
-rw-r--r--ndb/src/kernel/blocks/backup/Backup.hpp2
-rw-r--r--ndb/src/kernel/blocks/dbtup/Dbtup.hpp26
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp8
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp96
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp16
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp9
-rw-r--r--ndb/src/kernel/vm/DLHashTable.hpp22
-rw-r--r--ndb/src/kernel/vm/DLHashTable2.hpp22
-rw-r--r--ndb/src/kernel/vm/pc.hpp6
-rw-r--r--ndb/src/mgmapi/ndb_logevent.cpp2
-rw-r--r--ndb/src/mgmclient/CommandInterpreter.cpp17
-rw-r--r--ndb/src/mgmsrv/ConfigInfo.cpp12
-rw-r--r--ndb/src/ndbapi/DictCache.cpp1
-rw-r--r--ndb/src/ndbapi/DictCache.hpp1
-rw-r--r--ndb/src/ndbapi/Ndb.cpp131
-rw-r--r--ndb/src/ndbapi/NdbDictionaryImpl.cpp19
-rw-r--r--ndb/src/ndbapi/ndberror.c1
-rw-r--r--ndb/test/ndbapi/testBitfield.cpp407
-rw-r--r--ndb/test/ndbapi/testInterpreter.cpp89
-rw-r--r--ndb/test/ndbapi/testOIBasic.cpp2952
-rw-r--r--ndb/test/run-test/daily-basic-tests.txt8
-rw-r--r--ndb/tools/waiter.cpp127
-rwxr-xr-xscripts/CMakeLists.txt41
-rw-r--r--scripts/Makefile.am3
-rw-r--r--scripts/make_binary_distribution.sh10
-rwxr-xr-xscripts/make_win_bin_dist37
-rw-r--r--scripts/mysql_config.pl.in285
-rw-r--r--scripts/mysql_config.sh11
-rw-r--r--scripts/mysql_convert_table_format.sh2
-rw-r--r--scripts/mysql_explain_log.sh9
-rw-r--r--scripts/mysql_install_db.pl.in612
-rwxr-xr-xscripts/mysql_secure_installation.pl.in352
-rw-r--r--scripts/mysql_tableinfo.sh2
-rw-r--r--scripts/mysqld_multi.sh2
-rw-r--r--scripts/mysqldumpslow.sh2
-rw-r--r--scripts/mysqlhotcopy.sh101
-rwxr-xr-xsql/CMakeLists.txt2
-rw-r--r--sql/filesort.cc7
-rw-r--r--sql/ha_innodb.cc4
-rw-r--r--sql/ha_ndbcluster.cc10
-rw-r--r--sql/item.cc13
-rw-r--r--sql/item.h52
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/mysqld.cc225
-rw-r--r--sql/sql_class.h2
-rw-r--r--sql/sql_cursor.cc98
-rw-r--r--sql/sql_parse.cc19
-rw-r--r--sql/sql_prepare.cc39
-rw-r--r--sql/sql_view.cc242
-rw-r--r--sql/sql_view.h3
-rw-r--r--sql/sql_yacc.yy2
-rw-r--r--sql/stacktrace.c275
-rw-r--r--sql/stacktrace.h23
-rw-r--r--support-files/mysql.spec.sh74
-rw-r--r--tests/mysql_client_test.c169
-rw-r--r--vio/viossl.c35
136 files changed, 7115 insertions, 2944 deletions
diff --git a/BitKeeper/triggers/post-commit.innodb.pl b/BitKeeper/triggers/post-commit.innodb.pl
new file mode 100755
index 00000000000..44d98b04838
--- /dev/null
+++ b/BitKeeper/triggers/post-commit.innodb.pl
@@ -0,0 +1,22 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+
+use FindBin;
+require "$FindBin::Bin/triggers-lib.pl";
+
+# Don't run unless commit was successful
+check_status() || exit 0;
+
+my $cset = latest_cset();
+
+# Read most recent ChangeSet's changed files. Send merge changes along, since
+# they'll need to be incorporated in InnoDB's source tree eventually.
+my $changes = innodb_get_changes('cset', $cset, 'yes')
+ or exit 0;
+
+innodb_send_changes_email($cset, $changes)
+ or exit 1;
+
+exit 0;
diff --git a/BitKeeper/triggers/post-incoming.innodb.pl b/BitKeeper/triggers/post-incoming.innodb.pl
new file mode 100755
index 00000000000..4b100d88037
--- /dev/null
+++ b/BitKeeper/triggers/post-incoming.innodb.pl
@@ -0,0 +1,30 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+
+use FindBin;
+require "$FindBin::Bin/triggers-lib.pl";
+
+# Don't run unless push/pull was successful
+check_status() or exit 0;
+
+# Don't run if push/pull is in local clones
+exit 0 if repository_type() eq 'local';
+
+# For each pushed ChangeSet, check it for InnoDB files and send
+# diff of entire ChangeSet to InnoDB developers if such changes
+# exist.
+
+my $error = 0;
+
+foreach my $cset (read_bk_csetlist())
+{
+ my $changes = innodb_get_changes('cset', $cset, 'yes')
+ or next;
+
+ innodb_send_changes_email($cset, $changes)
+ or $error = 1;
+}
+
+exit ($error == 0 ? 0 : 1);
diff --git a/BitKeeper/triggers/pre-commit.innodb.pl b/BitKeeper/triggers/pre-commit.innodb.pl
new file mode 100755
index 00000000000..6e2b65113b0
--- /dev/null
+++ b/BitKeeper/triggers/pre-commit.innodb.pl
@@ -0,0 +1,21 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+
+use FindBin;
+require "$FindBin::Bin/triggers-lib.pl";
+
+die "$0: Script error: \$BK_PENDING is not set in pre-commit trigger\n"
+ unless defined $ENV{BK_PENDING};
+
+# Read changed files from $BK_PENDING directly. Do not bother user about
+# merge changes; they don't have any choice, the merge must be done.
+my $changes = innodb_get_changes('file', $ENV{BK_PENDING}, undef)
+ or exit 0;
+
+innodb_inform_and_query_user($changes)
+ or exit 1; # Abort commit
+
+# OK, continue with commit
+exit 0;
diff --git a/BitKeeper/triggers/triggers-lib.pl b/BitKeeper/triggers/triggers-lib.pl
new file mode 100644
index 00000000000..1c5f7a85726
--- /dev/null
+++ b/BitKeeper/triggers/triggers-lib.pl
@@ -0,0 +1,360 @@
+# To use this convenience library in a trigger, simply require it at
+# at the top of the script. For example:
+#
+# #! /usr/bin/perl
+#
+# use FindBin;
+# require "$FindBin::Bin/triggers-lib.pl";
+#
+# FindBin is needed, because sometimes a trigger is called from the
+# RESYNC directory, and the trigger dir is ../BitKeeper/triggers
+
+use strict;
+use warnings;
+
+use Carp;
+use FindBin;
+
+
+my $mysql_version = "5.0";
+
+# These addresses must be kept current in all MySQL versions.
+# See the wiki page InnoDBandOracle.
+#my @innodb_to_email = ('dev_innodb_ww@oracle.com');
+#my @innodb_cc_email = ('dev-innodb@mysql.com');
+# FIXME: Keep this for testing; remove it once it's been used for a
+# week or two.
+my @innodb_to_email = ('tim@mysql.com');
+my @innodb_cc_email = ();
+
+# This is for MySQL <= 5.0. Regex which defines the InnoDB files
+# which should generally not be touched by MySQL developers.
+my $innodb_files_description = <<EOF;
+ innobase/*
+ mysql-test/t/innodb* (except mysql-test/t/innodb_mysql*)
+ mysql-test/r/innodb* (except mysql-test/r/innodb_mysql*)
+ sql/ha_innodb*
+EOF
+my $innodb_files_regex = qr{
+ ^
+ (
+ # Case 1: innobase/*
+ innobase/
+ |
+ # Case 2: mysql-test/[tr]/innodb* (except innodb_mysql*)
+ mysql-test/(t|r)/SCCS/s.innodb
+ # The mysql-test/[tr]/innodb_mysql* are OK to edit
+ (?!_mysql)
+ |
+ # Case 3: sql/ha_innodb*
+ sql/SCCS/s.ha_innodb
+ )
+}x;
+
+
+# See 'bk help log', and the format of, e.g., $BK_PENDING.
+# Important: this already contains the terminating newline!
+my $file_rev_dspec = ':SFILE:|:REV:\n';
+
+my $bktmp = "$FindBin::Bin/../tmp";
+
+my $sendmail;
+foreach ('/usr/sbin/sendmail', 'sendmail') {
+ $sendmail = $_;
+ last if -x $sendmail;
+}
+my $from = $ENV{REAL_EMAIL} || $ENV{USER} . '@mysql.com';
+
+
+# close_or_warn
+# $fh file handle to be closed
+# $description description of the file handle
+# RETURN Return value of close($fh)
+#
+# Print a nice warning message if close() isn't successful. See
+# perldoc perlvar and perldoc -f close for details.
+
+sub close_or_warn (*$)
+{
+ my ($fh, $description) = @_;
+
+ my $status = close $fh;
+ if (not $status) {
+ warn "$0: error on close of '$description': ",
+ ($! ? "$!" : "exit status " . ($? >> 8)), "\n";
+ }
+
+ return $status;
+}
+
+
+# check_status
+# $warn If true, warn about bad status
+# RETURN TRUE, if $BK_STATUS is "OK"; FALSE otherwise
+#
+# Also checks the undocumented $BK_COMMIT env variable
+
+sub check_status
+{
+ my ($warn) = @_;
+
+ my $status = (grep { defined $_ }
+ $ENV{BK_STATUS}, $ENV{BK_COMMIT}, '<undef>')[0];
+
+ unless ($status eq 'OK')
+ {
+ warn "Bad BK_STATUS '$status'\n" if $warn;
+ return undef;
+ }
+
+ return 1;
+}
+
+
+# repository_location
+#
+# RETURN ('HOST', 'ROOT') for the repository being modified
+
+sub repository_location
+{
+ if ($ENV{BK_SIDE} eq 'client') {
+ return ($ENV{BK_HOST}, $ENV{BK_ROOT});
+ } else {
+ return ($ENV{BKD_HOST}, $ENV{BKD_ROOT});
+ }
+}
+
+
+# repository_type
+# RETURN:
+# 'main' for repo on bk-internal with post-incoming.bugdb trigger
+# 'team' for repo on bk-internal with post-incoming.queuepush.pl trigger
+# 'local' otherwise
+#
+# This definition may need to be modified if the host name or triggers change.
+
+sub repository_type
+{
+ my ($host, $root) = repository_location();
+
+ return 'local'
+ unless uc($host) eq 'BK-INTERNAL.MYSQL.COM'
+ and -e "$root/BitKeeper/triggers/post-incoming.queuepush.pl";
+
+ return 'main' if -e "$root/BitKeeper/triggers/post-incoming.bugdb";
+
+ return 'team';
+}
+
+
+# latest_cset
+# RETURN Key for most recent ChangeSet
+
+sub latest_cset {
+ chomp(my $retval = `bk changes -r+ -k`);
+ return $retval;
+}
+
+
+# read_bk_csetlist
+# RETURN list of cset keys from $BK_CSETLIST file
+sub read_bk_csetlist
+{
+ die "$0: script error: \$BK_CSETLIST not set\n"
+ unless defined $ENV{BK_CSETLIST};
+
+ open CSETS, '<', $ENV{BK_CSETLIST}
+ or die "$0: can't read \$BK_CSETLIST='$ENV{BK_CSETLIST}': $!\n";
+ chomp(my @csets = <CSETS>);
+ close_or_warn(CSETS, "\$BK_CSETLIST='$ENV{BK_CSETLIST}'");
+
+ return @csets;
+}
+
+
+# innodb_get_changes
+# $type 'file' or 'cset'
+# $value file name (e.g., $BK_PENDING) or ChangeSet key
+# $want_merge_changes flag; if false, merge changes will be ignored
+# RETURN A string describing the InnoDB changes, or undef if no changes
+#
+# The return value does *not* include ChangeSet comments, only per-file
+# comments.
+
+sub innodb_get_changes
+{
+ my ($type, $value, $want_merge_changes) = @_;
+
+ if ($type eq 'file')
+ {
+ open CHANGES, '<', $value
+ or die "$0: can't read '$value': $!\n";
+ }
+ elsif ($type eq 'cset')
+ {
+ open CHANGES, '-|', "bk changes -r'$value' -v -d'$file_rev_dspec'"
+ or die "$0: can't exec 'bk changes': $!\n";
+ }
+ else
+ {
+ croak "$0: script error: invalid type '$type'";
+ }
+
+ my @changes = grep { /$innodb_files_regex/ } <CHANGES>;
+
+ close_or_warn(CHANGES, "($type, '$value')");
+
+ return undef unless @changes;
+
+
+ # Set up a pipeline of 'bk log' commands to weed out unwanted deltas. We
+ # never want deltas which contain no actual changes. We may not want deltas
+ # which are merges.
+
+ my @filters;
+
+ # This tests if :LI: (lines inserted) or :LD: (lines deleted) is
+ # non-zero. That is, did this delta change the file contents?
+ push @filters,
+ "bk log -d'"
+ . "\$if(:LI: -gt 0){$file_rev_dspec}"
+ . "\$if(:LI: -eq 0){\$if(:LD: -gt 0){$file_rev_dspec}}"
+ . "' -";
+
+ push @filters, "bk log -d'\$unless(:MERGE:){$file_rev_dspec}' -"
+ unless $want_merge_changes;
+
+ my $tmpname = "$bktmp/ibchanges.txt";
+ my $pipeline = join(' | ', @filters) . " > $tmpname";
+ open TMP, '|-', $pipeline
+ or die "$0: can't exec [[$pipeline]]: $!\n";
+
+ print TMP @changes;
+ close_or_warn(TMP, "| $pipeline");
+
+ # Use bk log to describe the changes
+ open LOG, "bk log - < $tmpname |"
+ or die "$0: can't exec 'bk log - < $tmpname': $!\n";
+ my @log = <LOG>;
+ close_or_warn(LOG, "bk log - < $tmpname |");
+
+ unlink $tmpname;
+
+ return undef unless @log;
+
+ return join('', @log);
+}
+
+
+# Ask user if they really want to commit.
+# RETURN TRUE = YES, commit; FALSE = NO, do not commit
+
+sub innodb_inform_and_query_user
+{
+ my ($description) = @_;
+
+ my $tmpname = "$bktmp/ibquery.txt";
+
+ open MESSAGE, "> $tmpname"
+ or die "$0: can't write message to '$tmpname': $!";
+
+ print MESSAGE <<EOF;
+This ChangeSet modifies some files which should normally be changed by
+InnoDB developers only. In general, MySQL developers should not change:
+
+$innodb_files_description
+The following InnoDB files were modified:
+=========================================================
+$description
+=========================================================
+
+If you understand this, you may Commit these changes. The changes
+will be sent to the InnoDB developers at @{[join ', ', @innodb_to_email]},
+CC @{[join ', ', @innodb_cc_email]}.
+EOF
+
+ close_or_warn(MESSAGE, "$tmpname");
+
+ my $status = system('bk', 'prompt', '-w',
+ '-yCommit these changes', '-nDo not Commit', "-f$tmpname");
+
+ unlink $tmpname;
+
+ return ($status == 0 ? 1 : undef);
+}
+
+
+# innodb_send_changes_email
+# $cset The ChangeSet key
+# $description A (maybe brief) description of the changes
+# RETURN TRUE = Success, e-mail sent; FALSE = Failure
+#
+# Sends a complete diff of changes in $cset by e-mail.
+
+sub innodb_send_changes_email
+{
+ my ($cset, $description) = @_;
+
+ # FIXME: Much of this is duplicated in the 'post-commit' Bourne shell
+ # trigger
+
+ my $cset_short = `bk changes -r'$cset' -d':P:::I:'`;
+ my $cset_key = `bk changes -r'$cset' -d':KEY:'`;
+
+ my ($host, $bk_root) = repository_location();
+ my $type = repository_type();
+ (my $treename = $bk_root) =~ s,^.*/,,;
+
+ print "Nofifying InnoDB developers at ",
+ (join ', ', @innodb_to_email, @innodb_cc_email), "\n";
+
+ open SENDMAIL, '|-', "$sendmail -t"
+ or die "Can't exec '$sendmail -t': $!\n";
+
+ my @headers;
+ push @headers, "List-ID: <bk.innodb-$mysql_version>";
+ push @headers, "From: $from";
+ push @headers, "To: " . (join ', ', @innodb_to_email);
+ push @headers, "Cc: " . (join ', ', @innodb_cc_email) if @innodb_cc_email;
+ push @headers,
+ "Subject: InnoDB changes in $type $mysql_version tree ($cset_short)";
+ push @headers, "X-CSetKey: <$cset_key>";
+
+ print SENDMAIL map { "$_\n" } @headers, '';
+
+ if ($type eq 'main')
+ {
+ print SENDMAIL <<EOF;
+Changes pushed to $treename by $ENV{USER} affect the following
+files. These changes are in a $mysql_version main tree. They
+will be available publicly within 24 hours.
+EOF
+ }
+ elsif ($type eq 'team')
+ {
+ print SENDMAIL <<EOF;
+Changes added to $treename by $ENV{USER} affect the
+following files. These changes are in a $mysql_version team tree.
+EOF
+ }
+ else
+ {
+ print SENDMAIL <<EOF;
+A local commit by $ENV{USER} affects the following files. These
+changes are in a clone of a $mysql_version tree.
+EOF
+ }
+ print SENDMAIL "\n";
+ print SENDMAIL qx(bk changes -r'$cset');
+ print SENDMAIL "$description";
+ print SENDMAIL "The complete ChangeSet diffs follow.\n\n";
+ print SENDMAIL qx(bk rset -r'$cset' -ah | bk gnupatch -h -dup -T);
+
+ close_or_warn(SENDMAIL, "$sendmail -t")
+ or return undef;
+
+ return 1;
+}
+
+
+1;
diff --git a/client/mysql.cc b/client/mysql.cc
index af28dce2cdd..483b1829ec0 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2008 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -283,13 +283,6 @@ static COMMANDS commands[] = {
/* Get bash-like expansion for some commands */
{ "create table", 0, 0, 0, ""},
{ "create database", 0, 0, 0, ""},
- { "drop", 0, 0, 0, ""},
- { "select", 0, 0, 0, ""},
- { "insert", 0, 0, 0, ""},
- { "replace", 0, 0, 0, ""},
- { "update", 0, 0, 0, ""},
- { "delete", 0, 0, 0, ""},
- { "explain", 0, 0, 0, ""},
{ "show databases", 0, 0, 0, ""},
{ "show fields from", 0, 0, 0, ""},
{ "show keys from", 0, 0, 0, ""},
@@ -299,6 +292,718 @@ static COMMANDS commands[] = {
{ "set option", 0, 0, 0, ""},
{ "lock tables", 0, 0, 0, ""},
{ "unlock tables", 0, 0, 0, ""},
+ /* generated 2006-12-28. Refresh occasionally from lexer. */
+ { "ACTION", 0, 0, 0, ""},
+ { "ADD", 0, 0, 0, ""},
+ { "AFTER", 0, 0, 0, ""},
+ { "AGAINST", 0, 0, 0, ""},
+ { "AGGREGATE", 0, 0, 0, ""},
+ { "ALL", 0, 0, 0, ""},
+ { "ALGORITHM", 0, 0, 0, ""},
+ { "ALTER", 0, 0, 0, ""},
+ { "ANALYZE", 0, 0, 0, ""},
+ { "AND", 0, 0, 0, ""},
+ { "ANY", 0, 0, 0, ""},
+ { "AS", 0, 0, 0, ""},
+ { "ASC", 0, 0, 0, ""},
+ { "ASCII", 0, 0, 0, ""},
+ { "ASENSITIVE", 0, 0, 0, ""},
+ { "AUTO_INCREMENT", 0, 0, 0, ""},
+ { "AVG", 0, 0, 0, ""},
+ { "AVG_ROW_LENGTH", 0, 0, 0, ""},
+ { "BACKUP", 0, 0, 0, ""},
+ { "BDB", 0, 0, 0, ""},
+ { "BEFORE", 0, 0, 0, ""},
+ { "BEGIN", 0, 0, 0, ""},
+ { "BERKELEYDB", 0, 0, 0, ""},
+ { "BETWEEN", 0, 0, 0, ""},
+ { "BIGINT", 0, 0, 0, ""},
+ { "BINARY", 0, 0, 0, ""},
+ { "BINLOG", 0, 0, 0, ""},
+ { "BIT", 0, 0, 0, ""},
+ { "BLOB", 0, 0, 0, ""},
+ { "BOOL", 0, 0, 0, ""},
+ { "BOOLEAN", 0, 0, 0, ""},
+ { "BOTH", 0, 0, 0, ""},
+ { "BTREE", 0, 0, 0, ""},
+ { "BY", 0, 0, 0, ""},
+ { "BYTE", 0, 0, 0, ""},
+ { "CACHE", 0, 0, 0, ""},
+ { "CALL", 0, 0, 0, ""},
+ { "CASCADE", 0, 0, 0, ""},
+ { "CASCADED", 0, 0, 0, ""},
+ { "CASE", 0, 0, 0, ""},
+ { "CHAIN", 0, 0, 0, ""},
+ { "CHANGE", 0, 0, 0, ""},
+ { "CHANGED", 0, 0, 0, ""},
+ { "CHAR", 0, 0, 0, ""},
+ { "CHARACTER", 0, 0, 0, ""},
+ { "CHARSET", 0, 0, 0, ""},
+ { "CHECK", 0, 0, 0, ""},
+ { "CHECKSUM", 0, 0, 0, ""},
+ { "CIPHER", 0, 0, 0, ""},
+ { "CLIENT", 0, 0, 0, ""},
+ { "CLOSE", 0, 0, 0, ""},
+ { "CODE", 0, 0, 0, ""},
+ { "COLLATE", 0, 0, 0, ""},
+ { "COLLATION", 0, 0, 0, ""},
+ { "COLUMN", 0, 0, 0, ""},
+ { "COLUMNS", 0, 0, 0, ""},
+ { "COMMENT", 0, 0, 0, ""},
+ { "COMMIT", 0, 0, 0, ""},
+ { "COMMITTED", 0, 0, 0, ""},
+ { "COMPACT", 0, 0, 0, ""},
+ { "COMPRESSED", 0, 0, 0, ""},
+ { "CONCURRENT", 0, 0, 0, ""},
+ { "CONDITION", 0, 0, 0, ""},
+ { "CONNECTION", 0, 0, 0, ""},
+ { "CONSISTENT", 0, 0, 0, ""},
+ { "CONSTRAINT", 0, 0, 0, ""},
+ { "CONTAINS", 0, 0, 0, ""},
+ { "CONTINUE", 0, 0, 0, ""},
+ { "CONVERT", 0, 0, 0, ""},
+ { "CREATE", 0, 0, 0, ""},
+ { "CROSS", 0, 0, 0, ""},
+ { "CUBE", 0, 0, 0, ""},
+ { "CURRENT_DATE", 0, 0, 0, ""},
+ { "CURRENT_TIME", 0, 0, 0, ""},
+ { "CURRENT_TIMESTAMP", 0, 0, 0, ""},
+ { "CURRENT_USER", 0, 0, 0, ""},
+ { "CURSOR", 0, 0, 0, ""},
+ { "DATA", 0, 0, 0, ""},
+ { "DATABASE", 0, 0, 0, ""},
+ { "DATABASES", 0, 0, 0, ""},
+ { "DATE", 0, 0, 0, ""},
+ { "DATETIME", 0, 0, 0, ""},
+ { "DAY", 0, 0, 0, ""},
+ { "DAY_HOUR", 0, 0, 0, ""},
+ { "DAY_MICROSECOND", 0, 0, 0, ""},
+ { "DAY_MINUTE", 0, 0, 0, ""},
+ { "DAY_SECOND", 0, 0, 0, ""},
+ { "DEALLOCATE", 0, 0, 0, ""},
+ { "DEC", 0, 0, 0, ""},
+ { "DECIMAL", 0, 0, 0, ""},
+ { "DECLARE", 0, 0, 0, ""},
+ { "DEFAULT", 0, 0, 0, ""},
+ { "DEFINER", 0, 0, 0, ""},
+ { "DELAYED", 0, 0, 0, ""},
+ { "DELAY_KEY_WRITE", 0, 0, 0, ""},
+ { "DELETE", 0, 0, 0, ""},
+ { "DESC", 0, 0, 0, ""},
+ { "DESCRIBE", 0, 0, 0, ""},
+ { "DES_KEY_FILE", 0, 0, 0, ""},
+ { "DETERMINISTIC", 0, 0, 0, ""},
+ { "DIRECTORY", 0, 0, 0, ""},
+ { "DISABLE", 0, 0, 0, ""},
+ { "DISCARD", 0, 0, 0, ""},
+ { "DISTINCT", 0, 0, 0, ""},
+ { "DISTINCTROW", 0, 0, 0, ""},
+ { "DIV", 0, 0, 0, ""},
+ { "DO", 0, 0, 0, ""},
+ { "DOUBLE", 0, 0, 0, ""},
+ { "DROP", 0, 0, 0, ""},
+ { "DUAL", 0, 0, 0, ""},
+ { "DUMPFILE", 0, 0, 0, ""},
+ { "DUPLICATE", 0, 0, 0, ""},
+ { "DYNAMIC", 0, 0, 0, ""},
+ { "EACH", 0, 0, 0, ""},
+ { "ELSE", 0, 0, 0, ""},
+ { "ELSEIF", 0, 0, 0, ""},
+ { "ENABLE", 0, 0, 0, ""},
+ { "ENCLOSED", 0, 0, 0, ""},
+ { "END", 0, 0, 0, ""},
+ { "ENGINE", 0, 0, 0, ""},
+ { "ENGINES", 0, 0, 0, ""},
+ { "ENUM", 0, 0, 0, ""},
+ { "ERRORS", 0, 0, 0, ""},
+ { "ESCAPE", 0, 0, 0, ""},
+ { "ESCAPED", 0, 0, 0, ""},
+ { "EVENTS", 0, 0, 0, ""},
+ { "EXECUTE", 0, 0, 0, ""},
+ { "EXISTS", 0, 0, 0, ""},
+ { "EXIT", 0, 0, 0, ""},
+ { "EXPANSION", 0, 0, 0, ""},
+ { "EXPLAIN", 0, 0, 0, ""},
+ { "EXTENDED", 0, 0, 0, ""},
+ { "FALSE", 0, 0, 0, ""},
+ { "FAST", 0, 0, 0, ""},
+ { "FETCH", 0, 0, 0, ""},
+ { "FIELDS", 0, 0, 0, ""},
+ { "FILE", 0, 0, 0, ""},
+ { "FIRST", 0, 0, 0, ""},
+ { "FIXED", 0, 0, 0, ""},
+ { "FLOAT", 0, 0, 0, ""},
+ { "FLOAT4", 0, 0, 0, ""},
+ { "FLOAT8", 0, 0, 0, ""},
+ { "FLUSH", 0, 0, 0, ""},
+ { "FOR", 0, 0, 0, ""},
+ { "FORCE", 0, 0, 0, ""},
+ { "FOREIGN", 0, 0, 0, ""},
+ { "FOUND", 0, 0, 0, ""},
+ { "FRAC_SECOND", 0, 0, 0, ""},
+ { "FROM", 0, 0, 0, ""},
+ { "FULL", 0, 0, 0, ""},
+ { "FULLTEXT", 0, 0, 0, ""},
+ { "FUNCTION", 0, 0, 0, ""},
+ { "GEOMETRY", 0, 0, 0, ""},
+ { "GEOMETRYCOLLECTION", 0, 0, 0, ""},
+ { "GET_FORMAT", 0, 0, 0, ""},
+ { "GLOBAL", 0, 0, 0, ""},
+ { "GRANT", 0, 0, 0, ""},
+ { "GRANTS", 0, 0, 0, ""},
+ { "GROUP", 0, 0, 0, ""},
+ { "HANDLER", 0, 0, 0, ""},
+ { "HASH", 0, 0, 0, ""},
+ { "HAVING", 0, 0, 0, ""},
+ { "HELP", 0, 0, 0, ""},
+ { "HIGH_PRIORITY", 0, 0, 0, ""},
+ { "HOSTS", 0, 0, 0, ""},
+ { "HOUR", 0, 0, 0, ""},
+ { "HOUR_MICROSECOND", 0, 0, 0, ""},
+ { "HOUR_MINUTE", 0, 0, 0, ""},
+ { "HOUR_SECOND", 0, 0, 0, ""},
+ { "IDENTIFIED", 0, 0, 0, ""},
+ { "IF", 0, 0, 0, ""},
+ { "IGNORE", 0, 0, 0, ""},
+ { "IMPORT", 0, 0, 0, ""},
+ { "IN", 0, 0, 0, ""},
+ { "INDEX", 0, 0, 0, ""},
+ { "INDEXES", 0, 0, 0, ""},
+ { "INFILE", 0, 0, 0, ""},
+ { "INNER", 0, 0, 0, ""},
+ { "INNOBASE", 0, 0, 0, ""},
+ { "INNODB", 0, 0, 0, ""},
+ { "INOUT", 0, 0, 0, ""},
+ { "INSENSITIVE", 0, 0, 0, ""},
+ { "INSERT", 0, 0, 0, ""},
+ { "INSERT_METHOD", 0, 0, 0, ""},
+ { "INT", 0, 0, 0, ""},
+ { "INT1", 0, 0, 0, ""},
+ { "INT2", 0, 0, 0, ""},
+ { "INT3", 0, 0, 0, ""},
+ { "INT4", 0, 0, 0, ""},
+ { "INT8", 0, 0, 0, ""},
+ { "INTEGER", 0, 0, 0, ""},
+ { "INTERVAL", 0, 0, 0, ""},
+ { "INTO", 0, 0, 0, ""},
+ { "IO_THREAD", 0, 0, 0, ""},
+ { "IS", 0, 0, 0, ""},
+ { "ISOLATION", 0, 0, 0, ""},
+ { "ISSUER", 0, 0, 0, ""},
+ { "ITERATE", 0, 0, 0, ""},
+ { "INVOKER", 0, 0, 0, ""},
+ { "JOIN", 0, 0, 0, ""},
+ { "KEY", 0, 0, 0, ""},
+ { "KEYS", 0, 0, 0, ""},
+ { "KILL", 0, 0, 0, ""},
+ { "LANGUAGE", 0, 0, 0, ""},
+ { "LAST", 0, 0, 0, ""},
+ { "LEADING", 0, 0, 0, ""},
+ { "LEAVE", 0, 0, 0, ""},
+ { "LEAVES", 0, 0, 0, ""},
+ { "LEFT", 0, 0, 0, ""},
+ { "LEVEL", 0, 0, 0, ""},
+ { "LIKE", 0, 0, 0, ""},
+ { "LIMIT", 0, 0, 0, ""},
+ { "LINES", 0, 0, 0, ""},
+ { "LINESTRING", 0, 0, 0, ""},
+ { "LOAD", 0, 0, 0, ""},
+ { "LOCAL", 0, 0, 0, ""},
+ { "LOCALTIME", 0, 0, 0, ""},
+ { "LOCALTIMESTAMP", 0, 0, 0, ""},
+ { "LOCK", 0, 0, 0, ""},
+ { "LOCKS", 0, 0, 0, ""},
+ { "LOGS", 0, 0, 0, ""},
+ { "LONG", 0, 0, 0, ""},
+ { "LONGBLOB", 0, 0, 0, ""},
+ { "LONGTEXT", 0, 0, 0, ""},
+ { "LOOP", 0, 0, 0, ""},
+ { "LOW_PRIORITY", 0, 0, 0, ""},
+ { "MASTER", 0, 0, 0, ""},
+ { "MASTER_CONNECT_RETRY", 0, 0, 0, ""},
+ { "MASTER_HOST", 0, 0, 0, ""},
+ { "MASTER_LOG_FILE", 0, 0, 0, ""},
+ { "MASTER_LOG_POS", 0, 0, 0, ""},
+ { "MASTER_PASSWORD", 0, 0, 0, ""},
+ { "MASTER_PORT", 0, 0, 0, ""},
+ { "MASTER_SERVER_ID", 0, 0, 0, ""},
+ { "MASTER_SSL", 0, 0, 0, ""},
+ { "MASTER_SSL_CA", 0, 0, 0, ""},
+ { "MASTER_SSL_CAPATH", 0, 0, 0, ""},
+ { "MASTER_SSL_CERT", 0, 0, 0, ""},
+ { "MASTER_SSL_CIPHER", 0, 0, 0, ""},
+ { "MASTER_SSL_KEY", 0, 0, 0, ""},
+ { "MASTER_USER", 0, 0, 0, ""},
+ { "MATCH", 0, 0, 0, ""},
+ { "MAX_CONNECTIONS_PER_HOUR", 0, 0, 0, ""},
+ { "MAX_QUERIES_PER_HOUR", 0, 0, 0, ""},
+ { "MAX_ROWS", 0, 0, 0, ""},
+ { "MAX_UPDATES_PER_HOUR", 0, 0, 0, ""},
+ { "MAX_USER_CONNECTIONS", 0, 0, 0, ""},
+ { "MEDIUM", 0, 0, 0, ""},
+ { "MEDIUMBLOB", 0, 0, 0, ""},
+ { "MEDIUMINT", 0, 0, 0, ""},
+ { "MEDIUMTEXT", 0, 0, 0, ""},
+ { "MERGE", 0, 0, 0, ""},
+ { "MICROSECOND", 0, 0, 0, ""},
+ { "MIDDLEINT", 0, 0, 0, ""},
+ { "MIGRATE", 0, 0, 0, ""},
+ { "MINUTE", 0, 0, 0, ""},
+ { "MINUTE_MICROSECOND", 0, 0, 0, ""},
+ { "MINUTE_SECOND", 0, 0, 0, ""},
+ { "MIN_ROWS", 0, 0, 0, ""},
+ { "MOD", 0, 0, 0, ""},
+ { "MODE", 0, 0, 0, ""},
+ { "MODIFIES", 0, 0, 0, ""},
+ { "MODIFY", 0, 0, 0, ""},
+ { "MONTH", 0, 0, 0, ""},
+ { "MULTILINESTRING", 0, 0, 0, ""},
+ { "MULTIPOINT", 0, 0, 0, ""},
+ { "MULTIPOLYGON", 0, 0, 0, ""},
+ { "MUTEX", 0, 0, 0, ""},
+ { "NAME", 0, 0, 0, ""},
+ { "NAMES", 0, 0, 0, ""},
+ { "NATIONAL", 0, 0, 0, ""},
+ { "NATURAL", 0, 0, 0, ""},
+ { "NDB", 0, 0, 0, ""},
+ { "NDBCLUSTER", 0, 0, 0, ""},
+ { "NCHAR", 0, 0, 0, ""},
+ { "NEW", 0, 0, 0, ""},
+ { "NEXT", 0, 0, 0, ""},
+ { "NO", 0, 0, 0, ""},
+ { "NONE", 0, 0, 0, ""},
+ { "NOT", 0, 0, 0, ""},
+ { "NO_WRITE_TO_BINLOG", 0, 0, 0, ""},
+ { "NULL", 0, 0, 0, ""},
+ { "NUMERIC", 0, 0, 0, ""},
+ { "NVARCHAR", 0, 0, 0, ""},
+ { "OFFSET", 0, 0, 0, ""},
+ { "OLD_PASSWORD", 0, 0, 0, ""},
+ { "ON", 0, 0, 0, ""},
+ { "ONE", 0, 0, 0, ""},
+ { "ONE_SHOT", 0, 0, 0, ""},
+ { "OPEN", 0, 0, 0, ""},
+ { "OPTIMIZE", 0, 0, 0, ""},
+ { "OPTION", 0, 0, 0, ""},
+ { "OPTIONALLY", 0, 0, 0, ""},
+ { "OR", 0, 0, 0, ""},
+ { "ORDER", 0, 0, 0, ""},
+ { "OUT", 0, 0, 0, ""},
+ { "OUTER", 0, 0, 0, ""},
+ { "OUTFILE", 0, 0, 0, ""},
+ { "PACK_KEYS", 0, 0, 0, ""},
+ { "PARTIAL", 0, 0, 0, ""},
+ { "PASSWORD", 0, 0, 0, ""},
+ { "PHASE", 0, 0, 0, ""},
+ { "POINT", 0, 0, 0, ""},
+ { "POLYGON", 0, 0, 0, ""},
+ { "PRECISION", 0, 0, 0, ""},
+ { "PREPARE", 0, 0, 0, ""},
+ { "PREV", 0, 0, 0, ""},
+ { "PRIMARY", 0, 0, 0, ""},
+ { "PRIVILEGES", 0, 0, 0, ""},
+ { "PROCEDURE", 0, 0, 0, ""},
+ { "PROCESS", 0, 0, 0, ""},
+ { "PROCESSLIST", 0, 0, 0, ""},
+ { "PURGE", 0, 0, 0, ""},
+ { "QUARTER", 0, 0, 0, ""},
+ { "QUERY", 0, 0, 0, ""},
+ { "QUICK", 0, 0, 0, ""},
+ { "RAID0", 0, 0, 0, ""},
+ { "RAID_CHUNKS", 0, 0, 0, ""},
+ { "RAID_CHUNKSIZE", 0, 0, 0, ""},
+ { "RAID_TYPE", 0, 0, 0, ""},
+ { "READ", 0, 0, 0, ""},
+ { "READS", 0, 0, 0, ""},
+ { "REAL", 0, 0, 0, ""},
+ { "RECOVER", 0, 0, 0, ""},
+ { "REDUNDANT", 0, 0, 0, ""},
+ { "REFERENCES", 0, 0, 0, ""},
+ { "REGEXP", 0, 0, 0, ""},
+ { "RELAY_LOG_FILE", 0, 0, 0, ""},
+ { "RELAY_LOG_POS", 0, 0, 0, ""},
+ { "RELAY_THREAD", 0, 0, 0, ""},
+ { "RELEASE", 0, 0, 0, ""},
+ { "RELOAD", 0, 0, 0, ""},
+ { "RENAME", 0, 0, 0, ""},
+ { "REPAIR", 0, 0, 0, ""},
+ { "REPEATABLE", 0, 0, 0, ""},
+ { "REPLACE", 0, 0, 0, ""},
+ { "REPLICATION", 0, 0, 0, ""},
+ { "REPEAT", 0, 0, 0, ""},
+ { "REQUIRE", 0, 0, 0, ""},
+ { "RESET", 0, 0, 0, ""},
+ { "RESTORE", 0, 0, 0, ""},
+ { "RESTRICT", 0, 0, 0, ""},
+ { "RESUME", 0, 0, 0, ""},
+ { "RETURN", 0, 0, 0, ""},
+ { "RETURNS", 0, 0, 0, ""},
+ { "REVOKE", 0, 0, 0, ""},
+ { "RIGHT", 0, 0, 0, ""},
+ { "RLIKE", 0, 0, 0, ""},
+ { "ROLLBACK", 0, 0, 0, ""},
+ { "ROLLUP", 0, 0, 0, ""},
+ { "ROUTINE", 0, 0, 0, ""},
+ { "ROW", 0, 0, 0, ""},
+ { "ROWS", 0, 0, 0, ""},
+ { "ROW_FORMAT", 0, 0, 0, ""},
+ { "RTREE", 0, 0, 0, ""},
+ { "SAVEPOINT", 0, 0, 0, ""},
+ { "SCHEMA", 0, 0, 0, ""},
+ { "SCHEMAS", 0, 0, 0, ""},
+ { "SECOND", 0, 0, 0, ""},
+ { "SECOND_MICROSECOND", 0, 0, 0, ""},
+ { "SECURITY", 0, 0, 0, ""},
+ { "SELECT", 0, 0, 0, ""},
+ { "SENSITIVE", 0, 0, 0, ""},
+ { "SEPARATOR", 0, 0, 0, ""},
+ { "SERIAL", 0, 0, 0, ""},
+ { "SERIALIZABLE", 0, 0, 0, ""},
+ { "SESSION", 0, 0, 0, ""},
+ { "SET", 0, 0, 0, ""},
+ { "SHARE", 0, 0, 0, ""},
+ { "SHOW", 0, 0, 0, ""},
+ { "SHUTDOWN", 0, 0, 0, ""},
+ { "SIGNED", 0, 0, 0, ""},
+ { "SIMPLE", 0, 0, 0, ""},
+ { "SLAVE", 0, 0, 0, ""},
+ { "SNAPSHOT", 0, 0, 0, ""},
+ { "SMALLINT", 0, 0, 0, ""},
+ { "SOME", 0, 0, 0, ""},
+ { "SONAME", 0, 0, 0, ""},
+ { "SOUNDS", 0, 0, 0, ""},
+ { "SPATIAL", 0, 0, 0, ""},
+ { "SPECIFIC", 0, 0, 0, ""},
+ { "SQL", 0, 0, 0, ""},
+ { "SQLEXCEPTION", 0, 0, 0, ""},
+ { "SQLSTATE", 0, 0, 0, ""},
+ { "SQLWARNING", 0, 0, 0, ""},
+ { "SQL_BIG_RESULT", 0, 0, 0, ""},
+ { "SQL_BUFFER_RESULT", 0, 0, 0, ""},
+ { "SQL_CACHE", 0, 0, 0, ""},
+ { "SQL_CALC_FOUND_ROWS", 0, 0, 0, ""},
+ { "SQL_NO_CACHE", 0, 0, 0, ""},
+ { "SQL_SMALL_RESULT", 0, 0, 0, ""},
+ { "SQL_THREAD", 0, 0, 0, ""},
+ { "SQL_TSI_FRAC_SECOND", 0, 0, 0, ""},
+ { "SQL_TSI_SECOND", 0, 0, 0, ""},
+ { "SQL_TSI_MINUTE", 0, 0, 0, ""},
+ { "SQL_TSI_HOUR", 0, 0, 0, ""},
+ { "SQL_TSI_DAY", 0, 0, 0, ""},
+ { "SQL_TSI_WEEK", 0, 0, 0, ""},
+ { "SQL_TSI_MONTH", 0, 0, 0, ""},
+ { "SQL_TSI_QUARTER", 0, 0, 0, ""},
+ { "SQL_TSI_YEAR", 0, 0, 0, ""},
+ { "SSL", 0, 0, 0, ""},
+ { "START", 0, 0, 0, ""},
+ { "STARTING", 0, 0, 0, ""},
+ { "STATUS", 0, 0, 0, ""},
+ { "STOP", 0, 0, 0, ""},
+ { "STORAGE", 0, 0, 0, ""},
+ { "STRAIGHT_JOIN", 0, 0, 0, ""},
+ { "STRING", 0, 0, 0, ""},
+ { "STRIPED", 0, 0, 0, ""},
+ { "SUBJECT", 0, 0, 0, ""},
+ { "SUPER", 0, 0, 0, ""},
+ { "SUSPEND", 0, 0, 0, ""},
+ { "TABLE", 0, 0, 0, ""},
+ { "TABLES", 0, 0, 0, ""},
+ { "TABLESPACE", 0, 0, 0, ""},
+ { "TEMPORARY", 0, 0, 0, ""},
+ { "TEMPTABLE", 0, 0, 0, ""},
+ { "TERMINATED", 0, 0, 0, ""},
+ { "TEXT", 0, 0, 0, ""},
+ { "THEN", 0, 0, 0, ""},
+ { "TIME", 0, 0, 0, ""},
+ { "TIMESTAMP", 0, 0, 0, ""},
+ { "TIMESTAMPADD", 0, 0, 0, ""},
+ { "TIMESTAMPDIFF", 0, 0, 0, ""},
+ { "TINYBLOB", 0, 0, 0, ""},
+ { "TINYINT", 0, 0, 0, ""},
+ { "TINYTEXT", 0, 0, 0, ""},
+ { "TO", 0, 0, 0, ""},
+ { "TRAILING", 0, 0, 0, ""},
+ { "TRANSACTION", 0, 0, 0, ""},
+ { "TRIGGER", 0, 0, 0, ""},
+ { "TRIGGERS", 0, 0, 0, ""},
+ { "TRUE", 0, 0, 0, ""},
+ { "TRUNCATE", 0, 0, 0, ""},
+ { "TYPE", 0, 0, 0, ""},
+ { "TYPES", 0, 0, 0, ""},
+ { "UNCOMMITTED", 0, 0, 0, ""},
+ { "UNDEFINED", 0, 0, 0, ""},
+ { "UNDO", 0, 0, 0, ""},
+ { "UNICODE", 0, 0, 0, ""},
+ { "UNION", 0, 0, 0, ""},
+ { "UNIQUE", 0, 0, 0, ""},
+ { "UNKNOWN", 0, 0, 0, ""},
+ { "UNLOCK", 0, 0, 0, ""},
+ { "UNSIGNED", 0, 0, 0, ""},
+ { "UNTIL", 0, 0, 0, ""},
+ { "UPDATE", 0, 0, 0, ""},
+ { "UPGRADE", 0, 0, 0, ""},
+ { "USAGE", 0, 0, 0, ""},
+ { "USE", 0, 0, 0, ""},
+ { "USER", 0, 0, 0, ""},
+ { "USER_RESOURCES", 0, 0, 0, ""},
+ { "USE_FRM", 0, 0, 0, ""},
+ { "USING", 0, 0, 0, ""},
+ { "UTC_DATE", 0, 0, 0, ""},
+ { "UTC_TIME", 0, 0, 0, ""},
+ { "UTC_TIMESTAMP", 0, 0, 0, ""},
+ { "VALUE", 0, 0, 0, ""},
+ { "VALUES", 0, 0, 0, ""},
+ { "VARBINARY", 0, 0, 0, ""},
+ { "VARCHAR", 0, 0, 0, ""},
+ { "VARCHARACTER", 0, 0, 0, ""},
+ { "VARIABLES", 0, 0, 0, ""},
+ { "VARYING", 0, 0, 0, ""},
+ { "WARNINGS", 0, 0, 0, ""},
+ { "WEEK", 0, 0, 0, ""},
+ { "WHEN", 0, 0, 0, ""},
+ { "WHERE", 0, 0, 0, ""},
+ { "WHILE", 0, 0, 0, ""},
+ { "VIEW", 0, 0, 0, ""},
+ { "WITH", 0, 0, 0, ""},
+ { "WORK", 0, 0, 0, ""},
+ { "WRITE", 0, 0, 0, ""},
+ { "X509", 0, 0, 0, ""},
+ { "XOR", 0, 0, 0, ""},
+ { "XA", 0, 0, 0, ""},
+ { "YEAR", 0, 0, 0, ""},
+ { "YEAR_MONTH", 0, 0, 0, ""},
+ { "ZEROFILL", 0, 0, 0, ""},
+ { "ABS", 0, 0, 0, ""},
+ { "ACOS", 0, 0, 0, ""},
+ { "ADDDATE", 0, 0, 0, ""},
+ { "ADDTIME", 0, 0, 0, ""},
+ { "AES_ENCRYPT", 0, 0, 0, ""},
+ { "AES_DECRYPT", 0, 0, 0, ""},
+ { "AREA", 0, 0, 0, ""},
+ { "ASIN", 0, 0, 0, ""},
+ { "ASBINARY", 0, 0, 0, ""},
+ { "ASTEXT", 0, 0, 0, ""},
+ { "ASWKB", 0, 0, 0, ""},
+ { "ASWKT", 0, 0, 0, ""},
+ { "ATAN", 0, 0, 0, ""},
+ { "ATAN2", 0, 0, 0, ""},
+ { "BENCHMARK", 0, 0, 0, ""},
+ { "BIN", 0, 0, 0, ""},
+ { "BIT_COUNT", 0, 0, 0, ""},
+ { "BIT_OR", 0, 0, 0, ""},
+ { "BIT_AND", 0, 0, 0, ""},
+ { "BIT_XOR", 0, 0, 0, ""},
+ { "CAST", 0, 0, 0, ""},
+ { "CEIL", 0, 0, 0, ""},
+ { "CEILING", 0, 0, 0, ""},
+ { "BIT_LENGTH", 0, 0, 0, ""},
+ { "CENTROID", 0, 0, 0, ""},
+ { "CHAR_LENGTH", 0, 0, 0, ""},
+ { "CHARACTER_LENGTH", 0, 0, 0, ""},
+ { "COALESCE", 0, 0, 0, ""},
+ { "COERCIBILITY", 0, 0, 0, ""},
+ { "COMPRESS", 0, 0, 0, ""},
+ { "CONCAT", 0, 0, 0, ""},
+ { "CONCAT_WS", 0, 0, 0, ""},
+ { "CONNECTION_ID", 0, 0, 0, ""},
+ { "CONV", 0, 0, 0, ""},
+ { "CONVERT_TZ", 0, 0, 0, ""},
+ { "COUNT", 0, 0, 0, ""},
+ { "COS", 0, 0, 0, ""},
+ { "COT", 0, 0, 0, ""},
+ { "CRC32", 0, 0, 0, ""},
+ { "CROSSES", 0, 0, 0, ""},
+ { "CURDATE", 0, 0, 0, ""},
+ { "CURTIME", 0, 0, 0, ""},
+ { "DATE_ADD", 0, 0, 0, ""},
+ { "DATEDIFF", 0, 0, 0, ""},
+ { "DATE_FORMAT", 0, 0, 0, ""},
+ { "DATE_SUB", 0, 0, 0, ""},
+ { "DAYNAME", 0, 0, 0, ""},
+ { "DAYOFMONTH", 0, 0, 0, ""},
+ { "DAYOFWEEK", 0, 0, 0, ""},
+ { "DAYOFYEAR", 0, 0, 0, ""},
+ { "DECODE", 0, 0, 0, ""},
+ { "DEGREES", 0, 0, 0, ""},
+ { "DES_ENCRYPT", 0, 0, 0, ""},
+ { "DES_DECRYPT", 0, 0, 0, ""},
+ { "DIMENSION", 0, 0, 0, ""},
+ { "DISJOINT", 0, 0, 0, ""},
+ { "ELT", 0, 0, 0, ""},
+ { "ENCODE", 0, 0, 0, ""},
+ { "ENCRYPT", 0, 0, 0, ""},
+ { "ENDPOINT", 0, 0, 0, ""},
+ { "ENVELOPE", 0, 0, 0, ""},
+ { "EQUALS", 0, 0, 0, ""},
+ { "EXTERIORRING", 0, 0, 0, ""},
+ { "EXTRACT", 0, 0, 0, ""},
+ { "EXP", 0, 0, 0, ""},
+ { "EXPORT_SET", 0, 0, 0, ""},
+ { "FIELD", 0, 0, 0, ""},
+ { "FIND_IN_SET", 0, 0, 0, ""},
+ { "FLOOR", 0, 0, 0, ""},
+ { "FORMAT", 0, 0, 0, ""},
+ { "FOUND_ROWS", 0, 0, 0, ""},
+ { "FROM_DAYS", 0, 0, 0, ""},
+ { "FROM_UNIXTIME", 0, 0, 0, ""},
+ { "GET_LOCK", 0, 0, 0, ""},
+ { "GEOMETRYN", 0, 0, 0, ""},
+ { "GEOMETRYTYPE", 0, 0, 0, ""},
+ { "GEOMCOLLFROMTEXT", 0, 0, 0, ""},
+ { "GEOMCOLLFROMWKB", 0, 0, 0, ""},
+ { "GEOMETRYCOLLECTIONFROMTEXT", 0, 0, 0, ""},
+ { "GEOMETRYCOLLECTIONFROMWKB", 0, 0, 0, ""},
+ { "GEOMETRYFROMTEXT", 0, 0, 0, ""},
+ { "GEOMETRYFROMWKB", 0, 0, 0, ""},
+ { "GEOMFROMTEXT", 0, 0, 0, ""},
+ { "GEOMFROMWKB", 0, 0, 0, ""},
+ { "GLENGTH", 0, 0, 0, ""},
+ { "GREATEST", 0, 0, 0, ""},
+ { "GROUP_CONCAT", 0, 0, 0, ""},
+ { "GROUP_UNIQUE_USERS", 0, 0, 0, ""},
+ { "HEX", 0, 0, 0, ""},
+ { "IFNULL", 0, 0, 0, ""},
+ { "INET_ATON", 0, 0, 0, ""},
+ { "INET_NTOA", 0, 0, 0, ""},
+ { "INSTR", 0, 0, 0, ""},
+ { "INTERIORRINGN", 0, 0, 0, ""},
+ { "INTERSECTS", 0, 0, 0, ""},
+ { "ISCLOSED", 0, 0, 0, ""},
+ { "ISEMPTY", 0, 0, 0, ""},
+ { "ISNULL", 0, 0, 0, ""},
+ { "IS_FREE_LOCK", 0, 0, 0, ""},
+ { "IS_USED_LOCK", 0, 0, 0, ""},
+ { "LAST_INSERT_ID", 0, 0, 0, ""},
+ { "ISSIMPLE", 0, 0, 0, ""},
+ { "LAST_DAY", 0, 0, 0, ""},
+ { "LCASE", 0, 0, 0, ""},
+ { "LEAST", 0, 0, 0, ""},
+ { "LENGTH", 0, 0, 0, ""},
+ { "LN", 0, 0, 0, ""},
+ { "LINEFROMTEXT", 0, 0, 0, ""},
+ { "LINEFROMWKB", 0, 0, 0, ""},
+ { "LINESTRINGFROMTEXT", 0, 0, 0, ""},
+ { "LINESTRINGFROMWKB", 0, 0, 0, ""},
+ { "LOAD_FILE", 0, 0, 0, ""},
+ { "LOCATE", 0, 0, 0, ""},
+ { "LOG", 0, 0, 0, ""},
+ { "LOG2", 0, 0, 0, ""},
+ { "LOG10", 0, 0, 0, ""},
+ { "LOWER", 0, 0, 0, ""},
+ { "LPAD", 0, 0, 0, ""},
+ { "LTRIM", 0, 0, 0, ""},
+ { "MAKE_SET", 0, 0, 0, ""},
+ { "MAKEDATE", 0, 0, 0, ""},
+ { "MAKETIME", 0, 0, 0, ""},
+ { "MASTER_POS_WAIT", 0, 0, 0, ""},
+ { "MAX", 0, 0, 0, ""},
+ { "MBRCONTAINS", 0, 0, 0, ""},
+ { "MBRDISJOINT", 0, 0, 0, ""},
+ { "MBREQUAL", 0, 0, 0, ""},
+ { "MBRINTERSECTS", 0, 0, 0, ""},
+ { "MBROVERLAPS", 0, 0, 0, ""},
+ { "MBRTOUCHES", 0, 0, 0, ""},
+ { "MBRWITHIN", 0, 0, 0, ""},
+ { "MD5", 0, 0, 0, ""},
+ { "MID", 0, 0, 0, ""},
+ { "MIN", 0, 0, 0, ""},
+ { "MLINEFROMTEXT", 0, 0, 0, ""},
+ { "MLINEFROMWKB", 0, 0, 0, ""},
+ { "MPOINTFROMTEXT", 0, 0, 0, ""},
+ { "MPOINTFROMWKB", 0, 0, 0, ""},
+ { "MPOLYFROMTEXT", 0, 0, 0, ""},
+ { "MPOLYFROMWKB", 0, 0, 0, ""},
+ { "MONTHNAME", 0, 0, 0, ""},
+ { "MULTILINESTRINGFROMTEXT", 0, 0, 0, ""},
+ { "MULTILINESTRINGFROMWKB", 0, 0, 0, ""},
+ { "MULTIPOINTFROMTEXT", 0, 0, 0, ""},
+ { "MULTIPOINTFROMWKB", 0, 0, 0, ""},
+ { "MULTIPOLYGONFROMTEXT", 0, 0, 0, ""},
+ { "MULTIPOLYGONFROMWKB", 0, 0, 0, ""},
+ { "NAME_CONST", 0, 0, 0, ""},
+ { "NOW", 0, 0, 0, ""},
+ { "NULLIF", 0, 0, 0, ""},
+ { "NUMGEOMETRIES", 0, 0, 0, ""},
+ { "NUMINTERIORRINGS", 0, 0, 0, ""},
+ { "NUMPOINTS", 0, 0, 0, ""},
+ { "OCTET_LENGTH", 0, 0, 0, ""},
+ { "OCT", 0, 0, 0, ""},
+ { "ORD", 0, 0, 0, ""},
+ { "OVERLAPS", 0, 0, 0, ""},
+ { "PERIOD_ADD", 0, 0, 0, ""},
+ { "PERIOD_DIFF", 0, 0, 0, ""},
+ { "PI", 0, 0, 0, ""},
+ { "POINTFROMTEXT", 0, 0, 0, ""},
+ { "POINTFROMWKB", 0, 0, 0, ""},
+ { "POINTN", 0, 0, 0, ""},
+ { "POLYFROMTEXT", 0, 0, 0, ""},
+ { "POLYFROMWKB", 0, 0, 0, ""},
+ { "POLYGONFROMTEXT", 0, 0, 0, ""},
+ { "POLYGONFROMWKB", 0, 0, 0, ""},
+ { "POSITION", 0, 0, 0, ""},
+ { "POW", 0, 0, 0, ""},
+ { "POWER", 0, 0, 0, ""},
+ { "QUOTE", 0, 0, 0, ""},
+ { "RADIANS", 0, 0, 0, ""},
+ { "RAND", 0, 0, 0, ""},
+ { "RELEASE_LOCK", 0, 0, 0, ""},
+ { "REVERSE", 0, 0, 0, ""},
+ { "ROUND", 0, 0, 0, ""},
+ { "ROW_COUNT", 0, 0, 0, ""},
+ { "RPAD", 0, 0, 0, ""},
+ { "RTRIM", 0, 0, 0, ""},
+ { "SEC_TO_TIME", 0, 0, 0, ""},
+ { "SESSION_USER", 0, 0, 0, ""},
+ { "SUBDATE", 0, 0, 0, ""},
+ { "SIGN", 0, 0, 0, ""},
+ { "SIN", 0, 0, 0, ""},
+ { "SHA", 0, 0, 0, ""},
+ { "SHA1", 0, 0, 0, ""},
+ { "SLEEP", 0, 0, 0, ""},
+ { "SOUNDEX", 0, 0, 0, ""},
+ { "SPACE", 0, 0, 0, ""},
+ { "SQRT", 0, 0, 0, ""},
+ { "SRID", 0, 0, 0, ""},
+ { "STARTPOINT", 0, 0, 0, ""},
+ { "STD", 0, 0, 0, ""},
+ { "STDDEV", 0, 0, 0, ""},
+ { "STDDEV_POP", 0, 0, 0, ""},
+ { "STDDEV_SAMP", 0, 0, 0, ""},
+ { "STR_TO_DATE", 0, 0, 0, ""},
+ { "STRCMP", 0, 0, 0, ""},
+ { "SUBSTR", 0, 0, 0, ""},
+ { "SUBSTRING", 0, 0, 0, ""},
+ { "SUBSTRING_INDEX", 0, 0, 0, ""},
+ { "SUBTIME", 0, 0, 0, ""},
+ { "SUM", 0, 0, 0, ""},
+ { "SYSDATE", 0, 0, 0, ""},
+ { "SYSTEM_USER", 0, 0, 0, ""},
+ { "TAN", 0, 0, 0, ""},
+ { "TIME_FORMAT", 0, 0, 0, ""},
+ { "TIME_TO_SEC", 0, 0, 0, ""},
+ { "TIMEDIFF", 0, 0, 0, ""},
+ { "TO_DAYS", 0, 0, 0, ""},
+ { "TOUCHES", 0, 0, 0, ""},
+ { "TRIM", 0, 0, 0, ""},
+ { "UCASE", 0, 0, 0, ""},
+ { "UNCOMPRESS", 0, 0, 0, ""},
+ { "UNCOMPRESSED_LENGTH", 0, 0, 0, ""},
+ { "UNHEX", 0, 0, 0, ""},
+ { "UNIQUE_USERS", 0, 0, 0, ""},
+ { "UNIX_TIMESTAMP", 0, 0, 0, ""},
+ { "UPPER", 0, 0, 0, ""},
+ { "UUID", 0, 0, 0, ""},
+ { "VARIANCE", 0, 0, 0, ""},
+ { "VAR_POP", 0, 0, 0, ""},
+ { "VAR_SAMP", 0, 0, 0, ""},
+ { "VERSION", 0, 0, 0, ""},
+ { "WEEKDAY", 0, 0, 0, ""},
+ { "WEEKOFYEAR", 0, 0, 0, ""},
+ { "WITHIN", 0, 0, 0, ""},
+ { "X", 0, 0, 0, ""},
+ { "Y", 0, 0, 0, ""},
+ { "YEARWEEK", 0, 0, 0, ""},
+ /* end sentinel */
{ (char *)NULL, 0, 0, 0, ""}
};
@@ -795,7 +1500,7 @@ static void usage(int version)
if (version)
return;
printf("\
-Copyright (C) 2002 MySQL AB\n\
+Copyright (C) 2000-2008 MySQL AB\n\
This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
and you are welcome to modify and redistribute it under the GPL license\n");
printf("Usage: %s [OPTIONS] [database]\n", my_progname);
@@ -1750,12 +2455,6 @@ static void build_completion_hash(bool rehash, bool write_info)
if (status.batch || quick || !current_db)
DBUG_VOID_RETURN; // We don't need completion in batches
-
- /* hash SQL commands */
- while (cmd->name) {
- add_word(&ht,(char*) cmd->name);
- cmd++;
- }
if (!rehash)
DBUG_VOID_RETURN;
@@ -1765,6 +2464,12 @@ static void build_completion_hash(bool rehash, bool write_info)
completion_hash_clean(&ht);
free_root(&hash_mem_root,MYF(0));
+ /* hash this file's known subset of SQL commands */
+ while (cmd->name) {
+ add_word(&ht,(char*) cmd->name);
+ cmd++;
+ }
+
/* hash MySQL functions (to be implemented) */
/* hash all database names */
@@ -2146,7 +2851,8 @@ com_charset(String *buffer __attribute__((unused)), char *line)
static int
com_go(String *buffer,char *line __attribute__((unused)))
{
- char buff[200], time_buff[32], *pos;
+ char buff[200]; /* about 110 chars used so far */
+ char time_buff[52+3+1]; /* time max + space&parens + NUL */
MYSQL_RES *result;
ulong timer, warnings;
uint error= 0;
@@ -2212,6 +2918,8 @@ com_go(String *buffer,char *line __attribute__((unused)))
do
{
+ char *pos;
+
if (quick)
{
if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql))
@@ -2233,7 +2941,9 @@ com_go(String *buffer,char *line __attribute__((unused)))
if (verbose >= 3 || !opt_silent)
mysql_end_timer(timer,time_buff);
else
- time_buff[0]=0;
+ time_buff[0]= '\0';
+
+ /* Every branch must truncate buff . */
if (result)
{
if (!mysql_num_rows(result) && ! quick && !info_flag)
@@ -3792,6 +4502,11 @@ static ulong start_timer(void)
}
+/**
+ Write as many as 52+1 bytes to buff, in the form of a legible duration of time.
+
+ len("4294967296 days, 23 hours, 59 minutes, 60.00 seconds") -> 52
+*/
static void nice_time(double sec,char *buff,bool part_second)
{
ulong tmp;
diff --git a/cmd-line-utils/readline/bind.c b/cmd-line-utils/readline/bind.c
index 08c906bfcc3..baed1dfad49 100644
--- a/cmd-line-utils/readline/bind.c
+++ b/cmd-line-utils/readline/bind.c
@@ -27,7 +27,7 @@
#endif
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <stdio.h>
diff --git a/cmd-line-utils/readline/callback.c b/cmd-line-utils/readline/callback.c
index ada04d8593b..2f7e4b78057 100644
--- a/cmd-line-utils/readline/callback.c
+++ b/cmd-line-utils/readline/callback.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include "rlconf.h"
diff --git a/cmd-line-utils/readline/compat.c b/cmd-line-utils/readline/compat.c
index a66d210fd2e..3949bf6a16b 100644
--- a/cmd-line-utils/readline/compat.c
+++ b/cmd-line-utils/readline/compat.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <stdio.h>
diff --git a/cmd-line-utils/readline/complete.c b/cmd-line-utils/readline/complete.c
index 73f834a68a7..d0c9e772f0f 100644
--- a/cmd-line-utils/readline/complete.c
+++ b/cmd-line-utils/readline/complete.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/display.c b/cmd-line-utils/readline/display.c
index 47ff0615974..6f63faa9738 100644
--- a/cmd-line-utils/readline/display.c
+++ b/cmd-line-utils/readline/display.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/funmap.c b/cmd-line-utils/readline/funmap.c
index 9c760cc3475..2d2a35ed0c8 100644
--- a/cmd-line-utils/readline/funmap.c
+++ b/cmd-line-utils/readline/funmap.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#if !defined (BUFSIZ)
diff --git a/cmd-line-utils/readline/histexpand.c b/cmd-line-utils/readline/histexpand.c
index f46c0b2a45d..45377fc3b5e 100644
--- a/cmd-line-utils/readline/histexpand.c
+++ b/cmd-line-utils/readline/histexpand.c
@@ -23,7 +23,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <stdio.h>
diff --git a/cmd-line-utils/readline/histfile.c b/cmd-line-utils/readline/histfile.c
index 2f051a32563..d98293d933c 100644
--- a/cmd-line-utils/readline/histfile.c
+++ b/cmd-line-utils/readline/histfile.c
@@ -31,7 +31,7 @@
#endif
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <stdio.h>
diff --git a/cmd-line-utils/readline/history.c b/cmd-line-utils/readline/history.c
index 1ccf4db786c..5cd5788d1da 100644
--- a/cmd-line-utils/readline/history.c
+++ b/cmd-line-utils/readline/history.c
@@ -26,7 +26,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <stdio.h>
diff --git a/cmd-line-utils/readline/histsearch.c b/cmd-line-utils/readline/histsearch.c
index 1cc5875a4b4..b71965135cc 100644
--- a/cmd-line-utils/readline/histsearch.c
+++ b/cmd-line-utils/readline/histsearch.c
@@ -23,7 +23,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <stdio.h>
diff --git a/cmd-line-utils/readline/input.c b/cmd-line-utils/readline/input.c
index da5d771c481..62c0443d890 100644
--- a/cmd-line-utils/readline/input.c
+++ b/cmd-line-utils/readline/input.c
@@ -26,7 +26,7 @@
#endif
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/isearch.c b/cmd-line-utils/readline/isearch.c
index 9f67bfc0801..8060adb97cd 100644
--- a/cmd-line-utils/readline/isearch.c
+++ b/cmd-line-utils/readline/isearch.c
@@ -27,7 +27,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/keymaps.c b/cmd-line-utils/readline/keymaps.c
index 70d0cc08d3f..562c22d7558 100644
--- a/cmd-line-utils/readline/keymaps.c
+++ b/cmd-line-utils/readline/keymaps.c
@@ -21,7 +21,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#if defined (HAVE_STDLIB_H)
diff --git a/cmd-line-utils/readline/kill.c b/cmd-line-utils/readline/kill.c
index 031ddf47c5b..42c53948689 100644
--- a/cmd-line-utils/readline/kill.c
+++ b/cmd-line-utils/readline/kill.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/macro.c b/cmd-line-utils/readline/macro.c
index 00cd58d628c..3473f705335 100644
--- a/cmd-line-utils/readline/macro.c
+++ b/cmd-line-utils/readline/macro.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/mbutil.c b/cmd-line-utils/readline/mbutil.c
index 17dde53ed7b..e21708fb748 100644
--- a/cmd-line-utils/readline/mbutil.c
+++ b/cmd-line-utils/readline/mbutil.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/misc.c b/cmd-line-utils/readline/misc.c
index 94ecb25900a..e0e6893c60e 100644
--- a/cmd-line-utils/readline/misc.c
+++ b/cmd-line-utils/readline/misc.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#if defined (HAVE_UNISTD_H)
diff --git a/cmd-line-utils/readline/nls.c b/cmd-line-utils/readline/nls.c
index bcee87561aa..6ec685ed9ea 100644
--- a/cmd-line-utils/readline/nls.c
+++ b/cmd-line-utils/readline/nls.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/parens.c b/cmd-line-utils/readline/parens.c
index 737f7675e93..fe1578ed3e2 100644
--- a/cmd-line-utils/readline/parens.c
+++ b/cmd-line-utils/readline/parens.c
@@ -28,7 +28,7 @@
#include "rlconf.h"
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <stdio.h>
diff --git a/cmd-line-utils/readline/readline.c b/cmd-line-utils/readline/readline.c
index c2b74006b05..8c3cad52d36 100644
--- a/cmd-line-utils/readline/readline.c
+++ b/cmd-line-utils/readline/readline.c
@@ -23,7 +23,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/rldefs.h b/cmd-line-utils/readline/rldefs.h
index 0f6c87446dd..dcdfc49fbbc 100644
--- a/cmd-line-utils/readline/rldefs.h
+++ b/cmd-line-utils/readline/rldefs.h
@@ -27,7 +27,7 @@
#define _RLDEFS_H_
#if defined (HAVE_CONFIG_H)
-# include "config.h"
+# include "config_readline.h"
#endif
#include "rlstdc.h"
diff --git a/cmd-line-utils/readline/rltty.c b/cmd-line-utils/readline/rltty.c
index 0a570f85840..b5bc5d367a5 100644
--- a/cmd-line-utils/readline/rltty.c
+++ b/cmd-line-utils/readline/rltty.c
@@ -23,7 +23,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/rlwinsize.h b/cmd-line-utils/readline/rlwinsize.h
index 7838154d023..60729b0f549 100644
--- a/cmd-line-utils/readline/rlwinsize.h
+++ b/cmd-line-utils/readline/rlwinsize.h
@@ -26,7 +26,7 @@
#define _RLWINSIZE_H_
#if defined (HAVE_CONFIG_H)
-# include "config.h"
+# include "config_readline.h"
#endif
/* Try to find the definitions of `struct winsize' and TIOGCWINSZ */
diff --git a/cmd-line-utils/readline/savestring.c b/cmd-line-utils/readline/savestring.c
index 820428d8881..d42bcadf5d7 100644
--- a/cmd-line-utils/readline/savestring.c
+++ b/cmd-line-utils/readline/savestring.c
@@ -21,7 +21,7 @@
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#define READLINE_LIBRARY
-#include <config.h>
+#include "config_readline.h"
#ifdef HAVE_STRING_H
# include <string.h>
#endif
diff --git a/cmd-line-utils/readline/search.c b/cmd-line-utils/readline/search.c
index 33cc4fc1e73..cfa5db1dc17 100644
--- a/cmd-line-utils/readline/search.c
+++ b/cmd-line-utils/readline/search.c
@@ -23,7 +23,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/shell.c b/cmd-line-utils/readline/shell.c
index 346f8113d43..5d084476bed 100644
--- a/cmd-line-utils/readline/shell.c
+++ b/cmd-line-utils/readline/shell.c
@@ -23,7 +23,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/signals.c b/cmd-line-utils/readline/signals.c
index 54f2a642846..65c2ff308f6 100644
--- a/cmd-line-utils/readline/signals.c
+++ b/cmd-line-utils/readline/signals.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <stdio.h> /* Just for NULL. Yuck. */
diff --git a/cmd-line-utils/readline/tcap.h b/cmd-line-utils/readline/tcap.h
index 58ab894d93e..04252e72f2d 100644
--- a/cmd-line-utils/readline/tcap.h
+++ b/cmd-line-utils/readline/tcap.h
@@ -25,7 +25,7 @@
#define _RLTCAP_H_
#if defined (HAVE_CONFIG_H)
-# include "config.h"
+# include "config_readline.h"
#endif
#if defined (HAVE_TERMCAP_H)
diff --git a/cmd-line-utils/readline/terminal.c b/cmd-line-utils/readline/terminal.c
index 547f6f5dfe5..a630bc02e05 100644
--- a/cmd-line-utils/readline/terminal.c
+++ b/cmd-line-utils/readline/terminal.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/text.c b/cmd-line-utils/readline/text.c
index 399a48c5f1e..b26afeda525 100644
--- a/cmd-line-utils/readline/text.c
+++ b/cmd-line-utils/readline/text.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#if defined (HAVE_UNISTD_H)
diff --git a/cmd-line-utils/readline/tilde.c b/cmd-line-utils/readline/tilde.c
index 1b76c9f2404..d50f7a0ffa4 100644
--- a/cmd-line-utils/readline/tilde.c
+++ b/cmd-line-utils/readline/tilde.c
@@ -20,7 +20,7 @@
Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#if defined (HAVE_UNISTD_H)
diff --git a/cmd-line-utils/readline/undo.c b/cmd-line-utils/readline/undo.c
index 9d9bd25ba8f..5699193b14c 100644
--- a/cmd-line-utils/readline/undo.c
+++ b/cmd-line-utils/readline/undo.c
@@ -23,7 +23,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/util.c b/cmd-line-utils/readline/util.c
index e44ef64349d..935c9c927c2 100644
--- a/cmd-line-utils/readline/util.c
+++ b/cmd-line-utils/readline/util.c
@@ -22,7 +22,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/vi_mode.c b/cmd-line-utils/readline/vi_mode.c
index d0b7e330adc..25213cb762f 100644
--- a/cmd-line-utils/readline/vi_mode.c
+++ b/cmd-line-utils/readline/vi_mode.c
@@ -32,7 +32,7 @@
#if defined (VI_MODE)
#if defined (HAVE_CONFIG_H)
-# include <config.h>
+# include "config_readline.h"
#endif
#include <sys/types.h>
diff --git a/cmd-line-utils/readline/xmalloc.c b/cmd-line-utils/readline/xmalloc.c
index 8985d340d39..cf52da351a8 100644
--- a/cmd-line-utils/readline/xmalloc.c
+++ b/cmd-line-utils/readline/xmalloc.c
@@ -21,7 +21,7 @@
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
-#include <config.h>
+#include "config_readline.h"
#endif
#include <stdio.h>
diff --git a/configure.in b/configure.in
index e65bbd51432..2ee722b4905 100644
--- a/configure.in
+++ b/configure.in
@@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line!
# remember to also change ndb version below and update version.c in ndb
-AM_INIT_AUTOMAKE(mysql, 5.0.58)
+AM_INIT_AUTOMAKE(mysql, 5.0.60)
AM_CONFIG_HEADER([include/config.h:config.h.in])
PROTOCOL_VERSION=10
@@ -23,7 +23,7 @@ NDB_SHARED_LIB_VERSION=$NDB_SHARED_LIB_MAJOR_VERSION:0:0
# ndb version
NDB_VERSION_MAJOR=5
NDB_VERSION_MINOR=0
-NDB_VERSION_BUILD=58
+NDB_VERSION_BUILD=60
NDB_VERSION_STATUS=""
# Set all version vars based on $VERSION. How do we do this more elegant ?
diff --git a/extra/CMakeLists.txt b/extra/CMakeLists.txt
index a909bc93820..c1477e41a81 100755
--- a/extra/CMakeLists.txt
+++ b/extra/CMakeLists.txt
@@ -44,6 +44,9 @@ TARGET_LINK_LIBRARIES(my_print_defaults strings mysys debug dbug taocrypt wsock3
ADD_EXECUTABLE(perror perror.c)
TARGET_LINK_LIBRARIES(perror strings mysys debug dbug wsock32)
+ADD_EXECUTABLE(resolveip resolveip.c)
+TARGET_LINK_LIBRARIES(resolveip strings mysys debug dbug wsock32)
+
ADD_EXECUTABLE(replace replace.c)
TARGET_LINK_LIBRARIES(replace strings mysys debug dbug wsock32)
diff --git a/extra/resolveip.c b/extra/resolveip.c
index c613f6a8cb6..aedc2cc3418 100644
--- a/extra/resolveip.c
+++ b/extra/resolveip.c
@@ -21,13 +21,15 @@
#include <m_ctype.h>
#include <my_sys.h>
#include <m_string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#ifndef HAVE_BROKEN_NETINET_INCLUDES
-#include <netinet/in.h>
+#ifndef WIN32
+# include <sys/types.h>
+# include <sys/socket.h>
+# ifndef HAVE_BROKEN_NETINET_INCLUDES
+# include <netinet/in.h>
+# endif
+# include <arpa/inet.h>
+# include <netdb.h>
#endif
-#include <arpa/inet.h>
-#include <netdb.h>
#include <my_net.h>
#include <my_getopt.h>
@@ -116,13 +118,21 @@ int main(int argc, char **argv)
while (argc--)
{
+#ifndef WIN32
struct in_addr addr;
+#endif
ip = *argv++;
/* Not compatible with IPv6! Probably should use getnameinfo(). */
+#ifdef WIN32
+ taddr = inet_addr(ip);
+ if(taddr != INADDR_NONE)
+ {
+#else
if (inet_aton(ip, &addr) != 0)
{
taddr= addr.s_addr;
+#endif
if (taddr == htonl(INADDR_BROADCAST))
{
puts("Broadcast");
diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp
index 1d5a95820bb..262b5cb3b8b 100644
--- a/extra/yassl/src/handshake.cpp
+++ b/extra/yassl/src/handshake.cpp
@@ -527,6 +527,11 @@ void ProcessOldClientHello(input_buffer& input, SSL& ssl)
input.read(len, sizeof(len));
uint16 randomLen;
ato16(len, randomLen);
+ if (ch.suite_len_ > MAX_SUITE_SZ || sessionLen > ID_LEN ||
+ randomLen > RAN_LEN) {
+ ssl.SetError(bad_input);
+ return;
+ }
int j = 0;
for (uint16 i = 0; i < ch.suite_len_; i += 3) {
diff --git a/extra/yassl/src/template_instnt.cpp b/extra/yassl/src/template_instnt.cpp
index f82f7924359..fe3a251b865 100644
--- a/extra/yassl/src/template_instnt.cpp
+++ b/extra/yassl/src/template_instnt.cpp
@@ -101,6 +101,7 @@ template void ysArrayDelete<unsigned char>(unsigned char*);
template void ysArrayDelete<char>(char*);
template int min<int>(int, int);
+template uint16 min<uint16>(uint16, uint16);
template unsigned int min<unsigned int>(unsigned int, unsigned int);
template unsigned long min<unsigned long>(unsigned long, unsigned long);
}
diff --git a/extra/yassl/src/yassl_imp.cpp b/extra/yassl/src/yassl_imp.cpp
index 0bc95f64abc..b43d9c27355 100644
--- a/extra/yassl/src/yassl_imp.cpp
+++ b/extra/yassl/src/yassl_imp.cpp
@@ -621,6 +621,10 @@ void HandShakeHeader::Process(input_buffer& input, SSL& ssl)
}
uint len = c24to32(length_);
+ if (len > input.get_remaining()) {
+ ssl.SetError(bad_input);
+ return;
+ }
hashHandShake(ssl, input, len);
hs->set_length(len);
@@ -1391,10 +1395,15 @@ input_buffer& operator>>(input_buffer& input, ClientHello& hello)
// Suites
byte tmp[2];
+ uint16 len;
tmp[0] = input[AUTO];
tmp[1] = input[AUTO];
- ato16(tmp, hello.suite_len_);
+ ato16(tmp, len);
+
+ hello.suite_len_ = min(len, static_cast<uint16>(MAX_SUITE_SZ));
input.read(hello.cipher_suites_, hello.suite_len_);
+ if (len > hello.suite_len_) // ignore extra suites
+ input.set_current(input.get_current() + len - hello.suite_len_);
// Compression
hello.comp_len_ = input[AUTO];
diff --git a/mysql-test/include/ndb_wait_connected.inc b/mysql-test/include/ndb_wait_connected.inc
new file mode 100644
index 00000000000..cfea94db1f1
--- /dev/null
+++ b/mysql-test/include/ndb_wait_connected.inc
@@ -0,0 +1,26 @@
+# Check that mysqld has reconnected to ndbd after
+# restart of ndbd
+#
+--disable_query_log
+--disable_result_log
+let $mysql_errno= 1;
+let $counter= 600;
+while ($mysql_errno)
+{
+ --error 0,157
+ CREATE TABLE ndb_wait_connected (a int primary key);
+ if ($mysql_errno)
+ {
+ if (!$counter)
+ {
+ die Failed waiting for mysqld to reconnect to ndbd;
+ }
+ dec $counter;
+ --sleep 0.1
+ }
+}
+DROP TABLE ndb_wait_connected;
+--enable_query_log
+--enable_result_log
+
+
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 29c5648090c..7c4677b8274 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -3765,12 +3765,11 @@ sub mysqld_arguments ($$$$) {
# When mysqld is run by a root user(euid is 0), it will fail
- # to start unless we specify what user to run as. If not running
- # as root it will be ignored, see BUG#30630
+ # to start unless we specify what user to run as, see BUG#30630
my $euid= $>;
if (!$glob_win32 and $euid == 0 and
grep(/^--user/, @$extra_opt, @opt_extra_mysqld_opt) == 0) {
- mtr_add_arg($args, "%s--user=root");
+ mtr_add_arg($args, "%s--user=root", $prefix);
}
if ( $opt_valgrind_mysqld )
diff --git a/mysql-test/r/limit.result b/mysql-test/r/limit.result
index 01d7d7ca218..2acf74162a4 100644
--- a/mysql-test/r/limit.result
+++ b/mysql-test/r/limit.result
@@ -94,6 +94,9 @@ drop table t1;
prepare s from "select 1 limit ?";
set @a='qwe';
execute s using @a;
+1
+set @a=-1;
+execute s using @a;
ERROR HY000: Incorrect arguments to EXECUTE
prepare s from "select 1 limit 1, ?";
execute s using @a;
@@ -101,4 +104,10 @@ ERROR HY000: Incorrect arguments to EXECUTE
prepare s from "select 1 limit ?, ?";
execute s using @a, @a;
ERROR HY000: Incorrect arguments to EXECUTE
+set @a=14632475938453979136;
+execute s using @a, @a;
+1
+set @a=-14632475938453979136;
+execute s using @a, @a;
+ERROR HY000: Incorrect arguments to EXECUTE
End of 5.0 tests
diff --git a/mysql-test/r/ndb_alter_table2.result b/mysql-test/r/ndb_alter_table2.result
index 399578dc97b..886c300d53d 100644
--- a/mysql-test/r/ndb_alter_table2.result
+++ b/mysql-test/r/ndb_alter_table2.result
@@ -40,3 +40,22 @@ a b c
select * from t1;
a b c
drop table t1;
+DROP TABLE IF EXISTS truncate_test;
+CREATE TABLE truncate_test (
+i INT PRIMARY KEY,
+a INT,
+b VARCHAR(11),
+UNIQUE KEY (a)
+) ENGINE = NDB;
+INSERT INTO truncate_test VALUES (1, 1, 'test') ON DUPLICATE KEY UPDATE b = 'new';
+INSERT INTO truncate_test VALUES (1, 1, 'test') ON DUPLICATE KEY UPDATE b = 'new';
+TRUNCATE truncate_test;
+INSERT INTO truncate_test VALUES (1, 1, 'test') ON DUPLICATE KEY UPDATE b = 'new';
+SELECT * FROM truncate_test;
+i a b
+1 1 test
+INSERT INTO truncate_test VALUES (1, 1, 'test') ON DUPLICATE KEY UPDATE b = 'new';
+SELECT * FROM truncate_test;
+i a b
+1 1 new
+DROP TABLE truncate_test;
diff --git a/mysql-test/r/ndb_auto_increment.result b/mysql-test/r/ndb_auto_increment.result
index b7c9fa8e2b5..f8ef5af2770 100644
--- a/mysql-test/r/ndb_auto_increment.result
+++ b/mysql-test/r/ndb_auto_increment.result
@@ -421,10 +421,10 @@ select * from t1 order by a;
a
1
20
-21
33
34
35
+65
insert into t1 values (100);
insert into t1 values (NULL);
insert into t1 values (NULL);
@@ -432,11 +432,11 @@ select * from t1 order by a;
a
1
20
-21
-22
33
34
35
+65
+66
100
101
set auto_increment_offset = @old_auto_increment_offset;
diff --git a/mysql-test/r/ndb_bug31477.result b/mysql-test/r/ndb_bug31477.result
new file mode 100644
index 00000000000..002a928b485
--- /dev/null
+++ b/mysql-test/r/ndb_bug31477.result
@@ -0,0 +1,98 @@
+drop table if exists t1;
+create table t1(a int primary key, b int, c int, unique(b)) engine = ndb;
+insert into t1 values (2,2,2);
+insert into t1 values (3,3,3);
+insert into t1 values (4,4,4);
+begin;
+insert into t1 values (1,1,1);
+begin;
+update t1 set c = 2 where b = 1;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+rollback;
+rollback;
+drop table t1;
+create table t1(a int primary key, b int, c int, key(b)) engine = ndb;
+insert into t1 values (2,2,2);
+insert into t1 values (3,3,3);
+insert into t1 values (4,4,4);
+begin;
+insert into t1 values (1,1,1);
+begin;
+update t1 set c = 2 where b = 1;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+rollback;
+rollback;
+drop table t1;
+--con1
+create table t1(a int primary key, b int, c int, key(b)) engine = ndb;
+insert into t1 values (1,1,1);
+insert into t1 values (2,2,2);
+insert into t1 values (3,3,3);
+insert into t1 values (4,4,4);
+begin;
+update t1 set c = 10 where a = 1;
+update t1 set c = 20 where a = 1;
+update t1 set c = 30 where a = 1;
+--con1 c=30
+select * from t1 where b >= 1 order by b;
+a b c
+1 1 30
+2 2 2
+3 3 3
+4 4 4
+--con2 c=1
+select * from t1 where b >= 1 order by b;
+a b c
+1 1 1
+2 2 2
+3 3 3
+4 4 4
+--con1
+delete from t1 where a = 1;
+--con1 c=none
+select * from t1 where b >= 1 order by b;
+a b c
+2 2 2
+3 3 3
+4 4 4
+--con2 c=1
+select * from t1 where b >= 1 order by b;
+a b c
+1 1 1
+2 2 2
+3 3 3
+4 4 4
+--con1
+commit;
+--con1 c=none
+select * from t1 where b >= 1 order by b;
+a b c
+2 2 2
+3 3 3
+4 4 4
+--con2 c=none
+select * from t1 where b >= 1 order by b;
+a b c
+2 2 2
+3 3 3
+4 4 4
+--con1
+begin;
+insert into t1 values (1,1,1);
+update t1 set c = 10 where a = 1;
+update t1 set c = 20 where a = 1;
+update t1 set c = 30 where a = 1;
+--con1 c=30
+select * from t1 where b >= 1 order by b;
+a b c
+1 1 30
+2 2 2
+3 3 3
+4 4 4
+--con2 c=none
+select * from t1 where b >= 1 order by b;
+a b c
+2 2 2
+3 3 3
+4 4 4
+drop table t1;
diff --git a/mysql-test/r/ndb_condition_pushdown.result b/mysql-test/r/ndb_condition_pushdown.result
index d49c0cd983e..b211b9079d0 100644
--- a/mysql-test/r/ndb_condition_pushdown.result
+++ b/mysql-test/r/ndb_condition_pushdown.result
@@ -1904,6 +1904,12 @@ a b d
10 1 4369
20 2 8738
50 5 21845
+-- big filter just below limit
+a b d
+10 1 4369
+20 2 8738
+50 5 21845
+-- big filter just above limit
a b d
10 1 4369
20 2 8738
diff --git a/mysql-test/r/ndb_restore.result b/mysql-test/r/ndb_restore.result
index 9faac2df0a4..c48333f6ea8 100644
--- a/mysql-test/r/ndb_restore.result
+++ b/mysql-test/r/ndb_restore.result
@@ -266,21 +266,41 @@ a
2000
3000
10000
-show table status like 't1_c';
-Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
-X X X X X X X X X X 3001 X X X X X X X
-show table status like 't2_c';
-Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
-X X X X X X X X X X 501 X X X X X X X
-show table status like 't4_c';
-Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
-X X X X X X X X X X 290000001 X X X X X X X
-show table status like 't7_c';
-Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
-X X X X X X X X X X 29 X X X X X X X
-show table status like 't10_c';
-Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
-X X X X X X X X X X 10001 X X X X X X X
+select max(capgoaledatta) from t1_c;
+max(capgoaledatta)
+3000
+select auto_increment from information_schema.tables
+where table_name = 't1_c';
+auto_increment
+3001
+select max(capgotod) from t2_c;
+max(capgotod)
+500
+select auto_increment from information_schema.tables
+where table_name = 't2_c';
+auto_increment
+501
+select max(capfa) from t4_c;
+max(capfa)
+290000000
+select auto_increment from information_schema.tables
+where table_name = 't4_c';
+auto_increment
+290000001
+select max(dardtestard) from t7_c;
+max(dardtestard)
+28
+select auto_increment from information_schema.tables
+where table_name = 't7_c';
+auto_increment
+29
+select max(a) from t10_c;
+max(a)
+10000
+select auto_increment from information_schema.tables
+where table_name = 't10_c';
+auto_increment
+10001
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9, t10;
drop table if exists t1_c,t2_c,t3_c,t4_c,t5_c,t6_c,t7_c,t8_c,t9_c, t10_c;
520093696,<the_backup_id>
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 8845f011971..9aef58d5702 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -1709,4 +1709,186 @@ a b
9999999999999999 14632475938453979136
deallocate prepare stmt;
drop table t1;
+drop view if exists v1;
+drop table if exists t1;
+create table t1 (a int, b int);
+insert into t1 values (1,1), (2,2), (3,3);
+insert into t1 values (3,1), (1,2), (2,3);
+prepare stmt from "create view v1 as select * from t1";
+execute stmt;
+drop table t1;
+create table t1 (a int, b int);
+drop view v1;
+execute stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1`
+drop view v1;
+prepare stmt from "create view v1 (c,d) as select a,b from t1";
+execute stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `c`,`t1`.`b` AS `d` from `t1`
+select * from v1;
+c d
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `c`,`t1`.`b` AS `d` from `t1`
+select * from v1;
+c d
+drop view v1;
+prepare stmt from "create view v1 (c) as select b+1 from t1";
+execute stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select (`t1`.`b` + 1) AS `c` from `t1`
+select * from v1;
+c
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select (`t1`.`b` + 1) AS `c` from `t1`
+select * from v1;
+c
+drop view v1;
+prepare stmt from "create view v1 (c,d,e,f) as select a,b,a in (select a+2 from t1), a = all (select a from t1) from t1";
+execute stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `c`,`t1`.`b` AS `d`,`t1`.`a` in (select (`t1`.`a` + 2) AS `a+2` from `t1`) AS `e`,`t1`.`a` = all (select `t1`.`a` AS `a` from `t1`) AS `f` from `t1`
+select * from v1;
+c d e f
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `c`,`t1`.`b` AS `d`,`t1`.`a` in (select (`t1`.`a` + 2) AS `a+2` from `t1`) AS `e`,`t1`.`a` = all (select `t1`.`a` AS `a` from `t1`) AS `f` from `t1`
+select * from v1;
+c d e f
+drop view v1;
+prepare stmt from "create or replace view v1 as select 1";
+execute stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1`
+select * from v1;
+1
+1
+execute stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1`
+deallocate prepare stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1`
+select * from v1;
+1
+1
+drop view v1;
+prepare stmt from "create view v1 as select 1, 1";
+execute stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1`,1 AS `My_exp_1`
+select * from v1;
+1 My_exp_1
+1 1
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1`,1 AS `My_exp_1`
+select * from v1;
+1 My_exp_1
+1 1
+drop view v1;
+prepare stmt from "create view v1 (x) as select a from t1 where a > 1";
+execute stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `x` from `t1` where (`t1`.`a` > 1)
+select * from v1;
+x
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `x` from `t1` where (`t1`.`a` > 1)
+select * from v1;
+x
+drop view v1;
+prepare stmt from "create view v1 as select * from `t1` `b`";
+execute stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `b`.`a` AS `a`,`b`.`b` AS `b` from `t1` `b`
+select * from v1;
+a b
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `b`.`a` AS `a`,`b`.`b` AS `b` from `t1` `b`
+select * from v1;
+a b
+drop view v1;
+prepare stmt from "create view v1 (a,b,c) as select * from t1";
+execute stmt;
+ERROR HY000: View's SELECT and view's field list have different column counts
+execute stmt;
+ERROR HY000: View's SELECT and view's field list have different column counts
+deallocate prepare stmt;
+drop table t1;
+create temporary table t1 (a int, b int);
+prepare stmt from "create view v1 as select * from t1";
+execute stmt;
+ERROR HY000: View's SELECT refers to a temporary table 't1'
+execute stmt;
+ERROR HY000: View's SELECT refers to a temporary table 't1'
+deallocate prepare stmt;
+drop table t1;
+prepare stmt from "create view v1 as select * from t1";
+ERROR 42S02: Table 'test.t1' doesn't exist
+prepare stmt from "create view v1 as select * from `t1` `b`";
+ERROR 42S02: Table 'test.t1' doesn't exist
+prepare stmt from "select ?";
+set @arg= 123456789.987654321;
+select @arg;
+@arg
+123456789.987654321
+execute stmt using @arg;
+?
+123456789.987654321
+set @arg= "string";
+select @arg;
+@arg
+string
+execute stmt using @arg;
+?
+string
+set @arg= 123456;
+select @arg;
+@arg
+123456
+execute stmt using @arg;
+?
+123456
+set @arg= cast(-12345.54321 as decimal(20, 10));
+select @arg;
+@arg
+-12345.5432100000
+execute stmt using @arg;
+?
+-12345.5432100000
+deallocate prepare stmt;
End of 5.0 tests.
diff --git a/mysql-test/r/rpl_user_variables.result b/mysql-test/r/rpl_user_variables.result
index 26ac2b26aaa..b8032a9c362 100644
--- a/mysql-test/r/rpl_user_variables.result
+++ b/mysql-test/r/rpl_user_variables.result
@@ -290,6 +290,22 @@ select * from t1;
a b
2 1
drop table t1;
+create table t1(a int);
+insert into t1 values (1),(2);
+prepare s1 from 'insert into t1 select a from t1 limit ?';
+set @x='1.1';
+execute s1 using @x;
+select * from t1;
+a
+1
+2
+1
+select * from t1;
+a
+1
+2
+1
+drop table t1;
End of 5.0 tests.
DROP FUNCTION IF EXISTS f1;
DROP FUNCTION IF EXISTS f2;
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 4ba46079b27..520bf9426b8 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -3642,4 +3642,23 @@ MAX(a) COUNT(DISTINCT a)
1 1
DROP VIEW v1;
DROP TABLE t1;
-End of 5.0 tests.
+# -----------------------------------------------------------------
+# -- Bug#34337: Server crash when Altering a view using a table name.
+# -----------------------------------------------------------------
+
+DROP TABLE IF EXISTS t1;
+
+CREATE TABLE t1(c1 INT);
+
+SELECT * FROM t1;
+c1
+ALTER ALGORITHM=TEMPTABLE SQL SECURITY INVOKER VIEW t1 (c2) AS SELECT (1);
+ERROR HY000: 'test.t1' is not VIEW
+
+DROP TABLE t1;
+
+# -- End of test case for Bug#34337.
+
+# -----------------------------------------------------------------
+# -- End of 5.0 tests.
+# -----------------------------------------------------------------
diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result
index eef61c65fb8..53ad8642ba4 100644
--- a/mysql-test/r/view_grant.result
+++ b/mysql-test/r/view_grant.result
@@ -467,6 +467,7 @@ use test;
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
drop database mysqltest;
drop view if exists v1;
+drop table if exists t1;
create table t1 as select * from mysql.user where user='';
delete from mysql.user where user='';
flush privileges;
diff --git a/mysql-test/t/limit.test b/mysql-test/t/limit.test
index 286c04785ff..9cccca1adc3 100644
--- a/mysql-test/t/limit.test
+++ b/mysql-test/t/limit.test
@@ -76,15 +76,22 @@ drop table t1;
# Bug #28464: a string argument to 'limit ?' PS
#
-prepare s from "select 1 limit ?";
-set @a='qwe';
---error 1210
+prepare s from "select 1 limit ?";
+set @a='qwe';
+execute s using @a;
+set @a=-1;
+--error ER_WRONG_ARGUMENTS
execute s using @a;
prepare s from "select 1 limit 1, ?";
---error 1210
+--error ER_WRONG_ARGUMENTS
execute s using @a;
prepare s from "select 1 limit ?, ?";
---error 1210
+--error ER_WRONG_ARGUMENTS
+execute s using @a, @a;
+set @a=14632475938453979136;
+execute s using @a, @a;
+set @a=-14632475938453979136;
+--error ER_WRONG_ARGUMENTS
execute s using @a, @a;
--echo End of 5.0 tests
diff --git a/mysql-test/t/ndb_alter_table2.test b/mysql-test/t/ndb_alter_table2.test
index 3861fcc6c9d..99c201f7370 100644
--- a/mysql-test/t/ndb_alter_table2.test
+++ b/mysql-test/t/ndb_alter_table2.test
@@ -81,3 +81,34 @@ select * from t1;
select * from t1;
drop table t1;
+
+#For BUG#29851 TRUNCATE causes error 4350 from cluster in INSERT... ON DUPLICATE KEY UPDATE
+
+connection con1;
+
+--disable_warnings
+DROP TABLE IF EXISTS truncate_test;
+--enable_warnings
+
+CREATE TABLE truncate_test (
+ i INT PRIMARY KEY,
+ a INT,
+ b VARCHAR(11),
+ UNIQUE KEY (a)
+) ENGINE = NDB;
+
+INSERT INTO truncate_test VALUES (1, 1, 'test') ON DUPLICATE KEY UPDATE b = 'new';
+INSERT INTO truncate_test VALUES (1, 1, 'test') ON DUPLICATE KEY UPDATE b = 'new';
+
+connection con2;
+TRUNCATE truncate_test;
+
+connection con1;
+INSERT INTO truncate_test VALUES (1, 1, 'test') ON DUPLICATE KEY UPDATE b = 'new';
+SELECT * FROM truncate_test;
+
+connection con2;
+INSERT INTO truncate_test VALUES (1, 1, 'test') ON DUPLICATE KEY UPDATE b = 'new';
+SELECT * FROM truncate_test;
+
+DROP TABLE truncate_test;
diff --git a/mysql-test/t/ndb_autodiscover.test b/mysql-test/t/ndb_autodiscover.test
index 6eb039c2df2..049dcd9755e 100644
--- a/mysql-test/t/ndb_autodiscover.test
+++ b/mysql-test/t/ndb_autodiscover.test
@@ -491,6 +491,7 @@ select * from t1;
select * from t1;
--exec $NDB_MGM --no-defaults -e "all start" > /dev/null
--exec $NDB_TOOLS_DIR/ndb_waiter --no-defaults > /dev/null
+--source include/ndb_wait_connected.inc
use test;
drop database test_only_ndb_tables;
diff --git a/mysql-test/t/ndb_autodiscover3.test b/mysql-test/t/ndb_autodiscover3.test
index 259da6e3501..4a20e7dd430 100644
--- a/mysql-test/t/ndb_autodiscover3.test
+++ b/mysql-test/t/ndb_autodiscover3.test
@@ -25,6 +25,13 @@ insert into t1 values (1);
--exec $NDB_MGM --no-defaults -e "all restart" >> $NDB_TOOLS_OUTPUT
--exec $NDB_TOOLS_DIR/ndb_waiter --no-defaults -c $connect_str >> $NDB_TOOLS_OUTPUT
+# Create separate connection and use that for detecting
+# when mysqld has reconnected to ndbd
+connect (ndb_wait_con,127.0.0.1,root,,test,$MASTER_MYPORT,);
+--source include/ndb_wait_connected.inc
+disconnect ndb_wait_con;
+connection server1;
+
--error 1297
insert into t1 values (2);
--error 1296
@@ -44,6 +51,7 @@ select * from t2 order by a limit 3;
--exec $NDB_TOOLS_DIR/ndb_waiter --no-defaults -c $connect_str >> $NDB_TOOLS_OUTPUT
--connection server2
+--source include/ndb_wait_connected.inc
create table t2 (a int key) engine=ndbcluster;
insert into t2 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
select * from t2 order by a limit 3;
@@ -58,6 +66,7 @@ select * from t2 order by a limit 3;
--exec $NDB_TOOLS_DIR/ndb_waiter --no-defaults -c $connect_str >> $NDB_TOOLS_OUTPUT
--connection server1
+--source include/ndb_wait_connected.inc
show tables;
create table t2 (a int key) engine=ndbcluster;
insert into t2 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
diff --git a/mysql-test/t/ndb_bug31477.test b/mysql-test/t/ndb_bug31477.test
new file mode 100644
index 00000000000..41c519e56fd
--- /dev/null
+++ b/mysql-test/t/ndb_bug31477.test
@@ -0,0 +1,109 @@
+--source include/have_ndb.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+# setup
+
+connect (con1,localhost,root,,test);
+connect (con2,localhost,root,,test);
+
+# unique index
+connection con1;
+create table t1(a int primary key, b int, c int, unique(b)) engine = ndb;
+insert into t1 values (2,2,2);
+insert into t1 values (3,3,3);
+insert into t1 values (4,4,4);
+
+begin;
+insert into t1 values (1,1,1);
+
+connection con2;
+begin;
+--error 1205
+update t1 set c = 2 where b = 1;
+rollback;
+
+connection con1;
+rollback;
+drop table t1;
+# ordered index
+
+connection con1;
+create table t1(a int primary key, b int, c int, key(b)) engine = ndb;
+insert into t1 values (2,2,2);
+insert into t1 values (3,3,3);
+insert into t1 values (4,4,4);
+
+begin;
+insert into t1 values (1,1,1);
+
+connection con2;
+begin;
+--error 1205
+update t1 set c = 2 where b = 1;
+rollback;
+
+connection con1;
+rollback;
+drop table t1;
+
+# multiple versions
+
+--echo --con1
+connection con1;
+create table t1(a int primary key, b int, c int, key(b)) engine = ndb;
+insert into t1 values (1,1,1);
+insert into t1 values (2,2,2);
+insert into t1 values (3,3,3);
+insert into t1 values (4,4,4);
+
+begin;
+update t1 set c = 10 where a = 1;
+update t1 set c = 20 where a = 1;
+update t1 set c = 30 where a = 1;
+
+--echo --con1 c=30
+select * from t1 where b >= 1 order by b;
+--echo --con2 c=1
+connection con2;
+select * from t1 where b >= 1 order by b;
+
+--echo --con1
+connection con1;
+delete from t1 where a = 1;
+
+--echo --con1 c=none
+select * from t1 where b >= 1 order by b;
+--echo --con2 c=1
+connection con2;
+select * from t1 where b >= 1 order by b;
+
+--echo --con1
+connection con1;
+commit;
+
+--echo --con1 c=none
+select * from t1 where b >= 1 order by b;
+--echo --con2 c=none
+connection con2;
+select * from t1 where b >= 1 order by b;
+
+--echo --con1
+connection con1;
+begin;
+insert into t1 values (1,1,1);
+update t1 set c = 10 where a = 1;
+update t1 set c = 20 where a = 1;
+update t1 set c = 30 where a = 1;
+
+--echo --con1 c=30
+select * from t1 where b >= 1 order by b;
+--echo --con2 c=none
+connection con2;
+select * from t1 where b >= 1 order by b;
+
+# this fails with "no such table" via con2 ???
+connection con1;
+drop table t1;
diff --git a/mysql-test/t/ndb_condition_pushdown.test b/mysql-test/t/ndb_condition_pushdown.test
index b5b7e41fb21..ebfd9c7231a 100644
--- a/mysql-test/t/ndb_condition_pushdown.test
+++ b/mysql-test/t/ndb_condition_pushdown.test
@@ -1719,6 +1719,7 @@ set engine_condition_pushdown = 1;
SELECT fname, lname FROM t1 WHERE (fname like 'Y%') or (lname like 'F%');
# bug#29390 (scan filter is too large, discarded)
+# bug#34107 (previous limit was too large for TUP)
drop table t1;
@@ -1737,9 +1738,11 @@ select a,b,d from t1
where b in (0,1,2,5)
order by b;
+--echo -- big filter just below limit
--disable_query_log
select a,b,d from t1
where b in (
+0,1,2,5,0,1,2,5,0,1,
0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
@@ -1870,745 +1873,15 @@ select a,b,d from t1
0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
-0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
+0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2)
+ order by b;
+--enable_query_log
+
+--echo -- big filter just above limit
+--disable_query_log
+select a,b,d from t1
+ where b in (
+0,1,2,5,0,1,2,5,0,1,2,
0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,
diff --git a/mysql-test/t/ndb_restore.test b/mysql-test/t/ndb_restore.test
index 266a0c7fbc1..940b53adbe1 100644
--- a/mysql-test/t/ndb_restore.test
+++ b/mysql-test/t/ndb_restore.test
@@ -231,16 +231,21 @@ select count(*)
select * from t10_c order by a;
# Bug #27775 cont'd
# - auto inc info should be correct
---replace_column 1 X 2 X 3 X 4 X 5 X 6 X 7 X 8 X 9 X 10 X 12 X 13 X 14 X 15 X 16 X 17 X 18 X
-show table status like 't1_c';
---replace_column 1 X 2 X 3 X 4 X 5 X 6 X 7 X 8 X 9 X 10 X 12 X 13 X 14 X 15 X 16 X 17 X 18 X
-show table status like 't2_c';
---replace_column 1 X 2 X 3 X 4 X 5 X 6 X 7 X 8 X 9 X 10 X 12 X 13 X 14 X 15 X 16 X 17 X 18 X
-show table status like 't4_c';
---replace_column 1 X 2 X 3 X 4 X 5 X 6 X 7 X 8 X 9 X 10 X 12 X 13 X 14 X 15 X 16 X 17 X 18 X
-show table status like 't7_c';
---replace_column 1 X 2 X 3 X 4 X 5 X 6 X 7 X 8 X 9 X 10 X 12 X 13 X 14 X 15 X 16 X 17 X 18 X
-show table status like 't10_c';
+select max(capgoaledatta) from t1_c;
+select auto_increment from information_schema.tables
+where table_name = 't1_c';
+select max(capgotod) from t2_c;
+select auto_increment from information_schema.tables
+where table_name = 't2_c';
+select max(capfa) from t4_c;
+select auto_increment from information_schema.tables
+where table_name = 't4_c';
+select max(dardtestard) from t7_c;
+select auto_increment from information_schema.tables
+where table_name = 't7_c';
+select max(a) from t10_c;
+select auto_increment from information_schema.tables
+where table_name = 't10_c';
--disable_warnings
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9, t10;
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index 3f4b37f13f4..6c3f98f6a1a 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -1824,4 +1824,146 @@ select * from t1 where a = @a and b = @b;
deallocate prepare stmt;
drop table t1;
+#
+# Bug#32890 Crash after repeated create and drop of tables and views
+#
+
+--disable_warnings
+drop view if exists v1;
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (a int, b int);
+insert into t1 values (1,1), (2,2), (3,3);
+insert into t1 values (3,1), (1,2), (2,3);
+
+prepare stmt from "create view v1 as select * from t1";
+execute stmt;
+drop table t1;
+create table t1 (a int, b int);
+drop view v1;
+execute stmt;
+show create view v1;
+drop view v1;
+
+prepare stmt from "create view v1 (c,d) as select a,b from t1";
+execute stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+
+prepare stmt from "create view v1 (c) as select b+1 from t1";
+execute stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+
+prepare stmt from "create view v1 (c,d,e,f) as select a,b,a in (select a+2 from t1), a = all (select a from t1) from t1";
+execute stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+
+prepare stmt from "create or replace view v1 as select 1";
+execute stmt;
+show create view v1;
+select * from v1;
+execute stmt;
+show create view v1;
+deallocate prepare stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+
+prepare stmt from "create view v1 as select 1, 1";
+execute stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+
+prepare stmt from "create view v1 (x) as select a from t1 where a > 1";
+execute stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+
+prepare stmt from "create view v1 as select * from `t1` `b`";
+execute stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+
+prepare stmt from "create view v1 (a,b,c) as select * from t1";
+--error ER_VIEW_WRONG_LIST
+execute stmt;
+--error ER_VIEW_WRONG_LIST
+execute stmt;
+deallocate prepare stmt;
+
+drop table t1;
+create temporary table t1 (a int, b int);
+
+prepare stmt from "create view v1 as select * from t1";
+--error ER_VIEW_SELECT_TMPTABLE
+execute stmt;
+--error ER_VIEW_SELECT_TMPTABLE
+execute stmt;
+deallocate prepare stmt;
+
+drop table t1;
+
+--error ER_NO_SUCH_TABLE
+prepare stmt from "create view v1 as select * from t1";
+--error ER_NO_SUCH_TABLE
+prepare stmt from "create view v1 as select * from `t1` `b`";
+
+#
+# Bug#33851: Passing UNSIGNED param to EXECUTE returns ERROR 1210
+#
+
+prepare stmt from "select ?";
+set @arg= 123456789.987654321;
+select @arg;
+execute stmt using @arg;
+set @arg= "string";
+select @arg;
+execute stmt using @arg;
+set @arg= 123456;
+select @arg;
+execute stmt using @arg;
+set @arg= cast(-12345.54321 as decimal(20, 10));
+select @arg;
+execute stmt using @arg;
+deallocate prepare stmt;
+
--echo End of 5.0 tests.
diff --git a/mysql-test/t/rpl_user_variables.test b/mysql-test/t/rpl_user_variables.test
index 8f8f0accbd1..70b708be258 100644
--- a/mysql-test/t/rpl_user_variables.test
+++ b/mysql-test/t/rpl_user_variables.test
@@ -337,6 +337,23 @@ select * from t1;
connection master;
drop table t1;
+#
+# Bug#33851: Passing UNSIGNED param to EXECUTE returns ERROR 1210
+#
+
+connection master;
+create table t1(a int);
+insert into t1 values (1),(2);
+prepare s1 from 'insert into t1 select a from t1 limit ?';
+set @x='1.1';
+execute s1 using @x;
+select * from t1;
+sync_slave_with_master;
+connection slave;
+select * from t1;
+connection master;
+drop table t1;
+
--echo End of 5.0 tests.
# This test uses a stored function that uses user-defined variables to return data
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index d7461504b20..23e64b0546f 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -3505,5 +3505,38 @@ SELECT MAX(a), COUNT(DISTINCT a) FROM v1 GROUP BY a;
DROP VIEW v1;
DROP TABLE t1;
---echo End of 5.0 tests.
+###########################################################################
+--echo # -----------------------------------------------------------------
+--echo # -- Bug#34337: Server crash when Altering a view using a table name.
+--echo # -----------------------------------------------------------------
+--echo
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+--echo
+
+CREATE TABLE t1(c1 INT);
+
+--echo
+
+SELECT * FROM t1;
+
+--error ER_WRONG_OBJECT
+ALTER ALGORITHM=TEMPTABLE SQL SECURITY INVOKER VIEW t1 (c2) AS SELECT (1);
+
+--echo
+
+DROP TABLE t1;
+
+--echo
+--echo # -- End of test case for Bug#34337.
+--echo
+
+###########################################################################
+
+--echo # -----------------------------------------------------------------
+--echo # -- End of 5.0 tests.
+--echo # -----------------------------------------------------------------
diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test
index 7f9eb4e1cff..be9daacec4f 100644
--- a/mysql-test/t/view_grant.test
+++ b/mysql-test/t/view_grant.test
@@ -608,6 +608,7 @@ drop database mysqltest;
#
--disable_warnings
drop view if exists v1;
+drop table if exists t1;
--enable_warnings
# Backup anonymous users and remove them. (They get in the way of
diff --git a/ndb/include/kernel/ndb_limits.h b/ndb/include/kernel/ndb_limits.h
index c82288c762a..82fd0bd5d51 100644
--- a/ndb/include/kernel/ndb_limits.h
+++ b/ndb/include/kernel/ndb_limits.h
@@ -27,6 +27,17 @@
#define MAX_NDB_NODES 49
#define MAX_NODES 64
+/**************************************************************************
+ * IT SHOULD BE (MAX_NDB_NODES - 1).
+ * WHEN MAX_NDB_NODE IS CHANGED, IT SHOULD BE CHANGED ALSO
+ **************************************************************************/
+#define MAX_DATA_NODE_ID 48
+/**************************************************************************
+ * IT SHOULD BE (MAX_NODES - 1).
+ * WHEN MAX_NODES IS CHANGED, IT SHOULD BE CHANGED ALSO
+ **************************************************************************/
+#define MAX_NODES_ID 63
+
/**
* MAX_API_NODES = MAX_NODES - No of NDB Nodes in use
*/
diff --git a/ndb/include/mgmapi/ndb_logevent.h b/ndb/include/mgmapi/ndb_logevent.h
index 76e4c31baa2..389004da06b 100644
--- a/ndb/include/mgmapi/ndb_logevent.h
+++ b/ndb/include/mgmapi/ndb_logevent.h
@@ -551,7 +551,13 @@ extern "C" {
/** Log event specific data for for corresponding NDB_LE_ log event */
struct {
int gth;
- unsigned page_size_kb;
+ /* union is for compatibility backward.
+ * page_size_kb member variable should be removed in the future
+ */
+ union {
+ unsigned page_size_kb;
+ unsigned page_size_bytes;
+ };
unsigned pages_used;
unsigned pages_total;
unsigned block;
diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp
index 5f0da6ea83d..42f6302861c 100644
--- a/ndb/include/ndbapi/Ndb.hpp
+++ b/ndb/include/ndbapi/Ndb.hpp
@@ -1386,22 +1386,22 @@ public:
*
* @param cacheSize number of values to cache in this Ndb object
*
- * @return 0 or -1 on error, and tupleId in out parameter
+ * @return 0 or -1 on error, and autoValue in out parameter
*/
int getAutoIncrementValue(const char* aTableName,
- Uint64 & tupleId, Uint32 cacheSize,
+ Uint64 & autoValue, Uint32 cacheSize,
Uint64 step = 1, Uint64 start = 1);
int getAutoIncrementValue(const NdbDictionary::Table * aTable,
- Uint64 & tupleId, Uint32 cacheSize,
+ Uint64 & autoValue, Uint32 cacheSize,
Uint64 step = 1, Uint64 start = 1);
int readAutoIncrementValue(const char* aTableName,
- Uint64 & tupleId);
+ Uint64 & autoValue);
int readAutoIncrementValue(const NdbDictionary::Table * aTable,
- Uint64 & tupleId);
+ Uint64 & autoValue);
int setAutoIncrementValue(const char* aTableName,
- Uint64 tupleId, bool increase);
+ Uint64 autoValue, bool modify);
int setAutoIncrementValue(const NdbDictionary::Table * aTable,
- Uint64 tupleId, bool increase);
+ Uint64 autoValue, bool modify);
private:
int getTupleIdFromNdb(Ndb_local_table_info* info,
Uint64 & tupleId, Uint32 cacheSize,
@@ -1409,7 +1409,9 @@ private:
int readTupleIdFromNdb(Ndb_local_table_info* info,
Uint64 & tupleId);
int setTupleIdInNdb(Ndb_local_table_info* info,
- Uint64 tupleId, bool increase);
+ Uint64 tupleId, bool modify);
+ int checkTupleIdInNdb(Ndb_local_table_info* info,
+ Uint64 tupleId);
int opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op);
public:
diff --git a/ndb/include/ndbapi/ndbapi_limits.h b/ndb/include/ndbapi/ndbapi_limits.h
index e283913d059..98551866edc 100644
--- a/ndb/include/ndbapi/ndbapi_limits.h
+++ b/ndb/include/ndbapi/ndbapi_limits.h
@@ -26,6 +26,7 @@
#define NDB_MAX_TUPLE_SIZE (NDB_MAX_TUPLE_SIZE_IN_WORDS*4)
#define NDB_MAX_ACTIVE_EVENTS 100
-#define NDB_MAX_SCANFILTER_SIZE_IN_WORDS 50000
+/* TUP ZATTR_BUFFER_SIZE 16384 (minus 1) minus place for getValue()s */
+#define NDB_MAX_SCANFILTER_SIZE_IN_WORDS (16384 - 1 - 1024)
#endif
diff --git a/ndb/include/util/Bitmask.hpp b/ndb/include/util/Bitmask.hpp
index 3b3fe721cca..0383841a666 100644
--- a/ndb/include/util/Bitmask.hpp
+++ b/ndb/include/util/Bitmask.hpp
@@ -126,6 +126,7 @@ public:
/**
* setField - Set bitfield at given position and length (max 32 bits)
+ * Note : length == 0 not supported.
*/
static void setField(unsigned size, Uint32 data[],
unsigned pos, unsigned len, Uint32 val);
@@ -133,6 +134,7 @@ public:
/**
* getField - Get bitfield at given position and length
+ * Note : length == 0 not supported.
*/
static void getField(unsigned size, const Uint32 data[],
unsigned pos, unsigned len, Uint32 dst[]);
@@ -814,7 +816,10 @@ BitmaskImpl::getField(unsigned size, const Uint32 src[],
unsigned pos, unsigned len, Uint32 dst[])
{
assert(pos + len <= (size << 5));
-
+ assert (len != 0);
+ if (len == 0)
+ return;
+
src += (pos >> 5);
Uint32 offset = pos & 31;
* dst = (* src >> offset) & (len >= 32 ? ~0 : (1 << len) - 1);
@@ -833,6 +838,9 @@ BitmaskImpl::setField(unsigned size, Uint32 dst[],
unsigned pos, unsigned len, const Uint32 src[])
{
assert(pos + len <= (size << 5));
+ assert(len != 0);
+ if (len == 0)
+ return;
dst += (pos >> 5);
Uint32 offset = pos & 31;
diff --git a/ndb/src/common/debugger/SignalLoggerManager.cpp b/ndb/src/common/debugger/SignalLoggerManager.cpp
index 471bea64f64..48cacb6bc1a 100644
--- a/ndb/src/common/debugger/SignalLoggerManager.cpp
+++ b/ndb/src/common/debugger/SignalLoggerManager.cpp
@@ -129,7 +129,7 @@ SignalLoggerManager::log(LogMode logMode, const char * params)
const int count = getParameter(blocks, "BLOCK=", params);
int cnt = 0;
- if((count == 1 && blocks[0] == "ALL") ||
+ if((count == 1 && !strcmp(blocks[0], "ALL")) ||
count == 0){
for (int number = 0; number < NO_OF_BLOCKS; ++number){
diff --git a/ndb/src/common/debugger/signaldata/ScanTab.cpp b/ndb/src/common/debugger/signaldata/ScanTab.cpp
index 39589542800..db9bbb52eab 100644
--- a/ndb/src/common/debugger/signaldata/ScanTab.cpp
+++ b/ndb/src/common/debugger/signaldata/ScanTab.cpp
@@ -69,7 +69,7 @@ printSCANTABCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 recei
sig->transId1, sig->transId2);
fprintf(output, " requestInfo: Eod: %d OpCount: %d\n",
- (requestInfo & ScanTabConf::EndOfData == ScanTabConf::EndOfData),
+ (requestInfo & ScanTabConf::EndOfData) == ScanTabConf::EndOfData,
(requestInfo & (~ScanTabConf::EndOfData)));
size_t op_count= requestInfo & (~ScanTabConf::EndOfData);
if(op_count){
diff --git a/ndb/src/common/transporter/TCP_Transporter.cpp b/ndb/src/common/transporter/TCP_Transporter.cpp
index c8095defd86..ea9e0944915 100644
--- a/ndb/src/common/transporter/TCP_Transporter.cpp
+++ b/ndb/src/common/transporter/TCP_Transporter.cpp
@@ -337,22 +337,32 @@ TCP_Transporter::doSend() {
// Empty the SendBuffers
- const char * const sendPtr = m_sendBuffer.sendPtr;
- const Uint32 sizeToSend = m_sendBuffer.sendDataSize;
- if (sizeToSend > 0){
+ bool sent_any = true;
+ while (m_sendBuffer.dataSize > 0)
+ {
+ const char * const sendPtr = m_sendBuffer.sendPtr;
+ const Uint32 sizeToSend = m_sendBuffer.sendDataSize;
const int nBytesSent = inet_send(theSocket, sendPtr, sizeToSend, 0);
- if (nBytesSent > 0) {
+ if (nBytesSent > 0)
+ {
+ sent_any = true;
m_sendBuffer.bytesSent(nBytesSent);
sendCount ++;
sendSize += nBytesSent;
- if(sendCount == reportFreq){
+ if(sendCount == reportFreq)
+ {
reportSendLen(get_callback_obj(), remoteNodeId, sendCount, sendSize);
sendCount = 0;
sendSize = 0;
}
- } else {
+ }
+ else
+ {
+ if (nBytesSent < 0 && InetErrno == EAGAIN && sent_any)
+ break;
+
// Send failed
#if defined DEBUG_TRANSPORTER
ndbout_c("Send Failure(disconnect==%d) to node = %d nBytesSent = %d "
diff --git a/ndb/src/common/util/Bitmask.cpp b/ndb/src/common/util/Bitmask.cpp
index 4b90e5a01f4..22919fe585a 100644
--- a/ndb/src/common/util/Bitmask.cpp
+++ b/ndb/src/common/util/Bitmask.cpp
@@ -16,34 +16,63 @@
#include <Bitmask.hpp>
#include <NdbOut.hpp>
-#ifndef __TEST_BITMASK__
-
void
BitmaskImpl::getFieldImpl(const Uint32 src[],
unsigned shiftL, unsigned len, Uint32 dst[])
{
+ /* Copy whole words of src to dst, shifting src left
+ * by shiftL. Undefined bits of the last written dst word
+ * should be zeroed.
+ */
assert(shiftL < 32);
unsigned shiftR = 32 - shiftL;
unsigned undefined = shiftL ? ~0 : 0;
+ /* Merge first word with previously set bits if there's a shift */
* dst = shiftL ? * dst : 0;
-
- while(len >= 32)
- {
- * dst++ |= (* src) << shiftL;
- * dst = ((* src++) >> shiftR) & undefined;
- len -= 32;
- }
-
- if(len < shiftR)
+
+ /* Treat the zero-shift case separately to avoid
+ * trampling or reading past the end of src
+ */
+ if (shiftL == 0)
{
- * dst |= ((* src) & ((1 << len) - 1)) << shiftL;
+ while(len >= 32)
+ {
+ * dst++ = * src++;
+ len -=32;
+ }
+
+ if (len != 0)
+ {
+ /* Last word has some bits set */
+ Uint32 mask= ((1 << len) -1); // 0000111
+ * dst = (* src) & mask;
+ }
}
- else
+ else // shiftL !=0, need to build each word from two words shifted
{
- * dst++ |= ((* src) << shiftL);
- * dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined;
+ while(len >= 32)
+ {
+ * dst++ |= (* src) << shiftL;
+ * dst = ((* src++) >> shiftR) & undefined;
+ len -= 32;
+ }
+
+ /* Have space for shiftR more bits in the current dst word
+ * is that enough?
+ */
+ if(len <= shiftR)
+ {
+ /* Fit the remaining bits in the current dst word */
+ * dst |= ((* src) & ((1 << len) - 1)) << shiftL;
+ }
+ else
+ {
+ /* Need to write to two dst words */
+ * dst++ |= ((* src) << shiftL);
+ * dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined;
+ }
}
}
@@ -66,301 +95,23 @@ BitmaskImpl::setFieldImpl(Uint32 dst[],
len -= 32;
}
+ /* Copy last bits */
Uint32 mask = ((1 << len) -1);
* dst = (* dst & ~mask);
- if(len < shiftR)
+ if(len <= shiftR)
{
+ /* Remaining bits fit in current word */
* dst |= ((* src++) >> shiftL) & mask;
}
else
{
+ /* Remaining bits update 2 words */
* dst |= ((* src++) >> shiftL);
* dst |= ((* src) & ((1 << (len - shiftR)) - 1)) << shiftR ;
}
}
-#else
-
-static
-void print(const Uint32 src[], Uint32 len, Uint32 pos = 0)
-{
- printf("b'");
- for(unsigned i = 0; i<len; i++)
- {
- if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos))
- printf("1");
- else
- printf("0");
- if((i & 31) == 31)
- printf(" ");
- }
-}
-
-#define DEBUG 0
-#include <Vector.hpp>
-static void do_test(int bitmask_size);
-
-int
-main(int argc, char** argv)
-{
- int loops = argc > 1 ? atoi(argv[1]) : 1000;
- int max_size = argc > 2 ? atoi(argv[2]) : 1000;
-
-
- for(int i = 0; i<loops; i++)
- do_test(1 + (rand() % max_size));
-}
-
-struct Alloc
-{
- Uint32 pos;
- Uint32 size;
- Vector<Uint32> data;
-};
-
-static void require(bool b)
-{
- if(!b) abort();
-}
-
-static
-bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len)
-{
- Uint32 sz32 = (len + 31) >> 5;
- for(int i = 0; i<len; i++)
- {
- if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i))
- return false;
- }
- return true;
-}
-
-
-static int val_pos = 0;
-static int val[] = { 384, 241, 32,
- 1,1,1,1, 0,0,0,0, 1,1,1,1, 0,0,0,0,
- 241 };
-
-static int lrand()
-{
-#if 0
- return val[val_pos++];
-#else
- return rand();
-#endif
-}
-
-static
-void rand(Uint32 dst[], Uint32 len)
-{
- for(int i = 0; i<len; i++)
- BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500);
-}
-
-static
-void simple(int pos, int size)
-{
- ndbout_c("simple pos: %d size: %d", pos, size);
- Vector<Uint32> _mask;
- Vector<Uint32> _src;
- Vector<Uint32> _dst;
- Uint32 sz32 = (size + pos + 32) >> 5;
- const Uint32 sz = 4 * sz32;
-
- Uint32 zero = 0;
- _mask.fill(sz32+1, zero);
- _src.fill(sz32+1, zero);
- _dst.fill(sz32+1, zero);
-
- Uint32 * src = _src.getBase();
- Uint32 * dst = _dst.getBase();
- Uint32 * mask = _mask.getBase();
-
- memset(src, 0x0, sz);
- memset(dst, 0x0, sz);
- memset(mask, 0xFF, sz);
- rand(src, size);
- BitmaskImpl::setField(sz32, mask, pos, size, src);
- BitmaskImpl::getField(sz32, mask, pos, size, dst);
- printf("src: "); print(src, size+31); printf("\n");
- printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n");
- printf("dst: "); print(dst, size+31); printf("\n");
- require(cmp(src, dst, size+31));
-};
-
-static
-void simple2(int size, int loops)
-{
- ndbout_c("simple2 %d - ", size);
- Vector<Uint32> _mask;
- Vector<Uint32> _src;
- Vector<Uint32> _dst;
-
- Uint32 sz32 = (size + 32) >> 5;
- Uint32 sz = sz32 << 2;
-
- Uint32 zero = 0;
- _mask.fill(sz32+1, zero);
- _src.fill(sz32+1, zero);
- _dst.fill(sz32+1, zero);
-
- Uint32 * src = _src.getBase();
- Uint32 * dst = _dst.getBase();
- Uint32 * mask = _mask.getBase();
-
- Vector<Uint32> save;
- for(int i = 0; i<loops; i++)
- {
- memset(mask, 0xFF, sz);
- memset(dst, 0xFF, sz);
- int len;
- int pos = 0;
- while(pos+1 < size)
- {
- memset(src, 0xFF, sz);
- while(!(len = rand() % (size - pos)));
- BitmaskImpl::setField(sz32, mask, pos, len, src);
- if(memcmp(dst, mask, sz))
- {
- ndbout_c("pos: %d len: %d", pos, len);
- print(mask, size);
- abort();
- }
- printf("[ %d %d ]", pos, len);
- save.push_back(pos);
- save.push_back(len);
- pos += len;
- }
-
- for(int j = 0; j<save.size(); )
- {
- pos = save[j++];
- len = save[j++];
- memset(src, 0xFF, sz);
- BitmaskImpl::getField(sz32, mask, pos, len, src);
- if(memcmp(dst, src, sz))
- {
- ndbout_c("pos: %d len: %d", pos, len);
- printf("src: "); print(src, size); printf("\n");
- printf("dst: "); print(dst, size); printf("\n");
- printf("msk: "); print(mask, size); printf("\n");
- abort();
- }
- }
- ndbout_c("");
- }
-}
-
-static void
-do_test(int bitmask_size)
-{
-#if 1
- simple(rand() % 33, (rand() % 63)+1);
-//#else
- Vector<Alloc> alloc_list;
- bitmask_size = (bitmask_size + 31) & ~31;
- Uint32 sz32 = (bitmask_size >> 5);
- Vector<Uint32> alloc_mask;
- Vector<Uint32> test_mask;
-
- ndbout_c("Testing bitmask of size %d", bitmask_size);
- Uint32 zero = 0;
- alloc_mask.fill(sz32, zero);
- test_mask.fill(sz32, zero);
-
- for(int i = 0; i<5000; i++)
- {
- Vector<Uint32> tmp;
- tmp.fill(sz32, zero);
-
- int pos = lrand() % (bitmask_size - 1);
- int free = 0;
- if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos))
- {
- // Bit was allocated
- // 1) Look up allocation
- // 2) Check data
- // 3) free it
- size_t j;
- int min, max;
- for(j = 0; j<alloc_list.size(); j++)
- {
- min = alloc_list[j].pos;
- max = min + alloc_list[j].size;
- if(pos >= min && pos < max)
- {
- break;
- }
- }
- require(pos >= min && pos < max);
- BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min,
- tmp.getBase());
- if(DEBUG)
- {
- printf("freeing [ %d %d ]", min, max);
- printf("- mask: ");
- print(tmp.getBase(), max - min);
-
- printf(" save: ");
- size_t k;
- Alloc& a = alloc_list[j];
- for(k = 0; k<a.data.size(); k++)
- printf("%.8x ", a.data[k]);
- printf("\n");
- }
- int bytes = (max - min + 7) >> 3;
- if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min))
- {
- abort();
- }
- while(min < max)
- BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++);
- alloc_list.erase(j);
- }
- else
- {
- Vector<Uint32> tmp;
- tmp.fill(sz32, zero);
-
- // Bit was free
- // 1) Check how much space is avaiable
- // 2) Create new allocation of lrandom size
- // 3) Fill data with lrandom data
- // 4) Update alloc mask
- while(pos+free < bitmask_size &&
- !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free))
- free++;
-
- Uint32 sz =
- (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free);
- sz = sz ? sz : 1;
- sz = pos + sz == bitmask_size ? sz - 1 : sz;
- Alloc a;
- a.pos = pos;
- a.size = sz;
- a.data.fill(((sz+31)>> 5)-1, zero);
- if(DEBUG)
- printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz);
- for(size_t j = 0; j<sz; j++)
- {
- BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j);
- if((lrand() % 1000) > 500)
- BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j);
- }
- if(DEBUG)
- {
- printf("- mask: ");
- print(a.data.getBase(), sz);
- printf("\n");
- }
- BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz,
- a.data.getBase());
- alloc_list.push_back(a);
- }
- }
-#endif
-}
-
-template class Vector<Alloc>;
-template class Vector<Uint32>;
-#endif
+/* Bitmask testcase code moved from here to
+ * storage/ndb/test/ndbapi/testBitfield.cpp
+ * to get coverage from automated testing
+ */
diff --git a/ndb/src/common/util/NdbOut.cpp b/ndb/src/common/util/NdbOut.cpp
index 7ca7c91e266..61de2be7572 100644
--- a/ndb/src/common/util/NdbOut.cpp
+++ b/ndb/src/common/util/NdbOut.cpp
@@ -29,7 +29,7 @@ static const char * fms[] = {
"%d", "0x%08x", // Int32
"%u", "0x%08x", // Uint32
"%lld", "0x%016llx", // Int64
- "%llu", "0x%016llx" // Uint64
+ "%llu", "0x%016llx", // Uint64
"%llu", "0x%016llx" // UintPtr
};
diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp
index 70721bfca56..52ab11b8388 100644
--- a/ndb/src/kernel/blocks/backup/Backup.cpp
+++ b/ndb/src/kernel/blocks/backup/Backup.cpp
@@ -374,16 +374,18 @@ Backup::execCONTINUEB(Signal* signal)
ptr.p->files.getPtr(filePtr, ptr.p->ctlFilePtr);
FsBuffer & buf = filePtr.p->operation.dataBuffer;
- if(buf.getFreeSize() + buf.getMinRead() < buf.getUsableSize()) {
+ if(buf.getFreeSize() < buf.getMaxWrite()) {
jam();
TablePtr tabPtr LINT_SET_PTR;
c_tablePool.getPtr(tabPtr, Tdata2);
- DEBUG_OUT("Backup - Buffer full - " << buf.getFreeSize()
- << " + " << buf.getMinRead()
- << " < " << buf.getUsableSize()
- << " - tableId = " << tabPtr.p->tableId);
-
+ DEBUG_OUT("Backup - Buffer full - "
+ << buf.getFreeSize()
+ << " < " << buf.getMaxWrite()
+ << " (sz: " << buf.getUsableSize()
+ << " getMinRead: " << buf.getMinRead()
+ << ") - tableId = " << tabPtr.p->tableId);
+
signal->theData[0] = BackupContinueB::BUFFER_FULL_META;
signal->theData[1] = Tdata1;
signal->theData[2] = Tdata2;
diff --git a/ndb/src/kernel/blocks/backup/Backup.hpp b/ndb/src/kernel/blocks/backup/Backup.hpp
index 8b0c27727b0..e67d8f09f0e 100644
--- a/ndb/src/kernel/blocks/backup/Backup.hpp
+++ b/ndb/src/kernel/blocks/backup/Backup.hpp
@@ -518,7 +518,7 @@ public:
Uint32 m_diskless;
STATIC_CONST(NO_OF_PAGES_META_FILE =
- (MAX_WORDS_META_FILE + BACKUP_WORDS_PER_PAGE - 1) /
+ (2*MAX_WORDS_META_FILE + BACKUP_WORDS_PER_PAGE - 1) /
BACKUP_WORDS_PER_PAGE);
/**
diff --git a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
index 6fe0eefcdb5..829156ef15a 100644
--- a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
+++ b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
@@ -198,6 +198,7 @@
#define ZUNSUPPORTED_BRANCH 892
#define ZSTORED_SEIZE_ATTRINBUFREC_ERROR 873 // Part of Scan
+#define ZSTORED_TOO_MUCH_ATTRINFO_ERROR 874
#define ZREAD_ONLY_CONSTRAINT_VIOLATION 893
#define ZVAR_SIZED_NOT_SUPPORTED 894
@@ -1085,7 +1086,7 @@ public:
/*
* TUX checks if tuple is visible to scan.
*/
- bool tuxQueryTh(Uint32 fragPtrI, Uint32 tupAddr, Uint32 tupVersion, Uint32 transId1, Uint32 transId2, Uint32 savePointId);
+ bool tuxQueryTh(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32 tupVersion, Uint32 transId1, Uint32 transId2, bool dirty, Uint32 savePointId);
private:
BLOCK_DEFINES(Dbtup);
@@ -1942,6 +1943,8 @@ private:
bool getPageThroughSavePoint(Operationrec* const regOperPtr,
Operationrec* const leaderOpPtr);
+ bool find_savepoint(OperationrecPtr& loopOpPtr, Uint32 savepointId);
+
Uint32 calculateChecksum(Page* const pagePtr, Uint32 tupHeadOffset, Uint32 tupHeadSize);
void setChecksum(Page* const pagePtr, Uint32 tupHeadOffset, Uint32 tupHeadSize);
@@ -2171,7 +2174,8 @@ private:
Operationrec* regOperPtr,
Uint32 lenAttrInfo);
void storedSeizeAttrinbufrecErrorLab(Signal* signal,
- Operationrec* regOperPtr);
+ Operationrec* regOperPtr,
+ Uint32 errorCode);
bool storedProcedureAttrInfo(Signal* signal,
Operationrec* regOperPtr,
Uint32 length,
@@ -2467,4 +2471,22 @@ bool Dbtup::isPageUndoLogged(Fragrecord* const regFragPtr,
return false;
}//Dbtup::isUndoLoggingNeeded()
+inline
+bool Dbtup::find_savepoint(OperationrecPtr& loopOpPtr, Uint32 savepointId)
+{
+ while (true) {
+ if (savepointId > loopOpPtr.p->savePointId) {
+ jam();
+ return true;
+ }
+ // note 5.0 has reversed next/prev pointers
+ loopOpPtr.i = loopOpPtr.p->nextActiveOp;
+ if (loopOpPtr.i == RNIL) {
+ break;
+ }
+ ptrCheckGuard(loopOpPtr, cnoOfOprec, operationrec);
+ }
+ return false;
+}
+
#endif
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
index 298fb183bc3..9ab4fb34827 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
@@ -77,6 +77,14 @@ void Dbtup::copyAttrinfo(Signal* signal,
RbufLen = copyAttrBufPtr.p->attrbuf[ZBUF_DATA_LEN];
Rnext = copyAttrBufPtr.p->attrbuf[ZBUF_NEXT];
Rfirst = cfirstfreeAttrbufrec;
+ /*
+ * ATTRINFO comes from 2 mutually exclusive places:
+ * 1) TUPKEYREQ (also interpreted part)
+ * 2) STORED_PROCREQ before scan start
+ * Assert here that both have a check for overflow.
+ * The "<" instead of "<=" is intentional.
+ */
+ ndbrequire(RinBufIndex + RbufLen < ZATTR_BUFFER_SIZE);
MEMCOPY_NO_WORDS(&inBuffer[RinBufIndex],
&copyAttrBufPtr.p->attrbuf[0],
RbufLen);
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp b/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
index 964d8578217..c03ca35bc6a 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
@@ -246,8 +246,18 @@ Dbtup::accReadPk(Uint32 tableId, Uint32 fragId, Uint32 fragPageId, Uint32 pageIn
return ret;
}
+/*
+ * TUX index contains all tuple versions. A scan in TUX has scanned
+ * one of them and asks if it can be returned as scan result. This
+ * depends on trans id, dirty read flag, and savepoint within trans.
+ *
+ * Previously this faked a ZREAD operation and used getPage().
+ * In TUP getPage() is run after ACC locking, but TUX comes here
+ * before ACC access. Instead of modifying getPage() it is more
+ * clear to do the full check here.
+ */
bool
-Dbtup::tuxQueryTh(Uint32 fragPtrI, Uint32 tupAddr, Uint32 tupVersion, Uint32 transId1, Uint32 transId2, Uint32 savePointId)
+Dbtup::tuxQueryTh(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32 tupVersion, Uint32 transId1, Uint32 transId2, bool dirty, Uint32 savePointId)
{
ljamEntry();
FragrecordPtr fragPtr;
@@ -256,33 +266,73 @@ Dbtup::tuxQueryTh(Uint32 fragPtrI, Uint32 tupAddr, Uint32 tupVersion, Uint32 tra
TablerecPtr tablePtr;
tablePtr.i = fragPtr.p->fragTableId;
ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
- // get page
PagePtr pagePtr;
- Uint32 fragPageId = tupAddr >> MAX_TUPLES_BITS;
- Uint32 pageIndex = tupAddr & ((1 << MAX_TUPLES_BITS ) - 1);
- // use temp op rec
- Operationrec tempOp;
- tempOp.fragPageId = fragPageId;
- tempOp.pageIndex = pageIndex;
- tempOp.transid1 = transId1;
- tempOp.transid2 = transId2;
- tempOp.savePointId = savePointId;
- tempOp.optype = ZREAD;
- tempOp.dirtyOp = 1;
- if (getPage(pagePtr, &tempOp, fragPtr.p, tablePtr.p)) {
- /*
- * We use the normal getPage which will return the tuple to be used
- * for this transaction and savepoint id. If its tuple version
- * equals the requested then we have a visible tuple otherwise not.
- */
+ pagePtr.i = pageId;
+ ptrCheckGuard(pagePtr, cnoOfPage, page);
+
+ OperationrecPtr currOpPtr;
+ currOpPtr.i = pagePtr.p->pageWord[pageOffset];
+ if (currOpPtr.i == RNIL) {
+ ljam();
+ // tuple has no operation, any scan can see it
+ return true;
+ }
+ ptrCheckGuard(currOpPtr, cnoOfOprec, operationrec);
+
+ const bool sameTrans =
+ transId1 == currOpPtr.p->transid1 &&
+ transId2 == currOpPtr.p->transid2;
+
+ bool res = false;
+ OperationrecPtr loopOpPtr = currOpPtr;
+
+ if (!sameTrans) {
ljam();
- Uint32 read_tupVersion = pagePtr.p->pageWord[tempOp.pageOffset + 1];
- if (read_tupVersion == tupVersion) {
+ if (!dirty) {
ljam();
- return true;
+ if (currOpPtr.p->prevActiveOp == RNIL) {
+ ljam();
+ // last op - TUX makes ACC lock request in same timeslice
+ res = true;
+ }
+ }
+ else {
+ // loop to first op (returns false)
+ find_savepoint(loopOpPtr, 0);
+ const Uint32 op_type = loopOpPtr.p->optype;
+
+ if (op_type != ZINSERT) {
+ ljam();
+ // read committed version from the page
+ const Uint32 origVersion = pagePtr.p->pageWord[pageOffset + 1];
+ if (origVersion == tupVersion) {
+ ljam();
+ res = true;
+ }
+ }
}
}
- return false;
+ else {
+ ljam();
+ // for own trans, ignore dirty flag
+
+ if (find_savepoint(loopOpPtr, savePointId)) {
+ ljam();
+ const Uint32 op_type = loopOpPtr.p->optype;
+
+ if (op_type != ZDELETE) {
+ ljam();
+ // check if this op has produced the scanned version
+ Uint32 loopVersion = loopOpPtr.p->tupVersion;
+ if (loopVersion == tupVersion) {
+ ljam();
+ res = true;
+ }
+ }
+ }
+ }
+
+ return res;
}
// ordered index build
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp b/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp
index 37fcd3df317..f4215b6da7d 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp
@@ -108,6 +108,11 @@ void Dbtup::scanProcedure(Signal* signal,
regOperPtr->attrinbufLen = lenAttrInfo;
regOperPtr->currentAttrinbufLen = 0;
regOperPtr->pageOffset = storedPtr.i;
+ if (lenAttrInfo >= ZATTR_BUFFER_SIZE) { // yes ">="
+ jam();
+ // send REF and change state to ignore the ATTRINFO to come
+ storedSeizeAttrinbufrecErrorLab(signal, regOperPtr, ZSTORED_TOO_MUCH_ATTRINFO_ERROR);
+ }
}//Dbtup::scanProcedure()
void Dbtup::copyProcedure(Signal* signal,
@@ -146,7 +151,7 @@ bool Dbtup::storedProcedureAttrInfo(Signal* signal,
Uint32 RnoFree = cnoFreeAttrbufrec;
if (ERROR_INSERTED(4004) && !copyProcedure) {
CLEAR_ERROR_INSERT_VALUE;
- storedSeizeAttrinbufrecErrorLab(signal, regOperPtr);
+ storedSeizeAttrinbufrecErrorLab(signal, regOperPtr, ZSTORED_SEIZE_ATTRINBUFREC_ERROR);
return false;
}//if
regOperPtr->currentAttrinbufLen += length;
@@ -162,7 +167,7 @@ bool Dbtup::storedProcedureAttrInfo(Signal* signal,
regAttrPtr.p->attrbuf[ZBUF_NEXT] = RNIL;
} else {
ljam();
- storedSeizeAttrinbufrecErrorLab(signal, regOperPtr);
+ storedSeizeAttrinbufrecErrorLab(signal, regOperPtr, ZSTORED_SEIZE_ATTRINBUFREC_ERROR);
return false;
}//if
if (regOperPtr->firstAttrinbufrec == RNIL) {
@@ -190,7 +195,7 @@ bool Dbtup::storedProcedureAttrInfo(Signal* signal,
}//if
if (ERROR_INSERTED(4005) && !copyProcedure) {
CLEAR_ERROR_INSERT_VALUE;
- storedSeizeAttrinbufrecErrorLab(signal, regOperPtr);
+ storedSeizeAttrinbufrecErrorLab(signal, regOperPtr, ZSTORED_SEIZE_ATTRINBUFREC_ERROR);
return false;
}//if
@@ -211,7 +216,8 @@ bool Dbtup::storedProcedureAttrInfo(Signal* signal,
}//Dbtup::storedProcedureAttrInfo()
void Dbtup::storedSeizeAttrinbufrecErrorLab(Signal* signal,
- Operationrec* regOperPtr)
+ Operationrec* regOperPtr,
+ Uint32 errorCode)
{
StoredProcPtr storedPtr;
c_storedProcPool.getPtr(storedPtr, (Uint32)regOperPtr->pageOffset);
@@ -222,7 +228,7 @@ void Dbtup::storedSeizeAttrinbufrecErrorLab(Signal* signal,
regOperPtr->lastAttrinbufrec = RNIL;
regOperPtr->transstate = ERROR_WAIT_STORED_PROCREQ;
signal->theData[0] = regOperPtr->userpointer;
- signal->theData[1] = ZSTORED_SEIZE_ATTRINBUFREC_ERROR;
+ signal->theData[1] = errorCode;
signal->theData[2] = regOperPtr->pageOffset;
sendSignal(regOperPtr->userblockref, GSN_STORED_PROCREF, signal, 3, JBB);
}//Dbtup::storedSeizeAttrinbufrecErrorLab()
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
index 7eae1486d43..f72b1db1cc5 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
@@ -216,7 +216,8 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal)
// fill in any gap
while (maxAttrId[j] <= attrId) {
jam();
- BoundInfo& b = boundInfo[j][maxAttrId[j]++];
+ BoundInfo& b = boundInfo[j][maxAttrId[j]];
+ maxAttrId[j]++;
b.type2 = -1;
}
BoundInfo& b = boundInfo[j][attrId];
@@ -984,7 +985,8 @@ Dbtux::scanVisible(ScanOpPtr scanPtr, TreeEnt ent)
const Frag& frag = *c_fragPool.getPtr(scan.m_fragPtrI);
Uint32 fragBit = ent.m_fragBit;
Uint32 tableFragPtrI = frag.m_tupTableFragPtrI[fragBit];
- Uint32 tupAddr = getTupAddr(frag, ent);
+ Uint32 pageId = ent.m_tupLoc.getPageId();
+ Uint32 pageOffset = ent.m_tupLoc.getPageOffset();
Uint32 tupVersion = ent.m_tupVersion;
// check for same tuple twice in row
if (scan.m_scanEnt.m_tupLoc == ent.m_tupLoc &&
@@ -994,8 +996,9 @@ Dbtux::scanVisible(ScanOpPtr scanPtr, TreeEnt ent)
}
Uint32 transId1 = scan.m_transId1;
Uint32 transId2 = scan.m_transId2;
+ bool dirty = scan.m_readCommitted;
Uint32 savePointId = scan.m_savePointId;
- bool ret = c_tup->tuxQueryTh(tableFragPtrI, tupAddr, tupVersion, transId1, transId2, savePointId);
+ bool ret = c_tup->tuxQueryTh(tableFragPtrI, pageId, pageOffset, tupVersion, transId1, transId2, dirty, savePointId);
jamEntry();
return ret;
}
diff --git a/ndb/src/kernel/vm/DLHashTable.hpp b/ndb/src/kernel/vm/DLHashTable.hpp
index acf53944b07..cc6802db2bc 100644
--- a/ndb/src/kernel/vm/DLHashTable.hpp
+++ b/ndb/src/kernel/vm/DLHashTable.hpp
@@ -45,8 +45,8 @@ public:
/**
* Seize element from pool - return i
*
- * Note must be either added using <b>add</b> or released
- * using <b>release</b>
+ * Note *must* be added using <b>add</b> (even before hash.release)
+ * or be released using pool
*/
bool seize(Ptr<T> &);
@@ -374,7 +374,14 @@ DLHashTable<T>::remove(Ptr<T> & ptr){
prevP->nextHash = next;
} else {
const Uint32 hv = ptr.p->hashValue() & mask;
- hashValues[hv] = next;
+ if (hashValues[hv] == ptr.i)
+ {
+ hashValues[hv] = next;
+ }
+ else
+ {
+ // Will add assert in 5.1
+ }
}
if(next != RNIL){
@@ -395,7 +402,14 @@ DLHashTable<T>::release(Ptr<T> & ptr){
prevP->nextHash = next;
} else {
const Uint32 hv = ptr.p->hashValue() & mask;
- hashValues[hv] = next;
+ if (hashValues[hv] == ptr.i)
+ {
+ hashValues[hv] = next;
+ }
+ else
+ {
+ // Will add assert in 5.1
+ }
}
if(next != RNIL){
diff --git a/ndb/src/kernel/vm/DLHashTable2.hpp b/ndb/src/kernel/vm/DLHashTable2.hpp
index ad03e8ed3ba..20515af8cf6 100644
--- a/ndb/src/kernel/vm/DLHashTable2.hpp
+++ b/ndb/src/kernel/vm/DLHashTable2.hpp
@@ -43,8 +43,8 @@ public:
/**
* Seize element from pool - return i
*
- * Note must be either added using <b>add</b> or released
- * using <b>release</b>
+ * Note *must* be added using <b>add</b> (even before hash.release)
+ * or be released using pool
*/
bool seize(Ptr<T> &);
@@ -375,7 +375,14 @@ DLHashTable2<T, U>::remove(Ptr<T> & ptr){
prevP->nextHash = next;
} else {
const Uint32 hv = ptr.p->hashValue() & mask;
- hashValues[hv] = next;
+ if (hashValues[hv] == ptr.i)
+ {
+ hashValues[hv] = next;
+ }
+ else
+ {
+ // Will add assert in 5.1
+ }
}
if(next != RNIL){
@@ -396,7 +403,14 @@ DLHashTable2<T, U>::release(Ptr<T> & ptr){
prevP->nextHash = next;
} else {
const Uint32 hv = ptr.p->hashValue() & mask;
- hashValues[hv] = next;
+ if (hashValues[hv] == ptr.i)
+ {
+ hashValues[hv] = next;
+ }
+ else
+ {
+ // Will add assert in 5.1
+ }
}
if(next != RNIL){
diff --git a/ndb/src/kernel/vm/pc.hpp b/ndb/src/kernel/vm/pc.hpp
index 269719c44d0..ed592620a2e 100644
--- a/ndb/src/kernel/vm/pc.hpp
+++ b/ndb/src/kernel/vm/pc.hpp
@@ -49,7 +49,7 @@
theEmulatedJamBlockNumber = number(); \
Uint32 tEmulatedJamIndex = theEmulatedJamIndex; \
*(Uint32*)(theEmulatedJam + tEmulatedJamIndex) = \
- ((theEmulatedJamBlockNumber << 20) | line); \
+ ((theEmulatedJamBlockNumber << 20) | (line)); \
theEmulatedJamIndex = (tEmulatedJamIndex + 4) & JAM_MASK; }
#else
@@ -72,7 +72,7 @@
theEmulatedJamBlockNumber = number(); \
Uint32 tEmulatedJamIndex = theEmulatedJamIndex; \
*(Uint32*)((UintPtr)theEmulatedJam + (Uint32)tEmulatedJamIndex) = \
- ((theEmulatedJamBlockNumber << 20) | line); \
+ ((theEmulatedJamBlockNumber << 20) | (line)); \
theEmulatedJamIndex = (tEmulatedJamIndex + 4) & JAM_MASK; }
#endif
@@ -232,7 +232,7 @@
#define MEMCOPY_PAGE(to, from, page_size_in_bytes) \
memcpy((void*)(to), (void*)(from), (size_t)(page_size_in_bytes));
#define MEMCOPY_NO_WORDS(to, from, no_of_words) \
- memcpy((to), (void*)(from), (size_t)(no_of_words << 2));
+ memcpy((to), (void*)(from), (size_t)((no_of_words) << 2));
template <class T>
struct Ptr {
diff --git a/ndb/src/mgmapi/ndb_logevent.cpp b/ndb/src/mgmapi/ndb_logevent.cpp
index 3885bb79536..f0b7c26cf78 100644
--- a/ndb/src/mgmapi/ndb_logevent.cpp
+++ b/ndb/src/mgmapi/ndb_logevent.cpp
@@ -256,7 +256,7 @@ struct Ndb_logevent_body_row ndb_logevent_body[]= {
ROW( ReceiveBytesStatistic, "mean_received_bytes", 2, mean_received_bytes),
ROW( MemoryUsage, "gth", 1, gth),
- ROW( MemoryUsage, "page_size_kb", 2, page_size_kb),
+ ROW( MemoryUsage, "page_size_bytes", 2, page_size_bytes),
ROW( MemoryUsage, "pages_used", 3, pages_used),
ROW( MemoryUsage, "pages_total", 4, pages_total),
ROW( MemoryUsage, "block", 5, block),
diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp
index 1036461d404..b72f7b12f9b 100644
--- a/ndb/src/mgmclient/CommandInterpreter.cpp
+++ b/ndb/src/mgmclient/CommandInterpreter.cpp
@@ -921,10 +921,14 @@ event_thread_run(void* p)
{
do_event_thread= 1;
do {
- if (ndb_logevent_get_next(log_handle, &log_event, 2000) <= 0)
- continue;
- Guard g(printmutex);
- printLogEvent(&log_event);
+ int res= ndb_logevent_get_next(log_handle, &log_event, 2000);
+ if (res > 0)
+ {
+ Guard g(printmutex);
+ printLogEvent(&log_event);
+ }
+ else if (res < 0)
+ break;
} while(do_event_thread);
ndb_mgm_destroy_logevent_handle(&log_handle);
}
@@ -2722,8 +2726,9 @@ CommandInterpreter::executeStartBackup(char* parameters, bool interactive)
{
int count = 0;
int retry = 0;
+ int res;
do {
- if (ndb_logevent_get_next(log_handle, &log_event, 60000) > 0)
+ if ((res= ndb_logevent_get_next(log_handle, &log_event, 60000)) > 0)
{
int print = 0;
switch (log_event.type) {
@@ -2753,7 +2758,7 @@ CommandInterpreter::executeStartBackup(char* parameters, bool interactive)
{
retry++;
}
- } while(count < 2 && retry < 3);
+ } while(res >= 0 && count < 2 && retry < 3);
if (retry >= 3)
ndbout << "get backup event failed for " << retry << " times" << endl;
diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp
index 3600dfdeab3..2a22fc72183 100644
--- a/ndb/src/mgmsrv/ConfigInfo.cpp
+++ b/ndb/src/mgmsrv/ConfigInfo.cpp
@@ -398,7 +398,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = {
ConfigInfo::CI_INT,
MANDATORY,
"1",
- STR_VALUE(MAX_NODES) },
+ STR_VALUE(MAX_DATA_NODE_ID) },
{
CFG_NODE_ID,
@@ -410,7 +410,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = {
ConfigInfo::CI_INT,
MANDATORY,
"1",
- STR_VALUE(MAX_NODES) },
+ STR_VALUE(MAX_DATA_NODE_ID) },
{
KEY_INTERNAL,
@@ -1261,7 +1261,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = {
ConfigInfo::CI_INT,
MANDATORY,
"1",
- STR_VALUE(MAX_NODES) },
+ STR_VALUE(MAX_NODES_ID) },
{
CFG_NODE_ID,
@@ -1273,7 +1273,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = {
ConfigInfo::CI_INT,
MANDATORY,
"1",
- STR_VALUE(MAX_NODES) },
+ STR_VALUE(MAX_NODES_ID) },
{
KEY_INTERNAL,
@@ -1404,7 +1404,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = {
ConfigInfo::CI_INT,
MANDATORY,
"1",
- STR_VALUE(MAX_NODES) },
+ STR_VALUE(MAX_NODES_ID) },
{
CFG_NODE_ID,
@@ -1416,7 +1416,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = {
ConfigInfo::CI_INT,
MANDATORY,
"1",
- STR_VALUE(MAX_NODES) },
+ STR_VALUE(MAX_NODES_ID) },
{
CFG_LOG_DESTINATION,
diff --git a/ndb/src/ndbapi/DictCache.cpp b/ndb/src/ndbapi/DictCache.cpp
index 6a815067233..9234b6b5219 100644
--- a/ndb/src/ndbapi/DictCache.cpp
+++ b/ndb/src/ndbapi/DictCache.cpp
@@ -46,6 +46,7 @@ Ndb_local_table_info::Ndb_local_table_info(NdbTableImpl *table_impl)
m_table_impl= table_impl;
m_first_tuple_id = ~(Uint64)0;
m_last_tuple_id = ~(Uint64)0;
+ m_highest_seen = 0;
}
Ndb_local_table_info::~Ndb_local_table_info()
diff --git a/ndb/src/ndbapi/DictCache.hpp b/ndb/src/ndbapi/DictCache.hpp
index db90a07d487..6ada55cc05e 100644
--- a/ndb/src/ndbapi/DictCache.hpp
+++ b/ndb/src/ndbapi/DictCache.hpp
@@ -36,6 +36,7 @@ public:
// range of cached tuple ids per thread
Uint64 m_first_tuple_id;
Uint64 m_last_tuple_id;
+ Uint64 m_highest_seen;
Uint64 m_local_data[1]; // Must be last member. Used to access extra space.
private:
diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp
index dcdee3d4ea1..c784f557b4c 100644
--- a/ndb/src/ndbapi/Ndb.cpp
+++ b/ndb/src/ndbapi/Ndb.cpp
@@ -767,8 +767,8 @@ Ndb::getNodeId()
}
/****************************************************************************
-Uint64 getAutoIncrementValue( const char* aTableName,
- Uint64 & tupleId,
+int getAutoIncrementValue( const char* aTableName,
+ Uint64 & autoValue,
Uint32 cacheSize,
Uint64 step,
Uint64 start);
@@ -779,6 +779,7 @@ Parameters: aTableName (IN) : The table name.
step (IN) : Specifies the step between the
autoincrement values.
start (IN) : Start value for first value
+Returns: 0 if succesful, -1 if error encountered
Remark: Returns a new autoincrement value to the application.
The autoincrement values can be increased by steps
(default 1) and a number of values can be prefetched
@@ -892,9 +893,18 @@ Ndb::getTupleIdFromNdb(Ndb_local_table_info* info,
DBUG_RETURN(0);
}
+/****************************************************************************
+int readAutoIncrementValue( const char* aTableName,
+ Uint64 & autoValue);
+
+Parameters: aTableName (IN) : The table name.
+ autoValue (OUT) : The current autoincrement value
+Returns: 0 if succesful, -1 if error encountered
+Remark: Returns the current autoincrement value to the application.
+****************************************************************************/
int
Ndb::readAutoIncrementValue(const char* aTableName,
- Uint64 & tupleId)
+ Uint64 & autoValue)
{
DBUG_ENTER("Ndb::readAutoIncrementValue");
BaseString internal_tabname(internalize_table_name(aTableName));
@@ -905,15 +915,15 @@ Ndb::readAutoIncrementValue(const char* aTableName,
theError.code = theDictionary->getNdbError().code;
DBUG_RETURN(-1);
}
- if (readTupleIdFromNdb(info, tupleId) == -1)
+ if (readTupleIdFromNdb(info, autoValue) == -1)
DBUG_RETURN(-1);
- DBUG_PRINT("info", ("value %lu", (ulong)tupleId));
+ DBUG_PRINT("info", ("value %lu", (ulong)autoValue));
DBUG_RETURN(0);
}
int
Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable,
- Uint64 & tupleId)
+ Uint64 & autoValue)
{
DBUG_ENTER("Ndb::readAutoIncrementValue");
assert(aTable != 0);
@@ -926,9 +936,9 @@ Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable,
theError.code = theDictionary->getNdbError().code;
DBUG_RETURN(-1);
}
- if (readTupleIdFromNdb(info, tupleId) == -1)
+ if (readTupleIdFromNdb(info, autoValue) == -1)
DBUG_RETURN(-1);
- DBUG_PRINT("info", ("value %lu", (ulong)tupleId));
+ DBUG_PRINT("info", ("value %lu", (ulong)autoValue));
DBUG_RETURN(0);
}
@@ -956,9 +966,20 @@ Ndb::readTupleIdFromNdb(Ndb_local_table_info* info,
DBUG_RETURN(0);
}
+/****************************************************************************
+int setAutoIncrementValue( const char* aTableName,
+ Uint64 autoValue,
+ bool modify);
+
+Parameters: aTableName (IN) : The table name.
+ autoValue (IN) : The new autoincrement value
+ modify (IN) : Modify existing value (not initialization)
+Returns: 0 if succesful, -1 if error encountered
+Remark: Sets a new autoincrement value for the application.
+****************************************************************************/
int
Ndb::setAutoIncrementValue(const char* aTableName,
- Uint64 tupleId, bool increase)
+ Uint64 autoValue, bool modify)
{
DBUG_ENTER("Ndb::setAutoIncrementValue");
BaseString internal_tabname(internalize_table_name(aTableName));
@@ -969,14 +990,14 @@ Ndb::setAutoIncrementValue(const char* aTableName,
theError.code = theDictionary->getNdbError().code;
DBUG_RETURN(-1);
}
- if (setTupleIdInNdb(info, tupleId, increase) == -1)
+ if (setTupleIdInNdb(info, autoValue, modify) == -1)
DBUG_RETURN(-1);
DBUG_RETURN(0);
}
int
Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable,
- Uint64 tupleId, bool increase)
+ Uint64 autoValue, bool modify)
{
DBUG_ENTER("Ndb::setAutoIncrementValue");
assert(aTable != 0);
@@ -989,38 +1010,42 @@ Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable,
theError.code = theDictionary->getNdbError().code;
DBUG_RETURN(-1);
}
- if (setTupleIdInNdb(info, tupleId, increase) == -1)
+ if (setTupleIdInNdb(info, autoValue, modify) == -1)
DBUG_RETURN(-1);
DBUG_RETURN(0);
}
int
Ndb::setTupleIdInNdb(Ndb_local_table_info* info,
- Uint64 tupleId, bool increase)
+ Uint64 tupleId, bool modify)
{
DBUG_ENTER("Ndb::setTupleIdInNdb");
- if (increase)
+ if (modify)
{
- if (info->m_first_tuple_id != info->m_last_tuple_id)
+ if (checkTupleIdInNdb(info, tupleId))
{
- assert(info->m_first_tuple_id < info->m_last_tuple_id);
- if (tupleId <= info->m_first_tuple_id + 1)
- DBUG_RETURN(0);
- if (tupleId <= info->m_last_tuple_id)
+ if (info->m_first_tuple_id != info->m_last_tuple_id)
{
- info->m_first_tuple_id = tupleId - 1;
- DBUG_PRINT("info",
- ("Setting next auto increment cached value to %lu",
- (ulong)tupleId));
- DBUG_RETURN(0);
+ assert(info->m_first_tuple_id < info->m_last_tuple_id);
+ if (tupleId <= info->m_first_tuple_id + 1)
+ DBUG_RETURN(0);
+ if (tupleId <= info->m_last_tuple_id)
+ {
+ info->m_first_tuple_id = tupleId - 1;
+ DBUG_PRINT("info",
+ ("Setting next auto increment cached value to %lu",
+ (ulong)tupleId));
+ DBUG_RETURN(0);
+ }
}
+ /*
+ * if tupleId <= NEXTID, do nothing. otherwise update NEXTID to
+ * tupleId and set cached range to first = last = tupleId - 1.
+ */
+ Uint64 opValue = tupleId;
+ if (opTupleIdOnNdb(info, opValue, 2) == -1)
+ DBUG_RETURN(-1);
}
- /*
- * if tupleId <= NEXTID, do nothing. otherwise update NEXTID to
- * tupleId and set cached range to first = last = tupleId - 1.
- */
- if (opTupleIdOnNdb(info, tupleId, 2) == -1)
- DBUG_RETURN(-1);
}
else
{
@@ -1034,6 +1059,32 @@ Ndb::setTupleIdInNdb(Ndb_local_table_info* info,
}
int
+Ndb::checkTupleIdInNdb(Ndb_local_table_info* info, Uint64 tupleId)
+{
+ DBUG_ENTER("Ndb::checkTupleIdIndNdb");
+ if ((info->m_first_tuple_id != ~(Uint64)0) &&
+ (info->m_first_tuple_id > tupleId))
+ {
+ /*
+ * If we have ever cached a value in this object and this cached
+ * value is larger than the value we're trying to set then we
+ * need not check with the real value in the SYSTAB_0 table.
+ */
+ DBUG_RETURN(0);
+ }
+ if (info->m_highest_seen > tupleId)
+ {
+ /*
+ * Although we've never cached any higher value we have read
+ * a higher value and again it isn't necessary to change the
+ * auto increment value.
+ */
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(1);
+}
+
+int
Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op)
{
DBUG_ENTER("Ndb::opTupleIdOnNdb");
@@ -1094,6 +1145,7 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op)
info->m_first_tuple_id = ~(Uint64)0;
info->m_last_tuple_id = ~(Uint64)0;
+ info->m_highest_seen = 0;
break;
case 2:
tOperation->interpretedUpdateTuple();
@@ -1103,19 +1155,18 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op)
// compare NEXTID >= opValue
tOperation->branch_le(2, 1, 0);
tOperation->write_attr("NEXTID", 1);
- tOperation->interpret_exit_ok();
tOperation->def_label(0);
- tOperation->interpret_exit_nok(9999);
-
+ tOperation->interpret_exit_ok();
+ tRecAttrResult = tOperation->getValue("NEXTID");
if (tConnection->execute( Commit ) == -1)
{
- if (tConnection->theError.code != 9999)
- goto error_handler;
+ goto error_handler;
}
else
{
+ info->m_highest_seen = tRecAttrResult->u_64_value();
DBUG_PRINT("info",
- ("Setting next auto increment value (db) to %lu",
+ ("Setting auto increment value (db) to %lu",
(ulong)opValue));
info->m_first_tuple_id = info->m_last_tuple_id = opValue - 1;
}
@@ -1126,7 +1177,7 @@ Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op)
tRecAttrResult = tOperation->getValue("NEXTID");
if (tConnection->execute( Commit ) == -1 )
goto error_handler;
- opValue = tRecAttrResult->u_64_value(); // out
+ info->m_highest_seen = opValue = tRecAttrResult->u_64_value(); // out
break;
default:
goto error_handler;
@@ -1415,11 +1466,7 @@ Ndb::printState(const char* fmt, ...)
NdbMutex_Lock(ndb_print_state_mutex);
bool dups = false;
unsigned i;
- ndbout << buf << " ndb=" << hex << this << dec;
-#ifndef NDB_WIN32
- ndbout << " thread=" << (int)pthread_self();
-#endif
- ndbout << endl;
+ ndbout << buf << " ndb=" << hex << (void*)this << endl;
for (unsigned n = 0; n < MAX_NDB_NODES; n++) {
NdbTransaction* con = theConnectionArray[n];
if (con != 0) {
diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
index bf0c02714db..ecbf527c9ae 100644
--- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp
+++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
@@ -35,6 +35,7 @@
#include "NdbBlobImpl.hpp"
#include <AttributeHeader.hpp>
#include <my_sys.h>
+#include <NdbSleep.h>
#define DEBUG_PRINT 0
#define INCOMPATIBLE_VERSION -2
@@ -886,7 +887,23 @@ NdbDictInterface::dictSignal(NdbApiSignal* signal,
{
DBUG_ENTER("NdbDictInterface::dictSignal");
DBUG_PRINT("enter", ("useMasterNodeId: %d", useMasterNodeId));
- for(Uint32 i = 0; i<RETRIES; i++){
+
+ int sleep = 50;
+ int mod = 5;
+
+ for(Uint32 i = 0; i<RETRIES; i++)
+ {
+ if (i > 0)
+ NdbSleep_MilliSleep(sleep + 10 * (rand() % mod));
+ if (i == RETRIES / 2)
+ {
+ mod = 10;
+ }
+ if (i == 3*RETRIES/4)
+ {
+ sleep = 100;
+ }
+
//if (useMasterNodeId == 0)
m_buffer.clear();
diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c
index 4c60e384e6c..27b640489f6 100644
--- a/ndb/src/ndbapi/ndberror.c
+++ b/ndb/src/ndbapi/ndberror.c
@@ -291,6 +291,7 @@ ErrorBundle ErrorCodes[] = {
{ 242, AE, "Zero concurrency in scan"},
{ 244, AE, "Too high concurrency in scan"},
{ 269, AE, "No condition and attributes to read in scan"},
+ { 874, AE, "Too much attrinfo (e.g. scan filter) for scan in tuple manager" },
{ 4600, AE, "Transaction is already started"},
{ 4601, AE, "Transaction is not started"},
{ 4602, AE, "You must call getNdbOperation before executeScan" },
diff --git a/ndb/test/ndbapi/testBitfield.cpp b/ndb/test/ndbapi/testBitfield.cpp
index 8ba8f3d92ef..40a7a9d4557 100644
--- a/ndb/test/ndbapi/testBitfield.cpp
+++ b/ndb/test/ndbapi/testBitfield.cpp
@@ -4,6 +4,8 @@
#include <NDBT.hpp>
#include <NdbApi.hpp>
#include <HugoTransactions.hpp>
+#include <Bitmask.hpp>
+#include <Vector.hpp>
static const char* _dbname = "TEST_DB";
static int g_loops = 7;
@@ -37,6 +39,7 @@ static int unique_indexes(Ndb*, const NdbDictionary::Table* tab);
static int ordered_indexes(Ndb*, const NdbDictionary::Table* tab);
static int node_restart(Ndb*, const NdbDictionary::Table* tab);
static int system_restart(Ndb*, const NdbDictionary::Table* tab);
+static int testBitmask();
int
main(int argc, char** argv){
@@ -49,6 +52,15 @@ main(int argc, char** argv){
ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
+ int res = NDBT_FAILED;
+
+ /* Run cluster-independent tests */
+ for (int i=0; i<(10*g_loops); i++)
+ {
+ if (NDBT_OK != (res= testBitmask()))
+ return NDBT_ProgramExit(res);
+ }
+
Ndb_cluster_connection con(opt_connect_str);
if(con.connect(12, 5, 1))
{
@@ -60,7 +72,6 @@ main(int argc, char** argv){
pNdb = new Ndb(&con, _dbname);
pNdb->init();
while (pNdb->waitUntilReady() != 0);
- int res = NDBT_FAILED;
NdbDictionary::Dictionary * dict = pNdb->getDictionary();
@@ -121,14 +132,12 @@ create_random_table(Ndb* pNdb)
do {
NdbDictionary::Table tab;
Uint32 cols = 1 + (rand() % (NDB_MAX_ATTRIBUTES_IN_TABLE - 1));
- Uint32 keys = NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY;
Uint32 length = 4090;
- Uint32 key_size = NDB_MAX_KEYSIZE_IN_WORDS;
BaseString name;
name.assfmt("TAB_%d", rand() & 65535);
tab.setName(name.c_str());
- for(int i = 0; i<cols && length > 2; i++)
+ for(Uint32 i = 0; i<cols && length > 2; i++)
{
NdbDictionary::Column col;
name.assfmt("COL_%d", i);
@@ -206,3 +215,393 @@ system_restart(Ndb* pNdb, const NdbDictionary::Table* tab)
{
return 0;
}
+
+/* Note : folowing classes test functionality of storage/ndb/src/common/util/Bitmask.cpp
+ * and were originally defined there.
+ * Set BITMASK_DEBUG to 1 to get more test debugging info.
+ */
+#define BITMASK_DEBUG 0
+
+static
+bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len)
+{
+ Uint32 sz32 = (len + 31) >> 5;
+ for(Uint32 i = 0; i<len; i++)
+ {
+ if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i))
+ return false;
+ }
+ return true;
+}
+
+static
+void print(const Uint32 src[], Uint32 len, Uint32 pos = 0)
+{
+ printf("b'");
+ for(unsigned i = 0; i<len; i++)
+ {
+ if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos))
+ printf("1");
+ else
+ printf("0");
+ if((i & 31) == 31)
+ printf(" ");
+ }
+}
+
+static int lrand()
+{
+ return rand();
+}
+
+static
+void rand(Uint32 dst[], Uint32 len)
+{
+ for(Uint32 i = 0; i<len; i++)
+ BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500);
+}
+
+static
+int checkNoTramplingGetSetField(const Uint32 totalTests)
+{
+ const Uint32 numWords= 67;
+ const Uint32 maxBitsToCopy= (numWords * 32);
+ Uint32 sourceBuf[numWords];
+ Uint32 targetBuf[numWords];
+
+ ndbout << "Testing : Bitmask NoTrampling\n";
+
+ memset(sourceBuf, 0x00, (numWords*4));
+
+ for (Uint32 test=0; test<totalTests; test++)
+ {
+ /* Always copy at least 1 bit */
+ Uint32 srcStart= rand() % (maxBitsToCopy -1);
+ Uint32 length= (rand() % ((maxBitsToCopy -1) - srcStart)) + 1;
+
+ if (BITMASK_DEBUG)
+ ndbout << "Testing start %u, length %u \n"
+ << srcStart
+ << length;
+ // Set target to all ones.
+ memset(targetBuf, 0xff, (numWords*4));
+
+ BitmaskImpl::getField(numWords, sourceBuf, srcStart, length, targetBuf);
+
+ // Check that there is no trampling
+ Uint32 firstUntrampledWord= (length + 31)/32;
+
+ for (Uint32 word=0; word< numWords; word++)
+ {
+ Uint32 targetWord= targetBuf[word];
+ if (BITMASK_DEBUG)
+ ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
+ << word << targetWord << firstUntrampledWord;
+
+ if (! (word < firstUntrampledWord) ?
+ (targetWord == 0) :
+ (targetWord == 0xffffffff))
+ {
+ ndbout << "Notrampling getField failed for srcStart "
+ << srcStart
+ << " length " << length
+ << " at word " << word << "\n";
+ ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
+ << word << targetWord << firstUntrampledWord;
+ return -1;
+ }
+
+ }
+
+ /* Set target back to all ones. */
+ memset(targetBuf, 0xff, (numWords*4));
+
+ BitmaskImpl::setField(numWords, targetBuf, srcStart, length, sourceBuf);
+
+ /* Check we've got all ones, with zeros only where expected */
+ for (Uint32 word=0; word< numWords; word++)
+ {
+ Uint32 targetWord= targetBuf[word];
+
+ for (Uint32 bit=0; bit< 32; bit++)
+ {
+ Uint32 bitNum= (word << 5) + bit;
+ bool expectedValue= !((bitNum >= srcStart) &&
+ (bitNum < (srcStart + length)));
+ bool actualValue= (((targetWord >> bit) & 1) == 1);
+ if (BITMASK_DEBUG)
+ ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
+ << bitNum << expectedValue << actualValue;
+
+ if (actualValue != expectedValue)
+ {
+ ndbout << "Notrampling setField failed for srcStart "
+ << srcStart
+ << " length " << length
+ << " at word " << word << " bit " << bit << "\n";
+ ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
+ << bitNum << expectedValue << actualValue;
+ return -1;
+ }
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+static
+int simple(int pos, int size)
+{
+ ndbout << "Testing : Bitmask simple pos: " << pos << " size: " << size << "\n";
+ Vector<Uint32> _mask;
+ Vector<Uint32> _src;
+ Vector<Uint32> _dst;
+ Uint32 sz32 = (size + pos + 32) >> 5;
+ const Uint32 sz = 4 * sz32;
+
+ Uint32 zero = 0;
+ _mask.fill(sz32+1, zero);
+ _src.fill(sz32+1, zero);
+ _dst.fill(sz32+1, zero);
+
+ Uint32 * src = _src.getBase();
+ Uint32 * dst = _dst.getBase();
+ Uint32 * mask = _mask.getBase();
+
+ memset(src, 0x0, sz);
+ memset(dst, 0x0, sz);
+ memset(mask, 0xFF, sz);
+ rand(src, size);
+ BitmaskImpl::setField(sz32, mask, pos, size, src);
+ BitmaskImpl::getField(sz32, mask, pos, size, dst);
+ if (BITMASK_DEBUG)
+ {
+ printf("src: "); print(src, size+31); printf("\n");
+ printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n");
+ printf("dst: "); print(dst, size+31); printf("\n");
+ }
+ return (cmp(src, dst, size+31)?0 : -1);
+};
+
+struct Alloc
+{
+ Uint32 pos;
+ Uint32 size;
+ Vector<Uint32> data;
+};
+
+static
+int
+testRanges(Uint32 bitmask_size)
+{
+ Vector<Alloc> alloc_list;
+ bitmask_size = (bitmask_size + 31) & ~31;
+ Uint32 sz32 = (bitmask_size >> 5);
+ Vector<Uint32> alloc_mask;
+ Vector<Uint32> test_mask;
+
+ ndbout_c("Testing : Bitmask ranges for bitmask of size %d", bitmask_size);
+ Uint32 zero = 0;
+ alloc_mask.fill(sz32, zero);
+ test_mask.fill(sz32, zero);
+
+ /* Loop a number of times, setting and clearing bits in the mask
+ * and tracking the modifications in a separate structure.
+ * Check that both structures remain in sync
+ */
+ for(int i = 0; i<5000; i++)
+ {
+ Vector<Uint32> tmp;
+ tmp.fill(sz32, zero);
+
+ Uint32 pos = lrand() % (bitmask_size - 1);
+ Uint32 free = 0;
+ if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos))
+ {
+ // Bit was allocated
+ // 1) Look up allocation
+ // 2) Check data
+ // 3) free it
+ size_t j;
+ Uint32 min, max;
+ for(j = 0; j<alloc_list.size(); j++)
+ {
+ min = alloc_list[j].pos;
+ max = min + alloc_list[j].size;
+ if(pos >= min && pos < max)
+ {
+ break;
+ }
+ }
+ if (! ((pos >= min) && (pos < max)))
+ {
+ printf("Failed with pos %u, min %u, max %u\n",
+ pos, min, max);
+ return -1;
+ }
+ BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min,
+ tmp.getBase());
+ if(BITMASK_DEBUG)
+ {
+ printf("freeing [ %d %d ]", min, max);
+ printf("- mask: ");
+ print(tmp.getBase(), max - min);
+
+ printf(" save: ");
+ size_t k;
+ Alloc& a = alloc_list[j];
+ for(k = 0; k<a.data.size(); k++)
+ printf("%.8x ", a.data[k]);
+ printf("\n");
+ }
+ if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min))
+ {
+ return -1;
+ }
+ while(min < max)
+ BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++);
+ alloc_list.erase(j);
+ }
+ else
+ {
+ Vector<Uint32> tmp;
+ tmp.fill(sz32, zero);
+
+ // Bit was free
+ // 1) Check how much space is avaiable
+ // 2) Create new allocation of lrandom size
+ // 3) Fill data with lrandom data
+ // 4) Update alloc mask
+ while(pos+free < bitmask_size &&
+ !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free))
+ free++;
+
+ Uint32 sz =
+ (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free);
+ sz = sz ? sz : 1;
+ sz = pos + sz == bitmask_size ? sz - 1 : sz;
+ Alloc a;
+ a.pos = pos;
+ a.size = sz;
+ a.data.fill(((sz+31)>> 5)-1, zero);
+ if(BITMASK_DEBUG)
+ printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz);
+ for(size_t j = 0; j<sz; j++)
+ {
+ BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j);
+ if((lrand() % 1000) > 500)
+ BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j);
+ }
+ if(BITMASK_DEBUG)
+ {
+ printf("- mask: ");
+ print(a.data.getBase(), sz);
+ printf("\n");
+ }
+ BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz,
+ a.data.getBase());
+ alloc_list.push_back(a);
+ }
+ }
+
+#ifdef NDB_BM_SUPPORT_RANGE
+ for(Uint32 i = 0; i<1000; i++)
+ {
+ Uint32 sz32 = 10+rand() % 100;
+ Uint32 zero = 0;
+ Vector<Uint32> map;
+ map.fill(sz32, zero);
+
+ Uint32 sz = 32 * sz32;
+ Uint32 start = (rand() % sz);
+ Uint32 stop = start + ((rand() % (sz - start)) & 0xFFFFFFFF);
+
+ Vector<Uint32> check;
+ check.fill(sz32, zero);
+
+ /* Verify range setting method works correctly */
+ for(Uint32 j = 0; j<sz; j++)
+ {
+ bool expect = (j >= start && j<stop);
+ if(expect)
+ BitmaskImpl::set(sz32, check.getBase(), j);
+ }
+
+ BitmaskImpl::set_range(sz32, map.getBase(), start, stop);
+ if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
+ {
+ ndbout_c(" FAIL 1 sz: %d [ %d %d ]", sz, start, stop);
+ printf("check: ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", check[j]);
+ printf("\n");
+
+ printf("map : ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", map[j]);
+ printf("\n");
+ return -1;
+ }
+
+ map.clear();
+ check.clear();
+
+ /* Verify range clearing method works correctly */
+ Uint32 one = ~(Uint32)0;
+ map.fill(sz32, one);
+ check.fill(sz32, one);
+
+ for(Uint32 j = 0; j<sz; j++)
+ {
+ bool expect = (j >= start && j<stop);
+ if(expect)
+ BitmaskImpl::clear(sz32, check.getBase(), j);
+ }
+
+ BitmaskImpl::clear_range(sz32, map.getBase(), start, stop);
+ if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
+ {
+ ndbout_c(" FAIL 2 sz: %d [ %d %d ]", sz, start, stop);
+ printf("check: ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", check[j]);
+ printf("\n");
+
+ printf("map : ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", map[j]);
+ printf("\n");
+ return -1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static
+int
+testBitmask()
+{
+ /* Some testcases from storage/ndb/src/common/util/Bitmask.cpp */
+ int res= 0;
+
+ if ((res= checkNoTramplingGetSetField(100 /* totalTests */)) != 0)
+ return res;
+
+ if ((res= simple(rand() % 33, // position
+ (rand() % 63)+1) // size
+ ) != 0)
+ return res;
+
+ if ((res= testRanges(1+(rand() % 1000) // bitmask size
+ )) != 0)
+ return res;
+
+ return 0;
+}
+
+template class Vector<Alloc>;
+template class Vector<Uint32>;
diff --git a/ndb/test/ndbapi/testInterpreter.cpp b/ndb/test/ndbapi/testInterpreter.cpp
index 0dc032ba7aa..22b810107b4 100644
--- a/ndb/test/ndbapi/testInterpreter.cpp
+++ b/ndb/test/ndbapi/testInterpreter.cpp
@@ -77,6 +77,11 @@ int runTestIncValue32(NDBT_Context* ctx, NDBT_Step* step){
const NdbDictionary::Table * pTab = ctx->getTab();
Ndb* pNdb = GETNDB(step);
+ if (strcmp(pTab->getName(), "T1") != 0) {
+ g_err << "runTestBug19537: skip, table != T1" << endl;
+ return NDBT_OK;
+ }
+
NdbConnection* pTrans = pNdb->startTransaction();
if (pTrans == NULL){
@@ -258,6 +263,84 @@ int runTestBug19537(NDBT_Context* ctx, NDBT_Step* step){
}
+int runTestBug34107(NDBT_Context* ctx, NDBT_Step* step){
+ int result = NDBT_OK;
+ const NdbDictionary::Table * pTab = ctx->getTab();
+ Ndb* pNdb = GETNDB(step);
+
+ int i;
+ for (i = 0; i <= 1; i++) {
+ g_info << "bug34107:" << (i == 0 ? " small" : " too big") << endl;
+
+ NdbConnection* pTrans = pNdb->startTransaction();
+ if (pTrans == NULL){
+ ERR(pNdb->getNdbError());
+ return NDBT_FAILED;
+ }
+
+ NdbScanOperation* pOp = pTrans->getNdbScanOperation(pTab->getName());
+ if (pOp == NULL) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ if (pOp->readTuples() == -1) {
+ ERR(pOp->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ int n = i == 0 ? 10000 : 30000;
+ int k;
+
+ for (k = 0; k < n; k++) {
+
+ // inserts 1 word ATTRINFO
+
+ if (pOp->interpret_exit_ok() == -1) {
+ ERR(pOp->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+ }
+
+ if (pTrans->execute(NoCommit) == -1) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ int ret;
+ while ((ret = pOp->nextResult()) == 0)
+ ;
+ g_info << "ret=" << ret << " err=" << pOp->getNdbError().code << endl;
+
+ if (i == 0 && ret != 1) {
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ if (i == 1 && ret != -1) {
+ g_err << "unexpected big filter success" << endl;
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+ if (i == 1 && pOp->getNdbError().code != 874) {
+ g_err << "unexpected big filter error code, wanted 874" << endl;
+ ERR(pTrans->getNdbError());
+ pNdb->closeTransaction(pTrans);
+ return NDBT_FAILED;
+ }
+
+ pNdb->closeTransaction(pTrans);
+ }
+
+ return NDBT_OK;
+}
+
+
NDBT_TESTSUITE(testInterpreter);
TESTCASE("IncValue32",
"Test incValue for 32 bit integer\n"){
@@ -277,6 +360,12 @@ TESTCASE("Bug19537",
INITIALIZER(runTestBug19537);
FINALIZER(runClearTable);
}
+TESTCASE("Bug34107",
+ "Test too big scan filter (error 874)\n"){
+ INITIALIZER(runLoadTable);
+ INITIALIZER(runTestBug34107);
+ FINALIZER(runClearTable);
+}
#if 0
TESTCASE("MaxTransactions",
"Start transactions until no more can be created\n"){
diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp
index 8f77f0bb062..4e1c8400768 100644
--- a/ndb/test/ndbapi/testOIBasic.cpp
+++ b/ndb/test/ndbapi/testOIBasic.cpp
@@ -36,10 +36,11 @@
struct Opt {
// common options
- unsigned m_batch;
+ uint m_batch;
const char* m_bound;
const char* m_case;
bool m_collsp;
+ bool m_cont;
bool m_core;
const char* m_csname;
CHARSET_INFO* m_cs;
@@ -47,26 +48,29 @@ struct Opt {
bool m_dups;
NdbDictionary::Object::FragmentType m_fragtype;
const char* m_index;
- unsigned m_loop;
+ uint m_loop;
bool m_msglock;
bool m_nologging;
bool m_noverify;
- unsigned m_pctnull;
- unsigned m_rows;
- unsigned m_samples;
- unsigned m_scanbatch;
- unsigned m_scanpar;
- unsigned m_scanstop;
+ uint m_pctnull;
+ uint m_rows;
+ uint m_samples;
+ uint m_scanbatch;
+ uint m_scanpar;
+ uint m_scanstop;
int m_seed;
- unsigned m_subloop;
+ const char* m_skip;
+ uint m_sloop;
+ uint m_ssloop;
const char* m_table;
- unsigned m_threads;
+ uint m_threads;
int m_v; // int for lint
Opt() :
m_batch(32),
m_bound("01234"),
m_case(0),
m_collsp(false),
+ m_cont(false),
m_core(false),
m_csname("random"),
m_cs(0),
@@ -85,7 +89,9 @@ struct Opt {
m_scanpar(0),
m_scanstop(0),
m_seed(-1),
- m_subloop(4),
+ m_skip(0),
+ m_sloop(4),
+ m_ssloop(4),
m_table(0),
m_threads(4),
m_v(1) {
@@ -107,6 +113,7 @@ printhelp()
<< " -bound xyz use only these bound types 0-4 [" << d.m_bound << "]" << endl
<< " -case abc only given test cases (letters a-z)" << endl
<< " -collsp use strnncollsp instead of strnxfrm" << endl
+ << " -cont on error continue to next test case [" << d.m_cont << "]" << endl
<< " -core core dump on error [" << d.m_core << "]" << endl
<< " -csname S charset or collation [" << d.m_csname << "]" << endl
<< " -die nnn exit immediately on NDB error code nnn" << endl
@@ -122,7 +129,9 @@ printhelp()
<< " -scanbatch N scan batch 0=default [" << d.m_scanbatch << "]" << endl
<< " -scanpar N scan parallel 0=default [" << d.m_scanpar << "]" << endl
<< " -seed N srandom seed 0=loop number -1=random [" << d.m_seed << "]" << endl
- << " -subloop N subtest (and subsubtest) loop count [" << d.m_subloop << "]" << endl
+ << " -skip abc skip given test cases (letters a-z)" << endl
+ << " -sloop N level 2 (sub)loop count [" << d.m_sloop << "]" << endl
+ << " -ssloop N level 3 (sub)loop count [" << d.m_ssloop << "]" << endl
<< " -table xyz only given table numbers (digits 0-9)" << endl
<< " -threads N number of threads [" << d.m_threads << "]" << endl
<< " -vN verbosity [" << d.m_v << "]" << endl
@@ -142,17 +151,17 @@ static const char* hexstr = "0123456789abcdef";
// random ints
-static unsigned
-urandom(unsigned n)
+static uint
+urandom(uint n)
{
if (n == 0)
return 0;
- unsigned i = random() % n;
+ uint i = random() % n;
return i;
}
static int
-irandom(unsigned n)
+irandom(uint n)
{
if (n == 0)
return 0;
@@ -163,7 +172,7 @@ irandom(unsigned n)
}
static bool
-randompct(unsigned pct)
+randompct(uint pct)
{
if (pct == 0)
return false;
@@ -172,15 +181,15 @@ randompct(unsigned pct)
return urandom(100) < pct;
}
-static unsigned
-random_coprime(unsigned n)
+static uint
+random_coprime(uint n)
{
- unsigned prime[] = { 101, 211, 307, 401, 503, 601, 701, 809, 907 };
- unsigned count = sizeof(prime) / sizeof(prime[0]);
+ uint prime[] = { 101, 211, 307, 401, 503, 601, 701, 809, 907 };
+ uint count = sizeof(prime) / sizeof(prime[0]);
if (n == 0)
return 0;
while (1) {
- unsigned i = urandom(count);
+ uint i = urandom(count);
if (n % prime[i] != 0)
return prime[i];
}
@@ -189,16 +198,16 @@ random_coprime(unsigned n)
// random re-sequence of 0...(n-1)
struct Rsq {
- Rsq(unsigned n);
- unsigned next();
+ Rsq(uint n);
+ uint next();
private:
- unsigned m_n;
- unsigned m_i;
- unsigned m_start;
- unsigned m_prime;
+ uint m_n;
+ uint m_i;
+ uint m_start;
+ uint m_prime;
};
-Rsq::Rsq(unsigned n)
+Rsq::Rsq(uint n)
{
m_n = n;
m_i = 0;
@@ -206,7 +215,7 @@ Rsq::Rsq(unsigned n)
m_prime = random_coprime(n);
}
-unsigned
+uint
Rsq::next()
{
assert(m_n != 0);
@@ -216,30 +225,16 @@ Rsq::next()
// log and error macros
static NdbMutex *ndbout_mutex = NULL;
-
-static unsigned getthrno();
-
-static const char*
-getthrstr()
-{
- static char buf[20];
- unsigned n = getthrno();
- if (n == (unsigned)-1)
- strcpy(buf, "");
- else {
- unsigned m =
- g_opt.m_threads < 10 ? 1 :
- g_opt.m_threads < 100 ? 2 : 3;
- sprintf(buf, "[%0*u] ", m, n);
- }
- return buf;
-}
+static const char* getthrprefix();
#define LLN(n, s) \
do { \
if ((n) > g_opt.m_v) break; \
if (g_opt.m_msglock) NdbMutex_Lock(ndbout_mutex); \
- ndbout << getthrstr() << s << endl; \
+ ndbout << getthrprefix(); \
+ if ((n) > 2) \
+ ndbout << "line " << __LINE__ << ": "; \
+ ndbout << s << endl; \
if (g_opt.m_msglock) NdbMutex_Unlock(ndbout_mutex); \
} while(0)
@@ -250,6 +245,8 @@ getthrstr()
#define LL4(s) LLN(4, s)
#define LL5(s) LLN(5, s)
+#define HEX(x) hex << (x) << dec
+
// following check a condition and return -1 on failure
#undef CHK // simple check
@@ -281,53 +278,58 @@ getthrstr()
class Thr;
class Con;
class Tab;
+class ITab;
class Set;
class Tmr;
struct Par : public Opt {
- unsigned m_no;
+ uint m_no;
Con* m_con;
Con& con() const { assert(m_con != 0); return *m_con; }
const Tab* m_tab;
const Tab& tab() const { assert(m_tab != 0); return *m_tab; }
+ const ITab* m_itab;
+ const ITab& itab() const { assert(m_itab != 0); return *m_itab; }
Set* m_set;
Set& set() const { assert(m_set != 0); return *m_set; }
Tmr* m_tmr;
Tmr& tmr() const { assert(m_tmr != 0); return *m_tmr; }
char m_currcase[2];
- unsigned m_lno;
- unsigned m_slno;
- unsigned m_totrows;
+ uint m_lno;
+ uint m_slno;
+ uint m_totrows;
// value calculation
- unsigned m_range;
- unsigned m_pctrange;
- unsigned m_pctbrange;
+ uint m_range;
+ uint m_pctrange;
+ uint m_pctbrange;
int m_bdir;
bool m_noindexkeyupdate;
// choice of key
bool m_randomkey;
// do verify after read
bool m_verify;
- // deadlock possible
- bool m_deadlock;
- // abort percentabge
- unsigned m_abortpct;
+ // errors to catch (see Con)
+ bool m_catcherr;
+ // abort percentage
+ uint m_abortpct;
NdbOperation::LockMode m_lockmode;
// scan options
bool m_tupscan;
bool m_ordered;
bool m_descending;
- // timer location
+ // threads used by current test case
+ uint m_usedthreads;
Par(const Opt& opt) :
Opt(opt),
m_no(0),
m_con(0),
m_tab(0),
+ m_itab(0),
m_set(0),
m_tmr(0),
m_lno(0),
m_slno(0),
- m_totrows(m_threads * m_rows),
+ m_totrows(0),
m_range(m_rows),
m_pctrange(40),
m_pctbrange(80),
@@ -335,39 +337,40 @@ struct Par : public Opt {
m_noindexkeyupdate(false),
m_randomkey(false),
m_verify(false),
- m_deadlock(false),
+ m_catcherr(0),
m_abortpct(0),
m_lockmode(NdbOperation::LM_Read),
m_tupscan(false),
m_ordered(false),
- m_descending(false)
+ m_descending(false),
+ m_usedthreads(0)
{
m_currcase[0] = 0;
}
};
static bool
-usetable(Par par, unsigned i)
+usetable(Par par, uint i)
{
return par.m_table == 0 || strchr(par.m_table, '0' + i) != 0;
}
static bool
-useindex(Par par, unsigned i)
+useindex(Par par, uint i)
{
return par.m_index == 0 || strchr(par.m_index, '0' + i) != 0;
}
-static unsigned
-thrrow(Par par, unsigned j)
+static uint
+thrrow(Par par, uint j)
{
- return par.m_threads * j + par.m_no;
+ return par.m_usedthreads * j + par.m_no;
}
static bool
-isthrrow(Par par, unsigned i)
+isthrrow(Par par, uint i)
{
- return i % par.m_threads == par.m_no;
+ return i % par.m_usedthreads == par.m_no;
}
// timer
@@ -375,13 +378,13 @@ isthrrow(Par par, unsigned i)
struct Tmr {
void clr();
void on();
- void off(unsigned cnt = 0);
+ void off(uint cnt = 0);
const char* time();
const char* pct(const Tmr& t1);
const char* over(const Tmr& t1);
NDB_TICKS m_on;
- unsigned m_ms;
- unsigned m_cnt;
+ uint m_ms;
+ uint m_cnt;
char m_time[100];
char m_text[100];
Tmr() { clr(); }
@@ -401,7 +404,7 @@ Tmr::on()
}
void
-Tmr::off(unsigned cnt)
+Tmr::off(uint cnt)
{
NDB_TICKS off = NdbTick_CurrentMillisecond();
assert(m_on != 0 && off >= m_on);
@@ -446,53 +449,18 @@ Tmr::over(const Tmr& t1)
return m_text;
}
-// list of ints
-
-struct Lst {
- Lst();
- unsigned m_arr[1000];
- unsigned m_cnt;
- void push(unsigned i);
- unsigned cnt() const;
- void reset();
-};
-
-Lst::Lst() :
- m_cnt(0)
-{
-}
-
-void
-Lst::push(unsigned i)
-{
- assert(m_cnt < sizeof(m_arr)/sizeof(m_arr[0]));
- m_arr[m_cnt++] = i;
-}
-
-unsigned
-Lst::cnt() const
-{
- return m_cnt;
-}
-
-void
-Lst::reset()
-{
- m_cnt = 0;
-}
-
// character sets
-static const unsigned maxcsnumber = 512;
-static const unsigned maxcharcount = 32;
-static const unsigned maxcharsize = 4;
-static const unsigned maxxmulsize = 8;
+static const uint maxcsnumber = 512;
+static const uint maxcharcount = 32;
+static const uint maxcharsize = 4;
+static const uint maxxmulsize = 8;
// single mb char
struct Chr {
- unsigned char m_bytes[maxcharsize];
- unsigned char m_xbytes[maxxmulsize * maxcharsize];
- unsigned m_size;
+ uchar m_bytes[maxcharsize];
+ uchar m_xbytes[maxxmulsize * maxcharsize];
+ uint m_size;
Chr();
};
@@ -506,7 +474,7 @@ Chr::Chr()
// charset and random valid chars to use
struct Chs {
CHARSET_INFO* m_cs;
- unsigned m_xmul;
+ uint m_xmul;
Chr* m_chr;
Chs(CHARSET_INFO* cs);
~Chs();
@@ -523,22 +491,22 @@ Chs::Chs(CHARSET_INFO* cs) :
m_xmul = 1;
assert(m_xmul <= maxxmulsize);
m_chr = new Chr [maxcharcount];
- unsigned i = 0;
- unsigned miss1 = 0;
- unsigned miss2 = 0;
- unsigned miss3 = 0;
- unsigned miss4 = 0;
+ uint i = 0;
+ uint miss1 = 0;
+ uint miss2 = 0;
+ uint miss3 = 0;
+ uint miss4 = 0;
while (i < maxcharcount) {
- unsigned char* bytes = m_chr[i].m_bytes;
- unsigned char* xbytes = m_chr[i].m_xbytes;
- unsigned& size = m_chr[i].m_size;
+ uchar* bytes = m_chr[i].m_bytes;
+ uchar* xbytes = m_chr[i].m_xbytes;
+ uint& size = m_chr[i].m_size;
bool ok;
size = m_cs->mbminlen + urandom(m_cs->mbmaxlen - m_cs->mbminlen + 1);
assert(m_cs->mbminlen <= size && size <= m_cs->mbmaxlen);
// prefer longer chars
if (size == m_cs->mbminlen && m_cs->mbminlen < m_cs->mbmaxlen && urandom(5) != 0)
continue;
- for (unsigned j = 0; j < size; j++) {
+ for (uint j = 0; j < size; j++) {
bytes[j] = urandom(256);
}
int not_used;
@@ -550,13 +518,13 @@ Chs::Chs(CHARSET_INFO* cs) :
}
// check no proper prefix wellformed
ok = true;
- for (unsigned j = 1; j < size; j++) {
+ for (uint j = 1; j < size; j++) {
if ((*cs->cset->well_formed_len)(cs, sbytes, sbytes + j, 1, &not_used) == j) {
ok = false;
break;
}
}
- if (! ok) {
+ if (!ok) {
miss2++;
continue;
}
@@ -566,37 +534,37 @@ Chs::Chs(CHARSET_INFO* cs) :
int xlen = (*cs->coll->strnxfrm)(cs, xbytes, m_xmul * size, bytes, size);
// check we got something
ok = false;
- for (unsigned j = 0; j < xlen; j++) {
+ for (uint j = 0; j < xlen; j++) {
if (xbytes[j] != 0) {
ok = true;
break;
}
}
- if (! ok) {
+ if (!ok) {
miss3++;
continue;
}
// check for duplicate (before normalize)
ok = true;
- for (unsigned j = 0; j < i; j++) {
+ for (uint j = 0; j < i; j++) {
const Chr& chr = m_chr[j];
if (chr.m_size == size && memcmp(chr.m_bytes, bytes, size) == 0) {
ok = false;
break;
}
}
- if (! ok) {
+ if (!ok) {
miss4++;
continue;
}
i++;
}
bool disorder = true;
- unsigned bubbles = 0;
+ uint bubbles = 0;
while (disorder) {
disorder = false;
- for (unsigned i = 1; i < maxcharcount; i++) {
- unsigned len = sizeof(m_chr[i].m_xbytes);
+ for (uint i = 1; i < maxcharcount; i++) {
+ uint len = sizeof(m_chr[i].m_xbytes);
if (memcmp(m_chr[i-1].m_xbytes, m_chr[i].m_xbytes, len) > 0) {
Chr chr = m_chr[i];
m_chr[i] = m_chr[i-1];
@@ -627,7 +595,7 @@ static Chs* cslist[maxcsnumber];
static void
resetcslist()
{
- for (unsigned i = 0; i < maxcsnumber; i++) {
+ for (uint i = 0; i < maxcsnumber; i++) {
delete cslist[i];
cslist[i] = 0;
}
@@ -641,7 +609,7 @@ getcs(Par par)
cs = par.m_cs;
} else {
while (1) {
- unsigned n = urandom(maxcsnumber);
+ uint n = urandom(maxcsnumber);
cs = get_charset(n, MYF(0));
if (cs != 0) {
// prefer complex charsets
@@ -667,24 +635,24 @@ struct Col {
Longvarchar = NdbDictionary::Column::Longvarchar
};
const class Tab& m_tab;
- unsigned m_num;
+ uint m_num;
const char* m_name;
bool m_pk;
Type m_type;
- unsigned m_length;
- unsigned m_bytelength; // multiplied by char width
- unsigned m_attrsize; // base type size
- unsigned m_headsize; // length bytes
- unsigned m_bytesize; // full value size
+ uint m_length;
+ uint m_bytelength; // multiplied by char width
+ uint m_attrsize; // base type size
+ uint m_headsize; // length bytes
+ uint m_bytesize; // full value size
bool m_nullable;
const Chs* m_chs;
- Col(const class Tab& tab, unsigned num, const char* name, bool pk, Type type, unsigned length, bool nullable, const Chs* chs);
+ Col(const class Tab& tab, uint num, const char* name, bool pk, Type type, uint length, bool nullable, const Chs* chs);
~Col();
bool equal(const Col& col2) const;
void wellformed(const void* addr) const;
};
-Col::Col(const class Tab& tab, unsigned num, const char* name, bool pk, Type type, unsigned length, bool nullable, const Chs* chs) :
+Col::Col(const class Tab& tab, uint num, const char* name, bool pk, Type type, uint length, bool nullable, const Chs* chs) :
m_tab(tab),
m_num(num),
m_name(strcpy(new char [strlen(name) + 1], name)),
@@ -735,7 +703,7 @@ Col::wellformed(const void* addr) const
{
CHARSET_INFO* cs = m_chs->m_cs;
const char* src = (const char*)addr;
- unsigned len = m_bytelength;
+ uint len = m_bytelength;
int not_used;
assert((*cs->cset->well_formed_len)(cs, src, src + len, 0xffff, &not_used) == len);
}
@@ -743,9 +711,9 @@ Col::wellformed(const void* addr) const
case Col::Varchar:
{
CHARSET_INFO* cs = m_chs->m_cs;
- const unsigned char* src = (const unsigned char*)addr;
+ const uchar* src = (const uchar*)addr;
const char* ssrc = (const char*)src;
- unsigned len = src[0];
+ uint len = src[0];
int not_used;
assert(len <= m_bytelength);
assert((*cs->cset->well_formed_len)(cs, ssrc + 1, ssrc + 1 + len, 0xffff, &not_used) == len);
@@ -754,9 +722,9 @@ Col::wellformed(const void* addr) const
case Col::Longvarchar:
{
CHARSET_INFO* cs = m_chs->m_cs;
- const unsigned char* src = (const unsigned char*)addr;
+ const uchar* src = (const uchar*)addr;
const char* ssrc = (const char*)src;
- unsigned len = src[0] + (src[1] << 8);
+ uint len = src[0] + (src[1] << 8);
int not_used;
assert(len <= m_bytelength);
assert((*cs->cset->well_formed_len)(cs, ssrc + 2, ssrc + 2 + len, 0xffff, &not_used) == len);
@@ -774,7 +742,7 @@ operator<<(NdbOut& out, const Col& col)
out << "col[" << col.m_num << "] " << col.m_name;
switch (col.m_type) {
case Col::Unsigned:
- out << " unsigned";
+ out << " uint";
break;
case Col::Char:
{
@@ -808,13 +776,13 @@ operator<<(NdbOut& out, const Col& col)
struct ICol {
const class ITab& m_itab;
- unsigned m_num;
+ uint m_num;
const Col& m_col;
- ICol(const class ITab& itab, unsigned num, const Col& col);
+ ICol(const class ITab& itab, uint num, const Col& col);
~ICol();
};
-ICol::ICol(const class ITab& itab, unsigned num, const Col& col) :
+ICol::ICol(const class ITab& itab, uint num, const Col& col) :
m_itab(itab),
m_num(num),
m_col(col)
@@ -842,47 +810,47 @@ struct ITab {
const class Tab& m_tab;
const char* m_name;
Type m_type;
- unsigned m_icols;
+ uint m_icols;
const ICol** m_icol;
- unsigned m_colmask;
- ITab(const class Tab& tab, const char* name, Type type, unsigned icols);
+ uint m_keymask;
+ ITab(const class Tab& tab, const char* name, Type type, uint icols);
~ITab();
- void icoladd(unsigned k, const ICol* icolptr);
+ void icoladd(uint k, const ICol* icolptr);
};
-ITab::ITab(const class Tab& tab, const char* name, Type type, unsigned icols) :
+ITab::ITab(const class Tab& tab, const char* name, Type type, uint icols) :
m_tab(tab),
m_name(strcpy(new char [strlen(name) + 1], name)),
m_type(type),
m_icols(icols),
m_icol(new const ICol* [icols + 1]),
- m_colmask(0)
+ m_keymask(0)
{
- for (unsigned k = 0; k <= m_icols; k++)
+ for (uint k = 0; k <= m_icols; k++)
m_icol[k] = 0;
}
ITab::~ITab()
{
delete [] m_name;
- for (unsigned i = 0; i < m_icols; i++)
+ for (uint i = 0; i < m_icols; i++)
delete m_icol[i];
delete [] m_icol;
}
void
-ITab::icoladd(unsigned k, const ICol* icolptr)
+ITab::icoladd(uint k, const ICol* icolptr)
{
assert(k == icolptr->m_num && k < m_icols && m_icol[k] == 0);
m_icol[k] = icolptr;
- m_colmask |= (1 << icolptr->m_col.m_num);
+ m_keymask |= (1 << icolptr->m_col.m_num);
}
static NdbOut&
operator<<(NdbOut& out, const ITab& itab)
{
out << "itab " << itab.m_name << " icols=" << itab.m_icols;
- for (unsigned k = 0; k < itab.m_icols; k++) {
+ for (uint k = 0; k < itab.m_icols; k++) {
const ICol& icol = *itab.m_icol[k];
out << endl << icol;
}
@@ -893,56 +861,60 @@ operator<<(NdbOut& out, const ITab& itab)
struct Tab {
const char* m_name;
- unsigned m_cols;
+ uint m_cols;
const Col** m_col;
- unsigned m_itabs;
+ uint m_pkmask;
+ uint m_itabs;
const ITab** m_itab;
- unsigned m_orderedindexes;
- unsigned m_hashindexes;
+ uint m_orderedindexes;
+ uint m_hashindexes;
// pk must contain an Unsigned column
- unsigned m_keycol;
- void coladd(unsigned k, Col* colptr);
- void itabadd(unsigned j, ITab* itab);
- Tab(const char* name, unsigned cols, unsigned itabs, unsigned keycol);
+ uint m_keycol;
+ void coladd(uint k, Col* colptr);
+ void itabadd(uint j, ITab* itab);
+ Tab(const char* name, uint cols, uint itabs, uint keycol);
~Tab();
};
-Tab::Tab(const char* name, unsigned cols, unsigned itabs, unsigned keycol) :
+Tab::Tab(const char* name, uint cols, uint itabs, uint keycol) :
m_name(strcpy(new char [strlen(name) + 1], name)),
m_cols(cols),
m_col(new const Col* [cols + 1]),
+ m_pkmask(0),
m_itabs(itabs),
m_itab(new const ITab* [itabs + 1]),
m_orderedindexes(0),
m_hashindexes(0),
m_keycol(keycol)
{
- for (unsigned k = 0; k <= cols; k++)
+ for (uint k = 0; k <= cols; k++)
m_col[k] = 0;
- for (unsigned j = 0; j <= itabs; j++)
+ for (uint j = 0; j <= itabs; j++)
m_itab[j] = 0;
}
Tab::~Tab()
{
delete [] m_name;
- for (unsigned i = 0; i < m_cols; i++)
+ for (uint i = 0; i < m_cols; i++)
delete m_col[i];
delete [] m_col;
- for (unsigned i = 0; i < m_itabs; i++)
+ for (uint i = 0; i < m_itabs; i++)
delete m_itab[i];
delete [] m_itab;
}
void
-Tab::coladd(unsigned k, Col* colptr)
+Tab::coladd(uint k, Col* colptr)
{
assert(k == colptr->m_num && k < m_cols && m_col[k] == 0);
m_col[k] = colptr;
+ if (colptr->m_pk)
+ m_pkmask |= (1 << k);
}
void
-Tab::itabadd(unsigned j, ITab* itabptr)
+Tab::itabadd(uint j, ITab* itabptr)
{
assert(j < m_itabs && m_itab[j] == 0 && itabptr != 0);
m_itab[j] = itabptr;
@@ -956,11 +928,11 @@ static NdbOut&
operator<<(NdbOut& out, const Tab& tab)
{
out << "tab " << tab.m_name << " cols=" << tab.m_cols;
- for (unsigned k = 0; k < tab.m_cols; k++) {
+ for (uint k = 0; k < tab.m_cols; k++) {
const Col& col = *tab.m_col[k];
out << endl << col;
}
- for (unsigned i = 0; i < tab.m_itabs; i++) {
+ for (uint i = 0; i < tab.m_itabs; i++) {
if (tab.m_itab[i] == 0)
continue;
const ITab& itab = *tab.m_itab[i];
@@ -972,20 +944,20 @@ operator<<(NdbOut& out, const Tab& tab)
// make table structs
static const Tab** tablist = 0;
-static unsigned tabcount = 0;
+static uint tabcount = 0;
static void
verifytables()
{
- for (unsigned j = 0; j < tabcount; j++) {
+ for (uint j = 0; j < tabcount; j++) {
const Tab* t = tablist[j];
if (t == 0)
continue;
assert(t->m_cols != 0 && t->m_col != 0);
- for (unsigned k = 0; k < t->m_cols; k++) {
+ for (uint k = 0; k < t->m_cols; k++) {
const Col* c = t->m_col[k];
assert(c != 0 && c->m_num == k);
- assert(! (c->m_pk && c->m_nullable));
+ assert(!(c->m_pk && c->m_nullable));
}
assert(t->m_col[t->m_cols] == 0);
{
@@ -994,16 +966,16 @@ verifytables()
assert(c->m_pk && c->m_type == Col::Unsigned);
}
assert(t->m_itabs != 0 && t->m_itab != 0);
- for (unsigned i = 0; i < t->m_itabs; i++) {
+ for (uint i = 0; i < t->m_itabs; i++) {
const ITab* x = t->m_itab[i];
if (x == 0)
continue;
assert(x != 0 && x->m_icols != 0 && x->m_icol != 0);
- for (unsigned k = 0; k < x->m_icols; k++) {
+ for (uint k = 0; k < x->m_icols; k++) {
const ICol* c = x->m_icol[k];
assert(c != 0 && c->m_num == k && c->m_col.m_num < t->m_cols);
if (x->m_type == ITab::UniqueHashIndex) {
- assert(! c->m_col.m_nullable);
+ assert(!c->m_col.m_nullable);
}
}
}
@@ -1019,11 +991,11 @@ makebuiltintables(Par par)
tabcount = 3;
if (tablist == 0) {
tablist = new const Tab* [tabcount];
- for (unsigned j = 0; j < tabcount; j++) {
+ for (uint j = 0; j < tabcount; j++) {
tablist[j] = 0;
}
} else {
- for (unsigned j = 0; j < tabcount; j++) {
+ for (uint j = 0; j < tabcount; j++) {
delete tablist[j];
tablist[j] = 0;
}
@@ -1202,7 +1174,8 @@ static Ndb_cluster_connection* g_ncc = 0;
struct Con {
Ndb* m_ndb;
NdbDictionary::Dictionary* m_dic;
- NdbConnection* m_tx;
+ NdbTransaction* m_tx;
+ Uint64 m_txid;
NdbOperation* m_op;
NdbIndexOperation* m_indexop;
NdbScanOperation* m_scanop;
@@ -1210,10 +1183,16 @@ struct Con {
NdbScanFilter* m_scanfilter;
enum ScanMode { ScanNo = 0, Committed, Latest, Exclusive };
ScanMode m_scanmode;
- enum ErrType { ErrNone = 0, ErrDeadlock, ErrNospace, ErrOther };
+ enum ErrType {
+ ErrNone = 0,
+ ErrDeadlock = 1,
+ ErrNospace = 2,
+ ErrOther = 4
+ };
ErrType m_errtype;
+ char m_errname[100];
Con() :
- m_ndb(0), m_dic(0), m_tx(0), m_op(0), m_indexop(0),
+ m_ndb(0), m_dic(0), m_tx(0), m_txid(0), m_op(0), m_indexop(0),
m_scanop(0), m_indexscanop(0), m_scanfilter(0),
m_scanmode(ScanNo), m_errtype(ErrNone) {}
~Con() {
@@ -1237,18 +1216,20 @@ struct Con {
int setBound(int num, int type, const void* value);
int beginFilter(int group);
int endFilter();
- int setFilter(int num, int cond, const void* value, unsigned len);
- int execute(ExecType t);
- int execute(ExecType t, bool& deadlock, bool& nospace);
+ int setFilter(int num, int cond, const void* value, uint len);
+ int execute(ExecType et);
+ int execute(ExecType et, uint& err);
+ int readTuple(Par par);
int readTuples(Par par);
int readIndexTuples(Par par);
int executeScan();
int nextScanResult(bool fetchAllowed);
- int nextScanResult(bool fetchAllowed, bool& deadlock);
+ int nextScanResult(bool fetchAllowed, uint& err);
int updateScanTuple(Con& con2);
int deleteScanTuple(Con& con2);
void closeScan();
void closeTransaction();
+ const char* errname(uint err);
void printerror(NdbOut& out);
};
@@ -1259,7 +1240,7 @@ Con::connect()
m_ndb = new Ndb(g_ncc, "TEST_DB");
CHKCON(m_ndb->init() == 0, *this);
CHKCON(m_ndb->waitUntilReady(30) == 0, *this);
- m_tx = 0, m_op = 0;
+ m_tx = 0, m_txid = 0, m_op = 0;
return 0;
}
@@ -1274,7 +1255,7 @@ void
Con::disconnect()
{
delete m_ndb;
- m_ndb = 0, m_dic = 0, m_tx = 0, m_op = 0;
+ m_ndb = 0, m_dic = 0, m_tx = 0, m_txid = 0, m_op = 0;
}
int
@@ -1284,6 +1265,7 @@ Con::startTransaction()
if (m_tx != 0)
closeTransaction();
CHKCON((m_tx = m_ndb->startTransaction()) != 0, *this);
+ m_txid = m_tx->getTransactionId();
return 0;
}
@@ -1307,7 +1289,7 @@ int
Con::getNdbIndexOperation(const ITab& itab, const Tab& tab)
{
assert(m_tx != 0);
- unsigned tries = 0;
+ uint tries = 0;
while (1) {
if (getNdbIndexOperation1(itab, tab) == 0)
break;
@@ -1337,7 +1319,7 @@ int
Con::getNdbIndexScanOperation(const ITab& itab, const Tab& tab)
{
assert(m_tx != 0);
- unsigned tries = 0;
+ uint tries = 0;
while (1) {
if (getNdbIndexScanOperation1(itab, tab) == 0)
break;
@@ -1405,7 +1387,7 @@ Con::endFilter()
}
int
-Con::setFilter(int num, int cond, const void* value, unsigned len)
+Con::setFilter(int num, int cond, const void* value, uint len)
{
assert(m_tx != 0 && m_scanfilter != 0);
CHKCON(m_scanfilter->cmp((NdbScanFilter::BinaryCondition)cond, num, value, len) == 0, *this);
@@ -1413,34 +1395,46 @@ Con::setFilter(int num, int cond, const void* value, unsigned len)
}
int
-Con::execute(ExecType t)
+Con::execute(ExecType et)
{
assert(m_tx != 0);
- CHKCON(m_tx->execute(t) == 0, *this);
+ CHKCON(m_tx->execute(et) == 0, *this);
return 0;
}
int
-Con::execute(ExecType t, bool& deadlock, bool& nospace)
+Con::execute(ExecType et, uint& err)
{
- int ret = execute(t);
- if (ret != 0 && deadlock && m_errtype == ErrDeadlock) {
- LL3("caught deadlock");
- ret = 0;
- } else {
- deadlock = false;
- }
- if (ret != 0 && nospace && m_errtype == ErrNospace) {
- LL3("caught nospace");
- ret = 0;
- } else {
- nospace = false;
+ int ret = execute(et);
+ // err in: errors to catch, out: error caught
+ const uint errin = err;
+ err = 0;
+ if (ret == -1) {
+ if (m_errtype == ErrDeadlock && (errin & ErrDeadlock)) {
+ LL3("caught deadlock");
+ err = ErrDeadlock;
+ ret = 0;
+ }
+ if (m_errtype == ErrNospace && (errin & ErrNospace)) {
+ LL3("caught nospace");
+ err = ErrNospace;
+ ret = 0;
+ }
}
CHK(ret == 0);
return 0;
}
int
+Con::readTuple(Par par)
+{
+ assert(m_tx != 0 && m_op != 0);
+ NdbOperation::LockMode lm = par.m_lockmode;
+ CHKCON(m_op->readTuple(lm) == 0, *this);
+ return 0;
+}
+
+int
Con::readTuples(Par par)
{
assert(m_tx != 0 && m_scanop != 0);
@@ -1477,23 +1471,25 @@ Con::nextScanResult(bool fetchAllowed)
int ret;
assert(m_scanop != 0);
CHKCON((ret = m_scanop->nextResult(fetchAllowed)) != -1, *this);
- assert(ret == 0 || ret == 1 || (! fetchAllowed && ret == 2));
+ assert(ret == 0 || ret == 1 || (!fetchAllowed && ret == 2));
return ret;
}
int
-Con::nextScanResult(bool fetchAllowed, bool& deadlock)
+Con::nextScanResult(bool fetchAllowed, uint& err)
{
int ret = nextScanResult(fetchAllowed);
+ // err in: errors to catch, out: error caught
+ const uint errin = err;
+ err = 0;
if (ret == -1) {
- if (deadlock && m_errtype == ErrDeadlock) {
+ if (m_errtype == ErrDeadlock && (errin & ErrDeadlock)) {
LL3("caught deadlock");
+ err = ErrDeadlock;
ret = 0;
}
- } else {
- deadlock = false;
}
- CHK(ret == 0 || ret == 1 || (! fetchAllowed && ret == 2));
+ CHK(ret == 0 || ret == 1 || (!fetchAllowed && ret == 2));
return ret;
}
@@ -1502,6 +1498,7 @@ Con::updateScanTuple(Con& con2)
{
assert(con2.m_tx != 0);
CHKCON((con2.m_op = m_scanop->updateCurrentTuple(con2.m_tx)) != 0, *this);
+ con2.m_txid = m_txid; // in the kernel
return 0;
}
@@ -1510,6 +1507,7 @@ Con::deleteScanTuple(Con& con2)
{
assert(con2.m_tx != 0);
CHKCON(m_scanop->deleteCurrentTuple(con2.m_tx) == 0, *this);
+ con2.m_txid = m_txid; // in the kernel
return 0;
}
@@ -1527,15 +1525,26 @@ Con::closeTransaction()
{
assert(m_ndb != 0 && m_tx != 0);
m_ndb->closeTransaction(m_tx);
- m_tx = 0, m_op = 0;
+ m_tx = 0, m_txid = 0, m_op = 0;
m_scanop = 0, m_indexscanop = 0;
}
+const char*
+Con::errname(uint err)
+{
+ sprintf(m_errname, "0x%x", err);
+ if (err & ErrDeadlock)
+ strcat(m_errname, ",deadlock");
+ if (err & ErrNospace)
+ strcat(m_errname, ",nospace");
+ return m_errname;
+}
+
void
Con::printerror(NdbOut& out)
{
m_errtype = ErrOther;
- unsigned any = 0;
+ uint any = 0;
int code;
int die = 0;
if (m_ndb) {
@@ -1563,7 +1572,7 @@ Con::printerror(NdbOut& out)
}
}
}
- if (! any) {
+ if (!any) {
LL0("failed but no NDB error code");
}
if (die) {
@@ -1589,7 +1598,7 @@ invalidateindex(Par par)
{
Con& con = par.con();
const Tab& tab = par.tab();
- for (unsigned i = 0; i < tab.m_itabs; i++) {
+ for (uint i = 0; i < tab.m_itabs; i++) {
if (tab.m_itab[i] == 0)
continue;
const ITab& itab = *tab.m_itab[i];
@@ -1639,7 +1648,7 @@ createtable(Par par)
if (par.m_nologging) {
t.setLogging(false);
}
- for (unsigned k = 0; k < tab.m_cols; k++) {
+ for (uint k = 0; k < tab.m_cols; k++) {
const Col& col = *tab.m_col[k];
NdbDictionary::Column c(col.m_name);
c.setType((NdbDictionary::Column::Type)col.m_type);
@@ -1677,7 +1686,7 @@ static int
dropindex(Par par)
{
const Tab& tab = par.tab();
- for (unsigned i = 0; i < tab.m_itabs; i++) {
+ for (uint i = 0; i < tab.m_itabs; i++) {
if (tab.m_itab[i] == 0)
continue;
const ITab& itab = *tab.m_itab[i];
@@ -1699,7 +1708,7 @@ createindex(Par par, const ITab& itab)
if (par.m_nologging || itab.m_type == ITab::OrderedIndex) {
x.setLogging(false);
}
- for (unsigned k = 0; k < itab.m_icols; k++) {
+ for (uint k = 0; k < itab.m_icols; k++) {
const ICol& icol = *itab.m_icol[k];
const Col& col = icol.m_col;
x.addColumnName(col.m_name);
@@ -1714,7 +1723,7 @@ static int
createindex(Par par)
{
const Tab& tab = par.tab();
- for (unsigned i = 0; i < tab.m_itabs; i++) {
+ for (uint i = 0; i < tab.m_itabs; i++) {
if (tab.m_itab[i] == 0)
continue;
const ITab& itab = *tab.m_itab[i];
@@ -1731,27 +1740,29 @@ struct Val {
const Col& m_col;
union {
Uint32 m_uint32;
- unsigned char* m_char;
- unsigned char* m_varchar;
- unsigned char* m_longvarchar;
+ uchar* m_char;
+ uchar* m_varchar;
+ uchar* m_longvarchar;
};
+ bool m_null;
+ // construct
Val(const Col& col);
~Val();
void copy(const Val& val2);
void copy(const void* addr);
const void* dataaddr() const;
- bool m_null;
- int equal(Par par) const;
- int equal(Par par, const ICol& icol) const;
- int setval(Par par) const;
- void calc(Par par, unsigned i);
- void calckey(Par par, unsigned i);
- void calckeychars(Par par, unsigned i, unsigned& n, unsigned char* buf);
+ void calc(Par par, uint i);
+ void calckey(Par par, uint i);
+ void calckeychars(Par par, uint i, uint& n, uchar* buf);
void calcnokey(Par par);
- void calcnokeychars(Par par, unsigned& n, unsigned char* buf);
- int verify(Par par, const Val& val2) const;
+ void calcnokeychars(Par par, uint& n, uchar* buf);
+ // operations
+ int setval(Par par) const;
+ int setval(Par par, const ICol& icol) const;
+ // compare
int cmp(Par par, const Val& val2) const;
- int cmpchars(Par par, const unsigned char* buf1, unsigned len1, const unsigned char* buf2, unsigned len2) const;
+ int cmpchars(Par par, const uchar* buf1, uint len1, const uchar* buf2, uint len2) const;
+ int verify(Par par, const Val& val2) const;
private:
Val& operator=(const Val& val2);
};
@@ -1759,20 +1770,26 @@ private:
static NdbOut&
operator<<(NdbOut& out, const Val& val);
+// construct
+
Val::Val(const Col& col) :
m_col(col)
{
switch (col.m_type) {
case Col::Unsigned:
+ m_uint32 = 0x7e7e7e7e;
break;
case Col::Char:
- m_char = new unsigned char [col.m_bytelength];
+ m_char = new uchar [col.m_bytelength];
+ memset(m_char, 0x7e, col.m_bytelength);
break;
case Col::Varchar:
- m_varchar = new unsigned char [1 + col.m_bytelength];
+ m_varchar = new uchar [1 + col.m_bytelength];
+ memset(m_char, 0x7e, 1 + col.m_bytelength);
break;
case Col::Longvarchar:
- m_longvarchar = new unsigned char [2 + col.m_bytelength];
+ m_longvarchar = new uchar [2 + col.m_bytelength];
+ memset(m_char, 0x7e, 2 + col.m_bytelength);
break;
default:
assert(false);
@@ -1858,52 +1875,17 @@ Val::dataaddr() const
return 0;
}
-int
-Val::equal(Par par) const
-{
- Con& con = par.con();
- const Col& col = m_col;
- assert(col.m_pk && ! m_null);
- const char* addr = (const char*)dataaddr();
- LL5("equal [" << col << "] " << *this);
- CHK(con.equal(col.m_num, addr) == 0);
- return 0;
-}
-
-int
-Val::equal(Par par, const ICol& icol) const
-{
- Con& con = par.con();
- assert(! m_null);
- const char* addr = (const char*)dataaddr();
- LL5("equal [" << icol << "] " << *this);
- CHK(con.equal(icol.m_num, addr) == 0);
- return 0;
-}
-
-int
-Val::setval(Par par) const
-{
- Con& con = par.con();
- const Col& col = m_col;
- assert(! col.m_pk);
- const char* addr = ! m_null ? (const char*)dataaddr() : 0;
- LL5("setval [" << col << "] " << *this);
- CHK(con.setValue(col.m_num, addr) == 0);
- return 0;
-}
-
void
-Val::calc(Par par, unsigned i)
+Val::calc(Par par, uint i)
{
const Col& col = m_col;
col.m_pk ? calckey(par, i) : calcnokey(par);
- if (! m_null)
+ if (!m_null)
col.wellformed(dataaddr());
}
void
-Val::calckey(Par par, unsigned i)
+Val::calckey(Par par, uint i)
{
const Col& col = m_col;
m_null = false;
@@ -1915,7 +1897,7 @@ Val::calckey(Par par, unsigned i)
{
const Chs* chs = col.m_chs;
CHARSET_INFO* cs = chs->m_cs;
- unsigned n = 0;
+ uint n = 0;
calckeychars(par, i, n, m_char);
// extend by appropriate space
(*cs->cset->fill)(cs, (char*)&m_char[n], col.m_bytelength - n, 0x20);
@@ -1923,7 +1905,7 @@ Val::calckey(Par par, unsigned i)
break;
case Col::Varchar:
{
- unsigned n = 0;
+ uint n = 0;
calckeychars(par, i, n, m_varchar + 1);
// set length and pad with nulls
m_varchar[0] = n;
@@ -1932,7 +1914,7 @@ Val::calckey(Par par, unsigned i)
break;
case Col::Longvarchar:
{
- unsigned n = 0;
+ uint n = 0;
calckeychars(par, i, n, m_longvarchar + 2);
// set length and pad with nulls
m_longvarchar[0] = (n & 0xff);
@@ -1947,13 +1929,13 @@ Val::calckey(Par par, unsigned i)
}
void
-Val::calckeychars(Par par, unsigned i, unsigned& n, unsigned char* buf)
+Val::calckeychars(Par par, uint i, uint& n, uchar* buf)
{
const Col& col = m_col;
const Chs* chs = col.m_chs;
CHARSET_INFO* cs = chs->m_cs;
n = 0;
- unsigned len = 0;
+ uint len = 0;
while (len < col.m_length) {
if (i % (1 + n) == 0) {
break;
@@ -1980,7 +1962,7 @@ Val::calcnokey(Par par)
if (r < 0 && par.m_bdir > 0 || r > 0 && par.m_bdir < 0)
r = -r;
}
- unsigned v = par.m_range + r;
+ uint v = par.m_range + r;
switch (col.m_type) {
case Col::Unsigned:
m_uint32 = v;
@@ -1989,7 +1971,7 @@ Val::calcnokey(Par par)
{
const Chs* chs = col.m_chs;
CHARSET_INFO* cs = chs->m_cs;
- unsigned n = 0;
+ uint n = 0;
calcnokeychars(par, n, m_char);
// extend by appropriate space
(*cs->cset->fill)(cs, (char*)&m_char[n], col.m_bytelength - n, 0x20);
@@ -1997,7 +1979,7 @@ Val::calcnokey(Par par)
break;
case Col::Varchar:
{
- unsigned n = 0;
+ uint n = 0;
calcnokeychars(par, n, m_varchar + 1);
// set length and pad with nulls
m_varchar[0] = n;
@@ -2006,7 +1988,7 @@ Val::calcnokey(Par par)
break;
case Col::Longvarchar:
{
- unsigned n = 0;
+ uint n = 0;
calcnokeychars(par, n, m_longvarchar + 2);
// set length and pad with nulls
m_longvarchar[0] = (n & 0xff);
@@ -2021,24 +2003,24 @@ Val::calcnokey(Par par)
}
void
-Val::calcnokeychars(Par par, unsigned& n, unsigned char* buf)
+Val::calcnokeychars(Par par, uint& n, uchar* buf)
{
const Col& col = m_col;
const Chs* chs = col.m_chs;
CHARSET_INFO* cs = chs->m_cs;
n = 0;
- unsigned len = 0;
+ uint len = 0;
while (len < col.m_length) {
if (urandom(1 + col.m_bytelength) == 0) {
break;
}
- unsigned half = maxcharcount / 2;
+ uint half = maxcharcount / 2;
int r = irandom((par.m_pctrange * half) / 100);
if (par.m_bdir != 0 && urandom(10) != 0) {
if (r < 0 && par.m_bdir > 0 || r > 0 && par.m_bdir < 0)
r = -r;
}
- unsigned i = half + r;
+ uint i = half + r;
assert(i < maxcharcount);
const Chr& chr = chs->m_chr[i];
assert(n + chr.m_size <= col.m_bytelength);
@@ -2048,13 +2030,39 @@ Val::calcnokeychars(Par par, unsigned& n, unsigned char* buf)
}
}
+// operations
+
int
-Val::verify(Par par, const Val& val2) const
+Val::setval(Par par) const
{
- CHK(cmp(par, val2) == 0);
+ Con& con = par.con();
+ const Col& col = m_col;
+ if (col.m_pk) {
+ assert(!m_null);
+ const char* addr = (const char*)dataaddr();
+ LL5("setval pk [" << col << "] " << *this);
+ CHK(con.equal(col.m_num, addr) == 0);
+ } else {
+ const char* addr = !m_null ? (const char*)dataaddr() : 0;
+ LL5("setval non-pk [" << col << "] " << *this);
+ CHK(con.setValue(col.m_num, addr) == 0);
+ }
+ return 0;
+}
+
+int
+Val::setval(Par par, const ICol& icol) const
+{
+ Con& con = par.con();
+ assert(!m_null);
+ const char* addr = (const char*)dataaddr();
+ LL5("setval key [" << icol << "] " << *this);
+ CHK(con.equal(icol.m_num, addr) == 0);
return 0;
}
+// compare
+
int
Val::cmp(Par par, const Val& val2) const
{
@@ -2062,9 +2070,9 @@ Val::cmp(Par par, const Val& val2) const
const Col& col2 = val2.m_col;
assert(col.equal(col2));
if (m_null || val2.m_null) {
- if (! m_null)
+ if (!m_null)
return +1;
- if (! val2.m_null)
+ if (!val2.m_null)
return -1;
return 0;
}
@@ -2084,21 +2092,21 @@ Val::cmp(Par par, const Val& val2) const
break;
case Col::Char:
{
- unsigned len = col.m_bytelength;
+ uint len = col.m_bytelength;
return cmpchars(par, m_char, len, val2.m_char, len);
}
break;
case Col::Varchar:
{
- unsigned len1 = m_varchar[0];
- unsigned len2 = val2.m_varchar[0];
+ uint len1 = m_varchar[0];
+ uint len2 = val2.m_varchar[0];
return cmpchars(par, m_varchar + 1, len1, val2.m_varchar + 1, len2);
}
break;
case Col::Longvarchar:
{
- unsigned len1 = m_longvarchar[0] + (m_longvarchar[1] << 8);
- unsigned len2 = val2.m_longvarchar[0] + (val2.m_longvarchar[1] << 8);
+ uint len1 = m_longvarchar[0] + (m_longvarchar[1] << 8);
+ uint len2 = val2.m_longvarchar[0] + (val2.m_longvarchar[1] << 8);
return cmpchars(par, m_longvarchar + 2, len1, val2.m_longvarchar + 2, len2);
}
break;
@@ -2110,17 +2118,17 @@ Val::cmp(Par par, const Val& val2) const
}
int
-Val::cmpchars(Par par, const unsigned char* buf1, unsigned len1, const unsigned char* buf2, unsigned len2) const
+Val::cmpchars(Par par, const uchar* buf1, uint len1, const uchar* buf2, uint len2) const
{
const Col& col = m_col;
const Chs* chs = col.m_chs;
CHARSET_INFO* cs = chs->m_cs;
int k;
- if (! par.m_collsp) {
- unsigned char x1[maxxmulsize * 8000];
- unsigned char x2[maxxmulsize * 8000];
+ if (!par.m_collsp) {
+ uchar x1[maxxmulsize * 8000];
+ uchar x2[maxxmulsize * 8000];
// make strxfrm pad both to same length
- unsigned len = maxxmulsize * col.m_bytelength;
+ uint len = maxxmulsize * col.m_bytelength;
int n1 = NdbSqlUtil::strnxfrm_bug7284(cs, x1, chs->m_xmul * len, buf1, len1);
int n2 = NdbSqlUtil::strnxfrm_bug7284(cs, x2, chs->m_xmul * len, buf2, len2);
assert(n1 != -1 && n1 == n2);
@@ -2131,8 +2139,17 @@ Val::cmpchars(Par par, const unsigned char* buf1, unsigned len1, const unsigned
return k < 0 ? -1 : k > 0 ? +1 : 0;
}
+int
+Val::verify(Par par, const Val& val2) const
+{
+ CHK(cmp(par, val2) == 0);
+ return 0;
+}
+
+// print
+
static void
-printstring(NdbOut& out, const unsigned char* str, unsigned len, bool showlen)
+printstring(NdbOut& out, const uchar* str, uint len, bool showlen)
{
char buf[4 * 8000];
char *p = buf;
@@ -2141,12 +2158,12 @@ printstring(NdbOut& out, const unsigned char* str, unsigned len, bool showlen)
sprintf(p, "%u:", len);
p += strlen(p);
}
- for (unsigned i = 0; i < len; i++) {
- unsigned char c = str[i];
+ for (uint i = 0; i < len; i++) {
+ uchar c = str[i];
if (c == '\\') {
*p++ = '\\';
*p++ = c;
- } else if (0x20 <= c && c < 0x7e) {
+ } else if (0x20 <= c && c <= 0x7e) {
*p++ = c;
} else {
*p++ = '\\';
@@ -2173,19 +2190,19 @@ operator<<(NdbOut& out, const Val& val)
break;
case Col::Char:
{
- unsigned len = col.m_bytelength;
+ uint len = col.m_bytelength;
printstring(out, val.m_char, len, false);
}
break;
case Col::Varchar:
{
- unsigned len = val.m_varchar[0];
+ uint len = val.m_varchar[0];
printstring(out, val.m_varchar + 1, len, true);
}
break;
case Col::Longvarchar:
{
- unsigned len = val.m_longvarchar[0] + (val.m_longvarchar[1] << 8);
+ uint len = val.m_longvarchar[0] + (val.m_longvarchar[1] << 8);
printstring(out, val.m_longvarchar + 2, len, true);
}
break;
@@ -2202,16 +2219,36 @@ operator<<(NdbOut& out, const Val& val)
struct Row {
const Tab& m_tab;
Val** m_val;
- bool m_exist;
- enum Op { NoOp = 0, ReadOp = 1, InsOp = 2, UpdOp = 4, DelOp = 8, AnyOp = 15 };
- Op m_pending;
- Row* m_dbrow; // copy of db row before update
+ enum St {
+ StUndef = 0,
+ StDefine = 1,
+ StPrepare = 2,
+ StCommit = 3
+ };
+ enum Op {
+ OpNone = 0,
+ OpIns = 2,
+ OpUpd = 4,
+ OpDel = 8,
+ OpRead = 16,
+ OpReadEx = 32,
+ OpReadCom = 64,
+ OpDML = 2 | 4 | 8,
+ OpREAD = 16 | 32 | 64
+ };
+ St m_st;
+ Op m_op;
+ Uint64 m_txid;
+ Row* m_bi;
+ // construct
Row(const Tab& tab);
~Row();
- void copy(const Row& row2);
- void calc(Par par, unsigned i, unsigned mask = 0);
- const Row& dbrow() const;
- int verify(Par par, const Row& row2, bool pkonly) const;
+ void copy(const Row& row2, bool copy_bi);
+ void copyval(const Row& row2, uint colmask = ~0);
+ void calc(Par par, uint i, uint colmask = ~0);
+ // operations
+ int setval(Par par, uint colmask = ~0);
+ int setval(Par par, const ITab& itab);
int insrow(Par par);
int updrow(Par par);
int updrow(Par par, const ITab& itab);
@@ -2220,120 +2257,132 @@ struct Row {
int selrow(Par par);
int selrow(Par par, const ITab& itab);
int setrow(Par par);
+ // compare
int cmp(Par par, const Row& row2) const;
int cmp(Par par, const Row& row2, const ITab& itab) const;
+ int verify(Par par, const Row& row2, bool pkonly) const;
private:
Row& operator=(const Row& row2);
};
+static NdbOut&
+operator<<(NdbOut& out, const Row* rowp);
+
+static NdbOut&
+operator<<(NdbOut& out, const Row& row);
+
+// construct
+
Row::Row(const Tab& tab) :
m_tab(tab)
{
m_val = new Val* [tab.m_cols];
- for (unsigned k = 0; k < tab.m_cols; k++) {
+ for (uint k = 0; k < tab.m_cols; k++) {
const Col& col = *tab.m_col[k];
m_val[k] = new Val(col);
}
- m_exist = false;
- m_pending = NoOp;
- m_dbrow = 0;
+ m_st = StUndef;
+ m_op = OpNone;
+ m_txid = 0;
+ m_bi = 0;
}
Row::~Row()
{
const Tab& tab = m_tab;
- for (unsigned k = 0; k < tab.m_cols; k++) {
+ for (uint k = 0; k < tab.m_cols; k++) {
delete m_val[k];
}
delete [] m_val;
- delete m_dbrow;
+ delete m_bi;
}
void
-Row::copy(const Row& row2)
+Row::copy(const Row& row2, bool copy_bi)
+{
+ const Tab& tab = m_tab;
+ copyval(row2);
+ m_st = row2.m_st;
+ m_op = row2.m_op;
+ m_txid = row2.m_txid;
+ assert(m_bi == 0);
+ if (copy_bi && row2.m_bi != 0) {
+ m_bi = new Row(tab);
+ m_bi->copy(*row2.m_bi, copy_bi);
+ }
+}
+
+void
+Row::copyval(const Row& row2, uint colmask)
{
const Tab& tab = m_tab;
assert(&tab == &row2.m_tab);
- for (unsigned k = 0; k < tab.m_cols; k++) {
+ for (uint k = 0; k < tab.m_cols; k++) {
Val& val = *m_val[k];
const Val& val2 = *row2.m_val[k];
- val.copy(val2);
- }
- m_exist = row2.m_exist;
- m_pending = row2.m_pending;
- if (row2.m_dbrow == 0) {
- m_dbrow = 0;
- } else {
- assert(row2.m_dbrow->m_dbrow == 0);
- if (m_dbrow == 0)
- m_dbrow = new Row(tab);
- m_dbrow->copy(*row2.m_dbrow);
+ if ((1 << k) & colmask)
+ val.copy(val2);
}
}
void
-Row::calc(Par par, unsigned i, unsigned mask)
+Row::calc(Par par, uint i, uint colmask)
{
const Tab& tab = m_tab;
- for (unsigned k = 0; k < tab.m_cols; k++) {
- if (! (mask & (1 << k))) {
+ for (uint k = 0; k < tab.m_cols; k++) {
+ if ((1 << k) & colmask) {
Val& val = *m_val[k];
val.calc(par, i);
}
}
}
-const Row&
-Row::dbrow() const
-{
- if (m_dbrow == 0)
- return *this;
- assert(m_pending == Row::UpdOp || m_pending == Row::DelOp);
- return *m_dbrow;
-}
+// operations
int
-Row::verify(Par par, const Row& row2, bool pkonly) const
+Row::setval(Par par, uint colmask)
{
const Tab& tab = m_tab;
- const Row& row1 = *this;
- assert(&row1.m_tab == &row2.m_tab && row1.m_exist && row2.m_exist);
- for (unsigned k = 0; k < tab.m_cols; k++) {
- const Col& col = row1.m_val[k]->m_col;
- if (! pkonly || col.m_pk) {
- const Val& val1 = *row1.m_val[k];
- const Val& val2 = *row2.m_val[k];
- CHK(val1.verify(par, val2) == 0);
+ Rsq rsq(tab.m_cols);
+ for (uint k = 0; k < tab.m_cols; k++) {
+ uint k2 = rsq.next();
+ if ((1 << k2) & colmask) {
+ const Val& val = *m_val[k2];
+ CHK(val.setval(par) == 0);
}
}
return 0;
}
int
+Row::setval(Par par, const ITab& itab)
+{
+ Con& con = par.con();
+ Rsq rsq(itab.m_icols);
+ for (uint k = 0; k < itab.m_icols; k++) {
+ uint k2 = rsq.next();
+ const ICol& icol = *itab.m_icol[k2];
+ const Col& col = icol.m_col;
+ uint m = col.m_num;
+ const Val& val = *m_val[m];
+ CHK(val.setval(par, icol) == 0);
+ }
+ return 0;
+}
+
+int
Row::insrow(Par par)
{
Con& con = par.con();
const Tab& tab = m_tab;
- assert(! m_exist);
CHK(con.getNdbOperation(tab) == 0);
CHKCON(con.m_op->insertTuple() == 0, con);
- Rsq rsq1(tab.m_cols);
- for (unsigned k = 0; k < tab.m_cols; k++) {
- unsigned k2 = rsq1.next();
- const Val& val = *m_val[k2];
- const Col& col = val.m_col;
- if (col.m_pk)
- CHK(val.equal(par) == 0);
- }
- Rsq rsq2(tab.m_cols);
- for (unsigned k = 0; k < tab.m_cols; k++) {
- unsigned k2 = rsq2.next();
- const Val& val = *m_val[k2];
- const Col& col = val.m_col;
- if (! col.m_pk)
- CHK(val.setval(par) == 0);
- }
- m_pending = InsOp;
+ CHK(setval(par, tab.m_pkmask) == 0);
+ CHK(setval(par, ~tab.m_pkmask) == 0);
+ assert(m_st == StUndef);
+ m_st = StDefine;
+ m_op = OpIns;
+ m_txid = con.m_txid;
return 0;
}
@@ -2342,26 +2391,14 @@ Row::updrow(Par par)
{
Con& con = par.con();
const Tab& tab = m_tab;
- assert(m_exist);
CHK(con.getNdbOperation(tab) == 0);
CHKCON(con.m_op->updateTuple() == 0, con);
- Rsq rsq1(tab.m_cols);
- for (unsigned k = 0; k < tab.m_cols; k++) {
- unsigned k2 = rsq1.next();
- const Val& val = *m_val[k2];
- const Col& col = val.m_col;
- if (col.m_pk)
- CHK(val.equal(par) == 0);
- }
- Rsq rsq2(tab.m_cols);
- for (unsigned k = 0; k < tab.m_cols; k++) {
- unsigned k2 = rsq2.next();
- const Val& val = *m_val[k2];
- const Col& col = val.m_col;
- if (! col.m_pk)
- CHK(val.setval(par) == 0);
- }
- m_pending = UpdOp;
+ CHK(setval(par, tab.m_pkmask) == 0);
+ CHK(setval(par, ~tab.m_pkmask) == 0);
+ assert(m_st == StUndef);
+ m_st = StDefine;
+ m_op = OpUpd;
+ m_txid = con.m_txid;
return 0;
}
@@ -2371,27 +2408,14 @@ Row::updrow(Par par, const ITab& itab)
Con& con = par.con();
const Tab& tab = m_tab;
assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab);
- assert(m_exist);
CHK(con.getNdbIndexOperation(itab, tab) == 0);
CHKCON(con.m_op->updateTuple() == 0, con);
- Rsq rsq1(itab.m_icols);
- for (unsigned k = 0; k < itab.m_icols; k++) {
- unsigned k2 = rsq1.next();
- const ICol& icol = *itab.m_icol[k2];
- const Col& col = icol.m_col;
- unsigned m = col.m_num;
- const Val& val = *m_val[m];
- CHK(val.equal(par, icol) == 0);
- }
- Rsq rsq2(tab.m_cols);
- for (unsigned k = 0; k < tab.m_cols; k++) {
- unsigned k2 = rsq2.next();
- const Val& val = *m_val[k2];
- const Col& col = val.m_col;
- if (! col.m_pk)
- CHK(val.setval(par) == 0);
- }
- m_pending = UpdOp;
+ CHK(setval(par, itab) == 0);
+ CHK(setval(par, ~tab.m_pkmask) == 0);
+ assert(m_st == StUndef);
+ m_st = StDefine;
+ m_op = OpUpd;
+ m_txid = con.m_txid;
return 0;
}
@@ -2400,18 +2424,13 @@ Row::delrow(Par par)
{
Con& con = par.con();
const Tab& tab = m_tab;
- assert(m_exist);
CHK(con.getNdbOperation(m_tab) == 0);
CHKCON(con.m_op->deleteTuple() == 0, con);
- Rsq rsq1(tab.m_cols);
- for (unsigned k = 0; k < tab.m_cols; k++) {
- unsigned k2 = rsq1.next();
- const Val& val = *m_val[k2];
- const Col& col = val.m_col;
- if (col.m_pk)
- CHK(val.equal(par) == 0);
- }
- m_pending = DelOp;
+ CHK(setval(par, tab.m_pkmask) == 0);
+ assert(m_st == StUndef);
+ m_st = StDefine;
+ m_op = OpDel;
+ m_txid = con.m_txid;
return 0;
}
@@ -2421,19 +2440,13 @@ Row::delrow(Par par, const ITab& itab)
Con& con = par.con();
const Tab& tab = m_tab;
assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab);
- assert(m_exist);
CHK(con.getNdbIndexOperation(itab, tab) == 0);
CHKCON(con.m_op->deleteTuple() == 0, con);
- Rsq rsq1(itab.m_icols);
- for (unsigned k = 0; k < itab.m_icols; k++) {
- unsigned k2 = rsq1.next();
- const ICol& icol = *itab.m_icol[k2];
- const Col& col = icol.m_col;
- unsigned m = col.m_num;
- const Val& val = *m_val[m];
- CHK(val.equal(par, icol) == 0);
- }
- m_pending = DelOp;
+ CHK(setval(par, itab) == 0);
+ assert(m_st == StUndef);
+ m_st = StDefine;
+ m_op = OpDel;
+ m_txid = con.m_txid;
return 0;
}
@@ -2443,15 +2456,9 @@ Row::selrow(Par par)
Con& con = par.con();
const Tab& tab = m_tab;
CHK(con.getNdbOperation(m_tab) == 0);
- CHKCON(con.m_op->readTuple() == 0, con);
- Rsq rsq1(tab.m_cols);
- for (unsigned k = 0; k < tab.m_cols; k++) {
- unsigned k2 = rsq1.next();
- const Val& val = *m_val[k2];
- const Col& col = val.m_col;
- if (col.m_pk)
- CHK(val.equal(par) == 0);
- }
+ CHKCON(con.readTuple(par) == 0, con);
+ CHK(setval(par, tab.m_pkmask) == 0);
+ // TODO state
return 0;
}
@@ -2462,16 +2469,9 @@ Row::selrow(Par par, const ITab& itab)
const Tab& tab = m_tab;
assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab);
CHK(con.getNdbIndexOperation(itab, tab) == 0);
- CHKCON(con.m_op->readTuple() == 0, con);
- Rsq rsq1(itab.m_icols);
- for (unsigned k = 0; k < itab.m_icols; k++) {
- unsigned k2 = rsq1.next();
- const ICol& icol = *itab.m_icol[k2];
- const Col& col = icol.m_col;
- unsigned m = col.m_num;
- const Val& val = *m_val[m];
- CHK(val.equal(par, icol) == 0);
- }
+ CHKCON(con.readTuple(par) == 0, con);
+ CHK(setval(par, itab) == 0);
+ // TODO state
return 0;
}
@@ -2480,25 +2480,23 @@ Row::setrow(Par par)
{
Con& con = par.con();
const Tab& tab = m_tab;
- Rsq rsq1(tab.m_cols);
- for (unsigned k = 0; k < tab.m_cols; k++) {
- unsigned k2 = rsq1.next();
- const Val& val = *m_val[k2];
- const Col& col = val.m_col;
- if (! col.m_pk)
- CHK(val.setval(par) == 0);
- }
- m_pending = UpdOp;
+ CHK(setval(par, ~tab.m_pkmask) == 0);
+ assert(m_st == StUndef);
+ m_st = StDefine;
+ m_op = OpUpd;
+ m_txid = con.m_txid;
return 0;
}
+// compare
+
int
Row::cmp(Par par, const Row& row2) const
{
const Tab& tab = m_tab;
assert(&tab == &row2.m_tab);
int c = 0;
- for (unsigned k = 0; k < tab.m_cols; k++) {
+ for (uint k = 0; k < tab.m_cols; k++) {
const Val& val = *m_val[k];
const Val& val2 = *row2.m_val[k];
if ((c = val.cmp(par, val2)) != 0)
@@ -2512,10 +2510,10 @@ Row::cmp(Par par, const Row& row2, const ITab& itab) const
{
const Tab& tab = m_tab;
int c = 0;
- for (unsigned i = 0; i < itab.m_icols; i++) {
+ for (uint i = 0; i < itab.m_icols; i++) {
const ICol& icol = *itab.m_icol[i];
const Col& col = icol.m_col;
- unsigned k = col.m_num;
+ uint k = col.m_num;
assert(k < tab.m_cols);
const Val& val = *m_val[k];
const Val& val2 = *row2.m_val[k];
@@ -2525,19 +2523,70 @@ Row::cmp(Par par, const Row& row2, const ITab& itab) const
return c;
}
+int
+Row::verify(Par par, const Row& row2, bool pkonly) const
+{
+ const Tab& tab = m_tab;
+ const Row& row1 = *this;
+ assert(&row1.m_tab == &row2.m_tab);
+ for (uint k = 0; k < tab.m_cols; k++) {
+ const Col& col = row1.m_val[k]->m_col;
+ if (!pkonly || col.m_pk) {
+ const Val& val1 = *row1.m_val[k];
+ const Val& val2 = *row2.m_val[k];
+ CHK(val1.verify(par, val2) == 0);
+ }
+ }
+ return 0;
+}
+
+// print
+
+static NdbOut&
+operator<<(NdbOut& out, const Row::St st)
+{
+ if (st == Row::StUndef)
+ out << "StUndef";
+ else if (st == Row::StDefine)
+ out << "StDefine";
+ else if (st == Row::StPrepare)
+ out << "StPrepare";
+ else if (st == Row::StCommit)
+ out << "StCommit";
+ else
+ out << "st=" << st;
+ return out;
+}
+
static NdbOut&
operator<<(NdbOut& out, const Row::Op op)
{
- if (op == Row::NoOp)
- out << "NoOp";
- else if (op == Row::InsOp)
- out << "InsOp";
- else if (op == Row::UpdOp)
- out << "UpdOp";
- else if (op == Row::DelOp)
- out << "DelOp";
+ if (op == Row::OpNone)
+ out << "OpNone";
+ else if (op == Row::OpIns)
+ out << "OpIns";
+ else if (op == Row::OpUpd)
+ out << "OpUpd";
+ else if (op == Row::OpDel)
+ out << "OpDel";
+ else if (op == Row::OpRead)
+ out << "OpRead";
+ else if (op == Row::OpReadEx)
+ out << "OpReadEx";
+ else if (op == Row::OpReadCom)
+ out << "OpReadCom";
else
- out << op;
+ out << "op=" << op;
+ return out;
+}
+
+static NdbOut&
+operator<<(NdbOut& out, const Row* rowp)
+{
+ if (rowp == 0)
+ out << "[null]";
+ else
+ out << *rowp;
return out;
}
@@ -2545,26 +2594,18 @@ static NdbOut&
operator<<(NdbOut& out, const Row& row)
{
const Tab& tab = row.m_tab;
- for (unsigned i = 0; i < tab.m_cols; i++) {
+ out << "[";
+ for (uint i = 0; i < tab.m_cols; i++) {
if (i > 0)
out << " ";
out << *row.m_val[i];
}
- out << " exist=" << row.m_exist;
- if (row.m_pending)
- out << " pending=" << row.m_pending;
- if (row.m_dbrow != 0)
- out << " [dbrow=" << *row.m_dbrow << "]";
- return out;
-}
-
-static NdbOut&
-operator<<(NdbOut& out, const Row* rowptr)
-{
- if (rowptr == 0)
- out << "null";
- else
- out << *rowptr;
+ out << " " << row.m_st;
+ out << " " << row.m_op;
+ out << " " << HEX(row.m_txid);
+ if (row.m_bi != 0)
+ out << " " << row.m_bi;
+ out << "]";
return out;
}
@@ -2572,45 +2613,38 @@ operator<<(NdbOut& out, const Row* rowptr)
struct Set {
const Tab& m_tab;
- unsigned m_rows;
+ uint m_rows;
Row** m_row;
- unsigned* m_rowkey; // maps row number (from 0) in scan to tuple key
+ uint* m_rowkey; // maps row number (from 0) in scan to tuple key
Row* m_keyrow;
NdbRecAttr** m_rec;
- Set(const Tab& tab, unsigned rows);
+ // construct
+ Set(const Tab& tab, uint rows);
~Set();
void reset();
- unsigned count() const;
- // old and new values
- bool exist(unsigned i) const;
- void dbsave(unsigned i);
- void calc(Par par, unsigned i, unsigned mask = 0);
- bool pending(unsigned i, unsigned mask) const;
- void notpending(unsigned i, ExecType et = Commit);
- void notpending(const Lst& lst, ExecType et = Commit);
- void dbdiscard(unsigned i);
- void dbdiscard(const Lst& lst);
- const Row& dbrow(unsigned i) const;
+ bool compat(Par par, uint i, const Row::Op op) const;
+ void push(uint i);
+ void copyval(uint i, uint colmask = ~0); // from bi
+ void calc(Par par, uint i, uint colmask = ~0);
+ uint count() const;
+ const Row* getrow(uint i, bool dirty = false) const;
+ // transaction
+ void post(Par par, ExecType et);
// operations
- int insrow(Par par, unsigned i);
- int updrow(Par par, unsigned i);
- int updrow(Par par, const ITab& itab, unsigned i);
- int delrow(Par par, unsigned i);
- int delrow(Par par, const ITab& itab, unsigned i);
+ int insrow(Par par, uint i);
+ int updrow(Par par, uint i);
+ int updrow(Par par, const ITab& itab, uint i);
+ int delrow(Par par, uint i);
+ int delrow(Par par, const ITab& itab, uint i);
int selrow(Par par, const Row& keyrow);
int selrow(Par par, const ITab& itab, const Row& keyrow);
- // set and get
- void setkey(Par par, const Row& keyrow);
- void setkey(Par par, const ITab& itab, const Row& keyrow);
- int setrow(Par par, unsigned i);
+ int setrow(Par par, uint i);
int getval(Par par);
- int getkey(Par par, unsigned* i);
- int putval(unsigned i, bool force, unsigned n = ~0);
- // sort rows in-place according to ordered index
+ int getkey(Par par, uint* i);
+ int putval(uint i, bool force, uint n = ~0);
+ // compare
void sort(Par par, const ITab& itab);
- void sort(Par par, const ITab& itab, unsigned lo, unsigned hi);
- // verify
- int verify(Par par, const Set& set2, bool pkonly) const;
+ int verify(Par par, const Set& set2, bool pkonly, bool dirty = false) const;
int verifyorder(Par par, const ITab& itab, bool descending) const;
// protect structure
NdbMutex* m_mutex;
@@ -2621,26 +2655,27 @@ struct Set {
NdbMutex_Unlock(m_mutex);
}
private:
+ void sort(Par par, const ITab& itab, uint lo, uint hi);
Set& operator=(const Set& set2);
};
-Set::Set(const Tab& tab, unsigned rows) :
+// construct
+
+Set::Set(const Tab& tab, uint rows) :
m_tab(tab)
{
m_rows = rows;
m_row = new Row* [m_rows];
- for (unsigned i = 0; i < m_rows; i++) {
- // allocate on need to save space
+ for (uint i = 0; i < m_rows; i++) {
m_row[i] = 0;
}
- m_rowkey = new unsigned [m_rows];
- for (unsigned n = 0; n < m_rows; n++) {
- // initialize to null
+ m_rowkey = new uint [m_rows];
+ for (uint n = 0; n < m_rows; n++) {
m_rowkey[n] = ~0;
}
m_keyrow = new Row(tab);
m_rec = new NdbRecAttr* [tab.m_cols];
- for (unsigned k = 0; k < tab.m_cols; k++) {
+ for (uint k = 0; k < tab.m_cols; k++) {
m_rec[k] = 0;
}
m_mutex = NdbMutex_Create();
@@ -2649,7 +2684,7 @@ Set::Set(const Tab& tab, unsigned rows) :
Set::~Set()
{
- for (unsigned i = 0; i < m_rows; i++) {
+ for (uint i = 0; i < m_rows; i++) {
delete m_row[i];
}
delete [] m_row;
@@ -2662,132 +2697,203 @@ Set::~Set()
void
Set::reset()
{
- for (unsigned i = 0; i < m_rows; i++) {
- if (m_row[i] != 0) {
- Row& row = *m_row[i];
- row.m_exist = false;
- }
- }
-}
-
-unsigned
-Set::count() const
-{
- unsigned count = 0;
- for (unsigned i = 0; i < m_rows; i++) {
- if (m_row[i] != 0) {
- Row& row = *m_row[i];
- if (row.m_exist)
- count++;
- }
+ for (uint i = 0; i < m_rows; i++) {
+ m_row[i] = 0;
}
- return count;
}
-// old and new values
-
+// this sucks
bool
-Set::exist(unsigned i) const
+Set::compat(Par par, uint i, const Row::Op op) const
{
- assert(i < m_rows);
- if (m_row[i] == 0) // not allocated => not exist
- return false;
- return m_row[i]->m_exist;
+ Con& con = par.con();
+ int ret = -1;
+ int place = 0;
+ do {
+ const Row* rowp = getrow(i);
+ if (rowp == 0) {
+ ret = op == Row::OpIns;
+ place = 1;
+ break;
+ }
+ const Row& row = *rowp;
+ if (!(op & Row::OpREAD)) {
+ if (row.m_st == Row::StDefine || row.m_st == Row::StPrepare) {
+ assert(row.m_op & Row::OpDML);
+ assert(row.m_txid != 0);
+ if (con.m_txid != row.m_txid) {
+ ret = false;
+ place = 2;
+ break;
+ }
+ if (row.m_op != Row::OpDel) {
+ ret = op == Row::OpUpd || op == Row::OpDel;
+ place = 3;
+ break;
+ }
+ ret = op == Row::OpIns;
+ place = 4;
+ break;
+ }
+ if (row.m_st == Row::StCommit) {
+ assert(row.m_op == Row::OpNone);
+ assert(row.m_txid == 0);
+ ret = op == Row::OpUpd || op == Row::OpDel;
+ place = 5;
+ break;
+ }
+ }
+ if (op & Row::OpREAD) {
+ bool dirty =
+ con.m_txid != row.m_txid &&
+ par.m_lockmode == NdbOperation::LM_CommittedRead;
+ const Row* rowp2 = getrow(i, dirty);
+ if (rowp2 == 0 || rowp2->m_op == Row::OpDel) {
+ ret = false;
+ place = 6;
+ break;
+ }
+ ret = true;
+ place = 7;
+ break;
+ }
+ } while (0);
+ LL4("compat ret=" << ret << " place=" << place);
+ assert(ret == false || ret == true);
+ return ret;
}
void
-Set::dbsave(unsigned i)
+Set::push(uint i)
{
const Tab& tab = m_tab;
- assert(i < m_rows && m_row[i] != 0);
+ assert(i < m_rows);
+ Row* bi = m_row[i];
+ m_row[i] = new Row(tab);
Row& row = *m_row[i];
- LL5("dbsave " << i << ": " << row);
- assert(row.m_exist && ! row.m_pending && row.m_dbrow == 0);
- // could swap pointers but making copy is safer
- Row* rowptr = new Row(tab);
- rowptr->copy(row);
- row.m_dbrow = rowptr;
+ row.m_bi = bi;
+ if (bi != 0)
+ row.copyval(*bi);
}
void
-Set::calc(Par par, unsigned i, unsigned mask)
+Set::copyval(uint i, uint colmask)
{
- const Tab& tab = m_tab;
- if (m_row[i] == 0)
- m_row[i] = new Row(tab);
+ assert(m_row[i] != 0);
Row& row = *m_row[i];
- row.calc(par, i, mask);
-}
-
-bool
-Set::pending(unsigned i, unsigned mask) const
-{
- assert(i < m_rows);
- if (m_row[i] == 0) // not allocated => not pending
- return Row::NoOp;
- return m_row[i]->m_pending & mask;
+ assert(row.m_bi != 0);
+ row.copyval(*row.m_bi, colmask);
}
void
-Set::notpending(unsigned i, ExecType et)
+Set::calc(Par par, uint i, uint colmask)
{
assert(m_row[i] != 0);
Row& row = *m_row[i];
- if (et == Commit) {
- if (row.m_pending == Row::InsOp)
- row.m_exist = true;
- if (row.m_pending == Row::DelOp)
- row.m_exist = false;
- } else {
- if (row.m_pending == Row::InsOp)
- row.m_exist = false;
- if (row.m_pending == Row::DelOp)
- row.m_exist = true;
- }
- row.m_pending = Row::NoOp;
+ row.calc(par, i, colmask);
}
-void
-Set::notpending(const Lst& lst, ExecType et)
+uint
+Set::count() const
{
- for (unsigned j = 0; j < lst.m_cnt; j++) {
- unsigned i = lst.m_arr[j];
- notpending(i, et);
+ uint count = 0;
+ for (uint i = 0; i < m_rows; i++) {
+ if (m_row[i] != 0)
+ count++;
}
+ return count;
}
-void
-Set::dbdiscard(unsigned i)
+const Row*
+Set::getrow(uint i, bool dirty) const
{
- assert(m_row[i] != 0);
- Row& row = *m_row[i];
- LL5("dbdiscard " << i << ": " << row);
- assert(row.m_dbrow != 0);
- delete row.m_dbrow;
- row.m_dbrow = 0;
+ assert(i < m_rows);
+ const Row* rowp = m_row[i];
+ if (dirty) {
+ while (rowp != 0) {
+ bool b1 = rowp->m_op == Row::OpNone;
+ bool b2 = rowp->m_st == Row::StCommit;
+ assert(b1 == b2);
+ if (b1) {
+ assert(rowp->m_bi == 0);
+ break;
+ }
+ rowp = rowp->m_bi;
+ }
+ }
+ return rowp;
}
-const Row&
-Set::dbrow(unsigned i) const
-{
- assert(m_row[i] != 0);
- Row& row = *m_row[i];
- return row.dbrow();
-}
+// transaction
void
-Set::dbdiscard(const Lst& lst)
+Set::post(Par par, ExecType et)
{
- for (unsigned j = 0; j < lst.m_cnt; j++) {
- unsigned i = lst.m_arr[j];
- dbdiscard(i);
+ LL4("post");
+ Con& con = par.con();
+ assert(con.m_txid != 0);
+ uint i;
+ for (i = 0; i < m_rows; i++) {
+ Row* rowp = m_row[i];
+ if (rowp == 0) {
+ LL5("skip " << i << " " << rowp);
+ continue;
+ }
+ if (rowp->m_st == Row::StCommit) {
+ assert(rowp->m_op == Row::OpNone);
+ assert(rowp->m_txid == 0);
+ assert(rowp->m_bi == 0);
+ LL5("skip committed " << i << " " << rowp);
+ continue;
+ }
+ assert(rowp->m_st == Row::StDefine || rowp->m_st == Row::StPrepare);
+ assert(rowp->m_txid != 0);
+ if (con.m_txid != rowp->m_txid) {
+ LL5("skip txid " << i << " " << HEX(con.m_txid) << " " << rowp);
+ continue;
+ }
+ // TODO read ops
+ assert(rowp->m_op & Row::OpDML);
+ LL4("post BEFORE " << rowp);
+ if (et == NoCommit) {
+ if (rowp->m_st == Row::StDefine) {
+ rowp->m_st = Row::StPrepare;
+ Row* bi = rowp->m_bi;
+ while (bi != 0 && bi->m_st == Row::StDefine) {
+ bi->m_st = Row::StPrepare;
+ bi = bi->m_bi;
+ }
+ }
+ } else if (et == Commit) {
+ if (rowp->m_op != Row::OpDel) {
+ rowp->m_st = Row::StCommit;
+ rowp->m_op = Row::OpNone;
+ rowp->m_txid = 0;
+ delete rowp->m_bi;
+ rowp->m_bi = 0;
+ } else {
+ delete rowp;
+ rowp = 0;
+ }
+ } else if (et == Rollback) {
+ while (rowp != 0 && rowp->m_st != Row::StCommit) {
+ Row* tmp = rowp;
+ rowp = rowp->m_bi;
+ tmp->m_bi = 0;
+ delete tmp;
+ }
+ } else {
+ assert(false);
+ }
+ m_row[i] = rowp;
+ LL4("post AFTER " << rowp);
}
}
// operations
int
-Set::insrow(Par par, unsigned i)
+Set::insrow(Par par, uint i)
{
assert(m_row[i] != 0);
Row& row = *m_row[i];
@@ -2796,7 +2902,7 @@ Set::insrow(Par par, unsigned i)
}
int
-Set::updrow(Par par, unsigned i)
+Set::updrow(Par par, uint i)
{
assert(m_row[i] != 0);
Row& row = *m_row[i];
@@ -2805,7 +2911,7 @@ Set::updrow(Par par, unsigned i)
}
int
-Set::updrow(Par par, const ITab& itab, unsigned i)
+Set::updrow(Par par, const ITab& itab, uint i)
{
assert(m_row[i] != 0);
Row& row = *m_row[i];
@@ -2814,7 +2920,7 @@ Set::updrow(Par par, const ITab& itab, unsigned i)
}
int
-Set::delrow(Par par, unsigned i)
+Set::delrow(Par par, uint i)
{
assert(m_row[i] != 0);
Row& row = *m_row[i];
@@ -2823,7 +2929,7 @@ Set::delrow(Par par, unsigned i)
}
int
-Set::delrow(Par par, const ITab& itab, unsigned i)
+Set::delrow(Par par, const ITab& itab, uint i)
{
assert(m_row[i] != 0);
Row& row = *m_row[i];
@@ -2836,8 +2942,8 @@ Set::selrow(Par par, const Row& keyrow)
{
Con& con = par.con();
const Tab& tab = par.tab();
- setkey(par, keyrow);
- LL5("selrow " << tab.m_name << ": keyrow: " << keyrow);
+ LL5("selrow " << tab.m_name << " keyrow " << keyrow);
+ m_keyrow->copyval(keyrow, tab.m_pkmask);
CHK(m_keyrow->selrow(par) == 0);
CHK(getval(par) == 0);
return 0;
@@ -2847,45 +2953,15 @@ int
Set::selrow(Par par, const ITab& itab, const Row& keyrow)
{
Con& con = par.con();
- setkey(par, itab, keyrow);
- LL5("selrow " << itab.m_name << ": keyrow: " << keyrow);
+ LL5("selrow " << itab.m_name << " keyrow " << keyrow);
+ m_keyrow->copyval(keyrow, itab.m_keymask);
CHK(m_keyrow->selrow(par, itab) == 0);
CHK(getval(par) == 0);
return 0;
}
-// set and get
-
-void
-Set::setkey(Par par, const Row& keyrow)
-{
- const Tab& tab = m_tab;
- for (unsigned k = 0; k < tab.m_cols; k++) {
- const Col& col = *tab.m_col[k];
- if (col.m_pk) {
- Val& val1 = *m_keyrow->m_val[k];
- const Val& val2 = *keyrow.dbrow().m_val[k];
- val1.copy(val2);
- }
- }
-}
-
-void
-Set::setkey(Par par, const ITab& itab, const Row& keyrow)
-{
- const Tab& tab = m_tab;
- for (unsigned k = 0; k < itab.m_icols; k++) {
- const ICol& icol = *itab.m_icol[k];
- const Col& col = icol.m_col;
- unsigned m = col.m_num;
- Val& val1 = *m_keyrow->m_val[m];
- const Val& val2 = *keyrow.dbrow().m_val[m];
- val1.copy(val2);
- }
-}
-
int
-Set::setrow(Par par, unsigned i)
+Set::setrow(Par par, uint i)
{
Con& con = par.con();
assert(m_row[i] != 0);
@@ -2899,18 +2975,18 @@ Set::getval(Par par)
Con& con = par.con();
const Tab& tab = m_tab;
Rsq rsq1(tab.m_cols);
- for (unsigned k = 0; k < tab.m_cols; k++) {
- unsigned k2 = rsq1.next();
+ for (uint k = 0; k < tab.m_cols; k++) {
+ uint k2 = rsq1.next();
CHK(con.getValue(k2, m_rec[k2]) == 0);
}
return 0;
}
int
-Set::getkey(Par par, unsigned* i)
+Set::getkey(Par par, uint* i)
{
const Tab& tab = m_tab;
- unsigned k = tab.m_keycol;
+ uint k = tab.m_keycol;
assert(m_rec[k] != 0);
const char* aRef = m_rec[k]->aRef();
Uint32 key = *(const Uint32*)aRef;
@@ -2921,14 +2997,18 @@ Set::getkey(Par par, unsigned* i)
}
int
-Set::putval(unsigned i, bool force, unsigned n)
+Set::putval(uint i, bool force, uint n)
{
const Tab& tab = m_tab;
- if (m_row[i] == 0)
- m_row[i] = new Row(tab);
+ LL4("putval key=" << i << " row=" << n << " old=" << m_row[i]);
+ if (m_row[i] != 0) {
+ assert(force);
+ delete m_row[i];
+ m_row[i] = 0;
+ }
+ m_row[i] = new Row(tab);
Row& row = *m_row[i];
- CHK(! row.m_exist || force);
- for (unsigned k = 0; k < tab.m_cols; k++) {
+ for (uint k = 0; k < tab.m_cols; k++) {
Val& val = *row.m_val[k];
NdbRecAttr* rec = m_rec[k];
assert(rec != 0);
@@ -2940,13 +3020,13 @@ Set::putval(unsigned i, bool force, unsigned n)
val.copy(aRef);
val.m_null = false;
}
- if (! row.m_exist)
- row.m_exist = true;
if (n != ~0)
m_rowkey[n] = i;
return 0;
}
+// compare
+
void
Set::sort(Par par, const ITab& itab)
{
@@ -2955,12 +3035,12 @@ Set::sort(Par par, const ITab& itab)
}
void
-Set::sort(Par par, const ITab& itab, unsigned lo, unsigned hi)
+Set::sort(Par par, const ITab& itab, uint lo, uint hi)
{
assert(lo < m_rows && hi < m_rows && lo <= hi);
Row* const p = m_row[lo];
- unsigned i = lo;
- unsigned j = hi;
+ uint i = lo;
+ uint j = hi;
while (i < j) {
while (i < j && m_row[j]->cmp(par, *p, itab) >= 0)
j--;
@@ -2982,22 +3062,48 @@ Set::sort(Par par, const ITab& itab, unsigned lo, unsigned hi)
sort(par, itab, i + 1, hi);
}
+/*
+ * set1 (self) is from dml and can contain un-committed operations.
+ * set2 is from read and contains no operations. "dirty" applies
+ * to set1: false = use latest row, true = use committed row.
+ */
int
-Set::verify(Par par, const Set& set2, bool pkonly) const
-{
- assert(&m_tab == &set2.m_tab && m_rows == set2.m_rows);
- LL4("verify set1 count=" << count() << " vs set2 count=" << set2.count());
- for (unsigned i = 0; i < m_rows; i++) {
+Set::verify(Par par, const Set& set2, bool pkonly, bool dirty) const
+{
+ const Set& set1 = *this;
+ assert(&set1.m_tab == &set2.m_tab && set1.m_rows == set2.m_rows);
+ LL3("verify dirty:" << dirty);
+ for (uint i = 0; i < set1.m_rows; i++) {
+ // the row versions we actually compare
+ const Row* row1p = set1.getrow(i, dirty);
+ const Row* row2p = set2.getrow(i);
bool ok = true;
- if (exist(i) != set2.exist(i)) {
- ok = false;
- } else if (exist(i)) {
- if (dbrow(i).verify(par, set2.dbrow(i), pkonly) != 0)
+ int place = 0;
+ if (row1p == 0) {
+ if (row2p != 0) {
+ ok = false;
+ place = 1;
+ }
+ } else {
+ Row::Op op1 = row1p->m_op;
+ if (op1 != Row::OpDel) {
+ if (row2p == 0) {
+ ok = false;
+ place = 2;
+ } else if (row1p->verify(par, *row2p, pkonly) == -1) {
+ ok = false;
+ place = 3;
+ }
+ } else if (row2p != 0) {
ok = false;
+ place = 4;
+ }
}
- if (! ok) {
- LL1("verify failed: key=" << i << " row1=" << m_row[i] << " row2=" << set2.m_row[i]);
- CHK(0 == 1);
+ if (!ok) {
+ LL1("verify " << i << " failed at " << place);
+ LL1("row1 " << row1p);
+ LL1("row2 " << row2p);
+ CHK(false);
}
}
return 0;
@@ -3007,18 +3113,17 @@ int
Set::verifyorder(Par par, const ITab& itab, bool descending) const
{
const Tab& tab = m_tab;
- for (unsigned n = 0; n < m_rows; n++) {
- unsigned i2 = m_rowkey[n];
+ for (uint n = 0; n < m_rows; n++) {
+ uint i2 = m_rowkey[n];
if (i2 == ~0)
break;
if (n == 0)
continue;
- unsigned i1 = m_rowkey[n - 1];
- assert(i1 < m_rows && i2 < m_rows);
+ uint i1 = m_rowkey[n - 1];
+ assert(m_row[i1] != 0 && m_row[i2] != 0);
const Row& row1 = *m_row[i1];
const Row& row2 = *m_row[i2];
- assert(row1.m_exist && row2.m_exist);
- if (! descending)
+ if (!descending)
CHK(row1.cmp(par, row2, itab) <= 0);
else
CHK(row1.cmp(par, row2, itab) >= 0);
@@ -3026,10 +3131,12 @@ Set::verifyorder(Par par, const ITab& itab, bool descending) const
return 0;
}
+// print
+
static NdbOut&
operator<<(NdbOut& out, const Set& set)
{
- for (unsigned i = 0; i < set.m_rows; i++) {
+ for (uint i = 0; i < set.m_rows; i++) {
const Row& row = *set.m_row[i];
if (i > 0)
out << endl;
@@ -3058,8 +3165,8 @@ int
BVal::setbnd(Par par) const
{
Con& con = par.con();
- assert(g_compare_null || ! m_null);
- const char* addr = ! m_null ? (const char*)dataaddr() : 0;
+ assert(g_compare_null || !m_null);
+ const char* addr = !m_null ? (const char*)dataaddr() : 0;
const ICol& icol = m_icol;
CHK(con.setBound(icol.m_num, m_type, addr) == 0);
return 0;
@@ -3068,7 +3175,7 @@ BVal::setbnd(Par par) const
int
BVal::setflt(Par par) const
{
- static unsigned index_bound_to_filter_bound[5] = {
+ static uint index_bound_to_filter_bound[5] = {
NdbScanFilter::COND_GE,
NdbScanFilter::COND_GT,
NdbScanFilter::COND_LE,
@@ -3076,12 +3183,12 @@ BVal::setflt(Par par) const
NdbScanFilter::COND_EQ
};
Con& con = par.con();
- assert(g_compare_null || ! m_null);
- const char* addr = ! m_null ? (const char*)dataaddr() : 0;
+ assert(g_compare_null || !m_null);
+ const char* addr = !m_null ? (const char*)dataaddr() : 0;
const ICol& icol = m_icol;
const Col& col = icol.m_col;
- unsigned length = col.m_bytesize;
- unsigned cond = index_bound_to_filter_bound[m_type];
+ uint length = col.m_bytesize;
+ uint cond = index_bound_to_filter_bound[m_type];
CHK(con.setFilter(col.m_num, cond, addr, length) == 0);
return 0;
}
@@ -3104,27 +3211,27 @@ operator<<(NdbOut& out, const BVal& bval)
struct BSet {
const Tab& m_tab;
const ITab& m_itab;
- unsigned m_alloc;
- unsigned m_bvals;
+ uint m_alloc;
+ uint m_bvals;
BVal** m_bval;
- BSet(const Tab& tab, const ITab& itab, unsigned rows);
+ BSet(const Tab& tab, const ITab& itab);
~BSet();
void reset();
void calc(Par par);
- void calcpk(Par par, unsigned i);
+ void calcpk(Par par, uint i);
int setbnd(Par par) const;
int setflt(Par par) const;
void filter(Par par, const Set& set, Set& set2) const;
};
-BSet::BSet(const Tab& tab, const ITab& itab, unsigned rows) :
+BSet::BSet(const Tab& tab, const ITab& itab) :
m_tab(tab),
m_itab(itab),
m_alloc(2 * itab.m_icols),
m_bvals(0)
{
m_bval = new BVal* [m_alloc];
- for (unsigned i = 0; i < m_alloc; i++) {
+ for (uint i = 0; i < m_alloc; i++) {
m_bval[i] = 0;
}
}
@@ -3138,7 +3245,7 @@ void
BSet::reset()
{
while (m_bvals > 0) {
- unsigned i = --m_bvals;
+ uint i = --m_bvals;
delete m_bval[i];
m_bval[i] = 0;
}
@@ -3150,10 +3257,10 @@ BSet::calc(Par par)
const ITab& itab = m_itab;
par.m_pctrange = par.m_pctbrange;
reset();
- for (unsigned k = 0; k < itab.m_icols; k++) {
+ for (uint k = 0; k < itab.m_icols; k++) {
const ICol& icol = *itab.m_icol[k];
const Col& col = icol.m_col;
- for (unsigned i = 0; i <= 1; i++) {
+ for (uint i = 0; i <= 1; i++) {
if (m_bvals == 0 && urandom(100) == 0)
return;
if (m_bvals != 0 && urandom(3) == 0)
@@ -3162,7 +3269,7 @@ BSet::calc(Par par)
BVal& bval = *new BVal(icol);
m_bval[m_bvals++] = &bval;
bval.m_null = false;
- unsigned sel;
+ uint sel;
do {
// equality bound only on i==0
sel = urandom(5 - i);
@@ -3175,7 +3282,7 @@ BSet::calc(Par par)
bval.m_type = 4;
if (k + 1 < itab.m_icols)
bval.m_type = 4;
- if (! g_compare_null)
+ if (!g_compare_null)
par.m_pctnull = 0;
if (bval.m_type == 0 || bval.m_type == 1)
par.m_bdir = -1;
@@ -3199,11 +3306,11 @@ BSet::calc(Par par)
}
void
-BSet::calcpk(Par par, unsigned i)
+BSet::calcpk(Par par, uint i)
{
const ITab& itab = m_itab;
reset();
- for (unsigned k = 0; k < itab.m_icols; k++) {
+ for (uint k = 0; k < itab.m_icols; k++) {
const ICol& icol = *itab.m_icol[k];
const Col& col = icol.m_col;
assert(col.m_pk);
@@ -3220,14 +3327,14 @@ BSet::setbnd(Par par) const
{
if (m_bvals != 0) {
Rsq rsq1(m_bvals);
- for (unsigned j = 0; j < m_bvals; j++) {
- unsigned j2 = rsq1.next();
+ for (uint j = 0; j < m_bvals; j++) {
+ uint j2 = rsq1.next();
const BVal& bval = *m_bval[j2];
CHK(bval.setbnd(par) == 0);
}
// duplicate
if (urandom(5) == 0) {
- unsigned j3 = urandom(m_bvals);
+ uint j3 = urandom(m_bvals);
const BVal& bval = *m_bval[j3];
CHK(bval.setbnd(par) == 0);
}
@@ -3243,14 +3350,14 @@ BSet::setflt(Par par) const
CHK(con.beginFilter(NdbScanFilter::AND) == 0);
if (m_bvals != 0) {
Rsq rsq1(m_bvals);
- for (unsigned j = 0; j < m_bvals; j++) {
- unsigned j2 = rsq1.next();
+ for (uint j = 0; j < m_bvals; j++) {
+ uint j2 = rsq1.next();
const BVal& bval = *m_bval[j2];
CHK(bval.setflt(par) == 0);
}
// duplicate
if (urandom(5) == 0) {
- unsigned j3 = urandom(m_bvals);
+ uint j3 = urandom(m_bvals);
const BVal& bval = *m_bval[j3];
CHK(bval.setflt(par) == 0);
}
@@ -3266,57 +3373,59 @@ BSet::filter(Par par, const Set& set, Set& set2) const
const ITab& itab = m_itab;
assert(&tab == &set2.m_tab && set.m_rows == set2.m_rows);
assert(set2.count() == 0);
- for (unsigned i = 0; i < set.m_rows; i++) {
- if (! set.exist(i))
- continue;
+ for (uint i = 0; i < set.m_rows; i++) {
set.lock();
- const Row& row = set.dbrow(i);
- set.unlock();
- if (! g_store_null_key) {
- bool ok1 = false;
- for (unsigned k = 0; k < itab.m_icols; k++) {
- const ICol& icol = *itab.m_icol[k];
+ do {
+ if (set.m_row[i] == 0) {
+ break;
+ }
+ const Row& row = *set.m_row[i];
+ if (!g_store_null_key) {
+ bool ok1 = false;
+ for (uint k = 0; k < itab.m_icols; k++) {
+ const ICol& icol = *itab.m_icol[k];
+ const Col& col = icol.m_col;
+ const Val& val = *row.m_val[col.m_num];
+ if (!val.m_null) {
+ ok1 = true;
+ break;
+ }
+ }
+ if (!ok1)
+ break;
+ }
+ bool ok2 = true;
+ for (uint j = 0; j < m_bvals; j++) {
+ const BVal& bval = *m_bval[j];
+ const ICol& icol = bval.m_icol;
const Col& col = icol.m_col;
const Val& val = *row.m_val[col.m_num];
- if (! val.m_null) {
- ok1 = true;
- break;
+ int ret = bval.cmp(par, val);
+ LL5("cmp: ret=" << ret << " " << bval << " vs " << val);
+ if (bval.m_type == 0)
+ ok2 = (ret <= 0);
+ else if (bval.m_type == 1)
+ ok2 = (ret < 0);
+ else if (bval.m_type == 2)
+ ok2 = (ret >= 0);
+ else if (bval.m_type == 3)
+ ok2 = (ret > 0);
+ else if (bval.m_type == 4)
+ ok2 = (ret == 0);
+ else {
+ assert(false);
}
+ if (!ok2)
+ break;
}
- if (! ok1)
- continue;
- }
- bool ok2 = true;
- for (unsigned j = 0; j < m_bvals; j++) {
- const BVal& bval = *m_bval[j];
- const ICol& icol = bval.m_icol;
- const Col& col = icol.m_col;
- const Val& val = *row.m_val[col.m_num];
- int ret = bval.cmp(par, val);
- LL5("cmp: ret=" << ret << " " << bval << " vs " << val);
- if (bval.m_type == 0)
- ok2 = (ret <= 0);
- else if (bval.m_type == 1)
- ok2 = (ret < 0);
- else if (bval.m_type == 2)
- ok2 = (ret >= 0);
- else if (bval.m_type == 3)
- ok2 = (ret > 0);
- else if (bval.m_type == 4)
- ok2 = (ret == 0);
- else {
- assert(false);
- }
- if (! ok2)
+ if (!ok2)
break;
- }
- if (! ok2)
- continue;
- if (set2.m_row[i] == 0)
+ assert(set2.m_row[i] == 0);
set2.m_row[i] = new Row(tab);
- Row& row2 = *set2.m_row[i];
- assert(! row2.m_exist);
- row2.copy(row);
+ Row& row2 = *set2.m_row[i];
+ row2.copy(row, true);
+ } while (0);
+ set.unlock();
}
}
@@ -3324,7 +3433,7 @@ static NdbOut&
operator<<(NdbOut& out, const BSet& bset)
{
out << "bounds=" << bset.m_bvals;
- for (unsigned j = 0; j < bset.m_bvals; j++) {
+ for (uint j = 0; j < bset.m_bvals; j++) {
const BVal& bval = *bset.m_bval[j];
out << " [bound " << j << ": " << bval << "]";
}
@@ -3341,59 +3450,40 @@ pkinsert(Par par)
Set& set = par.set();
LL3("pkinsert " << tab.m_name);
CHK(con.startTransaction() == 0);
- Lst lst;
- for (unsigned j = 0; j < par.m_rows; j++) {
- unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
- unsigned i = thrrow(par, j2);
+ uint batch = 0;
+ for (uint j = 0; j < par.m_rows; j++) {
+ uint j2 = !par.m_randomkey ? j : urandom(par.m_rows);
+ uint i = thrrow(par, j2);
set.lock();
- if (set.exist(i) || set.pending(i, Row::AnyOp)) {
+ if (!set.compat(par, i, Row::OpIns)) {
+ LL3("pkinsert SKIP " << i << " " << set.getrow(i));
set.unlock();
- continue;
- }
- set.calc(par, i);
- CHK(set.insrow(par, i) == 0);
- set.unlock();
- LL4("pkinsert " << i << ": " << *set.m_row[i]);
- lst.push(i);
- if (lst.cnt() == par.m_batch) {
- bool deadlock = par.m_deadlock;
- bool nospace = true;
- ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
- CHK(con.execute(et, deadlock, nospace) == 0);
- con.closeTransaction();
- if (deadlock) {
- LL1("pkinsert: stop on deadlock [at 1]");
- return 0;
- }
- if (nospace) {
- LL1("pkinsert: cnt=" << j << " stop on nospace");
- return 0;
- }
+ } else {
+ set.push(i);
+ set.calc(par, i);
+ CHK(set.insrow(par, i) == 0);
+ set.unlock();
+ LL4("pkinsert key=" << i << " " << set.getrow(i));
+ batch++;
+ }
+ bool lastbatch = (batch != 0 && j + 1 == par.m_rows);
+ if (batch == par.m_batch || lastbatch) {
+ uint err = par.m_catcherr;
+ ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback;
+ CHK(con.execute(et, err) == 0);
set.lock();
- set.notpending(lst, et);
+ set.post(par, !err ? et : Rollback);
set.unlock();
- lst.reset();
- CHK(con.startTransaction() == 0);
- }
- }
- if (lst.cnt() != 0) {
- bool deadlock = par.m_deadlock;
- bool nospace = true;
- ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
- CHK(con.execute(et, deadlock, nospace) == 0);
- con.closeTransaction();
- if (deadlock) {
- LL1("pkinsert: stop on deadlock [at 2]");
- return 0;
- }
- if (nospace) {
- LL1("pkinsert: end: stop on nospace");
- return 0;
+ if (err) {
+ LL1("pkinsert key=" << i << " stop on " << con.errname(err));
+ break;
+ }
+ batch = 0;
+ if (!lastbatch) {
+ con.closeTransaction();
+ CHK(con.startTransaction() == 0);
+ }
}
- set.lock();
- set.notpending(lst, et);
- set.unlock();
- return 0;
}
con.closeTransaction();
return 0;
@@ -3407,59 +3497,40 @@ pkupdate(Par par)
Set& set = par.set();
LL3("pkupdate " << tab.m_name);
CHK(con.startTransaction() == 0);
- Lst lst;
- bool deadlock = false;
- bool nospace = false;
- for (unsigned j = 0; j < par.m_rows; j++) {
- unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
- unsigned i = thrrow(par, j2);
+ uint batch = 0;
+ for (uint j = 0; j < par.m_rows; j++) {
+ uint j2 = !par.m_randomkey ? j : urandom(par.m_rows);
+ uint i = thrrow(par, j2);
set.lock();
- if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
- set.unlock();
- continue;
- }
- set.dbsave(i);
- set.calc(par, i);
- CHK(set.updrow(par, i) == 0);
- set.unlock();
- LL4("pkupdate " << i << ": " << *set.m_row[i]);
- lst.push(i);
- if (lst.cnt() == par.m_batch) {
- deadlock = par.m_deadlock;
- nospace = true;
- ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
- CHK(con.execute(et, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("pkupdate: stop on deadlock [at 1]");
- break;
- }
- if (nospace) {
- LL1("pkupdate: cnt=" << j << " stop on nospace [at 1]");
- break;
- }
- con.closeTransaction();
- set.lock();
- set.notpending(lst, et);
- set.dbdiscard(lst);
+ if (!set.compat(par, i, Row::OpUpd)) {
+ LL3("pkupdate SKIP " << i << " " << set.getrow(i));
set.unlock();
- lst.reset();
- CHK(con.startTransaction() == 0);
- }
- }
- if (! deadlock && ! nospace && lst.cnt() != 0) {
- deadlock = par.m_deadlock;
- nospace = true;
- ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
- CHK(con.execute(et, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("pkupdate: stop on deadlock [at 2]");
- } else if (nospace) {
- LL1("pkupdate: end: stop on nospace [at 2]");
} else {
+ set.push(i);
+ set.copyval(i, tab.m_pkmask);
+ set.calc(par, i, ~tab.m_pkmask);
+ CHK(set.updrow(par, i) == 0);
+ set.unlock();
+ LL4("pkupdate key=" << i << " " << set.getrow(i));
+ batch++;
+ }
+ bool lastbatch = (batch != 0 && j + 1 == par.m_rows);
+ if (batch == par.m_batch || lastbatch) {
+ uint err = par.m_catcherr;
+ ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback;
+ CHK(con.execute(et, err) == 0);
set.lock();
- set.notpending(lst, et);
- set.dbdiscard(lst);
+ set.post(par, !err ? et : Rollback);
set.unlock();
+ if (err) {
+ LL1("pkupdate key=" << i << ": stop on " << con.errname(err));
+ break;
+ }
+ batch = 0;
+ if (!lastbatch) {
+ con.closeTransaction();
+ CHK(con.startTransaction() == 0);
+ }
}
}
con.closeTransaction();
@@ -3474,49 +3545,39 @@ pkdelete(Par par)
Set& set = par.set();
LL3("pkdelete " << tab.m_name);
CHK(con.startTransaction() == 0);
- Lst lst;
- bool deadlock = false;
- bool nospace = false;
- for (unsigned j = 0; j < par.m_rows; j++) {
- unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
- unsigned i = thrrow(par, j2);
+ uint batch = 0;
+ for (uint j = 0; j < par.m_rows; j++) {
+ uint j2 = !par.m_randomkey ? j : urandom(par.m_rows);
+ uint i = thrrow(par, j2);
set.lock();
- if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
+ if (!set.compat(par, i, Row::OpDel)) {
+ LL3("pkdelete SKIP " << i << " " << set.getrow(i));
set.unlock();
- continue;
- }
- CHK(set.delrow(par, i) == 0);
- set.unlock();
- LL4("pkdelete " << i << ": " << *set.m_row[i]);
- lst.push(i);
- if (lst.cnt() == par.m_batch) {
- deadlock = par.m_deadlock;
- nospace = true;
- ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
- CHK(con.execute(et, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("pkdelete: stop on deadlock [at 1]");
- break;
- }
- con.closeTransaction();
- set.lock();
- set.notpending(lst, et);
- set.unlock();
- lst.reset();
- CHK(con.startTransaction() == 0);
- }
- }
- if (! deadlock && ! nospace && lst.cnt() != 0) {
- deadlock = par.m_deadlock;
- nospace = true;
- ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
- CHK(con.execute(et, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("pkdelete: stop on deadlock [at 2]");
} else {
+ set.push(i);
+ set.copyval(i, tab.m_pkmask);
+ CHK(set.delrow(par, i) == 0);
+ set.unlock();
+ LL4("pkdelete key=" << i << " " << set.getrow(i));
+ batch++;
+ }
+ bool lastbatch = (batch != 0 && j + 1 == par.m_rows);
+ if (batch == par.m_batch || lastbatch) {
+ uint err = par.m_catcherr;
+ ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback;
+ CHK(con.execute(et, err) == 0);
set.lock();
- set.notpending(lst, et);
+ set.post(par, !err ? et : Rollback);
set.unlock();
+ if (err) {
+ LL1("pkdelete key=" << i << " stop on " << con.errname(err));
+ break;
+ }
+ batch = 0;
+ if (!lastbatch) {
+ con.closeTransaction();
+ CHK(con.startTransaction() == 0);
+ }
}
}
con.closeTransaction();
@@ -3533,9 +3594,11 @@ pkread(Par par)
// expected
const Set& set1 = set;
Set set2(tab, set.m_rows);
- for (unsigned i = 0; i < set.m_rows; i++) {
+ for (uint i = 0; i < set.m_rows; i++) {
set.lock();
- if (! set.exist(i)) {
+ // TODO lock mode
+ if (!set.compat(par, i, Row::OpREAD)) {
+ LL3("pkread SKIP " << i << " " << set.getrow(i));
set.unlock();
continue;
}
@@ -3543,10 +3606,10 @@ pkread(Par par)
CHK(con.startTransaction() == 0);
CHK(set2.selrow(par, *set1.m_row[i]) == 0);
CHK(con.execute(Commit) == 0);
- unsigned i2 = (unsigned)-1;
+ uint i2 = (uint)-1;
CHK(set2.getkey(par, &i2) == 0 && i == i2);
CHK(set2.putval(i, false) == 0);
- LL4("row " << set2.count() << ": " << *set2.m_row[i]);
+ LL4("row " << set2.count() << " " << set2.getrow(i));
con.closeTransaction();
}
if (par.m_verify)
@@ -3555,7 +3618,7 @@ pkread(Par par)
}
static int
-pkreadfast(Par par, unsigned count)
+pkreadfast(Par par, uint count)
{
Con& con = par.con();
const Tab& tab = par.tab();
@@ -3563,9 +3626,9 @@ pkreadfast(Par par, unsigned count)
LL3("pkfast " << tab.m_name);
Row keyrow(tab);
// not batched on purpose
- for (unsigned j = 0; j < count; j++) {
- unsigned i = urandom(set.m_rows);
- assert(set.exist(i));
+ for (uint j = 0; j < count; j++) {
+ uint i = urandom(set.m_rows);
+ assert(set.compat(par, i, Row::OpREAD));
CHK(con.startTransaction() == 0);
// define key
keyrow.calc(par, i);
@@ -3585,53 +3648,46 @@ static int
hashindexupdate(Par par, const ITab& itab)
{
Con& con = par.con();
+ const Tab& tab = par.tab();
Set& set = par.set();
LL3("hashindexupdate " << itab.m_name);
CHK(con.startTransaction() == 0);
- Lst lst;
- bool deadlock = false;
- bool nospace = false;
- for (unsigned j = 0; j < par.m_rows; j++) {
- unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
- unsigned i = thrrow(par, j2);
+ uint batch = 0;
+ for (uint j = 0; j < par.m_rows; j++) {
+ uint j2 = !par.m_randomkey ? j : urandom(par.m_rows);
+ uint i = thrrow(par, j2);
set.lock();
- if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
+ if (!set.compat(par, i, Row::OpUpd)) {
+ LL3("hashindexupdate SKIP " << i << " " << set.getrow(i));
set.unlock();
- continue;
- }
- set.dbsave(i);
- // index key columns are not re-calculated
- set.calc(par, i, itab.m_colmask);
- CHK(set.updrow(par, itab, i) == 0);
- set.unlock();
- LL4("hashindexupdate " << i << ": " << *set.m_row[i]);
- lst.push(i);
- if (lst.cnt() == par.m_batch) {
- deadlock = par.m_deadlock;
- CHK(con.execute(Commit, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("hashindexupdate: stop on deadlock [at 1]");
- break;
- }
- con.closeTransaction();
- set.lock();
- set.notpending(lst);
- set.dbdiscard(lst);
- set.unlock();
- lst.reset();
- CHK(con.startTransaction() == 0);
- }
- }
- if (! deadlock && lst.cnt() != 0) {
- deadlock = par.m_deadlock;
- CHK(con.execute(Commit, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("hashindexupdate: stop on deadlock [at 2]");
} else {
+ // table pk and index key are not updated
+ set.push(i);
+ uint keymask = tab.m_pkmask | itab.m_keymask;
+ set.copyval(i, keymask);
+ set.calc(par, i, ~keymask);
+ CHK(set.updrow(par, itab, i) == 0);
+ set.unlock();
+ LL4("hashindexupdate " << i << " " << set.getrow(i));
+ batch++;
+ }
+ bool lastbatch = (batch != 0 && j + 1 == par.m_rows);
+ if (batch == par.m_batch || lastbatch) {
+ uint err = par.m_catcherr;
+ ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback;
+ CHK(con.execute(et, err) == 0);
set.lock();
- set.notpending(lst);
- set.dbdiscard(lst);
+ set.post(par, !err ? et : Rollback);
set.unlock();
+ if (err) {
+ LL1("hashindexupdate " << i << " stop on " << con.errname(err));
+ break;
+ }
+ batch = 0;
+ if (!lastbatch) {
+ con.closeTransaction();
+ CHK(con.startTransaction() == 0);
+ }
}
}
con.closeTransaction();
@@ -3645,45 +3701,39 @@ hashindexdelete(Par par, const ITab& itab)
Set& set = par.set();
LL3("hashindexdelete " << itab.m_name);
CHK(con.startTransaction() == 0);
- Lst lst;
- bool deadlock = false;
- bool nospace = false;
- for (unsigned j = 0; j < par.m_rows; j++) {
- unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
- unsigned i = thrrow(par, j2);
+ uint batch = 0;
+ for (uint j = 0; j < par.m_rows; j++) {
+ uint j2 = !par.m_randomkey ? j : urandom(par.m_rows);
+ uint i = thrrow(par, j2);
set.lock();
- if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
- set.unlock();
- continue;
- }
- CHK(set.delrow(par, itab, i) == 0);
- set.unlock();
- LL4("hashindexdelete " << i << ": " << *set.m_row[i]);
- lst.push(i);
- if (lst.cnt() == par.m_batch) {
- deadlock = par.m_deadlock;
- CHK(con.execute(Commit, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("hashindexdelete: stop on deadlock [at 1]");
- break;
- }
- con.closeTransaction();
- set.lock();
- set.notpending(lst);
+ if (!set.compat(par, i, Row::OpDel)) {
+ LL3("hashindexdelete SKIP " << i << " " << set.getrow(i));
set.unlock();
- lst.reset();
- CHK(con.startTransaction() == 0);
- }
- }
- if (! deadlock && lst.cnt() != 0) {
- deadlock = par.m_deadlock;
- CHK(con.execute(Commit, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("hashindexdelete: stop on deadlock [at 2]");
} else {
+ set.push(i);
+ set.copyval(i, itab.m_keymask);
+ CHK(set.delrow(par, itab, i) == 0);
+ set.unlock();
+ LL4("hashindexdelete " << i << " " << set.getrow(i));
+ batch++;
+ }
+ bool lastbatch = (batch != 0 && j + 1 == par.m_rows);
+ if (batch == par.m_batch || lastbatch) {
+ uint err = par.m_catcherr;
+ ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback;
+ CHK(con.execute(et, err) == 0);
set.lock();
- set.notpending(lst);
+ set.post(par, !err ? et : Rollback);
set.unlock();
+ if (err) {
+ LL1("hashindexdelete " << i << " stop on " << con.errname(err));
+ break;
+ }
+ batch = 0;
+ if (!lastbatch) {
+ con.closeTransaction();
+ CHK(con.startTransaction() == 0);
+ }
}
}
con.closeTransaction();
@@ -3700,9 +3750,11 @@ hashindexread(Par par, const ITab& itab)
// expected
const Set& set1 = set;
Set set2(tab, set.m_rows);
- for (unsigned i = 0; i < set.m_rows; i++) {
+ for (uint i = 0; i < set.m_rows; i++) {
set.lock();
- if (! set.exist(i)) {
+ // TODO lock mode
+ if (!set.compat(par, i, Row::OpREAD)) {
+ LL3("hashindexread SKIP " << i << " " << set.getrow(i));
set.unlock();
continue;
}
@@ -3710,10 +3762,10 @@ hashindexread(Par par, const ITab& itab)
CHK(con.startTransaction() == 0);
CHK(set2.selrow(par, itab, *set1.m_row[i]) == 0);
CHK(con.execute(Commit) == 0);
- unsigned i2 = (unsigned)-1;
+ uint i2 = (uint)-1;
CHK(set2.getkey(par, &i2) == 0 && i == i2);
CHK(set2.putval(i, false) == 0);
- LL4("row " << set2.count() << ": " << *set2.m_row[i]);
+ LL4("row " << set2.count() << " " << *set2.m_row[i]);
con.closeTransaction();
}
if (par.m_verify)
@@ -3731,40 +3783,39 @@ scanreadtable(Par par)
const Set& set = par.set();
// expected
const Set& set1 = set;
- LL3("scanread " << tab.m_name << " lockmode=" << par.m_lockmode << " tupscan=" << par.m_tupscan << " expect=" << set1.count() << " verify=" << par.m_verify);
+ LL3("scanreadtable " << tab.m_name << " lockmode=" << par.m_lockmode << " tupscan=" << par.m_tupscan << " expect=" << set1.count() << " verify=" << par.m_verify);
Set set2(tab, set.m_rows);
CHK(con.startTransaction() == 0);
CHK(con.getNdbScanOperation(tab) == 0);
CHK(con.readTuples(par) == 0);
set2.getval(par);
CHK(con.executeScan() == 0);
- unsigned n = 0;
- bool deadlock = false;
+ uint n = 0;
while (1) {
int ret;
- deadlock = par.m_deadlock;
- CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
+ uint err = par.m_catcherr;
+ CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1);
if (ret == 1)
break;
- if (deadlock) {
- LL1("scanreadtable: stop on deadlock");
+ if (err) {
+ LL1("scanreadtable stop on " << con.errname(err));
break;
}
- unsigned i = (unsigned)-1;
+ uint i = (uint)-1;
CHK(set2.getkey(par, &i) == 0);
CHK(set2.putval(i, false, n) == 0);
- LL4("row " << n << ": " << *set2.m_row[i]);
+ LL4("row " << n << " " << *set2.m_row[i]);
n++;
}
con.closeTransaction();
if (par.m_verify)
CHK(set1.verify(par, set2, false) == 0);
- LL3("scanread " << tab.m_name << " done rows=" << n);
+ LL3("scanreadtable " << tab.m_name << " done rows=" << n);
return 0;
}
static int
-scanreadtablefast(Par par, unsigned countcheck)
+scanreadtablefast(Par par, uint countcheck)
{
Con& con = par.con();
const Tab& tab = par.tab();
@@ -3777,7 +3828,7 @@ scanreadtablefast(Par par, unsigned countcheck)
NdbRecAttr* rec;
CHK(con.getValue((Uint32)0, rec) == 0);
CHK(con.executeScan() == 0);
- unsigned count = 0;
+ uint count = 0;
while (1) {
int ret;
CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
@@ -3797,7 +3848,7 @@ calcscanbounds(Par par, const ITab& itab, BSet& bset, const Set& set, Set& set1)
while (true) {
bset.calc(par);
bset.filter(par, set, set1);
- unsigned n = set1.count();
+ uint n = set1.count();
// prefer proper subset
if (0 < n && n < set.m_rows)
break;
@@ -3819,7 +3870,7 @@ scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc)
} else {
bset.filter(par, set, set1);
}
- LL3("scanread " << itab.m_name << " " << bset << " lockmode=" << par.m_lockmode << " expect=" << set1.count() << " ordered=" << par.m_ordered << " descending=" << par.m_descending << " verify=" << par.m_verify);
+ LL3("scanreadindex " << itab.m_name << " " << bset << " lockmode=" << par.m_lockmode << " expect=" << set1.count() << " ordered=" << par.m_ordered << " descending=" << par.m_descending << " verify=" << par.m_verify);
Set set2(tab, set.m_rows);
CHK(con.startTransaction() == 0);
CHK(con.getNdbIndexScanOperation(itab, tab) == 0);
@@ -3827,22 +3878,21 @@ scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc)
CHK(bset.setbnd(par) == 0);
set2.getval(par);
CHK(con.executeScan() == 0);
- unsigned n = 0;
- bool deadlock = false;
+ uint n = 0;
while (1) {
int ret;
- deadlock = par.m_deadlock;
- CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
+ uint err = par.m_catcherr;
+ CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1);
if (ret == 1)
break;
- if (deadlock) {
- LL1("scanreadindex: stop on deadlock");
+ if (err) {
+ LL1("scanreadindex stop on " << con.errname(err));
break;
}
- unsigned i = (unsigned)-1;
+ uint i = (uint)-1;
CHK(set2.getkey(par, &i) == 0);
CHK(set2.putval(i, par.m_dups, n) == 0);
- LL4("key " << i << " row " << n << ": " << *set2.m_row[i]);
+ LL4("key " << i << " row " << n << " " << *set2.m_row[i]);
n++;
}
con.closeTransaction();
@@ -3851,12 +3901,12 @@ scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc)
if (par.m_ordered)
CHK(set2.verifyorder(par, itab, par.m_descending) == 0);
}
- LL3("scanread " << itab.m_name << " done rows=" << n);
+ LL3("scanreadindex " << itab.m_name << " done rows=" << n);
return 0;
}
static int
-scanreadindexfast(Par par, const ITab& itab, const BSet& bset, unsigned countcheck)
+scanreadindexfast(Par par, const ITab& itab, const BSet& bset, uint countcheck)
{
Con& con = par.con();
const Tab& tab = par.tab();
@@ -3871,7 +3921,7 @@ scanreadindexfast(Par par, const ITab& itab, const BSet& bset, unsigned countche
NdbRecAttr* rec;
CHK(con.getValue((Uint32)0, rec) == 0);
CHK(con.executeScan() == 0);
- unsigned count = 0;
+ uint count = 0;
while (1) {
int ret;
CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
@@ -3904,22 +3954,21 @@ scanreadfilter(Par par, const ITab& itab, BSet& bset, bool calc)
CHK(bset.setflt(par) == 0);
set2.getval(par);
CHK(con.executeScan() == 0);
- unsigned n = 0;
- bool deadlock = false;
+ uint n = 0;
while (1) {
int ret;
- deadlock = par.m_deadlock;
- CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
+ uint err = par.m_catcherr;
+ CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1);
if (ret == 1)
break;
- if (deadlock) {
- LL1("scanfilter: stop on deadlock");
+ if (err) {
+ LL1("scanfilter stop on " << con.errname(err));
break;
}
- unsigned i = (unsigned)-1;
+ uint i = (uint)-1;
CHK(set2.getkey(par, &i) == 0);
CHK(set2.putval(i, par.m_dups, n) == 0);
- LL4("key " << i << " row " << n << ": " << *set2.m_row[i]);
+ LL4("key " << i << " row " << n << " " << *set2.m_row[i]);
n++;
}
con.closeTransaction();
@@ -3934,9 +3983,9 @@ static int
scanreadindex(Par par, const ITab& itab)
{
const Tab& tab = par.tab();
- for (unsigned i = 0; i < par.m_subloop; i++) {
+ for (uint i = 0; i < par.m_ssloop; i++) {
if (itab.m_type == ITab::OrderedIndex) {
- BSet bset(tab, itab, par.m_rows);
+ BSet bset(tab, itab);
CHK(scanreadfilter(par, itab, bset, true) == 0);
CHK(scanreadindex(par, itab, bset, true) == 0);
}
@@ -3948,7 +3997,7 @@ static int
scanreadindex(Par par)
{
const Tab& tab = par.tab();
- for (unsigned i = 0; i < tab.m_itabs; i++) {
+ for (uint i = 0; i < tab.m_itabs; i++) {
if (tab.m_itab[i] == 0)
continue;
const ITab& itab = *tab.m_itab[i];
@@ -3985,7 +4034,7 @@ timescanpkindex(Par par)
{
const Tab& tab = par.tab();
const ITab& itab = *tab.m_itab[0]; // 1st index is on PK
- BSet bset(tab, itab, par.m_rows);
+ BSet bset(tab, itab);
par.tmr().on();
CHK(scanreadindexfast(par, itab, bset, par.m_totrows) == 0);
par.tmr().off(par.set().m_rows);
@@ -3996,7 +4045,7 @@ static int
timepkreadtable(Par par)
{
par.tmr().on();
- unsigned count = par.m_samples;
+ uint count = par.m_samples;
if (count == 0)
count = par.m_totrows;
CHK(pkreadfast(par, count) == 0);
@@ -4009,13 +4058,13 @@ timepkreadindex(Par par)
{
const Tab& tab = par.tab();
const ITab& itab = *tab.m_itab[0]; // 1st index is on PK
- BSet bset(tab, itab, par.m_rows);
- unsigned count = par.m_samples;
+ BSet bset(tab, itab);
+ uint count = par.m_samples;
if (count == 0)
count = par.m_totrows;
par.tmr().on();
- for (unsigned j = 0; j < count; j++) {
- unsigned i = urandom(par.m_totrows);
+ for (uint j = 0; j < count; j++) {
+ uint i = urandom(par.m_totrows);
bset.calcpk(par, i);
CHK(scanreadindexfast(par, itab, bset, 1) == 0);
}
@@ -4031,7 +4080,7 @@ scanupdatetable(Par par)
Con& con = par.con();
const Tab& tab = par.tab();
Set& set = par.set();
- LL3("scan update " << tab.m_name);
+ LL3("scanupdatetable " << tab.m_name);
Set set2(tab, set.m_rows);
par.m_lockmode = NdbOperation::LM_Exclusive;
CHK(con.startTransaction() == 0);
@@ -4039,87 +4088,70 @@ scanupdatetable(Par par)
CHK(con.readTuples(par) == 0);
set2.getval(par);
CHK(con.executeScan() == 0);
- unsigned count = 0;
+ uint count = 0;
// updating trans
Con con2;
con2.connect(con);
CHK(con2.startTransaction() == 0);
- Lst lst;
- bool deadlock = false;
- bool nospace = false;
+ uint batch = 0;
while (1) {
int ret;
- deadlock = par.m_deadlock;
- CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
- if (ret == 1)
+ uint32 err = par.m_catcherr;
+ CHK((ret = con.nextScanResult(true, err)) != -1);
+ if (ret != 0)
break;
- if (deadlock) {
- LL1("scanupdatetable: stop on deadlock [at 1]");
+ if (err) {
+ LL1("scanupdatetable [scan] stop on " << con.errname(err));
break;
}
if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) {
con.closeScan();
break;
}
- do {
- unsigned i = (unsigned)-1;
+ while (1) {
+ uint i = (uint)-1;
CHK(set2.getkey(par, &i) == 0);
- const Row& row = *set.m_row[i];
set.lock();
- if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
- LL4("scan update " << tab.m_name << ": skip: " << row);
+ if (!set.compat(par, i, Row::OpUpd)) {
+ LL3("scanupdatetable SKIP " << i << " " << set.getrow(i));
} else {
CHKTRY(set2.putval(i, false) == 0, set.unlock());
CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
Par par2 = par;
par2.m_con = &con2;
- set.dbsave(i);
- set.calc(par, i);
+ set.push(i);
+ set.calc(par, i, ~tab.m_pkmask);
CHKTRY(set.setrow(par2, i) == 0, set.unlock());
- LL4("scan update " << tab.m_name << ": " << row);
- lst.push(i);
+ LL4("scanupdatetable " << i << " " << set.getrow(i));
+ batch++;
}
set.unlock();
- if (lst.cnt() == par.m_batch) {
- deadlock = par.m_deadlock;
- CHK(con2.execute(Commit, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("scanupdatetable: stop on deadlock [at 2]");
- goto out;
- }
- con2.closeTransaction();
+ CHK((ret = con.nextScanResult(false)) != -1);
+ bool lastbatch = (batch != 0 && ret != 0);
+ if (batch == par.m_batch || lastbatch) {
+ uint err = par.m_catcherr;
+ ExecType et = Commit;
+ CHK(con2.execute(et, err) == 0);
set.lock();
- set.notpending(lst);
- set.dbdiscard(lst);
+ set.post(par, !err ? et : Rollback);
set.unlock();
- count += lst.cnt();
- lst.reset();
- CHK(con2.startTransaction() == 0);
- }
- CHK((ret = con.nextScanResult(false)) == 0 || ret == 1 || ret == 2);
- if (ret == 2 && lst.cnt() != 0) {
- deadlock = par.m_deadlock;
- CHK(con2.execute(Commit, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("scanupdatetable: stop on deadlock [at 3]");
+ if (err) {
+ LL1("scanupdatetable [update] stop on " << con2.errname(err));
goto out;
}
+ LL4("scanupdatetable committed batch");
+ count += batch;
+ batch = 0;
con2.closeTransaction();
- set.lock();
- set.notpending(lst);
- set.dbdiscard(lst);
- set.unlock();
- count += lst.cnt();
- lst.reset();
CHK(con2.startTransaction() == 0);
}
- } while (ret == 0);
- if (ret == 1)
- break;
+ if (ret != 0)
+ break;
+ }
}
out:
con2.closeTransaction();
- LL3("scan update " << tab.m_name << " rows updated=" << count);
+ LL3("scanupdatetable " << tab.m_name << " rows updated=" << count);
con.closeTransaction();
return 0;
}
@@ -4137,7 +4169,7 @@ scanupdateindex(Par par, const ITab& itab, BSet& bset, bool calc)
} else {
bset.filter(par, set, set1);
}
- LL3("scan update " << itab.m_name << " " << bset << " expect=" << set1.count() << " ordered=" << par.m_ordered << " descending=" << par.m_descending << " verify=" << par.m_verify);
+ LL3("scanupdateindex " << itab.m_name << " " << bset << " expect=" << set1.count() << " ordered=" << par.m_ordered << " descending=" << par.m_descending << " verify=" << par.m_verify);
Set set2(tab, set.m_rows);
par.m_lockmode = NdbOperation::LM_Exclusive;
CHK(con.startTransaction() == 0);
@@ -4146,83 +4178,67 @@ scanupdateindex(Par par, const ITab& itab, BSet& bset, bool calc)
CHK(bset.setbnd(par) == 0);
set2.getval(par);
CHK(con.executeScan() == 0);
- unsigned count = 0;
+ uint count = 0;
// updating trans
Con con2;
con2.connect(con);
CHK(con2.startTransaction() == 0);
- Lst lst;
- bool deadlock = false;
- bool nospace = false;
+ uint batch = 0;
while (1) {
int ret;
- deadlock = par.m_deadlock;
- CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
- if (ret == 1)
+ uint err = par.m_catcherr;
+ CHK((ret = con.nextScanResult(true, err)) != -1);
+ if (ret != 0)
break;
- if (deadlock) {
- LL1("scanupdateindex: stop on deadlock [at 1]");
+ if (err) {
+ LL1("scanupdateindex [scan] stop on " << con.errname(err));
break;
}
if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) {
con.closeScan();
break;
}
- do {
- unsigned i = (unsigned)-1;
+ while (1) {
+ uint i = (uint)-1;
CHK(set2.getkey(par, &i) == 0);
- const Row& row = *set.m_row[i];
set.lock();
- if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
- LL4("scan update " << itab.m_name << ": skip: " << row);
+ if (!set.compat(par, i, Row::OpUpd)) {
+ LL4("scanupdateindex SKIP " << set.getrow(i));
} else {
CHKTRY(set2.putval(i, par.m_dups) == 0, set.unlock());
CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
Par par2 = par;
par2.m_con = &con2;
- set.dbsave(i);
- set.calc(par, i, ! par.m_noindexkeyupdate ? 0 : itab.m_colmask);
+ set.push(i);
+ uint colmask = !par.m_noindexkeyupdate ? ~0 : ~itab.m_keymask;
+ set.calc(par, i, colmask);
CHKTRY(set.setrow(par2, i) == 0, set.unlock());
- LL4("scan update " << itab.m_name << ": " << row);
- lst.push(i);
+ LL4("scanupdateindex " << i << " " << set.getrow(i));
+ batch++;
}
set.unlock();
- if (lst.cnt() == par.m_batch) {
- deadlock = par.m_deadlock;
- CHK(con2.execute(Commit, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("scanupdateindex: stop on deadlock [at 2]");
- goto out;
- }
- con2.closeTransaction();
- LL4("scanupdateindex: committed batch [at 1]");
+ CHK((ret = con.nextScanResult(false)) != -1);
+ bool lastbatch = (batch != 0 && ret != 0);
+ if (batch == par.m_batch || lastbatch) {
+ uint err = par.m_catcherr;
+ ExecType et = Commit;
+ CHK(con2.execute(et, err) == 0);
set.lock();
- set.notpending(lst);
- set.dbdiscard(lst);
+ set.post(par, !err ? et : Rollback);
set.unlock();
- count += lst.cnt();
- lst.reset();
- CHK(con2.startTransaction() == 0);
- }
- CHK((ret = con.nextScanResult(false)) == 0 || ret == 1 || ret == 2);
- if (ret == 2 && lst.cnt() != 0) {
- deadlock = par.m_deadlock;
- CHK(con2.execute(Commit, deadlock, nospace) == 0);
- if (deadlock) {
- LL1("scanupdateindex: stop on deadlock [at 3]");
+ if (err) {
+ LL1("scanupdateindex [update] stop on " << con2.errname(err));
goto out;
}
+ LL4("scanupdateindex committed batch");
+ count += batch;
+ batch = 0;
con2.closeTransaction();
- LL4("scanupdateindex: committed batch [at 2]");
- set.lock();
- set.notpending(lst);
- set.dbdiscard(lst);
- set.unlock();
- count += lst.cnt();
- lst.reset();
CHK(con2.startTransaction() == 0);
}
- } while (ret == 0);
+ if (ret != 0)
+ break;
+ }
}
out:
con2.closeTransaction();
@@ -4231,7 +4247,7 @@ out:
if (par.m_ordered)
CHK(set2.verifyorder(par, itab, par.m_descending) == 0);
}
- LL3("scan update " << itab.m_name << " rows updated=" << count);
+ LL3("scanupdateindex " << itab.m_name << " rows updated=" << count);
con.closeTransaction();
return 0;
}
@@ -4240,9 +4256,9 @@ static int
scanupdateindex(Par par, const ITab& itab)
{
const Tab& tab = par.tab();
- for (unsigned i = 0; i < par.m_subloop; i++) {
+ for (uint i = 0; i < par.m_ssloop; i++) {
if (itab.m_type == ITab::OrderedIndex) {
- BSet bset(tab, itab, par.m_rows);
+ BSet bset(tab, itab);
CHK(scanupdateindex(par, itab, bset, true) == 0);
} else {
CHK(hashindexupdate(par, itab) == 0);
@@ -4255,7 +4271,7 @@ static int
scanupdateindex(Par par)
{
const Tab& tab = par.tab();
- for (unsigned i = 0; i < tab.m_itabs; i++) {
+ for (uint i = 0; i < tab.m_itabs; i++) {
if (tab.m_itab[i] == 0)
continue;
const ITab& itab = *tab.m_itab[i];
@@ -4294,14 +4310,14 @@ readverifyfull(Par par)
CHK(scanreadtable(par) == 0);
}
// each thread scans different indexes
- for (unsigned i = 0; i < tab.m_itabs; i++) {
- if (i % par.m_threads != par.m_no)
+ for (uint i = 0; i < tab.m_itabs; i++) {
+ if (i % par.m_usedthreads != par.m_no)
continue;
if (tab.m_itab[i] == 0)
continue;
const ITab& itab = *tab.m_itab[i];
if (itab.m_type == ITab::OrderedIndex) {
- BSet bset(tab, itab, par.m_rows);
+ BSet bset(tab, itab);
CHK(scanreadindex(par, itab, bset, false) == 0);
} else {
CHK(hashindexread(par, itab) == 0);
@@ -4317,7 +4333,7 @@ readverifyindex(Par par)
return 0;
par.m_verify = true;
par.m_lockmode = NdbOperation::LM_CommittedRead;
- unsigned sel = urandom(10);
+ uint sel = urandom(10);
if (sel < 9) {
par.m_ordered = true;
par.m_descending = (sel < 5);
@@ -4331,8 +4347,8 @@ pkops(Par par)
{
const Tab& tab = par.tab();
par.m_randomkey = true;
- for (unsigned i = 0; i < par.m_subloop; i++) {
- unsigned j = 0;
+ for (uint i = 0; i < par.m_ssloop; i++) {
+ uint j = 0;
while (j < tab.m_itabs) {
if (tab.m_itab[j] != 0) {
const ITab& itab = *tab.m_itab[j];
@@ -4341,7 +4357,7 @@ pkops(Par par)
}
j++;
}
- unsigned sel = urandom(10);
+ uint sel = urandom(10);
if (par.m_slno % 2 == 0) {
// favor insert
if (sel < 8) {
@@ -4389,8 +4405,8 @@ static int
pkupdatescanread(Par par)
{
par.m_dups = true;
- par.m_deadlock = true;
- unsigned sel = urandom(10);
+ par.m_catcherr |= Con::ErrDeadlock;
+ uint sel = urandom(10);
if (sel < 5) {
CHK(pkupdate(par) == 0);
} else if (sel < 6) {
@@ -4411,9 +4427,9 @@ static int
mixedoperations(Par par)
{
par.m_dups = true;
- par.m_deadlock = true;
+ par.m_catcherr |= Con::ErrDeadlock;
par.m_scanstop = par.m_totrows; // randomly close scans
- unsigned sel = urandom(10);
+ uint sel = urandom(10);
if (sel < 2) {
CHK(pkdelete(par) == 0);
} else if (sel < 4) {
@@ -4434,8 +4450,8 @@ static int
parallelorderedupdate(Par par)
{
const Tab& tab = par.tab();
- unsigned k = 0;
- for (unsigned i = 0; i < tab.m_itabs; i++) {
+ uint k = 0;
+ for (uint i = 0; i < tab.m_itabs; i++) {
if (tab.m_itab[i] == 0)
continue;
const ITab& itab = *tab.m_itab[i];
@@ -4447,10 +4463,11 @@ parallelorderedupdate(Par par)
par.m_noindexkeyupdate = true;
par.m_ordered = true;
par.m_descending = (par.m_slno != 0);
+ par.m_dups = false;
par.m_verify = true;
- BSet bset(tab, itab, par.m_rows); // empty bounds
+ BSet bset(tab, itab); // empty bounds
// prefer empty bounds
- unsigned sel = urandom(10);
+ uint sel = urandom(10);
CHK(scanupdateindex(par, itab, bset, sel < 2) == 0);
}
}
@@ -4469,6 +4486,418 @@ pkupdateindexbuild(Par par)
return 0;
}
+// savepoint tests (single thread for now)
+
+struct Spt {
+ enum Res { Committed, Latest, Deadlock };
+ bool m_same; // same transaction
+ NdbOperation::LockMode m_lm;
+ Res m_res;
+};
+
+static Spt sptlist[] = {
+ { 1, NdbOperation::LM_Read, Spt::Latest },
+ { 1, NdbOperation::LM_Exclusive, Spt::Latest },
+ { 1, NdbOperation::LM_CommittedRead, Spt::Latest },
+ { 0, NdbOperation::LM_Read, Spt::Deadlock },
+ { 0, NdbOperation::LM_Exclusive, Spt::Deadlock },
+ { 0, NdbOperation::LM_CommittedRead, Spt::Committed }
+};
+static uint sptcount = sizeof(sptlist)/sizeof(sptlist[0]);
+
+static int
+savepointreadpk(Par par, Spt spt)
+{
+ LL3("savepointreadpk");
+ Con& con = par.con();
+ const Tab& tab = par.tab();
+ Set& set = par.set();
+ const Set& set1 = set;
+ Set set2(tab, set.m_rows);
+ uint n = 0;
+ for (uint i = 0; i < set.m_rows; i++) {
+ set.lock();
+ if (!set.compat(par, i, Row::OpREAD)) {
+ LL4("savepointreadpk SKIP " << i << " " << set.getrow(i));
+ set.unlock();
+ continue;
+ }
+ set.unlock();
+ CHK(set2.selrow(par, *set1.m_row[i]) == 0);
+ uint err = par.m_catcherr | Con::ErrDeadlock;
+ ExecType et = NoCommit;
+ CHK(con.execute(et, err) == 0);
+ if (err) {
+ if (err & Con::ErrDeadlock) {
+ CHK(spt.m_res == Spt::Deadlock);
+ // all rows have same behaviour
+ CHK(n == 0);
+ }
+ LL1("savepointreadpk stop on " << con.errname(err));
+ break;
+ }
+ uint i2 = (uint)-1;
+ CHK(set2.getkey(par, &i2) == 0 && i == i2);
+ CHK(set2.putval(i, false) == 0);
+ LL4("row " << set2.count() << " " << set2.getrow(i));
+ n++;
+ }
+ bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead);
+ if (spt.m_res != Spt::Deadlock)
+ CHK(set1.verify(par, set2, false, dirty) == 0);
+ return 0;
+}
+
+static int
+savepointreadhashindex(Par par, Spt spt)
+{
+ if (spt.m_lm == NdbOperation::LM_CommittedRead && !spt.m_same) {
+ LL1("skip hash index dirty read");
+ return 0;
+ }
+ LL3("savepointreadhashindex");
+ Con& con = par.con();
+ const Tab& tab = par.tab();
+ const ITab& itab = par.itab();
+ Set& set = par.set();
+ const Set& set1 = set;
+ Set set2(tab, set.m_rows);
+ uint n = 0;
+ for (uint i = 0; i < set.m_rows; i++) {
+ set.lock();
+ if (!set.compat(par, i, Row::OpREAD)) {
+ LL3("savepointreadhashindex SKIP " << i << " " << set.getrow(i));
+ set.unlock();
+ continue;
+ }
+ set.unlock();
+ CHK(set2.selrow(par, itab, *set1.m_row[i]) == 0);
+ uint err = par.m_catcherr | Con::ErrDeadlock;
+ ExecType et = NoCommit;
+ CHK(con.execute(et, err) == 0);
+ if (err) {
+ if (err & Con::ErrDeadlock) {
+ CHK(spt.m_res == Spt::Deadlock);
+ // all rows have same behaviour
+ CHK(n == 0);
+ }
+ LL1("savepointreadhashindex stop on " << con.errname(err));
+ break;
+ }
+ uint i2 = (uint)-1;
+ CHK(set2.getkey(par, &i2) == 0 && i == i2);
+ CHK(set2.putval(i, false) == 0);
+ LL4("row " << set2.count() << " " << *set2.m_row[i]);
+ n++;
+ }
+ bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead);
+ if (spt.m_res != Spt::Deadlock)
+ CHK(set1.verify(par, set2, false, dirty) == 0);
+ return 0;
+}
+
+static int
+savepointscantable(Par par, Spt spt)
+{
+ LL3("savepointscantable");
+ Con& con = par.con();
+ const Tab& tab = par.tab();
+ const Set& set = par.set();
+ const Set& set1 = set; // not modifying current set
+ Set set2(tab, set.m_rows); // scan result
+ CHK(con.getNdbScanOperation(tab) == 0);
+ CHK(con.readTuples(par) == 0);
+ set2.getval(par); // getValue all columns
+ CHK(con.executeScan() == 0);
+ bool deadlock = false;
+ uint n = 0;
+ while (1) {
+ int ret;
+ uint err = par.m_catcherr | Con::ErrDeadlock;
+ CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1);
+ if (ret == 1)
+ break;
+ if (err) {
+ if (err & Con::ErrDeadlock) {
+ CHK(spt.m_res == Spt::Deadlock);
+ // all rows have same behaviour
+ CHK(n == 0);
+ deadlock = true;
+ }
+ LL1("savepointscantable stop on " << con.errname(err));
+ break;
+ }
+ CHK(spt.m_res != Spt::Deadlock);
+ uint i = (uint)-1;
+ CHK(set2.getkey(par, &i) == 0);
+ CHK(set2.putval(i, false, n) == 0);
+ LL4("row " << n << " key " << i << " " << set2.getrow(i));
+ n++;
+ }
+ if (set1.m_rows > 0) {
+ if (!deadlock)
+ CHK(spt.m_res != Spt::Deadlock);
+ else
+ CHK(spt.m_res == Spt::Deadlock);
+ }
+ LL2("savepointscantable " << n << " rows");
+ bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead);
+ if (spt.m_res != Spt::Deadlock)
+ CHK(set1.verify(par, set2, false, dirty) == 0);
+ return 0;
+}
+
+static int
+savepointscanindex(Par par, Spt spt)
+{
+ LL3("savepointscanindex");
+ Con& con = par.con();
+ const Tab& tab = par.tab();
+ const ITab& itab = par.itab();
+ const Set& set = par.set();
+ const Set& set1 = set;
+ Set set2(tab, set.m_rows);
+ CHK(con.getNdbIndexScanOperation(itab, tab) == 0);
+ CHK(con.readIndexTuples(par) == 0);
+ set2.getval(par);
+ CHK(con.executeScan() == 0);
+ bool deadlock = false;
+ uint n = 0;
+ while (1) {
+ int ret;
+ uint err = par.m_catcherr | Con::ErrDeadlock;
+ CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1);
+ if (ret == 1)
+ break;
+ if (err) {
+ if (err & Con::ErrDeadlock) {
+ CHK(spt.m_res == Spt::Deadlock);
+ // all rows have same behaviour
+ CHK(n == 0);
+ deadlock = true;
+ }
+ LL1("savepointscanindex stop on " << con.errname(err));
+ break;
+ }
+ CHK(spt.m_res != Spt::Deadlock);
+ uint i = (uint)-1;
+ CHK(set2.getkey(par, &i) == 0);
+ CHK(set2.putval(i, par.m_dups, n) == 0);
+ LL4("row " << n << " key " << i << " " << set2.getrow(i));
+ n++;
+ }
+ if (set1.m_rows > 0) {
+ if (!deadlock)
+ CHK(spt.m_res != Spt::Deadlock);
+ else
+ CHK(spt.m_res == Spt::Deadlock);
+ }
+ LL2("savepointscanindex " << n << " rows");
+ bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead);
+ if (spt.m_res != Spt::Deadlock)
+ CHK(set1.verify(par, set2, false, dirty) == 0);
+ return 0;
+}
+
+typedef int (*SptFun)(Par, Spt);
+
+static int
+savepointtest(Par par, Spt spt, SptFun fun)
+{
+ Con& con = par.con();
+ Par par2 = par;
+ Con con2;
+ if (!spt.m_same) {
+ con2.connect(con); // copy ndb reference
+ par2.m_con = &con2;
+ CHK(con2.startTransaction() == 0);
+ }
+ par2.m_lockmode = spt.m_lm;
+ CHK((*fun)(par2, spt) == 0);
+ if (!spt.m_same) {
+ con2.closeTransaction();
+ }
+ return 0;
+}
+
+static int
+savepointtest(Par par, const char* op)
+{
+ Con& con = par.con();
+ const Tab& tab = par.tab();
+ Set& set = par.set();
+ LL2("savepointtest op=\"" << op << "\"");
+ CHK(con.startTransaction() == 0);
+ const char* p = op;
+ char c;
+ while ((c = *p++) != 0) {
+ uint j;
+ for (j = 0; j < par.m_rows; j++) {
+ uint i = thrrow(par, j);
+ if (c == 'c') {
+ ExecType et = Commit;
+ CHK(con.execute(et) == 0);
+ set.lock();
+ set.post(par, et);
+ set.unlock();
+ CHK(con.startTransaction() == 0);
+ } else {
+ set.lock();
+ set.push(i);
+ if (c == 'i') {
+ set.calc(par, i);
+ CHK(set.insrow(par, i) == 0);
+ } else if (c == 'u') {
+ set.copyval(i, tab.m_pkmask);
+ set.calc(par, i, ~tab.m_pkmask);
+ CHK(set.updrow(par, i) == 0);
+ } else if (c == 'd') {
+ set.copyval(i, tab.m_pkmask);
+ CHK(set.delrow(par, i) == 0);
+ } else {
+ assert(false);
+ }
+ set.unlock();
+ }
+ }
+ }
+ {
+ ExecType et = NoCommit;
+ CHK(con.execute(et) == 0);
+ set.lock();
+ set.post(par, et);
+ set.unlock();
+ }
+ for (uint k = 0; k < sptcount; k++) {
+ Spt spt = sptlist[k];
+ LL2("spt lm=" << spt.m_lm << " same=" << spt.m_same);
+ CHK(savepointtest(par, spt, &savepointreadpk) == 0);
+ CHK(savepointtest(par, spt, &savepointscantable) == 0);
+ for (uint i = 0; i < tab.m_itabs; i++) {
+ if (tab.m_itab[i] == 0)
+ continue;
+ const ITab& itab = *tab.m_itab[i];
+ par.m_itab = &itab;
+ if (itab.m_type == ITab::OrderedIndex)
+ CHK(savepointtest(par, spt, &savepointscanindex) == 0);
+ else
+ CHK(savepointtest(par, spt, &savepointreadhashindex) == 0);
+ par.m_itab = 0;
+ }
+ }
+ {
+ ExecType et = Rollback;
+ CHK(con.execute(et) == 0);
+ set.lock();
+ set.post(par, et);
+ set.unlock();
+ }
+ con.closeTransaction();
+ return 0;
+}
+
+static int
+savepointtest(Par par)
+{
+ assert(par.m_usedthreads == 1);
+ const char* oplist[] = {
+ // each based on previous and "c" not last
+ "i",
+ "icu",
+ "uuuuu",
+ "d",
+ "dciuuuuud",
+ 0
+ };
+ int i;
+ for (i = 0; oplist[i] != 0; i++) {
+ CHK(savepointtest(par, oplist[i]) == 0);
+ }
+ return 0;
+}
+
+static int
+halloweentest(Par par, const ITab& itab)
+{
+ LL2("halloweentest " << itab.m_name);
+ Con& con = par.con();
+ const Tab& tab = par.tab();
+ Set& set = par.set();
+ CHK(con.startTransaction() == 0);
+ // insert 1 row
+ uint i = 0;
+ set.push(i);
+ set.calc(par, i);
+ CHK(set.insrow(par, i) == 0);
+ CHK(con.execute(NoCommit) == 0);
+ // scan via index until Set m_rows reached
+ uint scancount = 0;
+ bool stop = false;
+ while (!stop) {
+ par.m_lockmode = // makes no difference
+ scancount % 2 == 0 ? NdbOperation::LM_CommittedRead :
+ NdbOperation::LM_Read;
+ Set set1(tab, set.m_rows); // expected scan result
+ Set set2(tab, set.m_rows); // actual scan result
+ BSet bset(tab, itab);
+ calcscanbounds(par, itab, bset, set, set1);
+ CHK(con.getNdbIndexScanOperation(itab, tab) == 0);
+ CHK(con.readIndexTuples(par) == 0);
+ CHK(bset.setbnd(par) == 0);
+ set2.getval(par);
+ CHK(con.executeScan() == 0);
+ const uint savepoint = i;
+ LL3("scancount=" << scancount << " savepoint=" << savepoint);
+ uint n = 0;
+ while (1) {
+ int ret;
+ CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
+ if (ret == 1)
+ break;
+ uint k = (uint)-1;
+ CHK(set2.getkey(par, &k) == 0);
+ CHK(set2.putval(k, false, n) == 0);
+ LL3("row=" << n << " key=" << k);
+ CHK(k <= savepoint);
+ if (++i == set.m_rows) {
+ stop = true;
+ break;
+ }
+ set.push(i);
+ set.calc(par, i);
+ CHK(set.insrow(par, i) == 0);
+ CHK(con.execute(NoCommit) == 0);
+ n++;
+ }
+ con.closeScan();
+ LL3("scanrows=" << n);
+ if (!stop) {
+ CHK(set1.verify(par, set2, false) == 0);
+ }
+ scancount++;
+ }
+ CHK(con.execute(Commit) == 0);
+ set.post(par, Commit);
+ assert(set.count() == set.m_rows);
+ CHK(pkdelete(par) == 0);
+ return 0;
+}
+
+static int
+halloweentest(Par par)
+{
+ assert(par.m_usedthreads == 1);
+ const Tab& tab = par.tab();
+ for (uint i = 0; i < tab.m_itabs; i++) {
+ if (tab.m_itab[i] == 0)
+ continue;
+ const ITab& itab = *tab.m_itab[i];
+ if (itab.m_type == ITab::OrderedIndex)
+ CHK(halloweentest(par, itab) == 0);
+ }
+ return 0;
+}
+
// threads
typedef int (*TFunc)(Par par);
@@ -4477,22 +4906,22 @@ enum TMode { ST = 1, MT = 2 };
extern "C" { static void* runthread(void* arg); }
struct Thr {
- enum State { Wait, Start, Stop, Stopped, Exit };
+ enum State { Wait, Start, Stop, Exit };
State m_state;
Par m_par;
- Uint64 m_id;
+ pthread_t m_id;
NdbThread* m_thread;
NdbMutex* m_mutex;
NdbCondition* m_cond;
TFunc m_func;
int m_ret;
void* m_status;
- Thr(Par par, unsigned n);
+ char m_tmp[20]; // used for debug msg prefix
+ Thr(Par par, uint n);
~Thr();
int run();
void start();
void stop();
- void stopped();
void exit();
//
void lock() {
@@ -4513,10 +4942,9 @@ struct Thr {
}
};
-Thr::Thr(Par par, unsigned n) :
+Thr::Thr(Par par, uint n) :
m_state(Wait),
m_par(par),
- m_id(0),
m_thread(0),
m_mutex(0),
m_cond(0),
@@ -4533,7 +4961,7 @@ Thr::Thr(Par par, unsigned n) :
m_cond = NdbCondition_Create();
assert(m_mutex != 0 && m_cond != 0);
// run
- const unsigned stacksize = 256 * 1024;
+ const uint stacksize = 256 * 1024;
const NDB_THREAD_PRIO prio = NDB_THREAD_PRIO_LOW;
m_thread = NdbThread_Create(runthread, (void**)this, stacksize, name, prio);
}
@@ -4558,7 +4986,7 @@ static void*
runthread(void* arg)
{
Thr& thr = *(Thr*)arg;
- thr.m_id = (Uint64)pthread_self();
+ thr.m_id = pthread_self();
if (thr.run() < 0) {
LL1("exit on error");
} else {
@@ -4589,11 +5017,16 @@ Thr::run()
LL4("start");
assert(m_state == Start);
m_ret = (*m_func)(m_par);
- m_state = Stopped;
+ m_state = Stop;
LL4("stop");
signal();
unlock();
- CHK(m_ret == 0);
+ if (m_ret == -1) {
+ if (m_par.m_cont)
+ LL1("continue running due to -cont");
+ else
+ return -1;
+ }
}
con.disconnect();
return 0;
@@ -4612,16 +5045,7 @@ void
Thr::stop()
{
lock();
- m_state = Stop;
- signal();
- unlock();
-}
-
-void
-Thr::stopped()
-{
- lock();
- while (m_state != Stopped)
+ while (m_state != Stop)
wait();
m_state = Wait;
unlock();
@@ -4640,27 +5064,44 @@ Thr::exit()
static Thr** g_thrlist = 0;
-static unsigned
-getthrno()
+static Thr*
+getthr()
{
if (g_thrlist != 0) {
- Uint64 id = (Uint64)pthread_self();
- for (unsigned n = 0; n < g_opt.m_threads; n++) {
+ pthread_t id = pthread_self();
+ for (uint n = 0; n < g_opt.m_threads; n++) {
if (g_thrlist[n] != 0) {
- const Thr& thr = *g_thrlist[n];
- if (thr.m_id == id)
- return thr.m_par.m_no;
+ Thr& thr = *g_thrlist[n];
+ if (pthread_equal(thr.m_id, id))
+ return &thr;
}
}
}
- return (unsigned)-1;
+ return 0;
+}
+
+// for debug messages (par.m_no not available)
+static const char*
+getthrprefix()
+{
+ Thr* thrp = getthr();
+ if (thrp != 0) {
+ Thr& thr = *thrp;
+ uint n = thr.m_par.m_no;
+ uint m =
+ g_opt.m_threads < 10 ? 1 :
+ g_opt.m_threads < 100 ? 2 : 3;
+ sprintf(thr.m_tmp, "[%0*u] ", m, n);
+ return thr.m_tmp;
+ }
+ return "";
}
static int
-runstep(Par par, const char* fname, TFunc func, unsigned mode)
+runstep(Par par, const char* fname, TFunc func, uint mode)
{
LL2("step: " << fname);
- const int threads = (mode & ST ? 1 : par.m_threads);
+ const int threads = (mode & ST ? 1 : par.m_usedthreads);
int n;
for (n = 0; n < threads; n++) {
LL4("start " << n);
@@ -4673,11 +5114,11 @@ runstep(Par par, const char* fname, TFunc func, unsigned mode)
thr.m_func = func;
thr.start();
}
- unsigned errs = 0;
+ uint errs = 0;
for (n = threads - 1; n >= 0; n--) {
LL4("stop " << n);
Thr& thr = *g_thrlist[n];
- thr.stopped();
+ thr.stop();
if (thr.m_ret != 0)
errs++;
}
@@ -4689,7 +5130,7 @@ runstep(Par par, const char* fname, TFunc func, unsigned mode)
CHK(runstep(par, #func, func, mode) == 0)
#define SUBLOOP(par) \
- "subloop: " << par.m_lno << "/" << par.m_currcase << "/" << \
+ "sloop: " << par.m_lno << "/" << par.m_currcase << "/" << \
par.m_tab->m_name << "/" << par.m_slno
static int
@@ -4698,7 +5139,7 @@ tbuild(Par par)
RUNSTEP(par, droptable, ST);
RUNSTEP(par, createtable, ST);
RUNSTEP(par, invalidatetable, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
if (par.m_slno % 3 == 0) {
RUNSTEP(par, createindex, ST);
@@ -4718,7 +5159,7 @@ tbuild(Par par)
}
RUNSTEP(par, readverifyfull, MT);
// leave last one
- if (par.m_slno + 1 < par.m_subloop) {
+ if (par.m_slno + 1 < par.m_sloop) {
RUNSTEP(par, pkdelete, MT);
RUNSTEP(par, readverifyfull, MT);
RUNSTEP(par, dropindex, ST);
@@ -4737,7 +5178,7 @@ tindexscan(Par par)
RUNSTEP(par, invalidateindex, MT);
RUNSTEP(par, pkinsert, MT);
RUNSTEP(par, readverifyfull, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
RUNSTEP(par, readverifyindex, MT);
}
@@ -4753,7 +5194,7 @@ tpkops(Par par)
RUNSTEP(par, invalidatetable, MT);
RUNSTEP(par, createindex, ST);
RUNSTEP(par, invalidateindex, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
RUNSTEP(par, pkops, MT);
LL2("rows=" << par.set().count());
@@ -4772,7 +5213,7 @@ tpkopsread(Par par)
RUNSTEP(par, createindex, ST);
RUNSTEP(par, invalidateindex, MT);
RUNSTEP(par, readverifyfull, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
RUNSTEP(par, pkupdatescanread, MT);
RUNSTEP(par, readverifyfull, MT);
@@ -4792,7 +5233,7 @@ tmixedops(Par par)
RUNSTEP(par, createindex, ST);
RUNSTEP(par, invalidateindex, MT);
RUNSTEP(par, readverifyfull, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
RUNSTEP(par, mixedoperations, MT);
RUNSTEP(par, readverifyfull, MT);
@@ -4807,7 +5248,7 @@ tbusybuild(Par par)
RUNSTEP(par, createtable, ST);
RUNSTEP(par, invalidatetable, MT);
RUNSTEP(par, pkinsert, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
RUNSTEP(par, pkupdateindexbuild, MT);
RUNSTEP(par, invalidateindex, MT);
@@ -4828,7 +5269,7 @@ trollback(Par par)
RUNSTEP(par, createindex, ST);
RUNSTEP(par, invalidateindex, MT);
RUNSTEP(par, readverifyfull, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
RUNSTEP(par, mixedoperations, MT);
RUNSTEP(par, readverifyfull, MT);
@@ -4846,7 +5287,7 @@ tparupdate(Par par)
RUNSTEP(par, createindex, ST);
RUNSTEP(par, invalidateindex, MT);
RUNSTEP(par, readverifyfull, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
RUNSTEP(par, parallelorderedupdate, MT);
RUNSTEP(par, readverifyfull, MT);
@@ -4855,13 +5296,44 @@ tparupdate(Par par)
}
static int
+tsavepoint(Par par)
+{
+ RUNSTEP(par, droptable, ST);
+ RUNSTEP(par, createtable, ST);
+ RUNSTEP(par, invalidatetable, MT);
+ RUNSTEP(par, createindex, ST);
+ RUNSTEP(par, invalidateindex, MT);
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
+ LL1(SUBLOOP(par));
+ RUNSTEP(par, savepointtest, MT);
+ RUNSTEP(par, readverifyfull, MT);
+ }
+ return 0;
+}
+
+static int
+thalloween(Par par)
+{
+ RUNSTEP(par, droptable, ST);
+ RUNSTEP(par, createtable, ST);
+ RUNSTEP(par, invalidatetable, MT);
+ RUNSTEP(par, createindex, ST);
+ RUNSTEP(par, invalidateindex, MT);
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
+ LL1(SUBLOOP(par));
+ RUNSTEP(par, halloweentest, MT);
+ }
+ return 0;
+}
+
+static int
ttimebuild(Par par)
{
Tmr t1;
RUNSTEP(par, droptable, ST);
RUNSTEP(par, createtable, ST);
RUNSTEP(par, invalidatetable, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
RUNSTEP(par, pkinsert, MT);
t1.on();
@@ -4881,7 +5353,7 @@ ttimemaint(Par par)
RUNSTEP(par, droptable, ST);
RUNSTEP(par, createtable, ST);
RUNSTEP(par, invalidatetable, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
RUNSTEP(par, pkinsert, MT);
t1.on();
@@ -4911,7 +5383,7 @@ ttimescan(Par par)
RUNSTEP(par, droptable, ST);
RUNSTEP(par, createtable, ST);
RUNSTEP(par, invalidatetable, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
RUNSTEP(par, pkinsert, MT);
RUNSTEP(par, createindex, ST);
@@ -4938,7 +5410,7 @@ ttimepkread(Par par)
RUNSTEP(par, droptable, ST);
RUNSTEP(par, createtable, ST);
RUNSTEP(par, invalidatetable, MT);
- for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
LL1(SUBLOOP(par));
RUNSTEP(par, pkinsert, MT);
RUNSTEP(par, createindex, ST);
@@ -4981,7 +5453,9 @@ tcaselist[] = {
TCase("e", tmixedops, "pk operations and scan operations"),
TCase("f", tbusybuild, "pk operations and index build"),
TCase("g", trollback, "operations with random rollbacks"),
- TCase("h", tparupdate, "parallel ordered update (bug20446)"),
+ TCase("h", tparupdate, "parallel ordered update bug#20446"),
+ TCase("i", tsavepoint, "savepoint test locking bug#31477"),
+ TCase("j", thalloween, "savepoint test halloween problem"),
TCase("t", ttimebuild, "time index build"),
TCase("u", ttimemaint, "time index maintenance"),
TCase("v", ttimescan, "time full scan table vs index on pk"),
@@ -4989,14 +5463,14 @@ tcaselist[] = {
TCase("z", tdrop, "drop test tables")
};
-static const unsigned
+static const uint
tcasecount = sizeof(tcaselist) / sizeof(tcaselist[0]);
static void
printcases()
{
ndbout << "test cases:" << endl;
- for (unsigned i = 0; i < tcasecount; i++) {
+ for (uint i = 0; i < tcasecount; i++) {
const TCase& tcase = tcaselist[i];
ndbout << " " << tcase.m_name << " - " << tcase.m_desc << endl;
}
@@ -5008,13 +5482,13 @@ printtables()
Par par(g_opt);
makebuiltintables(par);
ndbout << "tables and indexes (x=ordered z=hash x0=on pk):" << endl;
- for (unsigned j = 0; j < tabcount; j++) {
+ for (uint j = 0; j < tabcount; j++) {
if (tablist[j] == 0)
continue;
const Tab& tab = *tablist[j];
const char* tname = tab.m_name;
ndbout << " " << tname;
- for (unsigned i = 0; i < tab.m_itabs; i++) {
+ for (uint i = 0; i < tab.m_itabs; i++) {
if (tab.m_itab[i] == 0)
continue;
const ITab& itab = *tab.m_itab[i];
@@ -5023,7 +5497,7 @@ printtables()
iname += strlen(tname);
ndbout << " " << iname;
ndbout << "(";
- for (unsigned k = 0; k < itab.m_icols; k++) {
+ for (uint k = 0; k < itab.m_icols; k++) {
if (k != 0)
ndbout << ",";
const ICol& icol = *itab.m_icol[k];
@@ -5036,14 +5510,48 @@ printtables()
}
}
+static bool
+setcasepar(Par& par)
+{
+ Opt d;
+ const char* c = par.m_currcase;
+ switch (c[0]) {
+ case 'i':
+ {
+ if (par.m_usedthreads > 1) {
+ par.m_usedthreads = 1;
+ LL1("case " << c << " reduce threads to " << par.m_usedthreads);
+ }
+ const uint rows = 100;
+ if (par.m_rows > rows) {
+ par.m_rows = rows;
+ LL1("case " << c << " reduce rows to " << rows);
+ }
+ }
+ break;
+ case 'j':
+ {
+ if (par.m_usedthreads > 1) {
+ par.m_usedthreads = 1;
+ LL1("case " << c << " reduce threads to " << par.m_usedthreads);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
static int
runtest(Par par)
{
+ int totret = 0;
if (par.m_seed == -1) {
// good enough for daily run
- unsigned short seed = (unsigned short)getpid();
+ ushort seed = (ushort)getpid();
LL0("random seed: " << seed);
- srandom((unsigned)seed);
+ srandom((uint)seed);
} else if (par.m_seed != 0) {
LL0("random seed: " << par.m_seed);
srandom(par.m_seed);
@@ -5061,9 +5569,10 @@ runtest(Par par)
Con con;
CHK(con.connect() == 0);
par.m_con = &con;
+ par.m_catcherr |= Con::ErrNospace;
// threads
g_thrlist = new Thr* [par.m_threads];
- unsigned n;
+ uint n;
for (n = 0; n < par.m_threads; n++) {
g_thrlist[n] = 0;
}
@@ -5078,23 +5587,38 @@ runtest(Par par)
LL1("random seed: " << par.m_lno);
srandom(par.m_lno);
}
- for (unsigned i = 0; i < tcasecount; i++) {
+ for (uint i = 0; i < tcasecount; i++) {
const TCase& tcase = tcaselist[i];
- if (par.m_case != 0 && strchr(par.m_case, tcase.m_name[0]) == 0)
+ if (par.m_case != 0 && strchr(par.m_case, tcase.m_name[0]) == 0 ||
+ par.m_skip != 0 && strchr(par.m_skip, tcase.m_name[0]) != 0) {
continue;
+ }
sprintf(par.m_currcase, "%c", tcase.m_name[0]);
+ par.m_usedthreads = par.m_threads;
+ if (!setcasepar(par)) {
+ LL1("case " << tcase.m_name << " cannot run with given options");
+ continue;
+ }
+ par.m_totrows = par.m_usedthreads * par.m_rows;
makebuiltintables(par);
LL1("case: " << par.m_lno << "/" << tcase.m_name << " - " << tcase.m_desc);
- for (unsigned j = 0; j < tabcount; j++) {
+ for (uint j = 0; j < tabcount; j++) {
if (tablist[j] == 0)
continue;
const Tab& tab = *tablist[j];
par.m_tab = &tab;
par.m_set = new Set(tab, par.m_totrows);
LL1("table: " << par.m_lno << "/" << tcase.m_name << "/" << tab.m_name);
- CHK(tcase.m_func(par) == 0);
+ int ret = tcase.m_func(par);
delete par.m_set;
par.m_set = 0;
+ if (ret == -1) {
+ if (!par.m_cont)
+ return -1;
+ totret = -1;
+ LL1("continue to next case due to -cont");
+ break;
+ }
}
}
}
@@ -5110,7 +5634,7 @@ runtest(Par par)
delete [] g_thrlist;
g_thrlist = 0;
con.disconnect();
- return 0;
+ return totret;
}
static const char* g_progname = "testOIBasic";
@@ -5119,7 +5643,7 @@ int
main(int argc, char** argv)
{
ndb_init();
- unsigned i;
+ uint i;
ndbout << g_progname;
for (i = 1; i < argc; i++)
ndbout << " " << argv[i];
@@ -5156,6 +5680,10 @@ main(int argc, char** argv)
g_opt.m_collsp = true;
continue;
}
+ if (strcmp(arg, "-cont") == 0) {
+ g_opt.m_cont = true;
+ continue;
+ }
if (strcmp(arg, "-core") == 0) {
g_opt.m_core = true;
continue;
@@ -5252,9 +5780,21 @@ main(int argc, char** argv)
continue;
}
}
- if (strcmp(arg, "-subloop") == 0) {
+ if (strcmp(arg, "-skip") == 0) {
+ if (++argv, --argc > 0) {
+ g_opt.m_skip = strdup(argv[0]);
+ continue;
+ }
+ }
+ if (strcmp(arg, "-sloop") == 0) {
+ if (++argv, --argc > 0) {
+ g_opt.m_sloop = atoi(argv[0]);
+ continue;
+ }
+ }
+ if (strcmp(arg, "-ssloop") == 0) {
if (++argv, --argc > 0) {
- g_opt.m_subloop = atoi(argv[0]);
+ g_opt.m_ssloop = atoi(argv[0]);
continue;
}
}
diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt
index 7b4a4ca0e2d..a27b94193e5 100644
--- a/ndb/test/run-test/daily-basic-tests.txt
+++ b/ndb/test/run-test/daily-basic-tests.txt
@@ -649,10 +649,10 @@ max-time: 1000
cmd: testNdbApi
args: -n Bug28443
-#max-time: 500
-#cmd: testInterpreter
-#args: T1
-#
+max-time: 500
+cmd: testInterpreter
+args: T1
+
max-time: 150000
cmd: testOperations
args:
diff --git a/ndb/tools/waiter.cpp b/ndb/tools/waiter.cpp
index e221a26182e..8226de87b49 100644
--- a/ndb/tools/waiter.cpp
+++ b/ndb/tools/waiter.cpp
@@ -21,13 +21,11 @@
#include <NdbMain.h>
#include <NdbOut.hpp>
#include <NdbSleep.h>
-#include <kernel/ndb_limits.h>
#include <NDBT.hpp>
-int
-waitClusterStatus(const char* _addr, ndb_mgm_node_status _status,
- unsigned int _timeout);
+static int
+waitClusterStatus(const char* _addr, ndb_mgm_node_status _status);
enum ndb_waiter_options {
OPT_WAIT_STATUS_NOT_STARTED = NDB_STD_OPTIONS_LAST,
@@ -55,12 +53,13 @@ static struct my_option my_long_options[] =
"Wait for cluster to enter single user mode",
(gptr*) &_single_user, (gptr*) &_single_user, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
- { "timeout", 't', "Timeout to wait",
+ { "timeout", 't', "Timeout to wait in seconds",
(gptr*) &_timeout, (gptr*) &_timeout, 0,
GET_INT, REQUIRED_ARG, 120, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
+
static void usage()
{
ndb_std_print_version();
@@ -70,16 +69,18 @@ static void usage()
my_print_variables(my_long_options);
}
+
int main(int argc, char** argv){
NDB_INIT(argv[0]);
load_defaults("my",load_default_groups,&argc,&argv);
const char* _hostName = NULL;
- int ho_error;
+
#ifndef DBUG_OFF
opt_debug= "d:t:O,/tmp/ndb_waiter.trace";
#endif
- if ((ho_error=handle_options(&argc, &argv, my_long_options,
- ndb_std_get_one_option)))
+
+ if (handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option))
return NDBT_ProgramExit(NDBT_WRONGARGS);
_hostName = argv[0];
@@ -105,7 +106,7 @@ int main(int argc, char** argv){
wait_status= NDB_MGM_NODE_STATUS_STARTED;
}
- if (waitClusterStatus(_hostName, wait_status, _timeout) != 0)
+ if (waitClusterStatus(_hostName, wait_status) != 0)
return NDBT_ProgramExit(NDBT_FAILED);
return NDBT_ProgramExit(NDBT_OK);
}
@@ -118,8 +119,6 @@ int main(int argc, char** argv){
NdbMgmHandle handle= NULL;
Vector<ndb_mgm_node_state> ndbNodes;
-Vector<ndb_mgm_node_state> mgmNodes;
-Vector<ndb_mgm_node_state> apiNodes;
int
getStatus(){
@@ -128,8 +127,6 @@ getStatus(){
struct ndb_mgm_node_state * node;
ndbNodes.clear();
- mgmNodes.clear();
- apiNodes.clear();
while(retries < 10){
status = ndb_mgm_get_status(handle);
@@ -153,18 +150,16 @@ getStatus(){
ndbNodes.push_back(*node);
break;
case NDB_MGM_NODE_TYPE_MGM:
- mgmNodes.push_back(*node);
+ /* Don't care about MGM nodes */
break;
case NDB_MGM_NODE_TYPE_API:
- apiNodes.push_back(*node);
+ /* Don't care about API nodes */
break;
default:
if(node->node_status == NDB_MGM_NODE_STATUS_UNKNOWN ||
node->node_status == NDB_MGM_NODE_STATUS_NO_CONTACT){
retries++;
ndbNodes.clear();
- mgmNodes.clear();
- apiNodes.clear();
free(status);
status = NULL;
count = 0;
@@ -183,24 +178,22 @@ getStatus(){
free(status);
return 0;
}
-
- g_err << "getStatus failed" << endl;
+
return -1;
}
-int
+static int
waitClusterStatus(const char* _addr,
- ndb_mgm_node_status _status,
- unsigned int _timeout)
+ ndb_mgm_node_status _status)
{
int _startphase = -1;
- int _nodes[MAX_NDB_NODES];
- int _num_nodes = 0;
+ /* Ignore SIGPIPE */
+ signal(SIGPIPE, SIG_IGN);
handle = ndb_mgm_create_handle();
if (handle == NULL){
- g_err << "handle == NULL" << endl;
+ g_err << "Could not create ndb_mgm handle" << endl;
return -1;
}
g_info << "Connecting to mgmsrv at " << _addr << endl;
@@ -216,19 +209,11 @@ waitClusterStatus(const char* _addr,
return -1;
}
- if (getStatus() != 0)
- return -1;
-
- // Collect all nodes into nodes
- for (size_t i = 0; i < ndbNodes.size(); i++){
- _nodes[i] = ndbNodes[i].node_id;
- _num_nodes++;
- }
-
- unsigned int attempts = 0;
- unsigned int resetAttempts = 0;
- const unsigned int MAX_RESET_ATTEMPTS = 10;
- bool allInState = false;
+ int attempts = 0;
+ int resetAttempts = 0;
+ const int MAX_RESET_ATTEMPTS = 10;
+ bool allInState = false;
+ int timeout_ms= _timeout * 10; /* In number of 100 milliseconds */
while (allInState == false){
if (_timeout > 0 && attempts > _timeout){
/**
@@ -236,8 +221,8 @@ waitClusterStatus(const char* _addr,
* the state we want
*/
bool waitMore = false;
- /**
- * Make special check if we are waiting for
+ /**
+ * Make special check if we are waiting for
* cluster to become started
*/
if(_status == NDB_MGM_NODE_STATUS_STARTED){
@@ -252,7 +237,7 @@ waitClusterStatus(const char* _addr,
waitMore = false;
}
- }
+ }
if (!waitMore || resetAttempts > MAX_RESET_ATTEMPTS){
g_err << "waitNodeState("
@@ -260,7 +245,7 @@ waitClusterStatus(const char* _addr,
<<", "<<_startphase<<")"
<< " timeout after " << attempts <<" attemps" << endl;
return -1;
- }
+ }
g_err << "waitNodeState("
<< ndb_mgm_get_node_status_string(_status)
@@ -269,62 +254,34 @@ waitClusterStatus(const char* _addr,
<< resetAttempts << endl;
attempts = 0;
resetAttempts++;
-
}
- allInState = true;
if (getStatus() != 0){
- g_err << "getStatus != 0" << endl;
return -1;
}
- // ndbout << "waitNodeState; _num_nodes = " << _num_nodes << endl;
- // for (int i = 0; i < _num_nodes; i++)
- // ndbout << " node["<<i<<"] =" <<_nodes[i] << endl;
+ /* Assume all nodes are in state(if there is any) */
+ allInState = (ndbNodes.size() > 0);
- for (int i = 0; i < _num_nodes; i++){
- ndb_mgm_node_state* ndbNode = NULL;
- for (size_t n = 0; n < ndbNodes.size(); n++){
- if (ndbNodes[n].node_id == _nodes[i])
- ndbNode = &ndbNodes[n];
- }
+ /* Loop through all nodes and check their state */
+ for (size_t n = 0; n < ndbNodes.size(); n++) {
+ ndb_mgm_node_state* ndbNode = &ndbNodes[n];
- if(ndbNode == NULL){
- allInState = false;
- continue;
- }
+ assert(ndbNode != NULL);
- g_info << "State node " << ndbNode->node_id << " "
+ g_info << "Node " << ndbNode->node_id << ": "
<< ndb_mgm_get_node_status_string(ndbNode->node_status)<< endl;
- assert(ndbNode != NULL);
-
- if(_status == NDB_MGM_NODE_STATUS_STARTING &&
- ((ndbNode->node_status == NDB_MGM_NODE_STATUS_STARTING &&
- ndbNode->start_phase >= _startphase) ||
- (ndbNode->node_status == NDB_MGM_NODE_STATUS_STARTED)))
- continue;
-
- if (_status == NDB_MGM_NODE_STATUS_STARTING){
- g_info << "status = "
- << ndb_mgm_get_node_status_string(ndbNode->node_status)
- <<", start_phase="<<ndbNode->start_phase<<endl;
- if (ndbNode->node_status != _status) {
- if (ndbNode->node_status < _status)
- allInState = false;
- else
- g_info << "node_status(" << (unsigned)ndbNode->node_status
- << ") != _status("<< (unsigned)_status << ")" <<endl;
- } else if (ndbNode->start_phase < _startphase)
- allInState = false;
- } else {
- if (ndbNode->node_status != _status)
+ if (ndbNode->node_status != _status)
allInState = false;
- }
}
- g_info << "Waiting for cluster enter state "
- << ndb_mgm_get_node_status_string(_status)<< endl;
- NdbSleep_SecSleep(1);
+
+ if (!allInState) {
+ g_info << "Waiting for cluster enter state "
+ << ndb_mgm_get_node_status_string(_status)<< endl;
+ NdbSleep_MilliSleep(100);
+ }
+
attempts++;
}
return 0;
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index 6fbfcab72d4..d7bcb8fd4e7 100755
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -40,3 +40,44 @@ ADD_CUSTOM_COMMAND(OUTPUT ${PROJECT_SOURCE_DIR}/scripts/mysql_fix_privilege_tabl
ADD_CUSTOM_TARGET(GenFixPrivs
ALL
DEPENDS ${PROJECT_SOURCE_DIR}/scripts/mysql_fix_privilege_tables_sql.c)
+
+# ----------------------------------------------------------------------
+# Replace some variables @foo@ in the .in/.sh file, and write the new script
+# ----------------------------------------------------------------------
+
+SET(CFLAGS "-D_WINDOWS ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
+SET(prefix "${CMAKE_INSTALL_PREFIX}/MySQL Server ${MYSQL_BASE_VERSION}")
+SET(sysconfdir ${prefix})
+SET(bindir ${prefix}/bin)
+SET(libexecdir ${prefix}/bin)
+SET(scriptdir ${prefix}/bin)
+SET(datadir ${prefix}/share)
+SET(pkgdatadir ${prefix}/share)
+SET(localstatedir ${prefix}/data)
+
+CONFIGURE_FILE(mysql_config.pl.in
+ scripts/mysql_config.pl ESCAPE_QUOTES @ONLY)
+
+CONFIGURE_FILE(mysql_convert_table_format.sh
+ scripts/mysql_convert_table_format.pl ESCAPE_QUOTES @ONLY)
+
+CONFIGURE_FILE(mysql_explain_log.sh
+ scripts/mysql_explain_log.pl ESCAPE_QUOTES @ONLY)
+
+CONFIGURE_FILE(mysql_install_db.pl.in
+ scripts/mysql_install_db.pl ESCAPE_QUOTES @ONLY)
+
+CONFIGURE_FILE(mysql_secure_installation.pl.in
+ scripts/mysql_secure_installation.pl ESCAPE_QUOTES @ONLY)
+
+CONFIGURE_FILE(mysql_tableinfo.sh
+ scripts/mysql_tableinfo.pl ESCAPE_QUOTES @ONLY)
+
+CONFIGURE_FILE(mysqld_multi.sh
+ scripts/mysqld_multi.pl ESCAPE_QUOTES @ONLY)
+
+CONFIGURE_FILE(mysqldumpslow.sh
+ scripts/mysqldumpslow.pl ESCAPE_QUOTES @ONLY)
+
+CONFIGURE_FILE(mysqlhotcopy.sh
+ scripts/mysqlhotcopy.pl ESCAPE_QUOTES @ONLY)
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 5db5fdd550f..87170b46675 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -48,11 +48,14 @@ EXTRA_SCRIPTS = make_binary_distribution.sh \
make_win_src_distribution_old.sh \
msql2mysql.sh \
mysql_config.sh \
+ mysql_config.pl.in \
mysql_fix_privilege_tables.sh \
mysql_fix_extensions.sh \
mysql_install_db.sh \
+ mysql_install_db.pl.in \
mysql_setpermission.sh \
mysql_secure_installation.sh \
+ mysql_secure_installation.pl.in \
mysql_zap.sh \
mysqlaccess.sh \
mysqlbug.sh \
diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh
index a87bb03526d..8598a022669 100644
--- a/scripts/make_binary_distribution.sh
+++ b/scripts/make_binary_distribution.sh
@@ -400,11 +400,13 @@ BASE=$BASE2
#
if [ x"@GXX@" = x"yes" ] ; then
- gcclib=`@CC@ @CFLAGS@ --print-libgcc-file`
- if [ $? -ne 0 ] ; then
- echo "Warning: Couldn't find libgcc.a!"
- else
+ gcclib=`@CC@ @CFLAGS@ --print-libgcc-file 2>/dev/null` || true
+ if [ -z "$gcclib" ] ; then
+ echo "Warning: Compiler doesn't tell libgcc.a!"
+ elif [ -f "$gcclib" ] ; then
$CP $gcclib $BASE/lib/libmygcc.a
+ else
+ echo "Warning: Compiler result '$gcclib' not found / no file!"
fi
fi
diff --git a/scripts/make_win_bin_dist b/scripts/make_win_bin_dist
index d065e171bb0..56510dc857b 100755
--- a/scripts/make_win_bin_dist
+++ b/scripts/make_win_bin_dist
@@ -327,35 +327,34 @@ if [ -d mysql-test/extra ] ; then
fi
# ----------------------------------------------------------------------
-# Copy what could be usable in the "scripts" directory. Currently
-# only SQL files, others are Bourne shell scripts or Perl scripts
-# not really usable on Windows.
-#
-# But to be nice to the few Cygwin users we might have in 5.0 we
-# continue to copy the stuff, but don't include it in the WiX install.
+# Copy what could be usable in the "scripts" directory
# ----------------------------------------------------------------------
+mysql_scripts="\
+mysql_config.pl \
+mysql_convert_table_format.pl \
+mysql_explain_log.pl \
+mysql_install_db.pl \
+mysql_secure_installation.pl \
+mysql_tableinfo.pl \
+mysqld_multi.pl \
+mysqldumpslow.pl \
+mysqlhotcopy.pl \
+"
+
mkdir -p $DESTDIR/scripts
-# Uncomment and remove the for loop in 5.1
-#cp scripts/*.sql $DESTDIR/scripts/
-
-for i in `cd scripts && ls`; do \
- if echo $i | grep -q '\.sh'; then \
- cp scripts/$i $DESTDIR/scripts/`echo $i | sed -e 's/\.sh$//'`; \
- elif [ -d scripts/$i -o $i = Makefile.am -o $i = Makefile.in -o -e scripts/$i.sh ] ; then \
- : ; \
- else \
- cp scripts/$i $DESTDIR/scripts/$i; \
- fi; \
+for i in $mysql_scripts
+do
+ cp scripts/$i $DESTDIR/scripts/$i
done
cp -pR sql/share $DESTDIR/
cp -pR sql-bench $DESTDIR/
rm -f $DESTDIR/sql-bench/*.sh $DESTDIR/sql-bench/Makefile*
-# The SQL initialisation code is really expected to be in "share"
-mv $DESTDIR/scripts/*.sql $DESTDIR/share/ || true
+# The SQL initialisation code is to be in "share"
+cp scripts/*.sql $DESTDIR/share/
# ----------------------------------------------------------------------
# Clean up from possibly copied SCCS directories
diff --git a/scripts/mysql_config.pl.in b/scripts/mysql_config.pl.in
new file mode 100644
index 00000000000..3ae8baf7db0
--- /dev/null
+++ b/scripts/mysql_config.pl.in
@@ -0,0 +1,285 @@
+#!/usr/bin/perl
+# -*- cperl -*-
+#
+# Copyright (C) 2007 MySQL AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+##############################################################################
+#
+# This script reports various configuration settings that may be needed
+# when using the MySQL client library.
+#
+# This script try to match the shell script version as close as possible,
+# but in addition being compatible with ActiveState Perl on Windows.
+#
+# All unrecognized arguments to this script are passed to mysqld.
+#
+# NOTE: This script will only be used on Windows until solved how to
+# handle @LIBS@ and other strings inserted that might contain
+# several arguments, possibly with spaces in them.
+#
+# NOTE: This script was deliberately written to be as close to the shell
+# script as possible, to make the maintenance of both in parallel
+# easier.
+#
+##############################################################################
+
+use File::Basename;
+use Getopt::Long;
+use Cwd;
+use strict;
+
+my @exclude_cflags =
+ qw/DDBUG_OFF DSAFEMALLOC USAFEMALLOC DSAFE_MUTEX
+ DPEDANTIC_SAFEMALLOC DUNIV_MUST_NOT_INLINE DFORCE_INIT_OF_VARS
+ DEXTRA_DEBUG DHAVE_purify O O[0-9] xO[0-9] W[-A-Za-z]*
+ Xa xstrconst xc99=none
+ unroll2 ip mp restrict/;
+
+my @exclude_libs = qw/lmtmalloc static-libcxa i-static static-intel/;
+
+my $cwd = cwd();
+my $basedir;
+
+my $socket = '@MYSQL_UNIX_ADDR@';
+my $version = '@VERSION@';
+
+sub which
+{
+ my $file = shift;
+
+ my $IFS = $^O eq "MSWin32" ? ";" : ":";
+
+ foreach my $dir ( split($IFS, $ENV{PATH}) )
+ {
+ if ( -f "$dir/$file" or -f "$dir/$file.exe" )
+ {
+ return "$dir/$file";
+ }
+ }
+ print STDERR "which: no $file in ($ENV{PATH})\n";
+ exit 1;
+}
+
+# ----------------------------------------------------------------------
+# If we can find the given directory relatively to where mysql_config is
+# we should use this instead of the incompiled one.
+# This is to ensure that this script also works with the binary MySQL
+# version
+# ----------------------------------------------------------------------
+
+sub fix_path
+{
+ my $default = shift;
+ my @dirs = @_;
+
+ foreach my $dirname ( @dirs )
+ {
+ my $path = "$basedir/$dirname";
+ if ( -d $path )
+ {
+ return $path;
+ }
+ }
+ return $default;
+}
+
+sub get_full_path
+{
+ my $file = shift;
+
+ # if the file is a symlink, try to resolve it
+ if ( $^O ne "MSWin32" and -l $file )
+ {
+ $file = readlink($file);
+ }
+
+ if ( $file =~ m,^/, )
+ {
+ # Do nothing, absolute path
+ }
+ elsif ( $file =~ m,/, )
+ {
+ # Make absolute, and remove "/./" in path
+ $file = "$cwd/$file";
+ $file =~ s,/\./,/,g;
+ }
+ else
+ {
+ # Find in PATH
+ $file = which($file);
+ }
+
+ return $file;
+}
+
+##############################################################################
+#
+# Form a command line that can handle spaces in paths and arguments
+#
+##############################################################################
+
+sub quote_options {
+ my @cmd;
+ foreach my $opt ( @_ )
+ {
+ next unless $opt; # If undefined or empty, just skip
+ push(@cmd, "\"$opt\""); # Quote argument
+ }
+ return join(" ", @cmd);
+}
+
+##############################################################################
+#
+# Main program
+#
+##############################################################################
+
+my $me = get_full_path($0);
+$basedir = dirname(dirname($me)); # Remove "/bin/mysql_config" part
+
+my $ldata = '@localstatedir@';
+my $execdir = '@libexecdir@';
+my $bindir = '@bindir@';
+
+# ----------------------------------------------------------------------
+# If installed, search for the compiled in directory first (might be "lib64")
+# ----------------------------------------------------------------------
+
+my $pkglibdir = fix_path('@pkglibdir@',"libmysql/relwithdebinfo",
+ "libmysql/release","libmysql/debug","lib/mysql","lib");
+
+my $pkgincludedir = fix_path('@pkgincludedir@', "include/mysql", "include");
+
+# Assume no argument with space in it
+my @ldflags = split(" ",'@LDFLAGS@');
+
+my $port;
+if ( '@MYSQL_TCP_PORT_DEFAULT@' == 0 ) {
+ $port = 0;
+} else {
+ $port = '@MYSQL_TCP_PORT@';
+}
+
+# ----------------------------------------------------------------------
+# Create options
+# We intentionally add a space to the beginning and end of lib strings, simplifies replace later
+# ----------------------------------------------------------------------
+
+my (@lib_opts,@lib_r_opts,@lib_e_opts);
+if ( $^O eq "MSWin32" )
+{
+ my $linkpath = "$pkglibdir";
+ # user32 is only needed for debug or embedded
+ my @winlibs = ("wsock32.lib","advapi32.lib","user32.lib");
+ @lib_opts = ("$linkpath/mysqlclient.lib",@winlibs);
+ @lib_r_opts = @lib_opts;
+ @lib_e_opts = ("$linkpath/mysqlserver.lib",@winlibs);
+}
+else
+{
+ my $linkpath = "-L$pkglibdir";
+ @lib_opts = ($linkpath,"-lmysqlclient");
+ @lib_r_opts = ($linkpath,"-lmysqlclient_r");
+ @lib_e_opts = ($linkpath,"-lmysqld");
+}
+
+my $flags;
+$flags->{libs} =
+ [@ldflags,@lib_opts,'@ZLIB_DEPS@','@NON_THREADED_LIBS@','@openssl_libs@','@STATIC_NSS_FLAGS@'];
+$flags->{libs_r} =
+ [@ldflags,@lib_r_opts,'@ZLIB_DEPS@','@LIBS@','@openssl_libs@'];
+$flags->{embedded_libs} =
+ [@ldflags,@lib_e_opts,'@ZLIB_DEPS@','@LIBS@','@WRAPLIBS@','@innodb_system_libs@','@openssl_libs@'];
+
+$flags->{include} = ["-I$pkgincludedir"];
+$flags->{cflags} = [@{$flags->{include}},split(" ",'@CFLAGS@')];
+
+# ----------------------------------------------------------------------
+# Remove some options that a client doesn't have to care about
+# FIXME until we have a --cxxflags, we need to remove -Xa
+# and -xstrconst to make --cflags usable for Sun Forte C++
+# ----------------------------------------------------------------------
+
+my $filter = join("|", @exclude_cflags);
+my @tmp = @{$flags->{cflags}}; # Copy the flag list
+$flags->{cflags} = []; # Clear it
+foreach my $cflag ( @tmp )
+{
+ push(@{$flags->{cflags}}, $cflag) unless $cflag =~ m/^($filter)$/o;
+}
+
+# Same for --libs(_r)
+$filter = join("|", @exclude_libs);
+foreach my $lib_type ( "libs","libs_r","embedded_libs" )
+{
+ my @tmp = @{$flags->{$lib_type}}; # Copy the flag list
+ $flags->{$lib_type} = []; # Clear it
+ foreach my $lib ( @tmp )
+ {
+ push(@{$flags->{$lib_type}}, $lib) unless $lib =~ m/^($filter)$/o;
+ }
+}
+
+my $include = quote_options(@{$flags->{include}});
+my $cflags = quote_options(@{$flags->{cflags}});
+my $libs = quote_options(@{$flags->{libs}});
+my $libs_r = quote_options(@{$flags->{libs_r}});
+my $embedded_libs = quote_options(@{$flags->{embedded_libs}});
+
+##############################################################################
+#
+# Usage information, output if no option is given
+#
+##############################################################################
+
+sub usage
+{
+ print <<EOF;
+Usage: $0 [OPTIONS]
+Options:
+ --cflags [$cflags]
+ --include [$include]
+ --libs [$libs]
+ --libs_r [$libs_r]
+ --socket [$socket]
+ --port [$port]
+ --version [$version]
+ --libmysqld-libs [$embedded_libs]
+EOF
+ exit 1;
+}
+
+@ARGV or usage();
+
+##############################################################################
+#
+# Get options and output the values
+#
+##############################################################################
+
+GetOptions(
+ "cflags" => sub { print "$cflags\n" },
+ "include" => sub { print "$include\n" },
+ "libs" => sub { print "$libs\n" },
+ "libs_r" => sub { print "$libs_r\n" },
+ "socket" => sub { print "$socket\n" },
+ "port" => sub { print "$port\n" },
+ "version" => sub { print "$version\n" },
+ "embedded-libs|embedded|libmysqld-libs" =>
+ sub { print "$embedded_libs\n" },
+ ) or usage();
+
+exit 0
diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh
index a0c3b43d690..915f623578d 100644
--- a/scripts/mysql_config.sh
+++ b/scripts/mysql_config.sh
@@ -107,6 +107,16 @@ libs="$libs @openssl_libs@ @STATIC_NSS_FLAGS@ "
libs_r=" $ldflags -L$pkglibdir -lmysqlclient_r @ZLIB_DEPS@ @LIBS@ @openssl_libs@ "
embedded_libs=" $ldflags -L$pkglibdir -lmysqld @ZLIB_DEPS@ @LIBS@ @WRAPLIBS@ @innodb_system_libs@ @openssl_libs@ "
+if [ -r "$pkglibdir/libmygcc.a" ]; then
+ # When linking against the static library with a different version of GCC
+ # from what was used to compile the library, some symbols may not be defined
+ # automatically. We package the libmygcc.a from the build host, to provide
+ # definitions for those. Bugs 4921, 19561, 19817, 21158, etc.
+ libs="$libs -lmygcc "
+ libs_r="$libs_r -lmygcc "
+ embedded_libs="$embedded_libs -lmygcc "
+fi
+
cflags="-I$pkgincludedir @CFLAGS@ " #note: end space!
include="-I$pkgincludedir"
@@ -118,6 +128,7 @@ include="-I$pkgincludedir"
for remove in DDBUG_OFF DSAFEMALLOC USAFEMALLOC DSAFE_MUTEX \
DPEDANTIC_SAFEMALLOC DUNIV_MUST_NOT_INLINE DFORCE_INIT_OF_VARS \
DEXTRA_DEBUG DHAVE_purify O 'O[0-9]' 'xO[0-9]' 'W[-A-Za-z]*' \
+ 'mtune=[-A-Za-z0-9]*' 'mcpu=[-A-Za-z0-9]*' 'march=[-A-Za-z0-9]*' \
Xa xstrconst "xc99=none" AC99 \
unroll2 ip mp restrict
do
diff --git a/scripts/mysql_convert_table_format.sh b/scripts/mysql_convert_table_format.sh
index 0c9ce3a67e0..833b5bf5f11 100644
--- a/scripts/mysql_convert_table_format.sh
+++ b/scripts/mysql_convert_table_format.sh
@@ -1,4 +1,4 @@
-#!@PERL@
+#!/usr/bin/perl
# Copyright (C) 2000-2002 MySQL AB
#
# This program is free software; you can redistribute it and/or modify
diff --git a/scripts/mysql_explain_log.sh b/scripts/mysql_explain_log.sh
index a549817db5a..30bee722873 100644
--- a/scripts/mysql_explain_log.sh
+++ b/scripts/mysql_explain_log.sh
@@ -1,4 +1,4 @@
-#!@PERL@
+#!/usr/bin/perl
# Copyright (C) 2001-2003, 2006 MySQL AB
#
# This program is free software; you can redistribute it and/or modify
@@ -196,9 +196,10 @@ if (defined ($help)) {
elsif (m/^\s+(.+)$/ ) { # command could be some lines ...
#print "multi-lined ($1)\n";
my ($A)=$1;
- chomp $A;
- $Param->{Query} .= " $1";
- #print "multi-lined ($1)<<$Param->{Query}>>\n";
+ $A =~ s/\-\-.*//;
+
+ $Param->{Query} .= " $A";
+ #print "multi-lined ($A)<<$Param->{Query}>>\n";
}
diff --git a/scripts/mysql_install_db.pl.in b/scripts/mysql_install_db.pl.in
new file mode 100644
index 00000000000..18bd713c041
--- /dev/null
+++ b/scripts/mysql_install_db.pl.in
@@ -0,0 +1,612 @@
+#!/usr/bin/perl
+# -*- cperl -*-
+#
+# Copyright (C) 2007 MySQL AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+##############################################################################
+#
+# This scripts creates the MySQL Server system tables.
+#
+# This script try to match the shell script version as close as possible,
+# but in addition being compatible with ActiveState Perl on Windows.
+#
+# All unrecognized arguments to this script are passed to mysqld.
+#
+# NOTE: This script in 5.0 doesn't really match the shell script
+# version 100%, it is more close to the 5.1 version.
+#
+# NOTE: This script was deliberately written to be as close to the shell
+# script as possible, to make the maintenance of both in parallel
+# easier.
+#
+##############################################################################
+
+use File::Basename;
+use Getopt::Long;
+use Sys::Hostname;
+use Data::Dumper;
+use strict;
+
+Getopt::Long::Configure("pass_through");
+
+my @args; # Argument list filled in
+
+##############################################################################
+#
+# Usage information
+#
+##############################################################################
+
+sub usage
+{
+ print <<EOF;
+Usage: $0 [OPTIONS]
+ --basedir=path The path to the MySQL installation directory.
+ --builddir=path If using --srcdir with out-of-directory builds, you
+ will need to set this to the location of the build
+ directory where built files reside.
+ --cross-bootstrap For internal use. Used when building the MySQL system
+ tables on a different host than the target.
+ --datadir=path The path to the MySQL data directory.
+ --force Causes mysql_install_db to run even if DNS does not
+ work. In that case, grant table entries that normally
+ use hostnames will use IP addresses.
+ --ldata=path The path to the MySQL data directory. Same as --datadir.
+ --rpm For internal use. This option is used by RPM files
+ during the MySQL installation process.
+ --skip-name-resolve Use IP addresses rather than hostnames when creating
+ grant table entries. This option can be useful if
+ your DNS does not work.
+ --srcdir=path The path to the MySQL source directory. This option
+ uses the compiled binaries and support files within the
+ source tree, useful for if you don't want to install
+ MySQL yet and just want to create the system tables.
+ --user=user_name The login username to use for running mysqld. Files
+ and directories created by mysqld will be owned by this
+ user. You must be root to use this option. By default
+ mysqld runs using your current login name and files and
+ directories that it creates will be owned by you.
+
+All other options are passed to the mysqld program
+
+EOF
+ exit 1;
+}
+
+##############################################################################
+#
+# Parse an argument list
+#
+# We only need to pass arguments through to the server if we don't
+# handle them here. So, we collect unrecognized options (passed on
+# the command line) into the args variable.
+#
+##############################################################################
+
+sub parse_arguments
+{
+ my $opt = shift;
+
+ my @saved_ARGV = @ARGV;
+ @ARGV = @_; # Set ARGV so GetOptions works
+
+ my $pick_args;
+ if (@ARGV and $ARGV[0] eq 'PICK-ARGS-FROM-ARGV')
+ {
+ $pick_args = 1;
+ shift @ARGV;
+ }
+
+ GetOptions(
+ $opt,
+ "force",
+ "basedir=s",
+ "builddir=s", # FIXME not documented
+ "srcdir=s",
+ "ldata|datadir=s",
+
+ # Note that the user will be passed to mysqld so that it runs
+ # as 'user' (crucial e.g. if log-bin=/some_other_path/
+ # where a chown of datadir won't help)
+ "user=s",
+
+ "skip-name-resolve",
+ "verbose",
+ "rpm",
+ "help",
+ "defaults-file|defaults-extra-file|no-defaults:s",
+
+ # Used when building the MySQL system tables on a different host than
+ # the target. The platform-independent files that are created in
+ # --datadir on the host can be copied to the target system.
+ #
+ # The most common use for this feature is in the Windows installer
+ # which will take the files from datadir and include them as part of
+ # the install package. See top-level 'dist-hook' make target.
+ #
+ # --windows is a deprecated alias
+ "cross-bootstrap|windows", # FIXME undocumented, even needed?
+ ) or usage();
+
+ usage() if $opt->{help};
+
+ @args = @ARGV if $pick_args;
+
+ @ARGV = @saved_ARGV; # Set back ARGV
+}
+
+##############################################################################
+#
+# Try to find a specific file within --basedir which can either be a binary
+# release or installed source directory and return the path.
+#
+##############################################################################
+
+sub find_in_basedir
+{
+ my $opt = shift;
+ my $mode = shift; # "dir" or "file"
+ my $files = shift;
+
+ foreach my $file ( @{ref($files) ? $files : [$files]} )
+ {
+ foreach my $dir ( @_ )
+ {
+ foreach my $part ( "$file","$file.exe","release/$file.exe",
+ "debug/$file.exe","relwithdebinfo/$file.exe" )
+ {
+ my $path = "$opt->{basedir}/$dir/$part";
+ if ( -f $path )
+ {
+ return $mode eq "dir" ? dirname($path) : $path;
+ }
+ }
+ }
+ }
+}
+
+##############################################################################
+#
+# Just a function to write out an error report
+#
+##############################################################################
+
+sub cannot_find_file
+{
+ my $file = shift;
+
+ print "FATAL ERROR: Could not find $file\n";
+ print "\n";
+ print "If you compiled from source, you need to run 'make install' to\n";
+ print "copy the software into the correct location ready for operation.\n";
+ print "\n";
+ print "If you are using a binary release, you must either be at the top\n";
+ print "level of the extracted archive, or pass the --basedir option\n";
+ print "pointing to that location.\n";
+ print "\n";
+
+ exit 1;
+}
+
+##############################################################################
+#
+# Form a command line that can handle spaces in paths and arguments
+#
+##############################################################################
+
+# FIXME this backslash escaping needed if using '"..."' ?
+# This regexp makes sure that any special chars are quoted,
+# so the arg gets passed exactly to the server.
+# XXX: This is broken; true fix requires using eval and proper
+# quoting of every single arg ($opt->{basedir}, $opt->{ldata}, etc.)
+# join(" ", map {s/([^\w\_\.\-])/\\$1/g}
+
+sub quote_options {
+ my @cmd;
+ foreach my $opt ( @_ )
+ {
+ next unless $opt; # If undefined or empty, just skip
+ push(@cmd, "\"$opt\""); # Quote argument
+ }
+ return join(" ", @cmd);
+}
+
+##############################################################################
+#
+# Ok, let's go. We first need to parse arguments which are required by
+# my_print_defaults so that we can execute it first, then later re-parse
+# the command line to add any extra bits that we need.
+#
+##############################################################################
+
+my $opt = {};
+parse_arguments($opt, 'PICK-ARGS-FROM-ARGV', @ARGV);
+
+# ----------------------------------------------------------------------
+# We can now find my_print_defaults. This script supports:
+#
+# --srcdir=path pointing to compiled source tree
+# --basedir=path pointing to installed binary location
+#
+# or default to compiled-in locations.
+# ----------------------------------------------------------------------
+
+my $print_defaults;
+
+if ( $opt->{srcdir} and $opt->{basedir} )
+{
+ error("Specify either --basedir or --srcdir, not both");
+}
+if ( $opt->{srcdir} )
+{
+ $opt->{builddir} = $opt->{srcdir} unless $opt->{builddir};
+ $print_defaults = "$opt->{builddir}/extra/my_print_defaults";
+}
+elsif ( $opt->{basedir} )
+{
+ $print_defaults = find_in_basedir($opt,"file","my_print_defaults","bin","extra");
+}
+else
+{
+ $print_defaults='@bindir@/my_print_defaults';
+}
+
+-x $print_defaults or -f "$print_defaults.exe"
+ or cannot_find_file($print_defaults);
+
+# ----------------------------------------------------------------------
+# Now we can get arguments from the groups [mysqld] and [mysql_install_db]
+# in the my.cfg file, then re-run to merge with command line arguments.
+# ----------------------------------------------------------------------
+
+my @default_options;
+my $cmd = quote_options($print_defaults,$opt->{'defaults-file'},
+ "mysqld","mysql_install_db");
+open(PIPE, "$cmd |") or error($opt,"can't run $cmd: $!");
+while ( <PIPE> )
+{
+ chomp;
+ next unless /\S/;
+ push(@default_options, $_);
+}
+close PIPE;
+$opt = {}; # Reset the arguments FIXME ?
+parse_arguments($opt, @default_options);
+parse_arguments($opt, 'PICK-ARGS-FROM-ARGV', @ARGV);
+
+# ----------------------------------------------------------------------
+# Configure paths to support files
+# ----------------------------------------------------------------------
+
+# FIXME $extra_bindir is not used
+my ($bindir,$extra_bindir,$mysqld,$pkgdatadir,$mysqld_opt,$scriptdir);
+
+if ( $opt->{srcdir} )
+{
+ $opt->{basedir} = $opt->{builddir};
+ $bindir = "$opt->{basedir}/client";
+ $extra_bindir = "$opt->{basedir}/extra";
+ $mysqld = "$opt->{basedir}/sql/mysqld";
+ $mysqld_opt = "--language=$opt->{srcdir}/sql/share/english";
+ $pkgdatadir = "$opt->{srcdir}/scripts";
+ $scriptdir = "$opt->{srcdir}/scripts";
+}
+elsif ( $opt->{basedir} )
+{
+ $bindir = "$opt->{basedir}/bin";
+ $extra_bindir = $bindir;
+ $mysqld = find_in_basedir($opt,"file",["mysqld-nt","mysqld"],
+ "libexec","sbin","bin") || # ,"sql"
+ find_in_basedir($opt,"file","mysqld-nt",
+ "bin"); # ,"sql"
+ $pkgdatadir = find_in_basedir($opt,"dir","fill_help_tables.sql",
+ "share","share/mysql"); # ,"scripts"
+ $scriptdir = "$opt->{basedir}/scripts";
+}
+else
+{
+ $opt->{basedir} = '@prefix@';
+ $bindir = '@bindir@';
+ $extra_bindir = $bindir;
+ $mysqld = '@libexecdir@/mysqld';
+ $pkgdatadir = '@pkgdatadir@';
+ $scriptdir = '@scriptdir@';
+}
+
+unless ( $opt->{ldata} )
+{
+ $opt->{ldata} = '@localstatedir@';
+}
+
+if ( $opt->{srcdir} )
+{
+ $pkgdatadir = "$opt->{srcdir}/scripts";
+}
+
+# ----------------------------------------------------------------------
+# Set up paths to SQL scripts required for bootstrap
+# ----------------------------------------------------------------------
+
+my $fill_help_tables = "$pkgdatadir/fill_help_tables.sql";
+my $create_system_tables = "$pkgdatadir/mysql_system_tables.sql";
+my $fill_system_tables = "$pkgdatadir/mysql_system_tables_data.sql";
+
+foreach my $f ( $fill_help_tables,$create_system_tables,$fill_system_tables )
+{
+ -f $f or cannot_find_file($f);
+}
+
+-x $mysqld or -f "$mysqld.exe" or cannot_find_file($mysqld);
+# Try to determine the hostname
+my $hostname = hostname();
+
+# ----------------------------------------------------------------------
+# Check if hostname is valid
+# ----------------------------------------------------------------------
+
+my $resolved;
+if ( !$opt->{'cross-bootstrap'} and !$opt->{rpm} and !$opt->{force} )
+{
+ my $resolveip;
+
+ $resolved = `$resolveip $hostname 2>&1`;
+ if ( $? != 0 )
+ {
+ $resolved=`$resolveip localhost 2>&1`;
+ if ( $? != 0 )
+ {
+ error($opt,
+ "Neither host '$hostname' nor 'localhost' could be looked up with",
+ "$bindir/resolveip",
+ "Please configure the 'hostname' command to return a correct",
+ "hostname.",
+ "If you want to solve this at a later stage, restart this script",
+ "with the --force option");
+ }
+ warning($opt,
+ "The host '$hostname' could not be looked up with resolveip.",
+ "This probably means that your libc libraries are not 100 % compatible",
+ "with this binary MySQL version. The MySQL daemon, mysqld, should work",
+ "normally with the exception that host name resolving will not work.",
+ "This means that you should use IP addresses instead of hostnames",
+ "when specifying MySQL privileges !");
+ }
+}
+
+# FIXME what does this really mean....
+if ( $opt->{'skip-name-resolve'} and $resolved and $resolved =~ /\s/ )
+{
+ $hostname = (split(' ', $resolved))[5];
+}
+
+# ----------------------------------------------------------------------
+# Create database directories mysql & test
+# ----------------------------------------------------------------------
+
+foreach my $dir ( $opt->{ldata}, "$opt->{ldata}/mysql", "$opt->{ldata}/test" )
+{
+ # FIXME not really the same as original "mkdir -p", but ok?
+ mkdir($dir, 0700) unless -d $dir;
+ chown($opt->{user}, $dir) if -w "/" and !$opt->{user};
+}
+
+push(@args, "--user=$opt->{user}") if $opt->{user};
+
+# ----------------------------------------------------------------------
+# Configure mysqld command line
+# ----------------------------------------------------------------------
+
+# FIXME use --init-file instead of --bootstrap ?!
+
+my $mysqld_bootstrap = $ENV{MYSQLD_BOOTSTRAP} || $mysqld;
+my $mysqld_install_cmd_line = quote_options($mysqld_bootstrap,
+ $opt->{'defaults-file'},
+ $mysqld_opt,
+ "--bootstrap",
+ "--basedir=$opt->{basedir}",
+ "--datadir=$opt->{ldata}",
+ "--skip-innodb",
+ "--skip-bdb",
+ "--skip-ndbcluster",
+ "--max_allowed_packet=8M",
+ "--net_buffer_length=16K",
+ @args,
+ );
+
+# ----------------------------------------------------------------------
+# Create the system and help tables by passing them to "mysqld --bootstrap"
+# ----------------------------------------------------------------------
+
+report_verbose_wait($opt,"Installing MySQL system tables...");
+
+open(SQL, $create_system_tables)
+ or error($opt,"can't open $create_system_tables for reading: $!");
+# FIXME > /dev/null ?
+if ( open(PIPE, "| $mysqld_install_cmd_line") )
+{
+ print PIPE "use mysql;\n";
+ while ( <SQL> )
+ {
+ # When doing a "cross bootstrap" install, no reference to the current
+ # host should be added to the system tables. So we filter out any
+ # lines which contain the current host name.
+ next if $opt->{'cross-bootstrap'} and /\@current_hostname/;
+
+ print PIPE $_;
+ }
+ close PIPE;
+ close SQL;
+
+ report_verbose($opt,"OK");
+
+ # ----------------------------------------------------------------------
+ # Pipe fill_help_tables.sql to "mysqld --bootstrap"
+ # ----------------------------------------------------------------------
+
+ report_verbose_wait($opt,"Filling help tables...");
+ open(SQL, $fill_help_tables)
+ or error($opt,"can't open $fill_help_tables for reading: $!");
+ # FIXME > /dev/null ?
+ if ( open(PIPE, "| $mysqld_install_cmd_line") )
+ {
+ print PIPE "use mysql;\n";
+ while ( <SQL> )
+ {
+ print PIPE $_;
+ }
+ close PIPE;
+ close SQL;
+
+ report_verbose($opt,"OK");
+ }
+ else
+ {
+ warning($opt,"HELP FILES ARE NOT COMPLETELY INSTALLED!",
+ "The \"HELP\" command might not work properly");
+ }
+
+ report_verbose($opt,"To start mysqld at boot time you have to copy",
+ "support-files/mysql.server to the right place " .
+ "for your system");
+
+ if ( !$opt->{'cross-bootstrap'} )
+ {
+ # This is not a true installation on a running system. The end user must
+ # set a password after installing the data files on the real host system.
+ # At this point, there is no end user, so it does not make sense to print
+ # this reminder.
+ report($opt,
+ "PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !",
+ "To do so, start the server, then issue the following commands:",
+ "",
+ " $bindir/mysqladmin -u root password 'new-password'",
+ " $bindir/mysqladmin -u root -h $hostname password 'new-password'",
+ "",
+ "Alternatively you can run:",
+ "",
+ " $bindir/mysql_secure_installation",
+ "",
+ "which will also give you the option of removing the test",
+ "databases and anonymous user created by default. This is",
+ "strongly recommended for production servers.",
+ "",
+ "See the manual for more instructions.");
+
+ if ( !$opt->{rpm} )
+ {
+ report($opt,
+ "You can start the MySQL daemon with:",
+ "",
+ " cd " . '@prefix@' . " ; $bindir/mysqld_safe &",
+ "",
+ "You can test the MySQL daemon with mysql-test-run.pl",
+ "",
+ " cd mysql-test ; perl mysql-test-run.pl");
+ }
+ report($opt,
+ "Please report any problems with the " . '@scriptdir@' . "/mysqlbug script!",
+ "",
+ "The latest information about MySQL is available on the web at",
+ "",
+ " http://www.mysql.com",
+ "",
+ "Support MySQL by buying support/licenses at http://shop.mysql.com");
+ }
+ exit 0
+}
+else
+{
+ error($opt,
+ "Installation of system tables failed!",
+ "",
+ "Examine the logs in $opt->{ldata} for more information.",
+ "You can try to start the mysqld daemon with:",
+ "$mysqld --skip-grant &",
+ "and use the command line tool",
+ "$bindir/mysql to connect to the mysql",
+ "database and look at the grant tables:",
+ "",
+ "shell> $bindir/mysql -u root mysql",
+ "mysql> show tables",
+ "",
+ "Try 'mysqld --help' if you have problems with paths. Using --log",
+ "gives you a log in $opt->{ldata} that may be helpful.",
+ "",
+ "The latest information about MySQL is available on the web at",
+ "http://www.mysql.com",
+ "Please consult the MySQL manual section: 'Problems running mysql_install_db',",
+ "and the manual section that describes problems on your OS.",
+ "Another information source is the MySQL email archive.",
+ "Please check all of the above before mailing us!",
+ "And if you do mail us, you MUST use the " . '@scriptdir@' . "/mysqlbug script!")
+}
+
+##############################################################################
+#
+# Misc
+#
+##############################################################################
+
+sub report_verbose
+{
+ my $opt = shift;
+ my $text = shift;
+
+ report_verbose_wait($opt, $text, @_);
+ print "\n\n";
+}
+
+sub report_verbose_wait
+{
+ my $opt = shift;
+ my $text = shift;
+
+ if ( $opt->{verbose} or (!$opt->{rpm} and !$opt->{'cross-bootstrap'}) )
+ {
+ print "$text";
+ map {print "\n$_"} @_;
+ }
+}
+
+sub report
+{
+ my $opt = shift;
+ my $text = shift;
+
+ print "$text\n";
+ map {print "$_\n"} @_;
+ print "\n";
+}
+
+sub error
+{
+ my $opt = shift;
+ my $text = shift;
+
+ print "FATAL ERROR: $text\n";
+ map {print "$_\n"} @_;
+ exit 1;
+}
+
+sub warning
+{
+ my $opt = shift;
+ my $text = shift;
+
+ print "WARNING: $text\n";
+ map {print "$_\n"} @_;
+ print "\n";
+}
diff --git a/scripts/mysql_secure_installation.pl.in b/scripts/mysql_secure_installation.pl.in
new file mode 100755
index 00000000000..4eeb50e6d2f
--- /dev/null
+++ b/scripts/mysql_secure_installation.pl.in
@@ -0,0 +1,352 @@
+#!/usr/bin/perl
+# -*- cperl -*-
+#
+# Copyright (C) 2002 MySQL AB and Jeremy Cole
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+use Fcntl;
+use strict;
+
+my $config = ".my.cnf.$$";
+my $command = ".mysql.$$";
+my $hadpass = 0;
+
+# FIXME
+# trap "interrupt" 2
+
+my $rootpass = "";
+
+sub echo_on {
+ if ($^O eq 'MSWin32') {
+ ReadMode('normal');
+ } else {
+ system("stty echo");
+ }
+}
+
+sub echo_off {
+ if ($^O eq 'MSWin32') {
+ ReadMode('noecho');
+ } else {
+ system("stty -echo");
+ }
+}
+
+sub write_file {
+ my $file = shift;
+ -f $file or die "ERROR: file is missing \"$file\": $!";
+ open(FILE, ">$file") or die "ERROR: can't write to file \"$file\": $!";
+ foreach my $line ( @_ ) {
+ print FILE $line, "\n"; # Add EOL char
+ }
+ close FILE;
+}
+
+sub prepare {
+ foreach my $file ( $config, $command ) {
+ next if -f $file; # Already exists
+ local *FILE;
+ sysopen(FILE, $file, O_CREAT, 0600)
+ or die "ERROR: can't create $file: $!";
+ close FILE;
+ }
+}
+
+sub do_query {
+ my $query = shift;
+ write_file($command, $query);
+ system("mysql --defaults-file=$config < $command");
+ return $?;
+}
+
+sub make_config {
+ my $password = shift;
+
+ write_file($config,
+ "# mysql_secure_installation config file",
+ "[mysql]",
+ "user=root",
+ "password=$rootpass");
+}
+
+sub get_root_password {
+ my $status = 1;
+ while ( $status == 1 ) {
+ echo_off();
+ print "Enter current password for root (enter for none): ";
+ my $password = <STDIN>;
+ echo_on();
+ if ( $password ) {
+ $hadpass = 1;
+ } else {
+ $hadpass = 0;
+ }
+ $rootpass = $password;
+ make_config($rootpass);
+ do_query("");
+ $status = $?;
+ }
+ print "OK, successfully used password, moving on...\n\n";
+}
+
+sub set_root_password {
+ echo_off();
+ print "New password: ";
+ my $password1 = <STDIN>;
+ print "\nRe-enter new password: ";
+ my $password2 = <STDIN>;
+ print "\n";
+ echo_on();
+
+ if ( $password1 eq $password2 ) {
+ print "Sorry, passwords do not match.\n\n";
+ return 1;
+ }
+
+ if ( !$password1 ) {
+ print "Sorry, you can't use an empty password here.\n\n";
+ return 1;
+ }
+
+ do_query("UPDATE mysql.user SET Password=PASSWORD('$password1') WHERE User='root';");
+ if ( $? == 0 ) {
+ print "Password updated successfully!\n";
+ print "Reloading privilege tables..\n";
+ if ( !reload_privilege_tables() ) {
+ exit 1;
+ }
+ print "\n";
+ $rootpass = $password1;
+ make_config($rootpass);
+ } else {
+ print "Password update failed!\n";
+ exit 1;
+ }
+
+ return 0;
+}
+
+sub remove_anonymous_users {
+ do_query("DELETE FROM mysql.user WHERE User='';");
+ if ( $? == 0 ) {
+ print " ... Success!\n";
+ } else {
+ print " ... Failed!\n";
+ exit 1;
+ }
+
+ return 0;
+}
+
+sub remove_remote_root {
+ do_query("DELETE FROM mysql.user WHERE User='root' AND Host!='localhost';");
+ if ( $? == 0 ) {
+ print " ... Success!\n";
+ } else {
+ print " ... Failed!\n";
+ }
+}
+
+sub remove_test_database {
+ print " - Dropping test database...\n";
+ do_query("DROP DATABASE test;");
+ if ( $? == 0 ) {
+ print " ... Success!\n";
+ } else {
+ print " ... Failed! Not critical, keep moving...\n";
+ }
+
+ print " - Removing privileges on test database...\n";
+ do_query("DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'");
+ if ( $? == 0 ) {
+ print " ... Success!\n";
+ } else {
+ print " ... Failed! Not critical, keep moving...\n";
+ }
+
+ return 0;
+}
+
+sub reload_privilege_tables {
+ do_query("FLUSH PRIVILEGES;");
+ if ( $? == 0 ) {
+ print " ... Success!\n";
+ return 0;
+ } else {
+ print " ... Failed!\n";
+ return 1;
+ }
+}
+
+sub interrupt {
+ print "\nAborting!\n\n";
+ cleanup();
+ echo_on();
+ exit 1;
+}
+
+sub cleanup {
+ print "Cleaning up...\n";
+ unlink($config,$command);
+}
+
+
+# The actual script starts here
+
+prepare();
+
+print <<HERE;
+
+
+
+NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
+ SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
+
+In order to log into MySQL to secure it, we'll need the current
+password for the root user. If you've just installed MySQL, and
+you haven't set the root password yet, the password will be blank,
+so you should just press enter here.
+
+HERE
+
+get_root_password();
+
+
+#
+# Set the root password
+#
+
+print "Setting the root password ensures that nobody can log into the MySQL\n";
+print "root user without the proper authorisation.\n\n";
+
+if ( $hadpass == 0 ) {
+ print "Set root password? [Y/n] ";
+} else {
+ print "You already have a root password set, so you can safely answer 'n'.\n\n";
+ print "Change the root password? [Y/n] ";
+}
+
+my $reply = <STDIN>;
+if ( $reply =~ /n/i ) {
+ print " ... skipping.\n";
+} else {
+ my $status = 1;
+ while ( $status == 1 ) {
+ set_root_password();
+ $status = $?;
+ }
+}
+print "\n";
+
+
+#
+# Remove anonymous users
+#
+
+print <<HERE;
+By default, a MySQL installation has an anonymous user, allowing anyone
+to log into MySQL without having to have a user account created for
+them. This is intended only for testing, and to make the installation
+go a bit smoother. You should remove them before moving into a
+production environment.
+
+HERE
+
+print "Remove anonymous users? [Y/n] ";
+$reply = <STDIN>;
+if ( $reply =~ /n/i ) {
+ print " ... skipping.\n";
+} else {
+ remove_anonymous_users();
+}
+print "\n";
+
+
+#
+# Disallow remote root login
+#
+
+print <<HERE;
+Normally, root should only be allowed to connect from 'localhost'. This
+ensures that someone cannot guess at the root password from the network.
+
+HERE
+
+print "Disallow root login remotely? [Y/n] ";
+$reply = <STDIN>;
+if ( $reply =~ /n/i ) {
+ print " ... skipping.\n";
+} else {
+ remove_remote_root();
+}
+print "\n";
+
+
+#
+# Remove test database
+#
+
+print <<HERE;
+By default, MySQL comes with a database named 'test' that anyone can
+access. This is also intended only for testing, and should be removed
+before moving into a production environment.
+
+HERE
+
+print "Remove test database and access to it? [Y/n] ";
+$reply = <STDIN>;
+if ( $reply =~ /n/i ) {
+ print " ... skipping.\n";
+} else {
+ remove_test_database();
+}
+print "\n";
+
+
+#
+# Reload privilege tables
+#
+
+print <<HERE;
+Reloading the privilege tables will ensure that all changes made so far
+will take effect immediately.
+
+HERE
+
+print "Reload privilege tables now? [Y/n] ";
+$reply = <STDIN>;
+if ( $reply =~ /n/i ) {
+ print " ... skipping.\n";
+} else {
+ reload_privilege_tables();
+}
+print "\n";
+
+cleanup();
+
+print <<HERE;
+
+
+
+All done! If you've completed all of the above steps, your MySQL
+installation should now be secure.
+
+Thanks for using MySQL!
+
+
+HERE
+
+
+
diff --git a/scripts/mysql_tableinfo.sh b/scripts/mysql_tableinfo.sh
index 2ed7e381fa3..c90c410ca78 100644
--- a/scripts/mysql_tableinfo.sh
+++ b/scripts/mysql_tableinfo.sh
@@ -1,4 +1,4 @@
-#!@PERL@ -w
+#!/usr/bin/perl
use strict;
use Getopt::Long;
diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh
index 92cfbe3ef22..3cb4665eb1c 100644
--- a/scripts/mysqld_multi.sh
+++ b/scripts/mysqld_multi.sh
@@ -1,4 +1,4 @@
-#!@PERL@
+#!/usr/bin/perl
use Getopt::Long;
use POSIX qw(strftime);
diff --git a/scripts/mysqldumpslow.sh b/scripts/mysqldumpslow.sh
index ff82a35ec3f..f05761bb837 100644
--- a/scripts/mysqldumpslow.sh
+++ b/scripts/mysqldumpslow.sh
@@ -1,4 +1,4 @@
-#!@PERL@
+#!/usr/bin/perl
# mysqldumpslow - parse and summarize the MySQL slow query log
# Original version by Tim Bunce, sometime in 2000.
diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh
index 6ad5c77b954..8814e36b2fa 100644
--- a/scripts/mysqlhotcopy.sh
+++ b/scripts/mysqlhotcopy.sh
@@ -1,4 +1,4 @@
-#!@PERL@ -w
+#!/usr/bin/perl
use strict;
use Getopt::Long;
@@ -39,7 +39,7 @@ WARNING: THIS PROGRAM IS STILL IN BETA. Comments/patches welcome.
# Documentation continued at end of file
-my $VERSION = "1.22";
+my $VERSION = "1.23";
my $opt_tmpdir = $ENV{TMPDIR} || "/tmp";
@@ -132,7 +132,6 @@ GetOptions( \%opt,
# 'target' - destination directory of the copy
# 'tables' - array-ref to list of tables in the db
# 'files' - array-ref to list of files to be copied
-# (RAID files look like 'nn/name.MYD')
# 'index' - array-ref to list of indexes to be copied
#
@@ -263,7 +262,6 @@ my $hc_locks = "";
my $hc_tables = "";
my $num_tables = 0;
my $num_files = 0;
-my $raid_dir_regex = '[A-Za-z0-9]{2}';
foreach my $rdb ( @db_desc ) {
my $db = $rdb->{src};
@@ -292,20 +290,12 @@ foreach my $rdb ( @db_desc ) {
or die "Cannot open dir '$db_dir': $!";
my %db_files;
- my @raid_dir = ();
while ( defined( my $name = readdir DBDIR ) ) {
- if ( $name =~ /^$raid_dir_regex$/ && -d "$db_dir/$name" ) {
- push @raid_dir, $name;
- }
- else {
- $db_files{$name} = $1 if ( $name =~ /(.+)\.\w+$/ );
- }
+ $db_files{$name} = $1 if ( $name =~ /(.+)\.\w+$/ );
}
closedir( DBDIR );
- scan_raid_dir( \%db_files, $db_dir, @raid_dir );
-
unless( keys %db_files ) {
warn "'$db' is an empty database\n";
}
@@ -336,8 +326,6 @@ foreach my $rdb ( @db_desc ) {
my @hc_tables = map { quote_names("$db.$_") } @dbh_tables;
$rdb->{tables} = [ @hc_tables ];
- $rdb->{raid_dirs} = [ get_raid_dirs( $rdb->{files} ) ];
-
$hc_locks .= ", " if ( length $hc_locks && @hc_tables );
$hc_locks .= join ", ", map { "$_ READ" } @hc_tables;
$hc_tables .= ", " if ( length $hc_tables && @hc_tables );
@@ -411,27 +399,24 @@ if ($opt{method} =~ /^cp\b/)
retire_directory( @existing ) if @existing && !$opt{addtodest};
foreach my $rdb ( @db_desc ) {
- foreach my $td ( '', @{$rdb->{raid_dirs}} ) {
-
- my $tgt_dirpath = "$rdb->{target}/$td";
- # Remove trailing slashes (needed for Mac OS X)
- substr($tgt_dirpath, 1) =~ s|/+$||;
- if ( $opt{dryrun} ) {
- print "mkdir $tgt_dirpath, 0750\n";
- }
- elsif ($opt{method} =~ /^scp\b/) {
- ## assume it's there?
- ## ...
- }
- else {
- mkdir($tgt_dirpath, 0750) or die "Can't create '$tgt_dirpath': $!\n"
- unless -d $tgt_dirpath;
- if ($^O !~ m/^(NetWare)$/)
- {
- my @f_info= stat "$datadir/$rdb->{src}";
- chown $f_info[4], $f_info[5], $tgt_dirpath;
- }
- }
+ my $tgt_dirpath = "$rdb->{target}";
+ # Remove trailing slashes (needed for Mac OS X)
+ substr($tgt_dirpath, 1) =~ s|/+$||;
+ if ( $opt{dryrun} ) {
+ print "mkdir $tgt_dirpath, 0750\n";
+ }
+ elsif ($opt{method} =~ /^scp\b/) {
+ ## assume it's there?
+ ## ...
+ }
+ else {
+ mkdir($tgt_dirpath, 0750) or die "Can't create '$tgt_dirpath': $!\n"
+ unless -d $tgt_dirpath;
+ if ($^O !~ m/^(NetWare)$/)
+ {
+ my @f_info= stat "$datadir/$rdb->{src}";
+ chown $f_info[4], $f_info[5], $tgt_dirpath;
+ }
}
}
@@ -489,7 +474,7 @@ foreach my $rdb ( @db_desc )
my @files = map { "$datadir/$rdb->{src}/$_" } @{$rdb->{files}};
next unless @files;
- eval { copy_files($opt{method}, \@files, $rdb->{target}, $rdb->{raid_dirs} ); };
+ eval { copy_files($opt{method}, \@files, $rdb->{target}); };
push @failed, "$rdb->{src} -> $rdb->{target} failed: $@"
if ( $@ );
@@ -582,7 +567,7 @@ exit 0;
# ---
sub copy_files {
- my ($method, $files, $target, $raid_dirs) = @_;
+ my ($method, $files, $target) = @_;
my @cmd;
print "Copying ".@$files." files...\n" unless $opt{quiet};
@@ -603,15 +588,8 @@ sub copy_files {
# add recursive option for scp
$cp.= " -r" if $^O =~ /m^(solaris|linux|freebsd|darwin)$/ && $method =~ /^scp\b/;
- my @non_raid = map { "'$_'" } grep { ! m:/$raid_dir_regex/[^/]+$: } @$files;
-
- # add files to copy and the destination directory
- safe_system( $cp, @non_raid, "'$target'" ) if (@non_raid);
-
- foreach my $rd ( @$raid_dirs ) {
- my @raid = map { "'$_'" } grep { m:$rd/: } @$files;
- safe_system( $cp, @raid, "'$target'/$rd" ) if ( @raid );
- }
+ # perform the actual copy
+ safe_system( $cp, (map { "'$_'" } @$files), "'$target'" );
}
else
{
@@ -789,35 +767,6 @@ sub get_row_hash {
return $sth->fetchrow_hashref();
}
-sub scan_raid_dir {
- my ( $r_db_files, $data_dir, @raid_dir ) = @_;
-
- local(*RAID_DIR);
-
- foreach my $rd ( @raid_dir ) {
-
- opendir(RAID_DIR, "$data_dir/$rd" )
- or die "Cannot open dir '$data_dir/$rd': $!";
-
- while ( defined( my $name = readdir RAID_DIR ) ) {
- $r_db_files->{"$rd/$name"} = $1 if ( $name =~ /(.+)\.\w+$/ );
- }
- closedir( RAID_DIR );
- }
-}
-
-sub get_raid_dirs {
- my ( $r_files ) = @_;
-
- my %dirs = ();
- foreach my $f ( @$r_files ) {
- if ( $f =~ m:^($raid_dir_regex)/: ) {
- $dirs{$1} = 1;
- }
- }
- return sort keys %dirs;
-}
-
sub get_list_of_tables {
my ( $db ) = @_;
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 84b042a91b1..9ea9874c1b1 100755
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -48,7 +48,7 @@ ENDIF(DISABLE_GRANT_OPTIONS)
ADD_EXECUTABLE(mysqld${MYSQLD_EXE_SUFFIX}
../sql-common/client.c derror.cc des_key_file.cc
- discover.cc ../libmysql/errmsg.c field.cc field_conv.cc
+ discover.cc ../libmysql/errmsg.c field.cc stacktrace.c stacktrace.h field_conv.cc
filesort.cc gstream.cc ha_blackhole.cc
ha_archive.cc ha_heap.cc ha_myisam.cc ha_myisammrg.cc
ha_innodb.cc ha_federated.cc ha_berkeley.cc
diff --git a/sql/filesort.cc b/sql/filesort.cc
index a85f9caefbe..70fc6937b59 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -112,6 +112,13 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
FILESORT_INFO table_sort;
TABLE_LIST *tab= table->pos_in_table_list;
Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
+
+ /*
+ Release InnoDB's adaptive hash index latch (if holding) before
+ running a sort.
+ */
+ ha_release_temporary_latches(thd);
+
/*
Don't use table->sort in filesort as it is also used by
QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index fa68da87661..2d2007c8fdd 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -6339,7 +6339,9 @@ void
innodb_export_status(void)
/*======================*/
{
- srv_export_innodb_status();
+ if (innodb_inited) {
+ srv_export_innodb_status();
+ }
}
/****************************************************************************
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index c93091e36d2..e3ab2b67e26 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -439,7 +439,8 @@ void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd)
void ha_ndbcluster::invalidate_dictionary_cache(bool global)
{
- NDBDICT *dict= get_ndb()->getDictionary();
+ Ndb * ndb= get_ndb();
+ NDBDICT *dict= ndb->getDictionary();
DBUG_ENTER("invalidate_dictionary_cache");
DBUG_PRINT("info", ("invalidating %s", m_tabname));
@@ -459,6 +460,7 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global)
}
else
dict->removeCachedTable(m_tabname);
+ build_index_list(ndb, table, ILBP_OPEN);
table->s->version=0L; /* Free when thread is ready */
/* Invalidate indexes */
for (uint i= 0; i < table->s->keys; i++)
@@ -470,17 +472,23 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global)
switch (idx_type) {
case PRIMARY_KEY_ORDERED_INDEX:
case ORDERED_INDEX:
+ if (!index)
+ break;
if (global)
dict->invalidateIndex(index->getName(), m_tabname);
else
dict->removeCachedIndex(index->getName(), m_tabname);
break;
case UNIQUE_ORDERED_INDEX:
+ if (!index)
+ break;
if (global)
dict->invalidateIndex(index->getName(), m_tabname);
else
dict->removeCachedIndex(index->getName(), m_tabname);
case UNIQUE_INDEX:
+ if (!unique_index)
+ break;
if (global)
dict->invalidateIndex(unique_index->getName(), m_tabname);
else
diff --git a/sql/item.cc b/sql/item.cc
index 6f0119393e7..11e9acb1e55 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2410,14 +2410,14 @@ default_set_param_func(Item_param *param,
Item_param::Item_param(unsigned pos_in_query_arg) :
- strict_type(FALSE),
state(NO_VALUE),
item_result_type(STRING_RESULT),
/* Don't pretend to be a literal unless value for this item is set. */
item_type(PARAM_ITEM),
param_type(MYSQL_TYPE_VARCHAR),
pos_in_query(pos_in_query_arg),
- set_param_func(default_set_param_func)
+ set_param_func(default_set_param_func),
+ limit_clause_param(FALSE)
{
name= (char*) "?";
/*
@@ -2606,8 +2606,13 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
{
item_result_type= entry->type;
unsigned_flag= entry->unsigned_flag;
- if (strict_type && required_result_type != item_result_type)
- DBUG_RETURN(1);
+ if (limit_clause_param)
+ {
+ my_bool unused;
+ set_int(entry->val_int(&unused), MY_INT64_NUM_DECIMAL_DIGITS);
+ item_type= Item::INT_ITEM;
+ DBUG_RETURN(!unsigned_flag && value.integer < 0 ? 1 : 0);
+ }
switch (item_result_type) {
case REAL_RESULT:
set_double(*(double*)entry->value);
diff --git a/sql/item.h b/sql/item.h
index 8cd84c3bc13..a948c5a45f7 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -880,6 +880,23 @@ public:
class sp_head;
+class Item_basic_constant :public Item
+{
+public:
+ /* to prevent drop fixed flag (no need parent cleanup call) */
+ void cleanup()
+ {
+ /*
+ Restore the original field name as it might not have been allocated
+ in the statement memory. If the name is auto generated, it must be
+ done again between subsequent executions of a prepared statement.
+ */
+ if (orig_name)
+ name= orig_name;
+ }
+};
+
+
/*****************************************************************************
The class is a base class for representation of stored routine variables in
the Item-hierarchy. There are the following kinds of SP-vars:
@@ -1155,7 +1172,7 @@ bool agg_item_charsets(DTCollation &c, const char *name,
Item **items, uint nitems, uint flags, int item_sep);
-class Item_num: public Item
+class Item_num: public Item_basic_constant
{
public:
Item_num() {} /* Remove gcc warning */
@@ -1346,7 +1363,7 @@ public:
friend class st_select_lex_unit;
};
-class Item_null :public Item
+class Item_null :public Item_basic_constant
{
public:
Item_null(char *name_par=0)
@@ -1368,8 +1385,6 @@ public:
bool send(Protocol *protocol, String *str);
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
- /* to prevent drop fixed flag (no need parent cleanup call) */
- void cleanup() {}
bool basic_const_item() const { return 1; }
Item *clone_item() { return new Item_null(name); }
bool is_null() { return 1; }
@@ -1396,8 +1411,6 @@ class Item_param :public Item
char cnvbuf[MAX_FIELD_WIDTH];
String cnvstr;
Item *cnvitem;
- bool strict_type;
- enum Item_result required_result_type;
public:
enum enum_item_param_state
@@ -1527,11 +1540,8 @@ public:
Otherwise return FALSE.
*/
bool eq(const Item *item, bool binary_cmp) const;
- void set_strict_type(enum Item_result result_type_arg)
- {
- strict_type= TRUE;
- required_result_type= result_type_arg;
- }
+ /** Item is a argument to a limit clause. */
+ bool limit_clause_param;
};
@@ -1561,8 +1571,6 @@ public:
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
Item *clone_item() { return new Item_int(name,value,max_length); }
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
void print(String *str);
Item_num *neg() { value= -value; return this; }
uint decimal_precision() const
@@ -1615,8 +1623,6 @@ public:
{
return new Item_decimal(name, &decimal_value, decimals, max_length);
}
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
void print(String *str);
Item_num *neg()
{
@@ -1667,8 +1673,6 @@ public:
String *val_str(String*);
my_decimal *val_decimal(my_decimal *);
bool basic_const_item() const { return 1; }
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
Item *clone_item()
{ return new Item_float(name, value, decimals, max_length); }
Item_num *neg() { value= -value; return this; }
@@ -1690,7 +1694,7 @@ public:
};
-class Item_string :public Item
+class Item_string :public Item_basic_constant
{
public:
Item_string(const char *str,uint length,
@@ -1774,8 +1778,6 @@ public:
max_length= str_value.numchars() * collation.collation->mbmaxlen;
}
void print(String *str);
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
};
@@ -1833,10 +1835,10 @@ public:
};
-class Item_hex_string: public Item
+class Item_hex_string: public Item_basic_constant
{
public:
- Item_hex_string(): Item() {}
+ Item_hex_string() {}
Item_hex_string(const char *str,uint str_length);
enum Type type() const { return VARBIN_ITEM; }
double val_real()
@@ -1852,8 +1854,6 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
enum Item_result cast_to_int_type() const { return INT_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
void print(String *str);
bool eq(const Item *item, bool binary_cmp) const;
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
@@ -2472,7 +2472,7 @@ private:
};
-class Item_cache: public Item
+class Item_cache: public Item_basic_constant
{
protected:
Item *example;
@@ -2509,8 +2509,6 @@ public:
static Item_cache* get_cache(const Item *item);
table_map used_tables() const { return used_table_map; }
virtual void keep_array() {}
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
void print(String *str);
bool eq_def(Field *field)
{
diff --git a/sql/item_func.cc b/sql/item_func.cc
index dbde4237511..44b8ed998fe 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -3985,7 +3985,7 @@ double user_var_entry::val_real(my_bool *null_value)
/* Get the value of a variable as an integer */
-longlong user_var_entry::val_int(my_bool *null_value)
+longlong user_var_entry::val_int(my_bool *null_value) const
{
if ((*null_value= (value == 0)))
return LL(0);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 4d688d795f7..b8df51e9e58 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -138,6 +138,13 @@ extern "C" { // Because of SCO 3.2V4.2
#include <sys/mman.h>
#endif
+#ifdef __WIN__
+#include <crtdbg.h>
+#define SIGNAL_FMT "exception 0x%x"
+#else
+#define SIGNAL_FMT "signal %d"
+#endif
+
#ifdef __NETWARE__
#define zVOLSTATE_ACTIVE 6
#define zVOLSTATE_DEACTIVE 2
@@ -227,6 +234,7 @@ inline void set_proper_floating_point_mode()
extern "C" int gethostname(char *name, int namelen);
#endif
+extern "C" sig_handler handle_segfault(int sig);
/* Constants */
@@ -1030,9 +1038,6 @@ static void __cdecl kill_server(int sig_ptr)
#endif
close_connections();
if (sig != MYSQL_KILL_SIGNAL &&
-#ifdef __WIN__
- sig != SIGINT && /* Bug#18235 */
-#endif
sig != 0)
unireg_abort(1); /* purecov: inspected */
else
@@ -1591,8 +1596,7 @@ static void network_init(void)
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL );
- MessageBox(NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe",
- MB_OK|MB_ICONINFORMATION);
+ sql_perror((char *)lpMsgBuf);
LocalFree(lpMsgBuf);
unireg_abort(1);
}
@@ -1795,17 +1799,163 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused)))
******************************************************************************/
-#if defined(__WIN__) || defined(OS2)
+#if defined(__WIN__)
+
+
+/*
+ On Windows, we use native SetConsoleCtrlHandler for handle events like Ctrl-C
+ with graceful shutdown.
+ Also, we do not use signal(), but SetUnhandledExceptionFilter instead - as it
+ provides possibility to pass the exception to just-in-time debugger, collect
+ dumps and potentially also the exception and thread context used to output
+ callstack.
+*/
+
+static BOOL WINAPI console_event_handler( DWORD type )
+{
+ DBUG_ENTER("console_event_handler");
+ if(type == CTRL_C_EVENT)
+ {
+ /*
+ Do not shutdown before startup is finished and shutdown
+ thread is initialized. Otherwise there is a race condition
+ between main thread doing initialization and CTRL-C thread doing
+ cleanup, which can result into crash.
+ */
+ if(hEventShutdown)
+ kill_mysql();
+ else
+ sql_print_warning("CTRL-C ignored during startup");
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ In Visual Studio 2005 and later, default SIGABRT handler will overwrite
+ any unhandled exception filter set by the application and will try to
+ call JIT debugger. This is not what we want, this we calling __debugbreak
+ to stop in debugger, if process is being debugged or to generate
+ EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
+*/
+
+#if (_MSC_VER >= 1400)
+static void my_sigabrt_handler(int sig)
+{
+ __debugbreak();
+}
+#endif /*_MSC_VER >=1400 */
+
+void win_install_sigabrt_handler(void)
+{
+#if (_MSC_VER >=1400)
+ /*abort() should not override our exception filter*/
+ _set_abort_behavior(0,_CALL_REPORTFAULT);
+ signal(SIGABRT,my_sigabrt_handler);
+#endif /* _MSC_VER >=1400 */
+}
+
+#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER
+#define DEBUGGER_ATTACH_TIMEOUT 120
+/*
+ Wait for debugger to attach and break into debugger. If debugger is not attached,
+ resume after timeout.
+*/
+static void wait_for_debugger(int timeout_sec)
+{
+ if(!IsDebuggerPresent())
+ {
+ int i;
+ printf("Waiting for debugger to attach, pid=%u\n",GetCurrentProcessId());
+ fflush(stdout);
+ for(i= 0; i < timeout_sec; i++)
+ {
+ Sleep(1000);
+ if(IsDebuggerPresent())
+ {
+ /* Break into debugger */
+ __debugbreak();
+ return;
+ }
+ }
+ printf("pid=%u, debugger not attached after %d seconds, resuming\n",GetCurrentProcessId(),
+ timeout_sec);
+ fflush(stdout);
+ }
+}
+#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */
+
+LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers)
+{
+ static BOOL first_time= TRUE;
+ if(!first_time)
+ {
+ /*
+ This routine can be called twice, typically
+ when detaching in JIT debugger.
+ Return EXCEPTION_EXECUTE_HANDLER to terminate process.
+ */
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ first_time= FALSE;
+#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER
+ /*
+ Unfortunately there is no clean way to debug unhandled exception filters,
+ as debugger does not stop there(also documented in MSDN)
+ To overcome, one could put a MessageBox, but this will not work in service.
+ Better solution is to print error message and sleep some minutes
+ until debugger is attached
+ */
+ wait_for_debugger(DEBUGGER_ATTACH_TIMEOUT);
+#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */
+ __try
+ {
+ set_exception_pointers(ex_pointers);
+ handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DWORD written;
+ const char msg[] = "Got exception in exception handler!\n";
+ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),msg, sizeof(msg)-1,
+ &written,NULL);
+ }
+ /*
+ Return EXCEPTION_CONTINUE_SEARCH to give JIT debugger
+ (drwtsn32 or vsjitdebugger) possibility to attach,
+ if JIT debugger is configured.
+ Windows Error reporting might generate a dump here.
+ */
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+
static void init_signals(void)
{
- int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ;
- for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++)
- signal(signals[i], kill_server) ;
-#if defined(__WIN__)
- signal(SIGBREAK,SIG_IGN); //ignore SIGBREAK for NT
-#else
- signal(SIGBREAK, kill_server);
-#endif
+ win_install_sigabrt_handler();
+ if(opt_console)
+ SetConsoleCtrlHandler(console_event_handler,TRUE);
+ else
+ {
+ /* Avoid MessageBox()es*/
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+
+ /*
+ Do not use SEM_NOGPFAULTERRORBOX in the following SetErrorMode (),
+ because it would prevent JIT debugger and Windows error reporting
+ from working. We need WER or JIT-debugging, since our own unhandled
+ exception filter is not guaranteed to work in all situation
+ (like heap corruption or stack overflow)
+ */
+ SetErrorMode(SetErrorMode(0)|SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+ }
+ SetUnhandledExceptionFilter(my_unhandler_exception_filter);
}
static void start_signal_handler(void)
@@ -2093,8 +2243,8 @@ static void start_signal_handler(void)
static void check_data_home(const char *path)
{}
+#endif /*__WIN__ || __NETWARE || __EMX__*/
-#else /* if ! __WIN__ && ! __EMX__ */
#ifdef HAVE_LINUXTHREADS
#define UNSAFE_DEFAULT_LINUX_THREADS 200
@@ -2114,7 +2264,7 @@ extern "C" sig_handler handle_segfault(int sig)
*/
if (segfaulted)
{
- fprintf(stderr, "Fatal signal %d while backtracing\n", sig);
+ fprintf(stderr, "Fatal " SIGNAL_FMT " while backtracing\n", sig);
exit(1);
}
@@ -2124,7 +2274,7 @@ extern "C" sig_handler handle_segfault(int sig)
localtime_r(&curr_time, &tm);
fprintf(stderr,"\
-%02d%02d%02d %2d:%02d:%02d - mysqld got signal %d;\n\
+%02d%02d%02d %2d:%02d:%02d - mysqld got " SIGNAL_FMT " ;\n\
This could be because you hit a bug. It is also possible that this binary\n\
or one of the libraries it was linked against is corrupt, improperly built,\n\
or misconfigured. This error can also be caused by malfunctioning hardware.\n",
@@ -2165,6 +2315,10 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n",
if (!(test_flags & TEST_NO_STACKTRACE))
{
fprintf(stderr,"thd=%p\n",thd);
+ fprintf(stderr,"\
+Attempting backtrace. You can use the following information to find out\n\
+where mysqld died. If you see no messages after this, something went\n\
+terribly wrong...\n");
print_stacktrace(thd ? (gptr) thd->thread_stack : (gptr) 0,
thread_stack);
}
@@ -2213,15 +2367,22 @@ of those buggy OS calls. You should consider whether you really need the\n\
bugs.\n");
}
+#ifdef HAVE_WRITE_CORE
if (test_flags & TEST_CORE_ON_SIGNAL)
{
fprintf(stderr, "Writing a core file\n");
fflush(stderr);
write_core(sig);
}
+#endif
+
+#ifndef __WIN__
+ /* On Windows, do not terminate, but pass control to exception filter */
exit(1);
+#endif
}
+#if !defined(__WIN__) && !defined(__NETWARE__) && !defined(__EMX__)
#ifndef SA_RESETHAND
#define SA_RESETHAND 0
#endif
@@ -2564,19 +2725,6 @@ static void my_str_free_mysqld(void *ptr)
#ifdef __WIN__
-
-struct utsname
-{
- char nodename[FN_REFLEN];
-};
-
-
-int uname(struct utsname *a)
-{
- return -1;
-}
-
-
pthread_handler_t handle_shutdown(void *arg)
{
MSG msg;
@@ -2590,18 +2738,6 @@ pthread_handler_t handle_shutdown(void *arg)
kill_server(MYSQL_KILL_SIGNAL);
return 0;
}
-
-
-int STDCALL handle_kill(ulong ctrl_type)
-{
- if (ctrl_type == CTRL_CLOSE_EVENT ||
- ctrl_type == CTRL_SHUTDOWN_EVENT)
- {
- kill_server(MYSQL_KILL_SIGNAL);
- return TRUE;
- }
- return FALSE;
-}
#endif
@@ -3630,11 +3766,6 @@ we force server id to 2, but this MySQL server will not act as a slave.");
freopen(log_error_file,"a+",stderr);
FreeConsole(); // Remove window
}
- else
- {
- /* Don't show error dialog box when on foreground: it stops the server */
- SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
- }
#endif
/*
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 97f2d07b1d3..4ca8947de30 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2329,7 +2329,7 @@ class user_var_entry
bool unsigned_flag;
double val_real(my_bool *null_value);
- longlong val_int(my_bool *null_value);
+ longlong val_int(my_bool *null_value) const;
String *val_str(my_bool *null_value, String *str, uint decimals);
my_decimal *val_decimal(my_bool *null_value, my_decimal *result);
DTCollation collation;
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
index 2e98da42be1..c2345f1f2cd 100644
--- a/sql/sql_cursor.cc
+++ b/sql/sql_cursor.cc
@@ -88,6 +88,7 @@ class Materialized_cursor: public Server_side_cursor
public:
Materialized_cursor(select_result *result, TABLE *table);
+ int fill_item_list(THD *thd, List<Item> &send_fields);
virtual bool is_open() const { return table != 0; }
virtual int open(JOIN *join __attribute__((unused)));
virtual void fetch(ulong num_rows);
@@ -109,6 +110,7 @@ class Select_materialize: public select_union
{
select_result *result; /* the result object of the caller (PS or SP) */
public:
+ Materialized_cursor *materialized_cursor;
Select_materialize(select_result *result_arg) :result(result_arg) {}
virtual bool send_fields(List<Item> &list, uint flags);
};
@@ -152,7 +154,7 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
if (! (sensitive_cursor= new (thd->mem_root) Sensitive_cursor(thd, result)))
{
- delete result;
+ delete result_materialize;
return 1;
}
@@ -174,13 +176,13 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
/*
Possible options here:
- a sensitive cursor is open. In this case rc is 0 and
- result_materialize->table is NULL, or
+ result_materialize->materialized_cursor is NULL, or
- a materialized cursor is open. In this case rc is 0 and
- result_materialize->table is not NULL
- - an error occured during materializaton.
- result_materialize->table is not NULL, but rc != 0
+ result_materialize->materialized is not NULL
+ - an error occurred during materialization.
+ result_materialize->materialized_cursor is not NULL, but rc != 0
- successful completion of mysql_execute_command without
- a cursor: rc is 0, result_materialize->table is NULL,
+ a cursor: rc is 0, result_materialize->materialized_cursor is NULL,
sensitive_cursor is not open.
This is possible if some command writes directly to the
network, bypassing select_result mechanism. An example of
@@ -191,7 +193,7 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
if (sensitive_cursor->is_open())
{
- DBUG_ASSERT(!result_materialize->table);
+ DBUG_ASSERT(!result_materialize->materialized_cursor);
/*
It's safer if we grab THD state after mysql_execute_command
is finished and not in Sensitive_cursor::open(), because
@@ -202,18 +204,10 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
*pcursor= sensitive_cursor;
goto end;
}
- else if (result_materialize->table)
+ else if (result_materialize->materialized_cursor)
{
- Materialized_cursor *materialized_cursor;
- TABLE *table= result_materialize->table;
- MEM_ROOT *mem_root= &table->mem_root;
-
- if (!(materialized_cursor= new (mem_root)
- Materialized_cursor(result, table)))
- {
- rc= 1;
- goto err_open;
- }
+ Materialized_cursor *materialized_cursor=
+ result_materialize->materialized_cursor;
if ((rc= materialized_cursor->open(0)))
{
@@ -229,8 +223,6 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
err_open:
DBUG_ASSERT(! (sensitive_cursor && sensitive_cursor->is_open()));
delete sensitive_cursor;
- if (result_materialize->table)
- free_tmp_table(thd, result_materialize->table);
end:
delete result_materialize;
return rc;
@@ -544,6 +536,51 @@ Materialized_cursor::Materialized_cursor(select_result *result_arg,
}
+/**
+ Preserve the original metadata that would be sent to the client.
+
+ @param thd Thread identifier.
+ @param send_fields List of fields that would be sent.
+*/
+
+int Materialized_cursor::fill_item_list(THD *thd, List<Item> &send_fields)
+{
+ Query_arena backup_arena;
+ int rc;
+ List_iterator_fast<Item> it_org(send_fields);
+ List_iterator_fast<Item> it_dst(item_list);
+ Item *item_org;
+ Item *item_dst;
+
+ thd->set_n_backup_active_arena(this, &backup_arena);
+
+ if ((rc= table->fill_item_list(&item_list)))
+ goto end;
+
+ DBUG_ASSERT(send_fields.elements == item_list.elements);
+
+ /*
+ Unless we preserve the original metadata, it will be lost,
+ since new fields describe columns of the temporary table.
+ Allocate a copy of the name for safety only. Currently
+ items with original names are always kept in memory,
+ but in case this changes a memory leak may be hard to notice.
+ */
+ while ((item_dst= it_dst++, item_org= it_org++))
+ {
+ Send_field send_field;
+ Item_ident *ident= static_cast<Item_ident *>(item_dst);
+ item_org->make_field(&send_field);
+
+ ident->db_name= thd->strdup(send_field.db_name);
+ ident->table_name= thd->strdup(send_field.table_name);
+ }
+end:
+ thd->restore_active_arena(this, &backup_arena);
+ /* Check for thd->is_error() in case of OOM */
+ return rc || thd->net.report_error;
+}
+
int Materialized_cursor::open(JOIN *join __attribute__((unused)))
{
THD *thd= fake_unit.thd;
@@ -552,8 +589,7 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused)))
thd->set_n_backup_active_arena(this, &backup_arena);
/* Create a list of fields and start sequential scan */
- rc= (table->fill_item_list(&item_list) ||
- result->prepare(item_list, &fake_unit) ||
+ rc= (result->prepare(item_list, &fake_unit) ||
table->file->ha_rnd_init(TRUE));
thd->restore_active_arena(this, &backup_arena);
if (rc == 0)
@@ -664,6 +700,24 @@ bool Select_materialize::send_fields(List<Item> &list, uint flags)
if (create_result_table(unit->thd, unit->get_unit_column_types(),
FALSE, thd->options | TMP_TABLE_ALL_COLUMNS, ""))
return TRUE;
+
+ materialized_cursor= new (&table->mem_root)
+ Materialized_cursor(result, table);
+
+ if (! materialized_cursor)
+ {
+ free_tmp_table(table->in_use, table);
+ table= 0;
+ return TRUE;
+ }
+ if (materialized_cursor->fill_item_list(unit->thd, list))
+ {
+ delete materialized_cursor;
+ table= 0;
+ materialized_cursor= 0;
+ return TRUE;
+ }
+
return FALSE;
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index fd16435ff9c..8bdbd812529 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -99,22 +99,7 @@ static bool do_command(THD *thd);
#endif // EMBEDDED_LIBRARY
#ifdef __WIN__
-static void test_signal(int sig_ptr)
-{
-#if !defined( DBUG_OFF)
- MessageBox(NULL,"Test signal","DBUG",MB_OK);
-#endif
-#if defined(OS2)
- fprintf(stderr, "Test signal %d\n", sig_ptr);
- fflush(stderr);
-#endif
-}
-static void init_signals(void)
-{
- int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
- for (int i=0 ; i < 7 ; i++)
- signal( signals[i], test_signal) ;
-}
+extern void win_install_sigabrt_handler(void);
#endif
static void unlock_locked_tables(THD *thd)
@@ -1125,7 +1110,7 @@ pthread_handler_t handle_one_connection(void *arg)
/* now that we've called my_thread_init(), it is safe to call DBUG_* */
#if defined(__WIN__)
- init_signals();
+ win_install_sigabrt_handler();
#elif !defined(OS2) && !defined(__NETWARE__)
sigset_t set;
VOID(sigemptyset(&set)); // Get mask in use
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 74cbd2c5505..18cfd8d7dfc 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1512,6 +1512,44 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
}
+/**
+ @brief Validate and prepare for execution CREATE VIEW statement
+
+ @param stmt prepared statement
+
+ @note This function handles create view commands.
+
+ @retval FALSE Operation was a success.
+ @retval TRUE An error occured.
+*/
+
+static bool mysql_test_create_view(Prepared_statement *stmt)
+{
+ DBUG_ENTER("mysql_test_create_view");
+ THD *thd= stmt->thd;
+ LEX *lex= stmt->lex;
+ bool res= TRUE;
+ /* Skip first table, which is the view we are creating */
+ bool link_to_local;
+ TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
+ TABLE_LIST *tables= lex->query_tables;
+
+ if (create_view_precheck(thd, tables, view, lex->create_view_mode))
+ goto err;
+
+ if (open_normal_and_derived_tables(thd, tables, 0))
+ goto err;
+
+ lex->view_prepare_mode= 1;
+ res= select_like_stmt_test(stmt, 0, 0);
+
+err:
+ /* put view back for PS rexecuting */
+ lex->link_first_table_back(view, link_to_local);
+ DBUG_RETURN(res);
+}
+
+
/*
Validate and prepare for execution a multi update statement.
@@ -1730,6 +1768,7 @@ static bool check_prepared_statement(Prepared_statement *stmt,
my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
goto error;
}
+ res= mysql_test_create_view(stmt);
break;
case SQLCOM_DO:
res= mysql_test_do_fields(stmt, tables, lex->insert_list);
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index dd0b92a06f8..4c8e6e80c41 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -182,10 +182,33 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view)
TABLE_LIST decoy;
memcpy (&decoy, view, sizeof (TABLE_LIST));
- if (!open_table(thd, &decoy, thd->mem_root, &not_used, OPEN_VIEW_NO_PARSE) &&
- !decoy.view)
+
+ /*
+ Let's reset decoy.view before calling open_table(): when we start
+ supporting ALTER VIEW in PS/SP that may save us from a crash.
+ */
+
+ decoy.view= NULL;
+
+ /*
+ open_table() will return NULL if 'decoy' is idenitifying a view *and*
+ there is no TABLE object for that view in the table cache. However,
+ decoy.view will be set to 1.
+
+ If there is a TABLE-instance for the oject identified by 'decoy',
+ open_table() will return that instance no matter if it is a table or
+ a view.
+
+ Thus, there is no need to check for the return value of open_table(),
+ since the return value itself does not mean anything.
+ */
+
+ open_table(thd, &decoy, thd->mem_root, &not_used, OPEN_VIEW_NO_PARSE);
+
+ if (!decoy.view)
{
- /* It's a table */
+ /* It's a table. */
+ my_error(ER_WRONG_OBJECT, MYF(0), view->db, view->table_name, "VIEW");
return TRUE;
}
@@ -204,104 +227,31 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view)
return FALSE;
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
/**
- @brief Creating/altering VIEW procedure
+ @brief CREATE VIEW privileges pre-check.
@param thd thread handler
+ @param tables tables used in the view
@param views views to create
@param mode VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
- @note This function handles both create and alter view commands.
-
@retval FALSE Operation was a success.
@retval TRUE An error occured.
*/
-bool mysql_create_view(THD *thd, TABLE_LIST *views,
- enum_view_create_mode mode)
+bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
+ enum_view_create_mode mode)
{
LEX *lex= thd->lex;
- bool link_to_local;
/* first table in list is target VIEW name => cut off it */
- TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
- TABLE_LIST *tables= lex->query_tables;
TABLE_LIST *tbl;
SELECT_LEX *select_lex= &lex->select_lex;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
SELECT_LEX *sl;
-#endif
- SELECT_LEX_UNIT *unit= &lex->unit;
- bool res= FALSE;
- DBUG_ENTER("mysql_create_view");
-
- /* This is ensured in the parser. */
- DBUG_ASSERT(!lex->proc_list.first && !lex->result &&
- !lex->param_list.elements && !lex->derived_tables);
-
- if (mode != VIEW_CREATE_NEW)
- {
- if (mode == VIEW_ALTER &&
- fill_defined_view_parts(thd, view))
- {
- res= TRUE;
- goto err;
- }
- sp_cache_invalidate();
- }
-
- if (!lex->definer)
- {
- /*
- DEFINER-clause is missing; we have to create default definer in
- persistent arena to be PS/SP friendly.
- If this is an ALTER VIEW then the current user should be set as
- the definer.
- */
- Query_arena original_arena;
- Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
-
- if (!(lex->definer= create_default_definer(thd)))
- res= TRUE;
+ bool res= TRUE;
+ DBUG_ENTER("create_view_precheck");
- if (ps_arena)
- thd->restore_active_arena(ps_arena, &original_arena);
-
- if (res)
- goto err;
- }
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /*
- check definer of view:
- - same as current user
- - current user has SUPER_ACL
- */
- if (lex->definer &&
- (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 ||
- my_strcasecmp(system_charset_info,
- lex->definer->host.str,
- thd->security_ctx->priv_host) != 0))
- {
- if (!(thd->security_ctx->master_access & SUPER_ACL))
- {
- my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
- res= TRUE;
- goto err;
- }
- else
- {
- if (!is_acl_user(lex->definer->host.str,
- lex->definer->user.str))
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_NO_SUCH_USER,
- ER(ER_NO_SUCH_USER),
- lex->definer->user.str,
- lex->definer->host.str);
- }
- }
- }
/*
Privilege check for view creation:
- user has CREATE VIEW privilege on view table
@@ -323,10 +273,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
(check_access(thd, DROP_ACL, view->db, &view->grant.privilege,
0, 0, is_schema_db(view->db)) ||
grant_option && check_grant(thd, DROP_ACL, view, 0, 1, 0))))
- {
- res= TRUE;
goto err;
- }
+
for (sl= select_lex; sl; sl= sl->next_select())
{
for (tbl= sl->get_table_list(); tbl; tbl= tbl->next_local)
@@ -340,7 +288,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
"ANY", thd->security_ctx->priv_user,
thd->security_ctx->priv_host, tbl->table_name);
- res= TRUE;
goto err;
}
/*
@@ -376,10 +323,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
if (check_access(thd, SELECT_ACL, tbl->db,
&tbl->grant.privilege, 0, 0, test(tbl->schema_table)) ||
grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 0))
- {
- res= TRUE;
goto err;
- }
}
}
}
@@ -403,8 +347,126 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
}
}
}
+
+ res= FALSE;
+
+err:
+ DBUG_RETURN(res || thd->net.report_error);
+}
+
+#else
+
+bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
+ enum_view_create_mode mode)
+{
+ return FALSE;
+}
+
#endif
+
+/**
+ @brief Creating/altering VIEW procedure
+
+ @param thd thread handler
+ @param views views to create
+ @param mode VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
+
+ @note This function handles both create and alter view commands.
+
+ @retval FALSE Operation was a success.
+ @retval TRUE An error occured.
+*/
+
+bool mysql_create_view(THD *thd, TABLE_LIST *views,
+ enum_view_create_mode mode)
+{
+ LEX *lex= thd->lex;
+ bool link_to_local;
+ /* first table in list is target VIEW name => cut off it */
+ TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
+ TABLE_LIST *tables= lex->query_tables;
+ TABLE_LIST *tbl;
+ SELECT_LEX *select_lex= &lex->select_lex;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ SELECT_LEX *sl;
+#endif
+ SELECT_LEX_UNIT *unit= &lex->unit;
+ bool res= FALSE;
+ DBUG_ENTER("mysql_create_view");
+
+ /* This is ensured in the parser. */
+ DBUG_ASSERT(!lex->proc_list.first && !lex->result &&
+ !lex->param_list.elements && !lex->derived_tables);
+
+ if (mode != VIEW_CREATE_NEW)
+ {
+ if (mode == VIEW_ALTER &&
+ fill_defined_view_parts(thd, view))
+ {
+ res= TRUE;
+ goto err;
+ }
+ sp_cache_invalidate();
+ }
+
+ if (!lex->definer)
+ {
+ /*
+ DEFINER-clause is missing; we have to create default definer in
+ persistent arena to be PS/SP friendly.
+ If this is an ALTER VIEW then the current user should be set as
+ the definer.
+ */
+ Query_arena original_arena;
+ Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
+
+ if (!(lex->definer= create_default_definer(thd)))
+ res= TRUE;
+
+ if (ps_arena)
+ thd->restore_active_arena(ps_arena, &original_arena);
+
+ if (res)
+ goto err;
+ }
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ check definer of view:
+ - same as current user
+ - current user has SUPER_ACL
+ */
+ if (lex->definer &&
+ (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 ||
+ my_strcasecmp(system_charset_info,
+ lex->definer->host.str,
+ thd->security_ctx->priv_host) != 0))
+ {
+ if (!(thd->security_ctx->master_access & SUPER_ACL))
+ {
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
+ res= TRUE;
+ goto err;
+ }
+ else
+ {
+ if (!is_acl_user(lex->definer->host.str,
+ lex->definer->user.str))
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NO_SUCH_USER,
+ ER(ER_NO_SUCH_USER),
+ lex->definer->user.str,
+ lex->definer->host.str);
+ }
+ }
+ }
+#endif
+
+ if ((res= create_view_precheck(thd, tables, view, mode)))
+ goto err;
+
if (open_and_lock_tables(thd, tables))
{
res= TRUE;
diff --git a/sql/sql_view.h b/sql/sql_view.h
index ab0920e0bf2..1d45283352b 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -15,6 +15,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
+ enum_view_create_mode mode);
+
bool mysql_create_view(THD *thd, TABLE_LIST *view,
enum_view_create_mode mode);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index fdd326b4748..80fa037b964 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -6341,7 +6341,7 @@ limit_options:
limit_option:
param_marker
{
- ((Item_param *) $1)->set_strict_type(INT_RESULT);
+ ((Item_param *) $1)->limit_clause_param= TRUE;
}
| ULONGLONG_NUM { $$= new Item_uint($1.str, $1.length); }
| LONG_NUM { $$= new Item_uint($1.str, $1.length); }
diff --git a/sql/stacktrace.c b/sql/stacktrace.c
index c947beafac3..ce91d63d3f7 100644
--- a/sql/stacktrace.c
+++ b/sql/stacktrace.c
@@ -13,11 +13,15 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/
+#define DONT_DEFINE_VOID 1
+
#include <my_global.h>
#include "stacktrace.h"
+
+#ifndef __WIN__
#include <signal.h>
#include <my_pthread.h>
-
#ifdef HAVE_STACKTRACE
#include <unistd.h>
#include <strings.h>
@@ -118,10 +122,7 @@ void print_stacktrace(gptr stack_bottom, ulong thread_stack)
#endif
LINT_INIT(fp);
- fprintf(stderr,"\
-Attempting backtrace. You can use the following information to find out\n\
-where mysqld died. If you see no messages after this, something went\n\
-terribly wrong...\n");
+
#ifdef __i386__
__asm __volatile__ ("movl %%ebp,%0"
:"=r"(fp)
@@ -257,3 +258,267 @@ void write_core(int sig)
#endif
}
#endif
+#else /* __WIN__*/
+
+#include <dbghelp.h>
+
+/*
+ Stack tracing on Windows is implemented using Debug Helper library(dbghelp.dll)
+ We do not redistribute dbghelp and the one comes with older OS (up to Windows 2000)
+ is missing some important functions like functions StackWalk64 or MinidumpWriteDump.
+ Hence, we have to load functions at runtime using LoadLibrary/GetProcAddress.
+*/
+
+typedef DWORD (WINAPI *SymSetOptions_FctType)(DWORD dwOptions);
+typedef BOOL (WINAPI *SymGetModuleInfo64_FctType)
+ (HANDLE,DWORD64,PIMAGEHLP_MODULE64) ;
+typedef BOOL (WINAPI *SymGetSymFromAddr64_FctType)
+ (HANDLE,DWORD64,PDWORD64,PIMAGEHLP_SYMBOL64) ;
+typedef BOOL (WINAPI *SymGetLineFromAddr64_FctType)
+ (HANDLE,DWORD64,PDWORD,PIMAGEHLP_LINE64);
+typedef BOOL (WINAPI *SymInitialize_FctType)
+ (HANDLE,PSTR,BOOL);
+typedef BOOL (WINAPI *StackWalk64_FctType)
+ (DWORD,HANDLE,HANDLE,LPSTACKFRAME64,PVOID,PREAD_PROCESS_MEMORY_ROUTINE64,
+ PFUNCTION_TABLE_ACCESS_ROUTINE64,PGET_MODULE_BASE_ROUTINE64 ,
+ PTRANSLATE_ADDRESS_ROUTINE64);
+typedef BOOL (WINAPI *MiniDumpWriteDump_FctType)(
+ IN HANDLE hProcess,
+ IN DWORD ProcessId,
+ IN HANDLE hFile,
+ IN MINIDUMP_TYPE DumpType,
+ IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
+ IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
+ IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
+ );
+
+static SymSetOptions_FctType pSymSetOptions;
+static SymGetModuleInfo64_FctType pSymGetModuleInfo64;
+static SymGetSymFromAddr64_FctType pSymGetSymFromAddr64;
+static SymInitialize_FctType pSymInitialize;
+static StackWalk64_FctType pStackWalk64;
+static SymGetLineFromAddr64_FctType pSymGetLineFromAddr64;
+static MiniDumpWriteDump_FctType pMiniDumpWriteDump;
+
+static EXCEPTION_POINTERS *exception_ptrs;
+
+#define MODULE64_SIZE_WINXP 576
+#define STACKWALK_MAX_FRAMES 64
+
+/*
+ Dynamically load dbghelp functions
+*/
+BOOL init_dbghelp_functions()
+{
+ static BOOL first_time= TRUE;
+ static BOOL rc;
+ HMODULE hDbghlp;
+
+ if(first_time)
+ {
+ first_time= FALSE;
+ hDbghlp= LoadLibrary("dbghelp");
+ if(!hDbghlp)
+ {
+ rc= FALSE;
+ return rc;
+ }
+ pSymSetOptions= (SymSetOptions_FctType)
+ GetProcAddress(hDbghlp,"SymSetOptions");
+ pSymInitialize= (SymInitialize_FctType)
+ GetProcAddress(hDbghlp,"SymInitialize");
+ pSymGetModuleInfo64= (SymGetModuleInfo64_FctType)
+ GetProcAddress(hDbghlp,"SymGetModuleInfo64");
+ pSymGetLineFromAddr64= (SymGetLineFromAddr64_FctType)
+ GetProcAddress(hDbghlp,"SymGetLineFromAddr64");
+ pSymGetSymFromAddr64=(SymGetSymFromAddr64_FctType)
+ GetProcAddress(hDbghlp,"SymGetSymFromAddr64");
+ pStackWalk64= (StackWalk64_FctType)
+ GetProcAddress(hDbghlp,"StackWalk64");
+ pMiniDumpWriteDump = (MiniDumpWriteDump_FctType)
+ GetProcAddress(hDbghlp,"MiniDumpWriteDump");
+
+ rc = (BOOL)(pSymSetOptions && pSymInitialize && pSymGetModuleInfo64
+ && pSymGetLineFromAddr64 && pSymGetSymFromAddr64 && pStackWalk64);
+ }
+ return rc;
+}
+
+void set_exception_pointers(EXCEPTION_POINTERS *ep)
+{
+ exception_ptrs = ep;
+}
+
+/* Platform SDK in VS2003 does not have definition for SYMOPT_NO_PROMPTS*/
+#ifndef SYMOPT_NO_PROMPTS
+#define SYMOPT_NO_PROMPTS 0
+#endif
+
+void print_stacktrace(gptr unused1, ulong unused2)
+{
+ HANDLE hProcess= GetCurrentProcess();
+ HANDLE hThread= GetCurrentThread();
+ static IMAGEHLP_MODULE64 module= {sizeof(module)};
+ static IMAGEHLP_SYMBOL64_PACKAGE package;
+ DWORD64 addr;
+ DWORD machine;
+ int i;
+ CONTEXT context;
+ STACKFRAME64 frame={0};
+
+ if(!exception_ptrs || !init_dbghelp_functions())
+ return;
+
+ /* Copy context, as stackwalking on original will unwind the stack */
+ context = *(exception_ptrs->ContextRecord);
+ /*Initialize symbols.*/
+ pSymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG);
+ pSymInitialize(hProcess,NULL,TRUE);
+
+ /*Prepare stackframe for the first StackWalk64 call*/
+ frame.AddrFrame.Mode= frame.AddrPC.Mode= frame.AddrStack.Mode= AddrModeFlat;
+#if (defined _M_IX86)
+ machine= IMAGE_FILE_MACHINE_I386;
+ frame.AddrFrame.Offset= context.Ebp;
+ frame.AddrPC.Offset= context.Eip;
+ frame.AddrStack.Offset= context.Esp;
+#elif (defined _M_X64)
+ machine = IMAGE_FILE_MACHINE_AMD64;
+ frame.AddrFrame.Offset= context.Rbp;
+ frame.AddrPC.Offset= context.Rip;
+ frame.AddrStack.Offset= context.Rsp;
+#else
+ /*There is currently no need to support IA64*/
+#pragma error ("unsupported architecture")
+#endif
+
+ package.sym.SizeOfStruct= sizeof(package.sym);
+ package.sym.MaxNameLength= sizeof(package.name);
+
+ /*Walk the stack, output useful information*/
+ for(i= 0; i< STACKWALK_MAX_FRAMES;i++)
+ {
+ DWORD64 function_offset= 0;
+ DWORD line_offset= 0;
+ IMAGEHLP_LINE64 line= {sizeof(line)};
+ BOOL have_module= FALSE;
+ BOOL have_symbol= FALSE;
+ BOOL have_source= FALSE;
+
+ if(!pStackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0))
+ break;
+ addr= frame.AddrPC.Offset;
+
+ have_module= pSymGetModuleInfo64(hProcess,addr,&module);
+#ifdef _M_IX86
+ if(!have_module)
+ {
+ /*
+ ModuleInfo structure has been "compatibly" extended in releases after XP,
+ and its size was increased. To make XP dbghelp.dll function
+ happy, pretend passing the old structure.
+ */
+ module.SizeOfStruct= MODULE64_SIZE_WINXP;
+ have_module= pSymGetModuleInfo64(hProcess, addr, &module);
+ }
+#endif
+
+ have_symbol= pSymGetSymFromAddr64(hProcess, addr, &function_offset,
+ &(package.sym));
+ have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line);
+
+ fprintf(stderr, "%p ", addr);
+ if(have_module)
+ {
+ char *base_image_name= strrchr(module.ImageName, '\\');
+ if(base_image_name)
+ base_image_name++;
+ else
+ base_image_name= module.ImageName;
+ fprintf(stderr, "%s!", base_image_name);
+ }
+ if(have_symbol)
+ fprintf(stderr, "%s()", package.sym.Name);
+ else if(have_module)
+ fprintf(stderr, "???");
+
+ if(have_source)
+ {
+ char *base_file_name= strrchr(line.FileName, '\\');
+ if(base_file_name)
+ base_file_name++;
+ else
+ base_file_name= line.FileName;
+ fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber);
+ }
+ fprintf(stderr, "\n");
+ }
+ fflush(stderr);
+}
+
+
+/*
+ Write dump. The dump is created in current directory,
+ file name is constructed from executable name plus
+ ".dmp" extension
+*/
+void write_core(int unused)
+{
+ char path[MAX_PATH];
+ char dump_fname[MAX_PATH]= "core.dmp";
+ MINIDUMP_EXCEPTION_INFORMATION info;
+ HANDLE hFile;
+
+ if(!exception_ptrs || !init_dbghelp_functions() || !pMiniDumpWriteDump)
+ return;
+
+ info.ExceptionPointers= exception_ptrs;
+ info.ClientPointers= FALSE;
+ info.ThreadId= GetCurrentThreadId();
+
+ if(GetModuleFileName(NULL, path, sizeof(path)))
+ {
+ _splitpath(path, NULL, NULL,dump_fname,NULL);
+ strncat(dump_fname, ".dmp", sizeof(dump_fname));
+ }
+
+ hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ if(hFile)
+ {
+ /* Create minidump */
+ if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
+ hFile, MiniDumpNormal, &info, 0, 0))
+ {
+ fprintf(stderr, "Minidump written to %s\n",
+ _fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname);
+ }
+ else
+ {
+ fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n",
+ GetLastError());
+ }
+ CloseHandle(hFile);
+ }
+ else
+ {
+ fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname,
+ GetLastError());
+ }
+ fflush(stderr);
+}
+
+
+void safe_print_str(const char *name, const char *val, int len)
+{
+ fprintf(stderr,"%s at %p", name, val);
+ __try
+ {
+ fprintf(stderr,"=%.*s\n", len, val);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ fprintf(stderr,"is an invalid string pointer\n");
+ }
+}
+#endif /*__WIN__*/
diff --git a/sql/stacktrace.h b/sql/stacktrace.h
index f5c92e54e1c..e5e17cc5b9b 100644
--- a/sql/stacktrace.h
+++ b/sql/stacktrace.h
@@ -29,20 +29,33 @@ extern char* heap_start;
heap_start = (char*) &__bss_start; \
check_thread_lib(); \
} while(0);
+void check_thread_lib(void);
+#endif /* defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */
+#elif defined (__WIN__)
+#define HAVE_STACKTRACE
+extern void set_exception_pointers(EXCEPTION_POINTERS *ep);
+#define init_stacktrace() {}
+#endif
+
+#ifdef HAVE_STACKTRACE
void print_stacktrace(gptr stack_bottom, ulong thread_stack);
void safe_print_str(const char* name, const char* val, int max_len);
-void check_thread_lib(void);
-#endif /* (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */
-#endif /* TARGET_OS_LINUX */
-
+#else
/* Define empty prototypes for functions that are not implemented */
-#ifndef HAVE_STACKTRACE
#define init_stacktrace() {}
#define print_stacktrace(A,B) {}
#define safe_print_str(A,B,C) {}
#endif /* HAVE_STACKTRACE */
+
+#if !defined(__NETWARE__)
+#define HAVE_WRITE_CORE
+#endif
+
+#ifdef HAVE_WRITE_CORE
void write_core(int sig);
+#endif
+
#ifdef __cplusplus
}
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index 8c4909fc8d5..acf7d571710 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -15,6 +15,7 @@
# MA 02110-1301 USA.
%define mysql_version @VERSION@
+%define mysql_vendor MySQL AB
# use "rpmbuild --with static" or "rpm --define '_with_static 1'" (for RPM 3.x)
# to enable static linking (off by default)
@@ -69,7 +70,7 @@ License: %{license}
Source: http://www.mysql.com/Downloads/MySQL-@MYSQL_BASE_VERSION@/mysql-%{mysql_version}.tar.gz
URL: http://www.mysql.com/
Packager: MySQL Production Engineering Team <build@mysql.com>
-Vendor: MySQL AB
+Vendor: %{mysql_vendor}
Provides: msqlormysql MySQL-server mysql
BuildRequires: ncurses-devel
Obsoletes: mysql
@@ -420,6 +421,72 @@ touch $RBR%{_sysconfdir}/my.cnf
touch $RBR%{_sysconfdir}/mysqlmanager.passwd
%pre server
+# Check if we can safely upgrade. An upgrade is only safe if it's from one
+# of our RPMs in the same version family.
+
+installed=`rpm -q --whatprovides mysql-server 2> /dev/null`
+if [ $? -eq 0 -a -n "$installed" ]; then
+ vendor=`rpm -q --queryformat='%{VENDOR}' "$installed" 2>&1`
+ version=`rpm -q --queryformat='%{VERSION}' "$installed" 2>&1`
+ myvendor='%{mysql_vendor}'
+ myversion='%{mysql_version}'
+
+ old_family=`echo $version | sed -n -e 's,^\([1-9][0-9]*\.[0-9][0-9]*\)\..*$,\1,p'`
+ new_family=`echo $myversion | sed -n -e 's,^\([1-9][0-9]*\.[0-9][0-9]*\)\..*$,\1,p'`
+
+ [ -z "$vendor" ] && vendor='<unknown>'
+ [ -z "$old_family" ] && old_family="<unrecognized version $version>"
+ [ -z "$new_family" ] && new_family="<bad package specification: version $myversion>"
+
+ error_text=
+ if [ "$vendor" != "$myvendor" ]; then
+ error_text="$error_text
+The current MySQL server package is provided by a different
+vendor ($vendor) than $myvendor. Some files may be installed
+to different locations, including log files and the service
+startup script in %{_sysconfdir}/init.d/.
+"
+ fi
+
+ if [ "$old_family" != "$new_family" ]; then
+ error_text="$error_text
+Upgrading directly from MySQL $old_family to MySQL $new_family may not
+be safe in all cases. A manual dump and restore using mysqldump is
+recommended. It is important to review the MySQL manual's Upgrading
+section for version-specific incompatibilities.
+"
+ fi
+
+ if [ -n "$error_text" ]; then
+ cat <<HERE >&2
+
+******************************************************************
+A MySQL server package ($installed) is installed.
+$error_text
+A manual upgrade is required.
+
+- Ensure that you have a complete, working backup of your data and my.cnf
+ files
+- Shut down the MySQL server cleanly
+- Remove the existing MySQL packages. Usually this command will
+ list the packages you should remove:
+ rpm -qa | grep -i '^mysql-'
+
+ You may choose to use 'rpm --nodeps -ev <package-name>' to remove
+ the package which contains the mysqlclient shared library. The
+ library will be reinstalled by the MySQL-shared-compat package.
+- Install the new MySQL packages supplied by $myvendor
+- Ensure that the MySQL server is started
+- Run the 'mysql_upgrade' program
+
+This is a brief description of the upgrade process. Important details
+can be found in the MySQL manual, in the Upgrading section.
+******************************************************************
+HERE
+ exit 1
+ fi
+fi
+
# Shut down a previously installed server first
if test -x %{_sysconfdir}/init.d/mysql
then
@@ -715,6 +782,11 @@ fi
# itself - note that they must be ordered by date (important when
# merging BK trees)
%changelog
+* Mon Feb 18 2008 Timothy Smith <tim@mysql.com>
+
+- Require a manual upgrade if the alread-installed mysql-server is
+ from another vendor, or is of a different major version.
+
* Fri Nov 16 2007 Joerg Bruehe <joerg@mysql.com>
- When testing the debug server, use "make test-bt-debug".
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index f8c554a06fd..c30f329a967 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -8702,8 +8702,8 @@ static void test_sqlmode()
strmov(c1, "My"); strmov(c2, "SQL");
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
-
mysql_stmt_close(stmt);
+
verify_col_data("test_piping", "name", "MySQL");
rc= mysql_query(mysql, "DELETE FROM test_piping");
@@ -12993,7 +12993,7 @@ from t2);");
static void test_bug8378()
{
#if defined(HAVE_CHARSET_gbk) && !defined(EMBEDDED_LIBRARY)
- MYSQL *old_mysql=mysql;
+ MYSQL *lmysql;
char out[9]; /* strlen(TEST_BUG8378)*2+1 */
char buf[256];
int len, rc;
@@ -13002,17 +13002,17 @@ static void test_bug8378()
if (!opt_silent)
fprintf(stdout, "\n Establishing a test connection ...");
- if (!(mysql= mysql_init(NULL)))
+ if (!(lmysql= mysql_init(NULL)))
{
myerror("mysql_init() failed");
exit(1);
}
- if (mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "gbk"))
+ if (mysql_options(lmysql, MYSQL_SET_CHARSET_NAME, "gbk"))
{
myerror("mysql_options() failed");
exit(1);
}
- if (!(mysql_real_connect(mysql, opt_host, opt_user,
+ if (!(mysql_real_connect(lmysql, opt_host, opt_user,
opt_password, current_db, opt_port,
opt_unix_socket, 0)))
{
@@ -13022,19 +13022,17 @@ static void test_bug8378()
if (!opt_silent)
fprintf(stdout, " OK");
- len= mysql_real_escape_string(mysql, out, TEST_BUG8378_IN, 4);
+ len= mysql_real_escape_string(lmysql, out, TEST_BUG8378_IN, 4);
/* No escaping should have actually happened. */
DIE_UNLESS(memcmp(out, TEST_BUG8378_OUT, len) == 0);
sprintf(buf, "SELECT '%s'", out);
- rc=mysql_real_query(mysql, buf, strlen(buf));
+ rc=mysql_real_query(lmysql, buf, strlen(buf));
myquery(rc);
- mysql_close(mysql);
-
- mysql=old_mysql;
+ mysql_close(lmysql);
#endif
}
@@ -14869,7 +14867,7 @@ static void test_opt_reconnect()
if (mysql_options(lmysql, MYSQL_OPT_RECONNECT, &my_true))
{
myerror("mysql_options failed: unknown option MYSQL_OPT_RECONNECT\n");
- exit(1);
+ DIE_UNLESS(0);
}
/* reconnect should be 1 */
@@ -14882,7 +14880,7 @@ static void test_opt_reconnect()
opt_unix_socket, 0)))
{
myerror("connection failed");
- exit(1);
+ DIE_UNLESS(0);
}
/* reconnect should still be 1 */
@@ -14896,7 +14894,7 @@ static void test_opt_reconnect()
if (!(lmysql= mysql_init(NULL)))
{
myerror("mysql_init() failed");
- exit(1);
+ DIE_UNLESS(0);
}
if (!opt_silent)
@@ -14908,7 +14906,7 @@ static void test_opt_reconnect()
opt_unix_socket, 0)))
{
myerror("connection failed");
- exit(1);
+ DIE_UNLESS(0);
}
/* reconnect should still be 0 */
@@ -14926,32 +14924,32 @@ static void test_opt_reconnect()
static void test_bug12744()
{
MYSQL_STMT *prep_stmt = NULL;
+ MYSQL *lmysql;
int rc;
myheader("test_bug12744");
- prep_stmt= mysql_stmt_init(mysql);
- rc= mysql_stmt_prepare(prep_stmt, "SELECT 1", 8);
- DIE_UNLESS(rc==0);
-
- mysql_close(mysql);
+ lmysql= mysql_init(NULL);
+ DIE_UNLESS(lmysql);
- if ((rc= mysql_stmt_execute(prep_stmt)))
- {
- if ((rc= mysql_stmt_reset(prep_stmt)))
- printf("OK!\n");
- else
- {
- printf("Error!");
- DIE_UNLESS(1==0);
- }
- }
- else
+ if (!mysql_real_connect(lmysql, opt_host, opt_user, opt_password,
+ current_db, opt_port, opt_unix_socket, 0))
{
- fprintf(stderr, "expected error but no error occured\n");
- DIE_UNLESS(1==0);
+ fprintf(stderr, "Failed to connect to the database\n");
+ DIE_UNLESS(0);
}
+
+ prep_stmt= mysql_stmt_init(lmysql);
+ rc= mysql_stmt_prepare(prep_stmt, "SELECT 1", 8);
+ DIE_UNLESS(rc == 0);
+
+ mysql_close(lmysql);
+
+ rc= mysql_stmt_execute(prep_stmt);
+ DIE_UNLESS(rc);
+ rc= mysql_stmt_reset(prep_stmt);
+ DIE_UNLESS(rc);
rc= mysql_stmt_close(prep_stmt);
- client_connect(0);
+ DIE_UNLESS(rc == 0);
}
#endif /* EMBEDDED_LIBRARY */
@@ -15217,6 +15215,10 @@ static void test_bug14169()
Test that mysql_insert_id() behaves as documented in our manual
*/
+#if 0
+
+ Commented out because of Bug#34889.
+
static void test_mysql_insert_id()
{
my_ulonglong res;
@@ -15408,6 +15410,7 @@ static void test_mysql_insert_id()
rc= mysql_query(mysql, "drop table t1,t2");
myquery(rc);
}
+#endif
/*
@@ -15775,6 +15778,7 @@ static void test_bug24179()
mysql_stmt_error(stmt));
}
DIE_UNLESS(mysql_stmt_errno(stmt) == 1323);
+ mysql_stmt_close(stmt);
DBUG_VOID_RETURN;
}
@@ -15817,6 +15821,7 @@ static void test_bug27876()
myquery(rc);
result= mysql_store_result(mysql);
mytest(result);
+ mysql_free_result(result);
sprintf(query, "DROP FUNCTION IF EXISTS %s", utf8_func);
rc= mysql_query(mysql, query);
@@ -15833,6 +15838,7 @@ static void test_bug27876()
myquery(rc);
result= mysql_store_result(mysql);
mytest(result);
+ mysql_free_result(result);
sprintf(query, "DROP FUNCTION %s", utf8_func);
rc= mysql_query(mysql, query);
@@ -15981,6 +15987,7 @@ static void test_bug29948()
exit(1);
}
+ bzero(&bind, sizeof(bind));
bind.buffer_type= MYSQL_TYPE_LONG;
bind.buffer= (char *)&buf;
bind.is_null= &is_null;
@@ -16168,6 +16175,99 @@ static void test_bug31669()
DBUG_VOID_RETURN;
}
+
+/**
+ Bug#32265 Server returns different metadata if prepared statement is used
+*/
+
+static void test_bug32265()
+{
+ int rc;
+ MYSQL_STMT *stmt;
+ MYSQL_FIELD *field;
+ MYSQL_RES *metadata;
+
+ DBUG_ENTER("test_bug32265");
+ myheader("test_bug32265");
+
+ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+ myquery(rc);
+ rc= mysql_query(mysql, "CREATE TABLE t1 (a INTEGER)");
+ myquery(rc);
+ rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)");
+ myquery(rc);
+ rc= mysql_query(mysql, "CREATE VIEW v1 AS SELECT * FROM t1");
+ myquery(rc);
+
+ stmt= open_cursor("SELECT * FROM t1");
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ metadata= mysql_stmt_result_metadata(stmt);
+ field= mysql_fetch_field(metadata);
+ DIE_UNLESS(field);
+ DIE_UNLESS(strcmp(field->table, "t1") == 0);
+ DIE_UNLESS(strcmp(field->org_table, "t1") == 0);
+ DIE_UNLESS(strcmp(field->db, "client_test_db") == 0);
+ mysql_free_result(metadata);
+ mysql_stmt_close(stmt);
+
+ stmt= open_cursor("SELECT a '' FROM t1 ``");
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ metadata= mysql_stmt_result_metadata(stmt);
+ field= mysql_fetch_field(metadata);
+ DIE_UNLESS(strcmp(field->table, "") == 0);
+ DIE_UNLESS(strcmp(field->org_table, "t1") == 0);
+ DIE_UNLESS(strcmp(field->db, "client_test_db") == 0);
+ mysql_free_result(metadata);
+ mysql_stmt_close(stmt);
+
+ stmt= open_cursor("SELECT a '' FROM t1 ``");
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ metadata= mysql_stmt_result_metadata(stmt);
+ field= mysql_fetch_field(metadata);
+ DIE_UNLESS(strcmp(field->table, "") == 0);
+ DIE_UNLESS(strcmp(field->org_table, "t1") == 0);
+ DIE_UNLESS(strcmp(field->db, "client_test_db") == 0);
+ mysql_free_result(metadata);
+ mysql_stmt_close(stmt);
+
+ stmt= open_cursor("SELECT * FROM v1");
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ metadata= mysql_stmt_result_metadata(stmt);
+ field= mysql_fetch_field(metadata);
+ DIE_UNLESS(strcmp(field->table, "v1") == 0);
+ DIE_UNLESS(strcmp(field->org_table, "t1") == 0);
+ DIE_UNLESS(strcmp(field->db, "client_test_db") == 0);
+ mysql_free_result(metadata);
+ mysql_stmt_close(stmt);
+
+ stmt= open_cursor("SELECT * FROM v1 /* SIC */ GROUP BY 1");
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ metadata= mysql_stmt_result_metadata(stmt);
+ field= mysql_fetch_field(metadata);
+ DIE_UNLESS(strcmp(field->table, "v1") == 0);
+ DIE_UNLESS(strcmp(field->org_table, "t1") == 0);
+ DIE_UNLESS(strcmp(field->db, "client_test_db") == 0);
+ mysql_free_result(metadata);
+ mysql_stmt_close(stmt);
+
+ rc= mysql_query(mysql, "DROP VIEW v1");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP TABLE t1");
+ myquery(rc);
+
+ DBUG_VOID_RETURN;
+}
+
/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -16448,7 +16548,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug17667", test_bug17667 },
{ "test_bug19671", test_bug19671 },
{ "test_bug15752", test_bug15752 },
- { "test_mysql_insert_id", test_mysql_insert_id },
+ /* { "test_mysql_insert_id", test_mysql_insert_id }, Bug#34889 */
{ "test_bug21206", test_bug21206 },
{ "test_bug21726", test_bug21726 },
{ "test_bug15518", test_bug15518 },
@@ -16462,6 +16562,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug29948", test_bug29948 },
{ "test_bug29306", test_bug29306 },
{ "test_bug31669", test_bug31669 },
+ { "test_bug32265", test_bug32265 },
{ 0, 0 }
};
diff --git a/vio/viossl.c b/vio/viossl.c
index c178d9e9d1b..eea274cf92d 100644
--- a/vio/viossl.c
+++ b/vio/viossl.c
@@ -172,20 +172,15 @@ void vio_ssl_delete(Vio *vio)
vio_delete(vio);
}
-int sslaccept(struct st_VioSSLFd *ptr, Vio *vio, long timeout)
-{
- DBUG_ENTER("sslaccept");
- DBUG_RETURN(sslconnect(ptr, vio, timeout));
-}
-
-int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout)
+static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout,
+ int (*connect_accept_func)(SSL*))
{
SSL *ssl;
my_bool unused;
my_bool was_blocking;
- DBUG_ENTER("sslconnect");
+ DBUG_ENTER("ssl_do");
DBUG_PRINT("enter", ("ptr: 0x%lx, sd: %d ctx: 0x%lx",
(long) ptr, vio->sd, (long) ptr->ssl_context));
@@ -204,13 +199,9 @@ int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout)
SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout);
SSL_set_fd(ssl, vio->sd);
- /*
- SSL_do_handshake will select between SSL_connect
- or SSL_accept depending on server or client side
- */
- if (SSL_do_handshake(ssl) < 1)
+ if (connect_accept_func(ssl) < 1)
{
- DBUG_PRINT("error", ("SSL_do_handshake failure"));
+ DBUG_PRINT("error", ("SSL_connect/accept failure"));
report_errors(ssl);
SSL_free(ssl);
vio_blocking(vio, was_blocking, &unused);
@@ -259,6 +250,20 @@ int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout)
}
+int sslaccept(struct st_VioSSLFd *ptr, Vio *vio, long timeout)
+{
+ DBUG_ENTER("sslaccept");
+ DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_accept));
+}
+
+
+int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout)
+{
+ DBUG_ENTER("sslconnect");
+ DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_connect));
+}
+
+
int vio_ssl_blocking(Vio *vio __attribute__((unused)),
my_bool set_blocking_mode,
my_bool *old_mode)
@@ -269,4 +274,6 @@ int vio_ssl_blocking(Vio *vio __attribute__((unused)),
return (set_blocking_mode ? 0 : 1);
}
+
+
#endif /* HAVE_OPENSSL */