diff options
author | tomas@poseidon.ndb.mysql.com <> | 2005-10-07 01:12:46 +0200 |
---|---|---|
committer | tomas@poseidon.ndb.mysql.com <> | 2005-10-07 01:12:46 +0200 |
commit | e72fdf56194b529b14696bbb0b743e25eefb7f0e (patch) | |
tree | 73ff186be5c6524a0a96e1d6359b8f58263b7a4c /ndb | |
parent | 3703570c9c8a1040ad66dc4d933dcaa9a0e767b4 (diff) | |
parent | 38fd830f9e7fc4f239a5a3acb40354cc49e7b5e9 (diff) | |
download | mariadb-git-e72fdf56194b529b14696bbb0b743e25eefb7f0e.tar.gz |
Merge
Diffstat (limited to 'ndb')
-rw-r--r-- | ndb/include/mgmapi/ndbd_exit_codes.h | 156 | ||||
-rw-r--r-- | ndb/src/kernel/error/ndbd_exit_codes.c | 251 | ||||
-rw-r--r-- | ndb/src/kernel/vm/ndbd_malloc.cpp | 63 | ||||
-rw-r--r-- | ndb/src/kernel/vm/ndbd_malloc.hpp | 26 | ||||
-rw-r--r-- | ndb/test/sql/test_create_drop.pl | 179 | ||||
-rw-r--r-- | ndb/test/sql/test_range_bounds.pl | 218 |
6 files changed, 893 insertions, 0 deletions
diff --git a/ndb/include/mgmapi/ndbd_exit_codes.h b/ndb/include/mgmapi/ndbd_exit_codes.h new file mode 100644 index 00000000000..794329ce637 --- /dev/null +++ b/ndb/include/mgmapi/ndbd_exit_codes.h @@ -0,0 +1,156 @@ +/* Copyright (C) 2003 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; either version 2 of the License, or + (at your option) any later version. + + 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 */ + +#ifndef NDBD_EXIT_CODES_H +#define NDBD_EXIT_CODES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + +/** + * Exit error codes for NDBD + * + * These errorcodes should be used whenever a condition + * is detected where it's necesssary to shutdown NDB. + * + * Example: When another node fails while a NDB node are performing + * a system restart the node should be shutdown. This + * is kind of an error but the cause of the error is known + * and a proper errormessage describing the problem should + * be printed in error.log. It's therefore important to use + * the proper errorcode. + * + */ + +typedef enum +{ + ndbd_exit_st_success = 0, + ndbd_exit_st_unknown = 1, + ndbd_exit_st_permanent = 2, + ndbd_exit_st_temporary = 3, + ndbd_exit_st_filesystem_error = 4 +} ndbd_exit_status_enum; + +typedef enum +{ + ndbd_exit_cl_none = 0, + ndbd_exit_cl_unknown = 1, + ndbd_exit_cl_internal_error = 2, + ndbd_exit_cl_configuration_error = 3, + ndbd_exit_cl_arbitration_error = 4, + ndbd_exit_cl_restart_error = 5, + ndbd_exit_cl_resource_configuration_error = 6, + ndbd_exit_cl_filesystem_full_error = 7, + ndbd_exit_cl_filesystem_inconsistency_error = 8, + ndbd_exit_cl_filesystem_limit = 9 +} ndbd_exit_classification_enum; + +typedef ndbd_exit_status_enum ndbd_exit_status; +typedef ndbd_exit_classification_enum ndbd_exit_classification; + +/* Errorcodes before block division was used */ +#define NDBD_EXIT_PRGERR 2301 +#define NDBD_EXIT_NODE_NOT_IN_CONFIG 2302 +#define NDBD_EXIT_SYSTEM_ERROR 2303 +#define NDBD_EXIT_INDEX_NOTINRANGE 2304 +#define NDBD_EXIT_ARBIT_SHUTDOWN 2305 +#define NDBD_EXIT_POINTER_NOTINRANGE 2306 +#define NDBD_EXIT_SR_OTHERNODEFAILED 2308 +#define NDBD_EXIT_NODE_NOT_DEAD 2309 +#define NDBD_EXIT_SR_REDOLOG 2310 +/* +#define NDBD_EXIT_SR_RESTARTCONFLICT 2311 +*/ +#define NDBD_EXIT_NO_MORE_UNDOLOG 2312 +#define NDBD_EXIT_SR_UNDOLOG 2313 +#define NDBD_EXIT_MEMALLOC 2327 +#define NDBD_EXIT_BLOCK_JBUFCONGESTION 2334 +#define NDBD_EXIT_TIME_QUEUE_SHORT 2335 +#define NDBD_EXIT_TIME_QUEUE_LONG 2336 +#define NDBD_EXIT_TIME_QUEUE_DELAY 2337 +#define NDBD_EXIT_TIME_QUEUE_INDEX 2338 +#define NDBD_EXIT_BLOCK_BNR_ZERO 2339 +#define NDBD_EXIT_WRONG_PRIO_LEVEL 2340 +#define NDBD_EXIT_NDBREQUIRE 2341 +#define NDBD_EXIT_ERROR_INSERT 2342 +#define NDBD_EXIT_NDBASSERT 2343 +#define NDBD_EXIT_INVALID_CONFIG 2350 +#define NDBD_EXIT_OUT_OF_LONG_SIGNAL_MEMORY 2351 + +#define NDBD_EXIT_OS_SIGNAL_RECEIVED 6000 + +/* VM 6050-> */ +#define NDBD_EXIT_WATCHDOG_TERMINATE 6050 +#define NDBD_EXIT_SIGNAL_LOST 6051 +#define NDBD_EXIT_SIGNAL_LOST_SEND_BUFFER_FULL 6052 +#define NDBD_EXIT_ILLEGAL_SIGNAL 6053 + +/* NDBCNTR 6100-> */ +#define NDBD_EXIT_RESTART_TIMEOUT 6100 + +/* TC 6200-> */ +/* DIH 6300-> */ +#define NDBD_EXIT_MAX_CRASHED_REPLICAS 6300 +#define NDBD_EXIT_MASTER_FAILURE_DURING_NR 6301 +#define NDBD_EXIT_LOST_NODE_GROUP 6302 +#define NDBD_EXIT_NO_RESTORABLE_REPLICA 6303 + +/* ACC 6600-> */ +#define NDBD_EXIT_SR_OUT_OF_INDEXMEMORY 6600 +/* TUP 6800-> */ +#define NDBD_EXIT_SR_OUT_OF_DATAMEMORY 6800 +/* LQH 7200-> */ + + +/* Errorcodes for NDB filesystem */ +#define NDBD_EXIT_AFS_NOPATH 2801 +/* +#define NDBD_EXIT_AFS_CHANNALFULL 2802 +#define NDBD_EXIT_AFS_NOMORETHREADS 2803 +*/ +#define NDBD_EXIT_AFS_PARAMETER 2804 +#define NDBD_EXIT_AFS_INVALIDPATH 2805 +#define NDBD_EXIT_AFS_MAXOPEN 2806 +#define NDBD_EXIT_AFS_ALREADY_OPEN 2807 + +#define NDBD_EXIT_AFS_ENVIRONMENT 2808 +#define NDBD_EXIT_AFS_TEMP_NO_ACCESS 2809 +#define NDBD_EXIT_AFS_DISK_FULL 2810 +#define NDBD_EXIT_AFS_PERMISSION_DENIED 2811 +#define NDBD_EXIT_AFS_INVALID_PARAM 2812 +#define NDBD_EXIT_AFS_UNKNOWN 2813 +#define NDBD_EXIT_AFS_NO_MORE_RESOURCES 2814 +#define NDBD_EXIT_AFS_NO_SUCH_FILE 2815 +#define NDBD_EXIT_AFS_READ_UNDERFLOW 2816 + +const char * +ndbd_exit_message(int faultId, ndbd_exit_classification *cl); +const char * +ndbd_exit_classification_message(ndbd_exit_classification classification, + ndbd_exit_status *status); +const char * +ndbd_exit_status_message(ndbd_exit_status status); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* NDBD_EXIT_CODES_H */ diff --git a/ndb/src/kernel/error/ndbd_exit_codes.c b/ndb/src/kernel/error/ndbd_exit_codes.c new file mode 100644 index 00000000000..4d9a61d69d1 --- /dev/null +++ b/ndb/src/kernel/error/ndbd_exit_codes.c @@ -0,0 +1,251 @@ +/* Copyright (C) 2003 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; either version 2 of the License, or + (at your option) any later version. + + 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 */ + +#include <ndbd_exit_codes.h> + +typedef struct ErrStruct { + int faultId; + ndbd_exit_classification classification; + const char* text; +} ErrStruct; + +/** + * Shorter names in table below + */ + +#define XST_S ndbd_exit_st_success +#define XST_U ndbd_exit_st_unknown +#define XST_P ndbd_exit_st_permanent +#define XST_R ndbd_exit_st_temporary +#define XST_I ndbd_exit_st_filesystem_error + +#define XNE ndbd_exit_cl_none +#define XUE ndbd_exit_cl_unknown +#define XIE ndbd_exit_cl_internal_error +#define XCE ndbd_exit_cl_configuration_error +#define XAE ndbd_exit_cl_arbitration_error +#define XRE ndbd_exit_cl_restart_error +#define XCR ndbd_exit_cl_resource_configuration_error +#define XFF ndbd_exit_cl_filesystem_full_error +#define XFI ndbd_exit_cl_filesystem_inconsistency_error +#define XFL ndbd_exit_cl_filesystem_limit + +static const ErrStruct errArray[] = +{ + {NDBD_EXIT_PRGERR, XIE, "Assertion"}, + {NDBD_EXIT_NODE_NOT_IN_CONFIG, XCE, + "node id in the configuration has the wrong type, (i.e. not an NDB node)"}, + {NDBD_EXIT_SYSTEM_ERROR, XIE, + "System error, node killed during node restart by other node"}, + {NDBD_EXIT_INDEX_NOTINRANGE, XIE, "Array index out of range"}, + {NDBD_EXIT_ARBIT_SHUTDOWN, XAE, "Arbitrator shutdown, " + "please investigate error(s) on other node(s)"}, + {NDBD_EXIT_POINTER_NOTINRANGE, XIE, "Pointer too large"}, + {NDBD_EXIT_SR_OTHERNODEFAILED, XRE, "Another node failed during system " + "restart, please investigate error(s) on other node(s)"}, + {NDBD_EXIT_NODE_NOT_DEAD, XRE, "Internal node state conflict, " + "most probably resolved by restarting node again"}, + {NDBD_EXIT_SR_REDOLOG, XFI, "Error while reading the REDO log"}, + /* Currently unused? */ + {2311, XIE, "Conflict when selecting restart type"}, + {NDBD_EXIT_NO_MORE_UNDOLOG, XCR, + "No more free UNDO log, increase UndoIndexBuffer"}, + {NDBD_EXIT_SR_UNDOLOG, XFI, + "Error while reading the datapages and UNDO log"}, + {NDBD_EXIT_MEMALLOC, XCE, "Memory allocation failure, " + "please decrease some configuration parameters"}, + {NDBD_EXIT_BLOCK_JBUFCONGESTION, XIE, "Job buffer congestion"}, + {NDBD_EXIT_TIME_QUEUE_SHORT, XIE, "Error in short time queue"}, + {NDBD_EXIT_TIME_QUEUE_LONG, XIE, "Error in long time queue"}, + {NDBD_EXIT_TIME_QUEUE_DELAY, XIE, "Error in time queue, too long delay"}, + {NDBD_EXIT_TIME_QUEUE_INDEX, XIE, "Time queue index out of range"}, + {NDBD_EXIT_BLOCK_BNR_ZERO, XIE, "Send signal error"}, + {NDBD_EXIT_WRONG_PRIO_LEVEL, XIE, "Wrong priority level when sending signal"}, + {NDBD_EXIT_NDBREQUIRE, XIE, "Internal program error (failed ndbrequire)"}, + {NDBD_EXIT_NDBASSERT, XIE, "Internal program error (failed ndbassert)"}, + {NDBD_EXIT_ERROR_INSERT, XNE, "Error insert executed" }, + /* this error message is complemented by additional info when generated */ + {NDBD_EXIT_INVALID_CONFIG, XCE, + "Invalid configuration received from Management Server"}, + /* this error message is complemented by additional info when + generated, such as signal, and text + */ + {NDBD_EXIT_OS_SIGNAL_RECEIVED, XIE, "Error OS signal received"}, + + /* VM */ + {NDBD_EXIT_OUT_OF_LONG_SIGNAL_MEMORY, XCR, + "Signal lost, out of long signal memory, please increase LongMessageBuffer"}, + {NDBD_EXIT_WATCHDOG_TERMINATE, XIE, "WatchDog terminate, internal error " + "or massive overload on the machine running this node"}, + {NDBD_EXIT_SIGNAL_LOST_SEND_BUFFER_FULL, XCR, + "Signal lost, out of send buffer memory, please increase SendBufferMemory"}, + {NDBD_EXIT_SIGNAL_LOST, XIE, "Signal lost (unknown reason)"}, + {NDBD_EXIT_ILLEGAL_SIGNAL, XIE, + "Illegal signal (version mismatch a possibility)"}, + + /* Ndbcntr */ + {NDBD_EXIT_RESTART_TIMEOUT, XCE, + "Total restart time too long, consider increasing StartFailureTimeout " + "or investigate error(s) on other node(s)"}, + + /* DIH */ + {NDBD_EXIT_MAX_CRASHED_REPLICAS, XFL, + "Too many crashed replicas (8 consecutive node restart failures)"}, + {NDBD_EXIT_MASTER_FAILURE_DURING_NR, XRE, + "Unhandled master failure during node restart"}, + {NDBD_EXIT_LOST_NODE_GROUP, XAE, + "All nodes in a node group are unavailable"}, + {NDBD_EXIT_NO_RESTORABLE_REPLICA, XFI, + "Unable to find a restorable replica"}, + + /* ACC */ + {NDBD_EXIT_SR_OUT_OF_INDEXMEMORY, XCR, + "Out of index memory during system restart, please increase IndexMemory"}, + + /* TUP */ + {NDBD_EXIT_SR_OUT_OF_DATAMEMORY, XCR, + "Out of data memory during system restart, please increase DataMemory"}, + + /* Ndbfs error messages */ + /* Most codes will have additional info, such as OS error code */ + {NDBD_EXIT_AFS_NOPATH, XIE, "No file system path"}, + {2802, XIE, "Channel is full"}, + {2803, XIE, "No more threads"}, + {NDBD_EXIT_AFS_PARAMETER, XIE, "Bad parameter"}, + {NDBD_EXIT_AFS_INVALIDPATH, XCE, "Illegal file system path"}, + {NDBD_EXIT_AFS_MAXOPEN, XCR, + "Max number of open files exceeded, please increase MaxNoOfOpenFiles"}, + {NDBD_EXIT_AFS_ALREADY_OPEN, XIE, "File has already been opened"}, + + {NDBD_EXIT_AFS_ENVIRONMENT , XIE, "Environment error using file"}, + {NDBD_EXIT_AFS_TEMP_NO_ACCESS , XIE, "Temporary on access to file"}, + {NDBD_EXIT_AFS_DISK_FULL , XFF, "The file system is full"}, + {NDBD_EXIT_AFS_PERMISSION_DENIED , XCE, "Received permission denied for file"}, + {NDBD_EXIT_AFS_INVALID_PARAM , XCE, "Invalid parameter for file"}, + {NDBD_EXIT_AFS_UNKNOWN , XIE, "Unknown file system error"}, + {NDBD_EXIT_AFS_NO_MORE_RESOURCES , XIE, + "System reports no more file system resources"}, + {NDBD_EXIT_AFS_NO_SUCH_FILE , XFI, "File not found"}, + {NDBD_EXIT_AFS_READ_UNDERFLOW , XFI, "Read underflow"}, + + /* Sentinel */ + {0, XUE, + "No message slogan found (please report a bug if you get this error code)"} +}; + +typedef struct StatusExitMessage { + ndbd_exit_status status; + const char * message; +} StatusExitMessage; + +typedef struct StatusExitClassification { + ndbd_exit_status status; + ndbd_exit_classification classification; + const char * message; +} StatusExitClassification; + +/** + * Mapping between classification and status + */ +static +const +StatusExitMessage StatusExitMessageMapping[] = { + { XST_S, "Success"}, + { XST_U ,"Unknown"}, + { XST_P, "Permanent error, external action needed"}, + { XST_R, "Temporary error, restart node"}, + { XST_I, "Ndbd file system error, restart node initial"} +}; + +static +const +int NbExitStatus = sizeof(StatusExitMessageMapping)/sizeof(StatusExitMessage); + +static +const +StatusExitClassification StatusExitClassificationMapping[] = { + { XST_S, XNE, "No error"}, + { XST_U, XUE, "Unknown"}, + { XST_R, XIE, "Internal error, programming error or missing error message, " + "please report a bug"}, + { XST_P, XCE, "Configuration error"}, + { XST_R, XAE, "Arbitration error"}, + { XST_R, XRE, "Restart error"}, + { XST_P, XCR, "Resource configuration error"}, + { XST_P, XFF, "File system full"}, + { XST_I, XFI, "Ndbd file system inconsistency error, please report a bug"}, + { XST_I, XFL, "Ndbd file system limit exceeded"} +}; + +static const int NbExitClassification = +sizeof(StatusExitClassificationMapping)/sizeof(StatusExitClassification); + +const char *ndbd_exit_message(int faultId, ndbd_exit_classification *cl) +{ + int i = 0; + while (errArray[i].faultId != faultId && errArray[i].faultId != 0) + i++; + *cl = errArray[i].classification; + return errArray[i].text; +} + +static const char* empty_xstring = ""; + +const +char *ndbd_exit_classification_message(ndbd_exit_classification classification, + ndbd_exit_status *status) +{ + int i; + for (i= 0; i < NbExitClassification; i++) + { + if (StatusExitClassificationMapping[i].classification == classification) + { + *status = StatusExitClassificationMapping[i].status; + return StatusExitClassificationMapping[i].message; + } + } + *status = XST_U; + return empty_xstring; +} + +const char *ndbd_exit_status_message(ndbd_exit_status status) +{ + int i; + for (i= 0; i < NbExitStatus; i++) + if (StatusExitMessageMapping[i].status == status) + return StatusExitMessageMapping[i].message; + return empty_xstring; +} + +int ndbd_exit_string(int err_no, char *str, unsigned int size) +{ + unsigned int len; + + ndbd_exit_classification cl; + ndbd_exit_status st; + const char *msg = ndbd_exit_message(err_no, &cl); + if (msg[0] != '\0') + { + const char *cl_msg = ndbd_exit_classification_message(cl, &st); + const char *st_msg = ndbd_exit_status_message(st); + + len = my_snprintf(str, size-1, "%s: %s: %s", msg, st_msg, cl_msg); + str[size-1]= '\0'; + + return len; + } + return -1; +} diff --git a/ndb/src/kernel/vm/ndbd_malloc.cpp b/ndb/src/kernel/vm/ndbd_malloc.cpp new file mode 100644 index 00000000000..4bfccf828fc --- /dev/null +++ b/ndb/src/kernel/vm/ndbd_malloc.cpp @@ -0,0 +1,63 @@ +/* Copyright (C) 2003 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; either version 2 of the License, or + (at your option) any later version. + + 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 */ + +#include <ndb_global.h> +#include "ndbd_malloc.hpp" +#include <NdbMem.h> + +//#define TRACE_MALLOC +#ifdef TRACE_MALLOC +#include <stdio.h> +#endif + +static void xxx(size_t size, size_t *s_m, size_t *s_k, size_t *s_b) +{ + *s_m = size/1024/1024; + *s_k = (size - *s_m*1024*1024)/1024; + *s_b = size - *s_m*1024*1024-*s_k*1024; +} + +static Uint64 g_allocated_memory; +void *ndbd_malloc(size_t size) +{ + void *p = NdbMem_Allocate(size); + if (p) + { + g_allocated_memory += size; +#ifdef TRACE_MALLOC + { + size_t s_m, s_k, s_b; + xxx(size, &s_m, &s_k, &s_b); + fprintf(stderr, "%p malloc(%um %uk %ub)", p, s_m, s_k, s_b); + xxx(g_allocated_memory, &s_m, &s_k, &s_b); + fprintf(stderr, "\t\ttotal(%um %uk %ub)\n", s_m, s_k, s_b); + } +#endif + } + return p; +} + +void ndbd_free(void *p, size_t size) +{ + NdbMem_Free(p); + if (p) + { + g_allocated_memory -= size; +#ifdef TRACE_MALLOC + fprintf(stderr, "%p free(%d)\n", p, size); +#endif + } +} diff --git a/ndb/src/kernel/vm/ndbd_malloc.hpp b/ndb/src/kernel/vm/ndbd_malloc.hpp new file mode 100644 index 00000000000..136e9f0c372 --- /dev/null +++ b/ndb/src/kernel/vm/ndbd_malloc.hpp @@ -0,0 +1,26 @@ +/* Copyright (C) 2003 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; either version 2 of the License, or + (at your option) any later version. + + 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 */ + +#ifndef NDBD_MALLOC_H +#define NDBD_MALLOC_H + +/** + * common memory allocation function for ndbd kernel + */ +void *ndbd_malloc(size_t size); +void ndbd_free(void *p, size_t size); + +#endif diff --git a/ndb/test/sql/test_create_drop.pl b/ndb/test/sql/test_create_drop.pl new file mode 100644 index 00000000000..7f62898b3d1 --- /dev/null +++ b/ndb/test/sql/test_create_drop.pl @@ -0,0 +1,179 @@ +use strict; +use IO::Socket; +use DBI; + +# mgm info +my $mgmhost = "localhost"; +my $mgmport = 38101; + +# location of ndb_x_fs +my $datadir = "c2"; +my @schemafiles = <$datadir/ndb_*_fs/D[12]/DBDICT/P0.SchemaLog>; +@schemafiles or die "no schemafiles in $datadir"; + +my $dsn; +$dsn = "dbi:mysql:test:localhost;port=38100"; + +# this works better for me +my $cnf = $ENV{MYSQL_HOME} . "/var/my.cnf"; +$dsn = "dbi:mysql:database=test;host=localhost;mysql_read_default_file=$cnf"; + +my $dbh; +$dbh = DBI->connect($dsn, 'root', undef, { RaiseError => 0, PrintError => 0 }); +$dbh or die $DBI::errstr; + +# mgm commands + +my $mgm = undef; + +sub mgmconnect { + $mgm = IO::Socket::INET->new( + Proto => "tcp", + PeerHost => $mgmhost, + PeerPort => $mgmport); + $mgm or die "connect to mgm failed: $!"; + $mgm->autoflush(1); +}; + +mgmconnect(); +warn "connected to mgm $mgmhost $mgmport\n"; + +my $nodeinfo = {}; + +sub getnodeinfo { + $nodeinfo = {}; + $mgm->print("get status\n"); + $mgm->print("\n"); + while (defined($_ = $mgm->getline)) { + /^node\s+status/ && last; + } + while (defined($_ = $mgm->getline)) { + /^\s*$/ && last; + /^node\.(\d+)\.(\w+):\s*(\S+)/ && ($nodeinfo->{$1}{$2} = $3); + } +} + +getnodeinfo(); + +my @dbnode = (); +for my $n (keys %$nodeinfo) { + my $p = $nodeinfo->{$n}; + ($p->{type} eq 'NDB') && push(@dbnode, $n); +} +@dbnode = sort { $a <=> $b } @dbnode; +@dbnode or die "mgm error, found no db nodes"; +warn "db nodes: @dbnode\n"; + +sub restartnode { + my($n, $initialstart) = @_; + warn "restart node $n initialstart=$initialstart\n"; + $mgm->print("restart node\n"); + $mgm->print("node: $n\n"); + $mgm->print("initialstart: $initialstart\n"); + $mgm->print("\n"); + while (1) { + sleep 5; + getnodeinfo(); + my $status = $nodeinfo->{$n}{status}; + my $sp = $nodeinfo->{$n}{startphase}; + warn "node $n status: $status sp: $sp\n"; + last if $status eq 'STARTED'; + } +} + +sub restartall { + warn "restart all\n"; + $mgm->print("restart all\n"); + $mgm->print("\n"); + while (1) { + sleep 5; + getnodeinfo(); + my $ok = 1; + for my $n (@dbnode) { + my $status = $nodeinfo->{$n}{status}; + my $sp = $nodeinfo->{$n}{startphase}; + warn "node $n status: $status sp: $sp\n"; + $ok = 0 if $status ne 'STARTED'; + } + last if $ok; + } +} + +# the sql stuff + +my $maxtab = 300; +my @tab = (); + +sub create { + my($n) = @_; + my $sql = "create table t$n (a int primary key, b varchar(20), key (b)) engine=ndb"; + warn "create t$n\n"; + $dbh->do($sql) or die "$sql\n$DBI::errstr"; +} + +sub drop { + my($n) = @_; + my $sql = "drop table t$n"; + warn "drop t$n\n"; + $dbh->do($sql) or die "$sql\n$DBI::errstr"; +} + +sub dropall { + for my $n (0..($maxtab-1)) { + my $sql = "drop table if exists t$n"; + $dbh->do($sql) or die "$sql\n$DBI::errstr"; + } +} + +sub createdrop { + my $n = int(rand($maxtab)); + if (! $tab[$n]) { + create($n); + $tab[$n] = 1; + } else { + drop($n); + $tab[$n] = 0; + } +} + +sub checkschemafiles { + system("printSchemaFile -ce @schemafiles"); + $? == 0 or die "schemafiles check failed"; +} + +sub randomrestart { + my($k) = @_; + my $s = int(rand(500)); + if ($s < 2) { + my $i = $k % scalar(@dbnode); + my $n = $dbnode[$i]; + my $initialstart = ($s < 1 ? 0 : 1); + restartnode($n, $initialstart); + return 1; + } + if ($s < 3) { + restartall(); + return 1; + } + return 0; +} + +# deterministic +srand(1); + +warn "drop any old tables\n"; +dropall(); + +my $loop = 1000000; +for my $k (0..($loop-1)) { + warn "$k\n"; + createdrop(); + checkschemafiles(); + if (randomrestart($k)) { + checkschemafiles(); + } +} + +$dbh->disconnect or die $DBI::errstr; + +# vim: set sw=2: diff --git a/ndb/test/sql/test_range_bounds.pl b/ndb/test/sql/test_range_bounds.pl new file mode 100644 index 00000000000..abe1ea28298 --- /dev/null +++ b/ndb/test/sql/test_range_bounds.pl @@ -0,0 +1,218 @@ +# +# test range scan bounds +# give option --all to test all cases +# set MYSQL_HOME to installation top +# + +use strict; +use integer; +use Getopt::Long; +use DBI; + +my $opt_all = 0; +my $opt_cnt = 5; +my $opt_verbose = 0; +GetOptions("all" => \$opt_all, "cnt=i" => \$opt_cnt, "verbose" => \$opt_verbose) + or die "options are: --all --cnt=N --verbose"; + +my $mysql_home = $ENV{MYSQL_HOME}; +defined($mysql_home) or die "no MYSQL_HOME"; +my $dsn = "dbi:mysql:database=test;host=localhost;mysql_read_default_file=$mysql_home/var/my.cnf"; +my $opts = { RaiseError => 0, PrintError => 0, AutoCommit => 1, }; + +my $dbh; +my $sth; +my $sql; + +$dbh = DBI->connect($dsn, "root", undef, $opts) or die $DBI::errstr; + +my $table = 't'; + +$sql = "drop table if exists $table"; +$dbh->do($sql) or die $DBI::errstr; + +sub cut ($$$) { + my($op, $key, $val) = @_; + $op = '==' if $op eq '='; + my(@w) = @$val; + eval "\@w = grep(\$_ $op $key, \@w)"; + $@ and die $@; + return [ @w ]; +} + +sub mkdummy ($) { + my ($val) = @_; + return { + 'dummy' => 1, + 'exp' => '9 = 9', + 'res' => $val, + }; +} + +sub mkone ($$$$) { + my($col, $op, $key, $val) = @_; + my $res = cut($op, $key, $val); + return { + 'exp' => "$col $op $key", + 'res' => $res, + }; +} + +sub mktwo ($$$$$$) { + my($col, $op1, $key1, $op2, $key2, $val) = @_; + my $res = cut($op2, $key2, cut($op1, $key1, $val)); + return { + 'exp' => "$col $op1 $key1 and $col $op2 $key2", + 'res' => $res, + }; +} + +sub mkall ($$$$) { + my($col, $key1, $key2, $val) = @_; + my @a = (); + my $p = mkdummy($val); + push(@a, $p) if $opt_all; + my @ops = qw(< <= = >= >); + for my $op (@ops) { + my $p = mkone($col, $op, $key1, $val); + push(@a, $p) if $opt_all || @{$p->{res}} != 0; + } + my @ops1 = $opt_all ? @ops : qw(= >= >); + my @ops2 = $opt_all ? @ops : qw(<= <); + for my $op1 (@ops1) { + for my $op2 (@ops2) { + my $p = mktwo($col, $op1, $key1, $op2, $key2, $val); + push(@a, $p) if $opt_all || @{$p->{res}} != 0; + } + } + warn scalar(@a)." cases\n" if $opt_verbose; + return \@a; +} + +my $casecnt = 0; + +sub verify ($$$) { + my($sql, $ord, $res) = @_; + warn "$sql\n" if $opt_verbose; + $sth = $dbh->prepare($sql) or die "prepare: $sql: $DBI::errstr"; + $sth->execute() or die "execute: $sql: $DBI::errstr"; + # + # BUG: execute can return success on error so check again + # + $sth->err and die "execute: $sql: $DBI::errstr"; + my @out = (); + for my $b (@{$res->[0]}) { + for my $c (@{$res->[1]}) { + for my $d (@{$res->[2]}) { + push(@out, [$b, $c, $d]); + } + } + } + if ($ord) { + @out = sort { + $ord * ($a->[0] - $b->[0]) || + $ord * ($a->[1] - $b->[1]) || + $ord * ($a->[2] - $b->[2]) || + 0 + } @out; + } + my $cnt = scalar @out; + my $n = 0; + while (1) { + my $row = $sth->fetchrow_arrayref; + $row || last; + @$row == 3 or die "bad row: $sql: @$row"; + for my $v (@$row) { + $v =~ s/^\s+|\s+$//g; + $v =~ /^\d+$/ or die "bad value: $sql: $v"; + } + if ($ord) { + my $out = $out[$n]; + $row->[0] == $out->[0] && + $row->[1] == $out->[1] && + $row->[2] == $out->[2] or + die "$sql: row $n: got row @$row != @$out"; + } + $n++; + } + $sth->err and die "fetch: $sql: $DBI::errstr"; + $n == $cnt or die "verify: $sql: got row count $n != $cnt"; + $casecnt++; +} + +for my $nn ("bcd", "") { + my %nn; + for my $x (qw(b c d)) { + $nn{$x} = $nn =~ /$x/ ? "not null" : "null"; + } + warn "create table\n"; + $sql = <<EOF; +create table $table ( + a int primary key, + b int $nn{b}, + c int $nn{c}, + d int $nn{d}, + index (b, c, d) +) engine=ndb +EOF + $dbh->do($sql) or die $DBI::errstr; + warn "insert\n"; + $sql = "insert into $table values(?, ?, ?, ?)"; + $sth = $dbh->prepare($sql) or die $DBI::errstr; + my @val = (0..($opt_cnt-1)); + my $v0 = 0; + for my $v1 (@val) { + for my $v2 (@val) { + for my $v3 (@val) { + $sth->bind_param(1, $v0) or die $DBI::errstr; + $sth->bind_param(2, $v1) or die $DBI::errstr; + $sth->bind_param(3, $v2) or die $DBI::errstr; + $sth->bind_param(4, $v3) or die $DBI::errstr; + $sth->execute or die $DBI::errstr; + $v0++; + } + } + } + warn "generate cases\n"; + my $key1 = 1; + my $key2 = 3; + my $a1 = mkall('b', $key1, $key2, \@val); + my $a2 = mkall('c', $key1, $key2, \@val); + my $a3 = mkall('d', $key1, $key2, \@val); + warn "select\n"; + for my $ord (0, +1, -1) { + my $orderby = + $ord == 0 ? "" : + $ord == +1 ? " order by b, c, d" : + $ord == -1 ? " order by b desc, c desc, d desc" : die "not here"; + for my $p1 (@$a1) { + my $res = [ $p1->{res}, \@val, \@val ]; + $sql = "select b, c, d from $table" . + " where $p1->{exp}" . + $orderby; + verify($sql, $ord, $res); + for my $p2 (@$a2) { + my $res = [ $p1->{res}, $p2->{res}, \@val ]; + $sql = "select b, c, d from $table" . + " where $p1->{exp} and $p2->{exp}" . + $orderby; + verify($sql, $ord, $res); + for my $p3 (@$a3) { + my $res = [ $p1->{res}, $p2->{res}, $p3->{res} ]; + $sql = "select b, c, d from $table" . + " where $p1->{exp} and $p2->{exp} and $p3->{exp}" . + $orderby; + verify($sql, $ord, $res); + } + } + } + } + warn "drop table\n"; + $sql = "drop table $table"; + $dbh->do($sql) or die $DBI::errstr; +} + +warn "verified $casecnt cases\n"; +warn "done\n"; + +# vim: set sw=2: |