Commit 3d7649ca authored by pekka@mysql.com's avatar pekka@mysql.com

ndb: index tests

parent 6463a6d7
# #
# test range scan bounds # test range scan bounds
# give option --all to test all cases # give option --all to test all cases
# set MYSQL_HOME to installation top
# #
use strict; use strict;
...@@ -14,8 +15,9 @@ my $opt_verbose = 0; ...@@ -14,8 +15,9 @@ my $opt_verbose = 0;
GetOptions("all" => \$opt_all, "cnt=i" => \$opt_cnt, "verbose" => \$opt_verbose) GetOptions("all" => \$opt_all, "cnt=i" => \$opt_cnt, "verbose" => \$opt_verbose)
or die "options are: --all --cnt=N --verbose"; or die "options are: --all --cnt=N --verbose";
my $mysql_top = $ENV{MYSQL_TOP}; my $mysql_home = $ENV{MYSQL_HOME};
my $dsn = "dbi:mysql:database=test;host=localhost;mysql_read_default_file=$mysql_top/.target/var/my.cnf"; 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 $opts = { RaiseError => 0, PrintError => 0, AutoCommit => 1, };
my $dbh; my $dbh;
......
...@@ -383,6 +383,7 @@ b c ...@@ -383,6 +383,7 @@ b c
select min(b), max(b) from t1; select min(b), max(b) from t1;
min(b) max(b) min(b) max(b)
1 5000000 1 5000000
drop table t1;
CREATE TABLE test1 ( CREATE TABLE test1 (
SubscrID int(11) NOT NULL auto_increment, SubscrID int(11) NOT NULL auto_increment,
UsrID int(11) NOT NULL default '0', UsrID int(11) NOT NULL default '0',
......
...@@ -175,6 +175,8 @@ select b, c from t1 where 1000<=b and b<=100000 and c<'j' order by b, c; ...@@ -175,6 +175,8 @@ select b, c from t1 where 1000<=b and b<=100000 and c<'j' order by b, c;
select b, c from t1 where 1000<=b and b<=100000 and c<'j' order by b desc, c desc; select b, c from t1 where 1000<=b and b<=100000 and c<'j' order by b desc, c desc;
# #
select min(b), max(b) from t1; select min(b), max(b) from t1;
#
drop table t1;
# #
# Bug #6435 # Bug #6435
......
...@@ -72,7 +72,7 @@ struct Opt { ...@@ -72,7 +72,7 @@ struct Opt {
m_die(0), m_die(0),
m_dups(false), m_dups(false),
m_fragtype(NdbDictionary::Object::FragUndefined), m_fragtype(NdbDictionary::Object::FragUndefined),
m_subsubloop(4), m_subsubloop(2),
m_index(0), m_index(0),
m_loop(1), m_loop(1),
m_msglock(true), m_msglock(true),
...@@ -257,6 +257,9 @@ struct Par : public Opt { ...@@ -257,6 +257,9 @@ struct Par : public Opt {
bool m_verify; bool m_verify;
// deadlock possible // deadlock possible
bool m_deadlock; bool m_deadlock;
// ordered range scan
bool m_ordered;
bool m_descending;
// timer location // timer location
Par(const Opt& opt) : Par(const Opt& opt) :
Opt(opt), Opt(opt),
...@@ -274,7 +277,9 @@ struct Par : public Opt { ...@@ -274,7 +277,9 @@ struct Par : public Opt {
m_bdir(0), m_bdir(0),
m_randomkey(false), m_randomkey(false),
m_verify(false), m_verify(false),
m_deadlock(false) { m_deadlock(false),
m_ordered(false),
m_descending(false) {
} }
}; };
...@@ -444,6 +449,9 @@ struct Chs { ...@@ -444,6 +449,9 @@ struct Chs {
~Chs(); ~Chs();
}; };
static NdbOut&
operator<<(NdbOut& out, const Chs& chs);
Chs::Chs(CHARSET_INFO* cs) : Chs::Chs(CHARSET_INFO* cs) :
m_cs(cs) m_cs(cs)
{ {
...@@ -455,10 +463,14 @@ Chs::Chs(CHARSET_INFO* cs) : ...@@ -455,10 +463,14 @@ Chs::Chs(CHARSET_INFO* cs) :
unsigned i = 0; unsigned i = 0;
unsigned miss1 = 0; unsigned miss1 = 0;
unsigned miss2 = 0; unsigned miss2 = 0;
unsigned miss3 = 0;
unsigned miss4 = 0;
while (i < maxcharcount) { while (i < maxcharcount) {
unsigned char* bytes = m_chr[i].m_bytes; unsigned char* bytes = m_chr[i].m_bytes;
unsigned char* xbytes = m_chr[i].m_xbytes; unsigned char* xbytes = m_chr[i].m_xbytes;
unsigned size = m_cs->mbminlen + urandom(m_cs->mbmaxlen - m_cs->mbminlen + 1); unsigned& 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); assert(m_cs->mbminlen <= size && size <= m_cs->mbmaxlen);
// prefer longer chars // prefer longer chars
if (size == m_cs->mbminlen && m_cs->mbminlen < m_cs->mbmaxlen && urandom(5) != 0) if (size == m_cs->mbminlen && m_cs->mbminlen < m_cs->mbmaxlen && urandom(5) != 0)
...@@ -466,33 +478,57 @@ Chs::Chs(CHARSET_INFO* cs) : ...@@ -466,33 +478,57 @@ Chs::Chs(CHARSET_INFO* cs) :
for (unsigned j = 0; j < size; j++) { for (unsigned j = 0; j < size; j++) {
bytes[j] = urandom(256); bytes[j] = urandom(256);
} }
// check wellformed
const char* sbytes = (const char*)bytes; const char* sbytes = (const char*)bytes;
if ((*cs->cset->well_formed_len)(cs, sbytes, sbytes + size, 1) != size) { if ((*cs->cset->well_formed_len)(cs, sbytes, sbytes + size, 1) != size) {
miss1++; miss1++;
continue; continue;
} }
// do not trust well_formed_len currently // check no proper prefix wellformed
ok = true;
for (unsigned j = 1; j < size; j++) {
if ((*cs->cset->well_formed_len)(cs, sbytes, sbytes + j, 1) == j) {
ok = false;
break;
}
}
if (! ok) {
miss2++;
continue;
}
// normalize
memset(xbytes, 0, sizeof(xbytes)); memset(xbytes, 0, sizeof(xbytes));
// currently returns buffer size always // currently returns buffer size always
int xlen = (*cs->coll->strnxfrm)(cs, xbytes, m_xmul * size, bytes, size); int xlen = (*cs->coll->strnxfrm)(cs, xbytes, m_xmul * size, bytes, size);
// check we got something // check we got something
bool xok = false; ok = false;
for (unsigned j = 0; j < xlen; j++) { for (unsigned j = 0; j < xlen; j++) {
if (xbytes[j] != 0) { if (xbytes[j] != 0) {
xok = true; ok = true;
break; break;
} }
} }
if (! xok) { if (! ok) {
miss2++; miss3++;
continue;
}
// check for duplicate (before normalize)
ok = true;
for (unsigned 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) {
miss4++;
continue; continue;
} }
// occasional duplicate char is ok
m_chr[i].m_size = size;
i++; i++;
} }
bool disorder = true; bool disorder = true;
unsigned bubbels = 0; unsigned bubbles = 0;
while (disorder) { while (disorder) {
disorder = false; disorder = false;
for (unsigned i = 1; i < maxcharcount; i++) { for (unsigned i = 1; i < maxcharcount; i++) {
...@@ -502,11 +538,11 @@ Chs::Chs(CHARSET_INFO* cs) : ...@@ -502,11 +538,11 @@ Chs::Chs(CHARSET_INFO* cs) :
m_chr[i] = m_chr[i-1]; m_chr[i] = m_chr[i-1];
m_chr[i-1] = chr; m_chr[i-1] = chr;
disorder = true; disorder = true;
bubbels++; bubbles++;
} }
} }
} }
LL3("inited charset " << cs->name << " miss1=" << miss1 << " miss2=" << miss2 << " bubbels=" << bubbels); LL3("inited charset " << *this << " miss=" << miss1 << "," << miss2 << "," << miss3 << "," << miss4 << " bubbles=" << bubbles);
} }
Chs::~Chs() Chs::~Chs()
...@@ -514,6 +550,14 @@ Chs::~Chs() ...@@ -514,6 +550,14 @@ Chs::~Chs()
delete [] m_chr; delete [] m_chr;
} }
static NdbOut&
operator<<(NdbOut& out, const Chs& chs)
{
CHARSET_INFO* cs = chs.m_cs;
out << cs->name << "[" << cs->mbminlen << "-" << cs->mbmaxlen << "," << chs.m_xmul << "]";
return out;
}
static Chs* cslist[maxcsnumber]; static Chs* cslist[maxcsnumber];
static void static void
...@@ -552,22 +596,26 @@ getcs(Par par) ...@@ -552,22 +596,26 @@ getcs(Par par)
// Col - table column // Col - table column
struct Col { struct Col {
enum Type {
Unsigned = NdbDictionary::Column::Unsigned,
Char = NdbDictionary::Column::Char
};
const class Tab& m_tab; const class Tab& m_tab;
unsigned m_num; unsigned m_num;
const char* m_name; const char* m_name;
bool m_pk; bool m_pk;
NdbDictionary::Column::Type m_type; Type m_type;
unsigned m_length; unsigned m_length;
unsigned m_bytelength; unsigned m_bytelength;
bool m_nullable; bool m_nullable;
const Chs* m_chs; const Chs* m_chs;
Col(const class Tab& tab, unsigned num, const char* name, bool pk, NdbDictionary::Column::Type type, unsigned length, bool nullable, const Chs* chs); Col(const class Tab& tab, unsigned num, const char* name, bool pk, Type type, unsigned length, bool nullable, const Chs* chs);
~Col(); ~Col();
bool equal(const Col& col2) const; bool equal(const Col& col2) const;
void verify(const void* addr) const; void verify(const void* addr) const;
}; };
Col::Col(const class Tab& tab, unsigned num, const char* name, bool pk, NdbDictionary::Column::Type type, unsigned length, bool nullable, const Chs* chs) : Col::Col(const class Tab& tab, unsigned num, const char* name, bool pk, Type type, unsigned length, bool nullable, const Chs* chs) :
m_tab(tab), m_tab(tab),
m_num(num), m_num(num),
m_name(strcpy(new char [strlen(name) + 1], name)), m_name(strcpy(new char [strlen(name) + 1], name)),
...@@ -595,9 +643,9 @@ void ...@@ -595,9 +643,9 @@ void
Col::verify(const void* addr) const Col::verify(const void* addr) const
{ {
switch (m_type) { switch (m_type) {
case NdbDictionary::Column::Unsigned: case Col::Unsigned:
break; break;
case NdbDictionary::Column::Char: case Col::Char:
{ {
CHARSET_INFO* cs = m_chs->m_cs; CHARSET_INFO* cs = m_chs->m_cs;
const char* src = (const char*)addr; const char* src = (const char*)addr;
...@@ -616,10 +664,10 @@ operator<<(NdbOut& out, const Col& col) ...@@ -616,10 +664,10 @@ operator<<(NdbOut& out, const Col& col)
{ {
out << "col[" << col.m_num << "] " << col.m_name; out << "col[" << col.m_num << "] " << col.m_name;
switch (col.m_type) { switch (col.m_type) {
case NdbDictionary::Column::Unsigned: case Col::Unsigned:
out << " unsigned"; out << " unsigned";
break; break;
case NdbDictionary::Column::Char: case Col::Char:
{ {
CHARSET_INFO* cs = col.m_chs->m_cs; CHARSET_INFO* cs = col.m_chs->m_cs;
out << " char(" << col.m_length << "*" << cs->mbmaxlen << ";" << cs->name << ")"; out << " char(" << col.m_length << "*" << cs->mbmaxlen << ";" << cs->name << ")";
...@@ -656,25 +704,41 @@ ICol::~ICol() ...@@ -656,25 +704,41 @@ ICol::~ICol()
{ {
} }
static NdbOut&
operator<<(NdbOut& out, const ICol& icol)
{
out << "icol[" << icol.m_num << "] " << icol.m_col;
return out;
}
// ITab - index // ITab - index
struct ITab { struct ITab {
enum Type {
OrderedIndex = NdbDictionary::Index::OrderedIndex,
UniqueHashIndex = NdbDictionary::Index::UniqueHashIndex
};
const class Tab& m_tab; const class Tab& m_tab;
const char* m_name; const char* m_name;
Type m_type;
unsigned m_icols; unsigned m_icols;
const ICol** m_icol; const ICol** m_icol;
ITab(const class Tab& tab, const char* name, unsigned icols); unsigned m_colmask;
ITab(const class Tab& tab, const char* name, Type type, unsigned icols);
~ITab(); ~ITab();
void icoladd(unsigned k, const ICol* icolptr);
}; };
ITab::ITab(const class Tab& tab, const char* name, unsigned icols) : ITab::ITab(const class Tab& tab, const char* name, Type type, unsigned icols) :
m_tab(tab), m_tab(tab),
m_name(strcpy(new char [strlen(name) + 1], name)), m_name(strcpy(new char [strlen(name) + 1], name)),
m_type(type),
m_icols(icols), m_icols(icols),
m_icol(new const ICol* [icols + 1]) m_icol(new const ICol* [icols + 1]),
m_colmask(0)
{ {
for (unsigned i = 0; i <= m_icols; i++) for (unsigned k = 0; k <= m_icols; k++)
m_icol[0] = 0; m_icol[k] = 0;
} }
ITab::~ITab() ITab::~ITab()
...@@ -685,13 +749,21 @@ ITab::~ITab() ...@@ -685,13 +749,21 @@ ITab::~ITab()
delete [] m_icol; delete [] m_icol;
} }
void
ITab::icoladd(unsigned 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);
}
static NdbOut& static NdbOut&
operator<<(NdbOut& out, const ITab& itab) operator<<(NdbOut& out, const ITab& itab)
{ {
out << "itab " << itab.m_name << " icols=" << itab.m_icols; out << "itab " << itab.m_name << " icols=" << itab.m_icols;
for (unsigned k = 0; k < itab.m_icols; k++) { for (unsigned k = 0; k < itab.m_icols; k++) {
out << endl; const ICol& icol = *itab.m_icol[k];
out << "icol[" << k << "] " << itab.m_icol[k]->m_col; out << endl << icol;
} }
return out; return out;
} }
...@@ -706,6 +778,8 @@ struct Tab { ...@@ -706,6 +778,8 @@ struct Tab {
const ITab** m_itab; const ITab** m_itab;
// pk must contain an Unsigned column // pk must contain an Unsigned column
unsigned m_keycol; 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); Tab(const char* name, unsigned cols, unsigned itabs, unsigned keycol);
~Tab(); ~Tab();
}; };
...@@ -718,10 +792,10 @@ Tab::Tab(const char* name, unsigned cols, unsigned itabs, unsigned keycol) : ...@@ -718,10 +792,10 @@ Tab::Tab(const char* name, unsigned cols, unsigned itabs, unsigned keycol) :
m_itab(new const ITab* [itabs + 1]), m_itab(new const ITab* [itabs + 1]),
m_keycol(keycol) m_keycol(keycol)
{ {
for (unsigned i = 0; i <= cols; i++) for (unsigned k = 0; k <= cols; k++)
m_col[i] = 0; m_col[k] = 0;
for (unsigned i = 0; i <= itabs; i++) for (unsigned j = 0; j <= itabs; j++)
m_itab[i] = 0; m_itab[j] = 0;
} }
Tab::~Tab() Tab::~Tab()
...@@ -735,19 +809,33 @@ Tab::~Tab() ...@@ -735,19 +809,33 @@ Tab::~Tab()
delete [] m_itab; delete [] m_itab;
} }
void
Tab::coladd(unsigned k, Col* colptr)
{
assert(k == colptr->m_num && k < m_cols && m_col[k] == 0);
m_col[k] = colptr;
}
void
Tab::itabadd(unsigned j, ITab* itabptr)
{
assert(j < m_itabs && m_itab[j] == 0);
m_itab[j] = itabptr;
}
static NdbOut& static NdbOut&
operator<<(NdbOut& out, const Tab& tab) operator<<(NdbOut& out, const Tab& tab)
{ {
out << "tab " << tab.m_name << " cols=" << tab.m_cols; out << "tab " << tab.m_name << " cols=" << tab.m_cols;
for (unsigned k = 0; k < tab.m_cols; k++) { for (unsigned k = 0; k < tab.m_cols; k++) {
out << endl; const Col& col = *tab.m_col[k];
out << *tab.m_col[k]; out << endl << col;
} }
for (unsigned i = 0; i < tab.m_itabs; i++) { for (unsigned i = 0; i < tab.m_itabs; i++) {
if (tab.m_itab[i] == 0) if (tab.m_itab[i] == 0)
continue; continue;
out << endl; const ITab& itab = *tab.m_itab[i];
out << *tab.m_itab[i]; out << endl << itab;
} }
return out; return out;
} }
...@@ -774,7 +862,7 @@ verifytables() ...@@ -774,7 +862,7 @@ verifytables()
{ {
assert(t->m_keycol < t->m_cols); assert(t->m_keycol < t->m_cols);
const Col* c = t->m_col[t->m_keycol]; const Col* c = t->m_col[t->m_keycol];
assert(c->m_pk && c->m_type == NdbDictionary::Column::Unsigned); assert(c->m_pk && c->m_type == Col::Unsigned);
} }
assert(t->m_itabs != 0 && t->m_itab != 0); assert(t->m_itabs != 0 && t->m_itab != 0);
for (unsigned i = 0; i < t->m_itabs; i++) { for (unsigned i = 0; i < t->m_itabs; i++) {
...@@ -785,6 +873,9 @@ verifytables() ...@@ -785,6 +873,9 @@ verifytables()
for (unsigned k = 0; k < x->m_icols; k++) { for (unsigned k = 0; k < x->m_icols; k++) {
const ICol* c = x->m_icol[k]; const ICol* c = x->m_icol[k];
assert(c != 0 && c->m_num == k && c->m_col.m_num < t->m_cols); 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(t->m_itab[t->m_itabs] == 0); assert(t->m_itab[t->m_itabs] == 0);
...@@ -810,127 +901,186 @@ makebuiltintables(Par par) ...@@ -810,127 +901,186 @@ makebuiltintables(Par par)
} }
// ti0 - basic // ti0 - basic
if (usetable(par, 0)) { if (usetable(par, 0)) {
const Tab* t = new Tab("ti0", 5, 5, 0); Tab* t = new Tab("ti0", 5, 7, 0);
// name - pk - type - length - nullable - cs // name - pk - type - length - nullable - cs
t->m_col[0] = new Col(*t, 0, "a", 1, NdbDictionary::Column::Unsigned, 1, 0, 0); t->coladd(0, new Col(*t, 0, "a", 1, Col::Unsigned, 1, 0, 0));
t->m_col[1] = new Col(*t, 1, "b", 0, NdbDictionary::Column::Unsigned, 1, 1, 0); t->coladd(1, new Col(*t, 1, "b", 0, Col::Unsigned, 1, 1, 0));
t->m_col[2] = new Col(*t, 2, "c", 0, NdbDictionary::Column::Unsigned, 1, 1, 0); t->coladd(2, new Col(*t, 2, "c", 0, Col::Unsigned, 1, 0, 0));
t->m_col[3] = new Col(*t, 3, "d", 0, NdbDictionary::Column::Unsigned, 1, 1, 0); t->coladd(3, new Col(*t, 3, "d", 0, Col::Unsigned, 1, 1, 0));
t->m_col[4] = new Col(*t, 4, "e", 0, NdbDictionary::Column::Unsigned, 1, 1, 0); t->coladd(4, new Col(*t, 4, "e", 0, Col::Unsigned, 1, 0, 0));
if (useindex(par, 0)) { if (useindex(par, 0)) {
// a // a
const ITab* x = t->m_itab[0] = new ITab(*t, "ti0x0", 1); ITab* x = new ITab(*t, "ti0x0", ITab::OrderedIndex, 1);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[0]); x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
t->itabadd(0, x);
} }
if (useindex(par, 1)) { if (useindex(par, 1)) {
// b // b
const ITab* x = t->m_itab[1] = new ITab(*t, "ti0x1", 1); ITab* x = new ITab(*t, "ti0x1", ITab::OrderedIndex, 1);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[1]); x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
t->itabadd(1, x);
} }
if (useindex(par, 2)) { if (useindex(par, 2)) {
// b, c // b, c
const ITab* x = t->m_itab[2] = new ITab(*t, "ti0x2", 2); ITab* x = new ITab(*t, "ti0x2", ITab::OrderedIndex, 2);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[1]); x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
x->m_icol[1] = new ICol(*x, 1, *t->m_col[2]); x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
t->itabadd(2, x);
} }
if (useindex(par, 3)) { if (useindex(par, 3)) {
// d, c, b // d, c, b
const ITab* x = t->m_itab[3] = new ITab(*t, "ti0x3", 3); ITab* x = new ITab(*t, "ti0x3", ITab::OrderedIndex, 3);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[3]); x->icoladd(0, new ICol(*x, 0, *t->m_col[3]));
x->m_icol[1] = new ICol(*x, 1, *t->m_col[2]); x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
x->m_icol[2] = new ICol(*x, 2, *t->m_col[1]); x->icoladd(2, new ICol(*x, 2, *t->m_col[1]));
t->itabadd(3, x);
} }
if (useindex(par, 4)) { if (useindex(par, 4)) {
// b, e, c, d // b, e, c, d
const ITab* x = t->m_itab[4] = new ITab(*t, "ti0x4", 4); ITab* x = new ITab(*t, "ti0x4", ITab::OrderedIndex, 4);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[1]); x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
x->m_icol[1] = new ICol(*x, 1, *t->m_col[4]); x->icoladd(1, new ICol(*x, 1, *t->m_col[4]));
x->m_icol[2] = new ICol(*x, 2, *t->m_col[2]); x->icoladd(2, new ICol(*x, 2, *t->m_col[2]));
x->m_icol[3] = new ICol(*x, 3, *t->m_col[3]); x->icoladd(3, new ICol(*x, 3, *t->m_col[3]));
t->itabadd(4, x);
}
if (useindex(par, 5)) {
// a, c
ITab* x = new ITab(*t, "ti0z5", ITab::UniqueHashIndex, 2);
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
t->itabadd(5, x);
}
if (useindex(par, 6)) {
// a, e
ITab* x = new ITab(*t, "ti0z6", ITab::UniqueHashIndex, 2);
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
x->icoladd(1, new ICol(*x, 1, *t->m_col[4]));
t->itabadd(6, x);
} }
tablist[0] = t; tablist[0] = t;
} }
// ti1 - simple char fields // ti1 - simple char fields
if (usetable(par, 1)) { if (usetable(par, 1)) {
const Tab* t = new Tab("ti1", 5, 5, 1); Tab* t = new Tab("ti1", 5, 7, 1);
// name - pk - type - length - nullable - cs // name - pk - type - length - nullable - cs
t->m_col[0] = new Col(*t, 0, "a", 0, NdbDictionary::Column::Unsigned, 1, 1, 0); t->coladd(0, new Col(*t, 0, "a", 0, Col::Unsigned, 1, 0, 0));
t->m_col[1] = new Col(*t, 1, "b", 1, NdbDictionary::Column::Unsigned, 1, 0, 0); t->coladd(1, new Col(*t, 1, "b", 1, Col::Unsigned, 1, 0, 0));
t->m_col[2] = new Col(*t, 2, "c", 0, NdbDictionary::Column::Char, 20, 1, getcs(par)); t->coladd(2, new Col(*t, 2, "c", 0, Col::Char, 20, 1, getcs(par)));
t->m_col[3] = new Col(*t, 3, "d", 0, NdbDictionary::Column::Char, 5, 1, getcs(par)); t->coladd(3, new Col(*t, 3, "d", 0, Col::Char, 5, 0, getcs(par)));
t->m_col[4] = new Col(*t, 4, "e", 0, NdbDictionary::Column::Char, 5, 1, getcs(par)); t->coladd(4, new Col(*t, 4, "e", 0, Col::Char, 5, 1, getcs(par)));
if (useindex(par, 0)) { if (useindex(par, 0)) {
// b // b
const ITab* x = t->m_itab[0] = new ITab(*t, "ti1x0", 1); ITab* x = new ITab(*t, "ti1x0", ITab::OrderedIndex, 1);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[1]); x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
} }
if (useindex(par, 1)) { if (useindex(par, 1)) {
// a, c // a, c
const ITab* x = t->m_itab[1] = new ITab(*t, "ti1x1", 2); ITab* x = new ITab(*t, "ti1x1", ITab::OrderedIndex, 2);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[0]); x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
x->m_icol[1] = new ICol(*x, 1, *t->m_col[2]); x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
t->itabadd(1, x);
} }
if (useindex(par, 2)) { if (useindex(par, 2)) {
// c, a // c, a
const ITab* x = t->m_itab[2] = new ITab(*t, "ti1x2", 2); ITab* x = new ITab(*t, "ti1x2", ITab::OrderedIndex, 2);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[2]); x->icoladd(0, new ICol(*x, 0, *t->m_col[2]));
x->m_icol[1] = new ICol(*x, 1, *t->m_col[0]); x->icoladd(1, new ICol(*x, 1, *t->m_col[0]));
t->itabadd(2, x);
} }
if (useindex(par, 3)) { if (useindex(par, 3)) {
// e // e
const ITab* x = t->m_itab[3] = new ITab(*t, "ti1x3", 1); ITab* x = new ITab(*t, "ti1x3", ITab::OrderedIndex, 1);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[4]); x->icoladd(0, new ICol(*x, 0, *t->m_col[4]));
t->itabadd(3, x);
} }
if (useindex(par, 4)) { if (useindex(par, 4)) {
// e, d, c, b // e, d, c, b
const ITab* x = t->m_itab[4] = new ITab(*t, "ti1x4", 4); ITab* x = new ITab(*t, "ti1x4", ITab::OrderedIndex, 4);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[4]); x->icoladd(0, new ICol(*x, 0, *t->m_col[4]));
x->m_icol[1] = new ICol(*x, 1, *t->m_col[3]); x->icoladd(1, new ICol(*x, 1, *t->m_col[3]));
x->m_icol[2] = new ICol(*x, 2, *t->m_col[2]); x->icoladd(2, new ICol(*x, 2, *t->m_col[2]));
x->m_icol[3] = new ICol(*x, 3, *t->m_col[1]); x->icoladd(3, new ICol(*x, 3, *t->m_col[1]));
t->itabadd(4, x);
}
if (useindex(par, 5)) {
// a, b
ITab* x = new ITab(*t, "ti1z5", ITab::UniqueHashIndex, 2);
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
x->icoladd(1, new ICol(*x, 1, *t->m_col[1]));
t->itabadd(5, x);
}
if (useindex(par, 6)) {
// a, b, d
ITab* x = new ITab(*t, "ti1z6", ITab::UniqueHashIndex, 3);
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
x->icoladd(1, new ICol(*x, 1, *t->m_col[1]));
x->icoladd(2, new ICol(*x, 2, *t->m_col[3]));
t->itabadd(6, x);
} }
tablist[1] = t; tablist[1] = t;
} }
// ti2 - complex char fields // ti2 - complex char fields
if (usetable(par, 2)) { if (usetable(par, 2)) {
const Tab* t = new Tab("ti2", 5, 5, 2); Tab* t = new Tab("ti2", 5, 7, 2);
// name - pk - type - length - nullable - cs // name - pk - type - length - nullable - cs
t->m_col[0] = new Col(*t, 0, "a", 1, NdbDictionary::Column::Char, 101, 0, getcs(par)); t->coladd(0, new Col(*t, 0, "a", 1, Col::Char, 31, 0, getcs(par)));
t->m_col[1] = new Col(*t, 1, "b", 0, NdbDictionary::Column::Char, 4, 1, getcs(par)); t->coladd(1, new Col(*t, 1, "b", 0, Col::Char, 4, 1, getcs(par)));
t->m_col[2] = new Col(*t, 2, "c", 1, NdbDictionary::Column::Unsigned, 1, 0, 0); t->coladd(2, new Col(*t, 2, "c", 1, Col::Unsigned, 1, 0, 0));
t->m_col[3] = new Col(*t, 3, "d", 1, NdbDictionary::Column::Char, 3, 0, getcs(par)); t->coladd(3, new Col(*t, 3, "d", 1, Col::Char, 3, 0, getcs(par)));
t->m_col[4] = new Col(*t, 4, "e", 0, NdbDictionary::Column::Char, 101, 0, getcs(par)); t->coladd(4, new Col(*t, 4, "e", 0, Col::Char, 17, 0, getcs(par)));
if (useindex(par, 0)) { if (useindex(par, 0)) {
// a, c, d // a, c, d
const ITab* x = t->m_itab[0] = new ITab(*t, "ti2x0", 3); ITab* x = new ITab(*t, "ti2x0", ITab::OrderedIndex, 3);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[0]); x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
x->m_icol[1] = new ICol(*x, 1, *t->m_col[2]); x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
x->m_icol[2] = new ICol(*x, 2, *t->m_col[3]); x->icoladd(2, new ICol(*x, 2, *t->m_col[3]));
t->itabadd(0, x);
} }
if (useindex(par, 1)) { if (useindex(par, 1)) {
// e, d, c, b, a // e, d, c, b, a
const ITab* x = t->m_itab[1] = new ITab(*t, "ti2x1", 5); ITab* x = new ITab(*t, "ti2x1", ITab::OrderedIndex, 5);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[4]); x->icoladd(0, new ICol(*x, 0, *t->m_col[4]));
x->m_icol[1] = new ICol(*x, 1, *t->m_col[3]); x->icoladd(1, new ICol(*x, 1, *t->m_col[3]));
x->m_icol[2] = new ICol(*x, 2, *t->m_col[2]); x->icoladd(2, new ICol(*x, 2, *t->m_col[2]));
x->m_icol[3] = new ICol(*x, 3, *t->m_col[1]); x->icoladd(3, new ICol(*x, 3, *t->m_col[1]));
x->m_icol[4] = new ICol(*x, 4, *t->m_col[0]); x->icoladd(4, new ICol(*x, 4, *t->m_col[0]));
t->itabadd(1, x);
} }
if (useindex(par, 2)) { if (useindex(par, 2)) {
// d // d
const ITab* x = t->m_itab[2] = new ITab(*t, "ti2x2", 1); ITab* x = new ITab(*t, "ti2x2", ITab::OrderedIndex, 1);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[3]); x->icoladd(0, new ICol(*x, 0, *t->m_col[3]));
t->itabadd(2, x);
} }
if (useindex(par, 3)) { if (useindex(par, 3)) {
// b // b
const ITab* x = t->m_itab[3] = new ITab(*t, "ti2x3", 1); ITab* x = new ITab(*t, "ti2x3", ITab::OrderedIndex, 1);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[1]); x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
t->itabadd(3, x);
} }
if (useindex(par, 4)) { if (useindex(par, 4)) {
// a, e // a, e
const ITab* x = t->m_itab[4] = new ITab(*t, "ti2x4", 2); ITab* x = new ITab(*t, "ti2x4", ITab::OrderedIndex, 2);
x->m_icol[0] = new ICol(*x, 0, *t->m_col[0]); x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
x->m_icol[1] = new ICol(*x, 1, *t->m_col[4]); x->icoladd(1, new ICol(*x, 1, *t->m_col[4]));
t->itabadd(4, x);
}
if (useindex(par, 5)) {
// a, c
ITab* x = new ITab(*t, "ti2z5", ITab::UniqueHashIndex, 2);
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
t->itabadd(5, x);
}
if (useindex(par, 6)) {
// a, c, d, e
ITab* x = new ITab(*t, "ti2z6", ITab::UniqueHashIndex, 4);
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
x->icoladd(2, new ICol(*x, 2, *t->m_col[3]));
x->icoladd(3, new ICol(*x, 3, *t->m_col[4]));
t->itabadd(6, x);
} }
tablist[2] = t; tablist[2] = t;
} }
...@@ -944,6 +1094,7 @@ struct Con { ...@@ -944,6 +1094,7 @@ struct Con {
NdbDictionary::Dictionary* m_dic; NdbDictionary::Dictionary* m_dic;
NdbConnection* m_tx; NdbConnection* m_tx;
NdbOperation* m_op; NdbOperation* m_op;
NdbIndexOperation* m_indexop;
NdbScanOperation* m_scanop; NdbScanOperation* m_scanop;
NdbIndexScanOperation* m_indexscanop; NdbIndexScanOperation* m_indexscanop;
enum ScanMode { ScanNo = 0, Committed, Latest, Exclusive }; enum ScanMode { ScanNo = 0, Committed, Latest, Exclusive };
...@@ -951,7 +1102,7 @@ struct Con { ...@@ -951,7 +1102,7 @@ struct Con {
enum ErrType { ErrNone = 0, ErrDeadlock, ErrOther }; enum ErrType { ErrNone = 0, ErrDeadlock, ErrOther };
ErrType m_errtype; ErrType m_errtype;
Con() : Con() :
m_ndb(0), m_dic(0), m_tx(0), m_op(0), m_ndb(0), m_dic(0), m_tx(0), m_op(0), m_indexop(0),
m_scanop(0), m_indexscanop(0), m_scanmode(ScanNo), m_errtype(ErrNone) {} m_scanop(0), m_indexscanop(0), m_scanmode(ScanNo), m_errtype(ErrNone) {}
~Con() { ~Con() {
if (m_tx != 0) if (m_tx != 0)
...@@ -962,6 +1113,7 @@ struct Con { ...@@ -962,6 +1113,7 @@ struct Con {
void disconnect(); void disconnect();
int startTransaction(); int startTransaction();
int getNdbOperation(const Tab& tab); int getNdbOperation(const Tab& tab);
int getNdbIndexOperation(const ITab& itab, const Tab& tab);
int getNdbScanOperation(const Tab& tab); int getNdbScanOperation(const Tab& tab);
int getNdbScanOperation(const ITab& itab, const Tab& tab); int getNdbScanOperation(const ITab& itab, const Tab& tab);
int equal(int num, const char* addr); int equal(int num, const char* addr);
...@@ -972,6 +1124,8 @@ struct Con { ...@@ -972,6 +1124,8 @@ struct Con {
int execute(ExecType t, bool& deadlock); int execute(ExecType t, bool& deadlock);
int openScanRead(unsigned scanbat, unsigned scanpar); int openScanRead(unsigned scanbat, unsigned scanpar);
int openScanExclusive(unsigned scanbat, unsigned scanpar); int openScanExclusive(unsigned scanbat, unsigned scanpar);
int openScanOrdered(unsigned scanbat, unsigned scanpar, bool descending);
int openScanOrderedExclusive(unsigned scanbat, unsigned scanpar, bool descending);
int executeScan(); int executeScan();
int nextScanResult(bool fetchAllowed); int nextScanResult(bool fetchAllowed);
int nextScanResult(bool fetchAllowed, bool& deadlock); int nextScanResult(bool fetchAllowed, bool& deadlock);
...@@ -1025,6 +1179,14 @@ Con::getNdbOperation(const Tab& tab) ...@@ -1025,6 +1179,14 @@ Con::getNdbOperation(const Tab& tab)
return 0; return 0;
} }
int
Con::getNdbIndexOperation(const ITab& itab, const Tab& tab)
{
assert(m_tx != 0);
CHKCON((m_op = m_indexop = m_tx->getNdbIndexOperation(itab.m_name, tab.m_name)) != 0, *this);
return 0;
}
int int
Con::getNdbScanOperation(const Tab& tab) Con::getNdbScanOperation(const Tab& tab)
{ {
...@@ -1115,6 +1277,25 @@ Con::openScanExclusive(unsigned scanbat, unsigned scanpar) ...@@ -1115,6 +1277,25 @@ Con::openScanExclusive(unsigned scanbat, unsigned scanpar)
return 0; return 0;
} }
int
Con::openScanOrdered(unsigned scanbat, unsigned scanpar, bool descending)
{
assert(m_tx != 0 && m_indexscanop != 0);
NdbOperation::LockMode lm = NdbOperation::LM_Read;
CHKCON(m_indexscanop->readTuples(lm, scanbat, scanpar, true, descending) == 0, *this);
return 0;
}
int
Con::openScanOrderedExclusive(unsigned scanbat, unsigned scanpar, bool descending)
{
assert(m_tx != 0 && m_indexscanop != 0);
NdbOperation::LockMode lm = NdbOperation::LM_Exclusive;
CHKCON(m_indexscanop->readTuples(lm, scanbat, scanpar, true, descending) == 0, *this);
return 0;
}
int int
Con::executeScan() Con::executeScan()
{ {
...@@ -1202,6 +1383,7 @@ Con::printerror(NdbOut& out) ...@@ -1202,6 +1383,7 @@ Con::printerror(NdbOut& out)
if ((code = m_tx->getNdbError().code) != 0) { if ((code = m_tx->getNdbError().code) != 0) {
LL0(++any << " con: error " << m_tx->getNdbError()); LL0(++any << " con: error " << m_tx->getNdbError());
die += (code == g_opt.m_die); die += (code == g_opt.m_die);
// 631 is new, occurs only on 4 db nodes, needs to be checked out
if (code == 266 || code == 274 || code == 296 || code == 297 || code == 499 || code == 631) if (code == 266 || code == 274 || code == 296 || code == 297 || code == 499 || code == 631)
m_errtype = ErrDeadlock; m_errtype = ErrDeadlock;
} }
...@@ -1290,7 +1472,7 @@ createtable(Par par) ...@@ -1290,7 +1472,7 @@ createtable(Par par)
for (unsigned k = 0; k < tab.m_cols; k++) { for (unsigned k = 0; k < tab.m_cols; k++) {
const Col& col = *tab.m_col[k]; const Col& col = *tab.m_col[k];
NdbDictionary::Column c(col.m_name); NdbDictionary::Column c(col.m_name);
c.setType(col.m_type); c.setType((NdbDictionary::Column::Type)col.m_type);
c.setLength(col.m_bytelength); // NDB API uses length in bytes c.setLength(col.m_bytelength); // NDB API uses length in bytes
c.setPrimaryKey(col.m_pk); c.setPrimaryKey(col.m_pk);
c.setNullable(col.m_nullable); c.setNullable(col.m_nullable);
...@@ -1343,8 +1525,10 @@ createindex(Par par, const ITab& itab) ...@@ -1343,8 +1525,10 @@ createindex(Par par, const ITab& itab)
LL4(itab); LL4(itab);
NdbDictionary::Index x(itab.m_name); NdbDictionary::Index x(itab.m_name);
x.setTable(tab.m_name); x.setTable(tab.m_name);
x.setType(NdbDictionary::Index::OrderedIndex); x.setType((NdbDictionary::Index::Type)itab.m_type);
if (par.m_nologging || itab.m_type == ITab::OrderedIndex) {
x.setLogging(false); x.setLogging(false);
}
for (unsigned k = 0; k < itab.m_icols; k++) { for (unsigned k = 0; k < itab.m_icols; k++) {
const ICol& icol = *itab.m_icol[k]; const ICol& icol = *itab.m_icol[k];
const Col& col = icol.m_col; const Col& col = icol.m_col;
...@@ -1385,6 +1569,8 @@ struct Val { ...@@ -1385,6 +1569,8 @@ struct Val {
void copy(const void* addr); void copy(const void* addr);
const void* dataaddr() const; const void* dataaddr() const;
bool m_null; bool m_null;
int equal(Par par) const;
int equal(Par par, const ICol& icol) const;
int setval(Par par) const; int setval(Par par) const;
void calc(Par par, unsigned i); void calc(Par par, unsigned i);
void calckey(Par par, unsigned i); void calckey(Par par, unsigned i);
...@@ -1402,9 +1588,9 @@ Val::Val(const Col& col) : ...@@ -1402,9 +1588,9 @@ Val::Val(const Col& col) :
m_col(col) m_col(col)
{ {
switch (col.m_type) { switch (col.m_type) {
case NdbDictionary::Column::Unsigned: case Col::Unsigned:
break; break;
case NdbDictionary::Column::Char: case Col::Char:
m_char = new unsigned char [col.m_bytelength]; m_char = new unsigned char [col.m_bytelength];
break; break;
default: default:
...@@ -1417,9 +1603,9 @@ Val::~Val() ...@@ -1417,9 +1603,9 @@ Val::~Val()
{ {
const Col& col = m_col; const Col& col = m_col;
switch (col.m_type) { switch (col.m_type) {
case NdbDictionary::Column::Unsigned: case Col::Unsigned:
break; break;
case NdbDictionary::Column::Char: case Col::Char:
delete [] m_char; delete [] m_char;
break; break;
default: default:
...@@ -1446,10 +1632,10 @@ Val::copy(const void* addr) ...@@ -1446,10 +1632,10 @@ Val::copy(const void* addr)
{ {
const Col& col = m_col; const Col& col = m_col;
switch (col.m_type) { switch (col.m_type) {
case NdbDictionary::Column::Unsigned: case Col::Unsigned:
m_uint32 = *(const Uint32*)addr; m_uint32 = *(const Uint32*)addr;
break; break;
case NdbDictionary::Column::Char: case Col::Char:
memcpy(m_char, addr, col.m_bytelength); memcpy(m_char, addr, col.m_bytelength);
break; break;
default: default:
...@@ -1464,9 +1650,9 @@ Val::dataaddr() const ...@@ -1464,9 +1650,9 @@ Val::dataaddr() const
{ {
const Col& col = m_col; const Col& col = m_col;
switch (col.m_type) { switch (col.m_type) {
case NdbDictionary::Column::Unsigned: case Col::Unsigned:
return &m_uint32; return &m_uint32;
case NdbDictionary::Column::Char: case Col::Char:
return m_char; return m_char;
default: default:
break; break;
...@@ -1476,17 +1662,36 @@ Val::dataaddr() const ...@@ -1476,17 +1662,36 @@ Val::dataaddr() const
} }
int int
Val::setval(Par par) const Val::equal(Par par) const
{ {
Con& con = par.con(); Con& con = par.con();
const Col& col = m_col; const Col& col = m_col;
assert(col.m_pk && ! m_null);
const char* addr = (const char*)dataaddr(); const char* addr = (const char*)dataaddr();
if (m_null) LL5("equal [" << col << "] " << *this);
addr = 0;
LL5("setval [" << m_col << "] " << *this);
if (col.m_pk)
CHK(con.equal(col.m_num, addr) == 0); CHK(con.equal(col.m_num, addr) == 0);
else 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); CHK(con.setValue(col.m_num, addr) == 0);
return 0; return 0;
} }
...@@ -1506,10 +1711,10 @@ Val::calckey(Par par, unsigned i) ...@@ -1506,10 +1711,10 @@ Val::calckey(Par par, unsigned i)
const Col& col = m_col; const Col& col = m_col;
m_null = false; m_null = false;
switch (col.m_type) { switch (col.m_type) {
case NdbDictionary::Column::Unsigned: case Col::Unsigned:
m_uint32 = i; m_uint32 = i;
break; break;
case NdbDictionary::Column::Char: case Col::Char:
{ {
const Chs* chs = col.m_chs; const Chs* chs = col.m_chs;
CHARSET_INFO* cs = chs->m_cs; CHARSET_INFO* cs = chs->m_cs;
...@@ -1549,10 +1754,10 @@ Val::calcnokey(Par par) ...@@ -1549,10 +1754,10 @@ Val::calcnokey(Par par)
} }
unsigned v = par.m_range + r; unsigned v = par.m_range + r;
switch (col.m_type) { switch (col.m_type) {
case NdbDictionary::Column::Unsigned: case Col::Unsigned:
m_uint32 = v; m_uint32 = v;
break; break;
case NdbDictionary::Column::Char: case Col::Char:
{ {
const Chs* chs = col.m_chs; const Chs* chs = col.m_chs;
CHARSET_INFO* cs = chs->m_cs; CHARSET_INFO* cs = chs->m_cs;
...@@ -1609,7 +1814,7 @@ Val::cmp(const Val& val2) const ...@@ -1609,7 +1814,7 @@ Val::cmp(const Val& val2) const
col.verify(val2.dataaddr()); col.verify(val2.dataaddr());
// compare // compare
switch (col.m_type) { switch (col.m_type) {
case NdbDictionary::Column::Unsigned: case Col::Unsigned:
{ {
if (m_uint32 < val2.m_uint32) if (m_uint32 < val2.m_uint32)
return -1; return -1;
...@@ -1618,7 +1823,7 @@ Val::cmp(const Val& val2) const ...@@ -1618,7 +1823,7 @@ Val::cmp(const Val& val2) const
return 0; return 0;
} }
break; break;
case NdbDictionary::Column::Char: case Col::Char:
{ {
const Chs* chs = col.m_chs; const Chs* chs = col.m_chs;
CHARSET_INFO* cs = chs->m_cs; CHARSET_INFO* cs = chs->m_cs;
...@@ -1657,10 +1862,10 @@ operator<<(NdbOut& out, const Val& val) ...@@ -1657,10 +1862,10 @@ operator<<(NdbOut& out, const Val& val)
return out; return out;
} }
switch (col.m_type) { switch (col.m_type) {
case NdbDictionary::Column::Unsigned: case Col::Unsigned:
out << val.m_uint32; out << val.m_uint32;
break; break;
case NdbDictionary::Column::Char: case Col::Char:
{ {
char buf[4 * 8000]; char buf[4 * 8000];
char *p = buf; char *p = buf;
...@@ -1697,19 +1902,25 @@ struct Row { ...@@ -1697,19 +1902,25 @@ struct Row {
const Tab& m_tab; const Tab& m_tab;
Val** m_val; Val** m_val;
bool m_exist; bool m_exist;
enum Op { NoOp = 0, ReadOp, InsOp, UpdOp, DelOp }; enum Op { NoOp = 0, ReadOp = 1, InsOp = 2, UpdOp = 4, DelOp = 8, AnyOp = 15 };
Op m_pending; Op m_pending;
Row* m_dbrow; // copy of db row before update
Row(const Tab& tab); Row(const Tab& tab);
~Row(); ~Row();
void copy(const Row& row2); void copy(const Row& row2);
void calc(Par par, unsigned i); void calc(Par par, unsigned i, unsigned mask = 0);
const Row& dbrow() const;
int verify(const Row& row2) const; int verify(const Row& row2) const;
int insrow(Par par); int insrow(Par par);
int updrow(Par par); int updrow(Par par);
int updrow(Par par, const ITab& itab);
int delrow(Par par); int delrow(Par par);
int delrow(Par par, const ITab& itab);
int selrow(Par par); int selrow(Par par);
int selrow(Par par, const ITab& itab);
int setrow(Par par); int setrow(Par par);
int cmp(const Row& row2) const; int cmp(const Row& row2) const;
int cmp(const Row& row2, const ITab& itab) const;
private: private:
Row& operator=(const Row& row2); Row& operator=(const Row& row2);
}; };
...@@ -1724,6 +1935,7 @@ Row::Row(const Tab& tab) : ...@@ -1724,6 +1935,7 @@ Row::Row(const Tab& tab) :
} }
m_exist = false; m_exist = false;
m_pending = NoOp; m_pending = NoOp;
m_dbrow = 0;
} }
Row::~Row() Row::~Row()
...@@ -1733,6 +1945,7 @@ Row::~Row() ...@@ -1733,6 +1945,7 @@ Row::~Row()
delete m_val[k]; delete m_val[k];
} }
delete [] m_val; delete [] m_val;
delete m_dbrow;
} }
void void
...@@ -1745,27 +1958,49 @@ Row::copy(const Row& row2) ...@@ -1745,27 +1958,49 @@ Row::copy(const Row& row2)
const Val& val2 = *row2.m_val[k]; const Val& val2 = *row2.m_val[k];
val.copy(val2); 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);
}
} }
void void
Row::calc(Par par, unsigned i) Row::calc(Par par, unsigned i, unsigned mask)
{ {
const Tab& tab = m_tab; const Tab& tab = m_tab;
for (unsigned k = 0; k < tab.m_cols; k++) { for (unsigned k = 0; k < tab.m_cols; k++) {
if (! (mask & (1 << k))) {
Val& val = *m_val[k]; Val& val = *m_val[k];
val.calc(par, i); 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;
} }
int int
Row::verify(const Row& row2) const Row::verify(const Row& row2) const
{ {
const Tab& tab = m_tab; const Tab& tab = m_tab;
assert(&tab == &row2.m_tab && m_exist && row2.m_exist); 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++) { for (unsigned k = 0; k < tab.m_cols; k++) {
const Val& val = *m_val[k]; const Val& val1 = *row1.m_val[k];
const Val& val2 = *row2.m_val[k]; const Val& val2 = *row2.m_val[k];
CHK(val.verify(val2) == 0); CHK(val1.verify(val2) == 0);
} }
return 0; return 0;
} }
...@@ -1780,6 +2015,14 @@ Row::insrow(Par par) ...@@ -1780,6 +2015,14 @@ Row::insrow(Par par)
CHKCON(con.m_op->insertTuple() == 0, con); CHKCON(con.m_op->insertTuple() == 0, con);
for (unsigned k = 0; k < tab.m_cols; k++) { for (unsigned k = 0; k < tab.m_cols; k++) {
const Val& val = *m_val[k]; const Val& val = *m_val[k];
const Col& col = val.m_col;
if (col.m_pk)
CHK(val.equal(par) == 0);
}
for (unsigned k = 0; k < tab.m_cols; k++) {
const Val& val = *m_val[k];
const Col& col = val.m_col;
if (! col.m_pk)
CHK(val.setval(par) == 0); CHK(val.setval(par) == 0);
} }
m_pending = InsOp; m_pending = InsOp;
...@@ -1794,18 +2037,42 @@ Row::updrow(Par par) ...@@ -1794,18 +2037,42 @@ Row::updrow(Par par)
assert(m_exist); assert(m_exist);
CHK(con.getNdbOperation(tab) == 0); CHK(con.getNdbOperation(tab) == 0);
CHKCON(con.m_op->updateTuple() == 0, con); CHKCON(con.m_op->updateTuple() == 0, con);
for (unsigned k = 0; k < tab.m_cols; k++) {
const Val& val = *m_val[k];
const Col& col = val.m_col;
if (col.m_pk)
CHK(val.equal(par) == 0);
}
for (unsigned k = 0; k < tab.m_cols; k++) { for (unsigned k = 0; k < tab.m_cols; k++) {
const Val& val = *m_val[k]; const Val& val = *m_val[k];
const Col& col = val.m_col; const Col& col = val.m_col;
if (! col.m_pk) if (! col.m_pk)
continue;
CHK(val.setval(par) == 0); CHK(val.setval(par) == 0);
} }
m_pending = UpdOp;
return 0;
}
int
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);
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;
const Val& val = *m_val[m];
CHK(val.equal(par, icol) == 0);
}
for (unsigned k = 0; k < tab.m_cols; k++) { for (unsigned k = 0; k < tab.m_cols; k++) {
const Val& val = *m_val[k]; const Val& val = *m_val[k];
const Col& col = val.m_col; const Col& col = val.m_col;
if (col.m_pk) if (! col.m_pk)
continue;
CHK(val.setval(par) == 0); CHK(val.setval(par) == 0);
} }
m_pending = UpdOp; m_pending = UpdOp;
...@@ -1824,7 +2091,27 @@ Row::delrow(Par par) ...@@ -1824,7 +2091,27 @@ Row::delrow(Par par)
const Val& val = *m_val[k]; const Val& val = *m_val[k];
const Col& col = val.m_col; const Col& col = val.m_col;
if (col.m_pk) if (col.m_pk)
CHK(val.setval(par) == 0); CHK(val.equal(par) == 0);
}
m_pending = DelOp;
return 0;
}
int
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);
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;
const Val& val = *m_val[m];
CHK(val.equal(par, icol) == 0);
} }
m_pending = DelOp; m_pending = DelOp;
return 0; return 0;
...@@ -1841,7 +2128,25 @@ Row::selrow(Par par) ...@@ -1841,7 +2128,25 @@ Row::selrow(Par par)
const Val& val = *m_val[k]; const Val& val = *m_val[k];
const Col& col = val.m_col; const Col& col = val.m_col;
if (col.m_pk) if (col.m_pk)
CHK(val.setval(par) == 0); CHK(val.equal(par) == 0);
}
return 0;
}
int
Row::selrow(Par par, const ITab& itab)
{
Con& con = par.con();
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);
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;
const Val& val = *m_val[m];
CHK(val.equal(par, icol) == 0);
} }
return 0; return 0;
} }
...@@ -1876,6 +2181,40 @@ Row::cmp(const Row& row2) const ...@@ -1876,6 +2181,40 @@ Row::cmp(const Row& row2) const
return c; return c;
} }
int
Row::cmp(const Row& row2, const ITab& itab) const
{
const Tab& tab = m_tab;
int c = 0;
for (unsigned 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;
assert(k < tab.m_cols);
const Val& val = *m_val[k];
const Val& val2 = *row2.m_val[k];
if ((c = val.cmp(val2)) != 0)
break;
}
return c;
}
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";
else
out << op;
return out;
}
static NdbOut& static NdbOut&
operator<<(NdbOut& out, const Row& row) operator<<(NdbOut& out, const Row& row)
{ {
...@@ -1885,10 +2224,21 @@ operator<<(NdbOut& out, const Row& row) ...@@ -1885,10 +2224,21 @@ operator<<(NdbOut& out, const Row& row)
out << " "; out << " ";
out << *row.m_val[i]; out << *row.m_val[i];
} }
out << " [exist=" << row.m_exist; out << " exist=" << row.m_exist;
if (row.m_pending) if (row.m_pending)
out << " pending=" << row.m_pending; out << " pending=" << row.m_pending;
out << "]"; 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;
return out; return out;
} }
...@@ -1898,38 +2248,47 @@ struct Set { ...@@ -1898,38 +2248,47 @@ struct Set {
const Tab& m_tab; const Tab& m_tab;
unsigned m_rows; unsigned m_rows;
Row** m_row; Row** m_row;
Row** m_saverow; unsigned* m_rowkey; // maps row number (from 0) in scan to tuple key
Row* m_keyrow; Row* m_keyrow;
NdbRecAttr** m_rec; NdbRecAttr** m_rec;
Set(const Tab& tab, unsigned rows); Set(const Tab& tab, unsigned rows);
~Set(); ~Set();
void reset(); void reset();
unsigned count() const; unsigned count() const;
// row methods // old and new values
bool exist(unsigned i) const; bool exist(unsigned i) const;
Row::Op pending(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); void notpending(unsigned i);
void notpending(const Lst& lst); void notpending(const Lst& lst);
void calc(Par par, unsigned i); void dbdiscard(unsigned i);
void dbdiscard(const Lst& lst);
const Row& dbrow(unsigned i) const;
// operations
int insrow(Par par, unsigned i); int insrow(Par par, unsigned i);
int updrow(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, unsigned i);
int selrow(Par par, unsigned i); int delrow(Par par, const ITab& itab, unsigned 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, unsigned i);
int getval(Par par); int getval(Par par);
int getkey(Par par, unsigned* i); int getkey(Par par, unsigned* i);
int putval(unsigned i, bool force); int putval(unsigned i, bool force, unsigned n = ~0);
// set methods // verify
int verify(const Set& set2) const; int verify(const Set& set2) const;
void savepoint(); int verifyorder(const ITab& itab, bool descending) const;
void commit();
void rollback();
// protect structure // protect structure
NdbMutex* m_mutex; NdbMutex* m_mutex;
void lock() { void lock() const {
NdbMutex_Lock(m_mutex); NdbMutex_Lock(m_mutex);
} }
void unlock() { void unlock() const {
NdbMutex_Unlock(m_mutex); NdbMutex_Unlock(m_mutex);
} }
private: private:
...@@ -1945,7 +2304,11 @@ Set::Set(const Tab& tab, unsigned rows) : ...@@ -1945,7 +2304,11 @@ Set::Set(const Tab& tab, unsigned rows) :
// allocate on need to save space // allocate on need to save space
m_row[i] = 0; m_row[i] = 0;
} }
m_saverow = 0; m_rowkey = new unsigned [m_rows];
for (unsigned n = 0; n < m_rows; n++) {
// initialize to null
m_rowkey[n] = ~0;
}
m_keyrow = new Row(tab); m_keyrow = new Row(tab);
m_rec = new NdbRecAttr* [tab.m_cols]; m_rec = new NdbRecAttr* [tab.m_cols];
for (unsigned k = 0; k < tab.m_cols; k++) { for (unsigned k = 0; k < tab.m_cols; k++) {
...@@ -1959,11 +2322,9 @@ Set::~Set() ...@@ -1959,11 +2322,9 @@ Set::~Set()
{ {
for (unsigned i = 0; i < m_rows; i++) { for (unsigned i = 0; i < m_rows; i++) {
delete m_row[i]; delete m_row[i];
if (m_saverow != 0)
delete m_saverow[i];
} }
delete [] m_row; delete [] m_row;
delete [] m_saverow; delete [] m_rowkey;
delete m_keyrow; delete m_keyrow;
delete [] m_rec; delete [] m_rec;
NdbMutex_Destroy(m_mutex); NdbMutex_Destroy(m_mutex);
...@@ -1994,6 +2355,8 @@ Set::count() const ...@@ -1994,6 +2355,8 @@ Set::count() const
return count; return count;
} }
// old and new values
bool bool
Set::exist(unsigned i) const Set::exist(unsigned i) const
{ {
...@@ -2003,13 +2366,37 @@ Set::exist(unsigned i) const ...@@ -2003,13 +2366,37 @@ Set::exist(unsigned i) const
return m_row[i]->m_exist; return m_row[i]->m_exist;
} }
Row::Op void
Set::pending(unsigned i) const Set::dbsave(unsigned i)
{
const Tab& tab = m_tab;
assert(i < m_rows && m_row[i] != 0);
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;
}
void
Set::calc(Par par, unsigned i, unsigned mask)
{
const Tab& tab = m_tab;
if (m_row[i] == 0)
m_row[i] = new Row(tab);
Row& row = *m_row[i];
row.calc(par, i, mask);
}
bool
Set::pending(unsigned i, unsigned mask) const
{ {
assert(i < m_rows); assert(i < m_rows);
if (m_row[i] == 0) // not allocated => not pending if (m_row[i] == 0) // not allocated => not pending
return Row::NoOp; return Row::NoOp;
return m_row[i]->m_pending; return m_row[i]->m_pending & mask;
} }
void void
...@@ -2017,10 +2404,13 @@ Set::notpending(unsigned i) ...@@ -2017,10 +2404,13 @@ Set::notpending(unsigned i)
{ {
assert(m_row[i] != 0); assert(m_row[i] != 0);
Row& row = *m_row[i]; Row& row = *m_row[i];
if (row.m_pending == Row::InsOp) if (row.m_pending == Row::InsOp) {
row.m_exist = true; row.m_exist = true;
if (row.m_pending == Row::DelOp) } else if (row.m_pending == Row::UpdOp) {
;
} else if (row.m_pending == Row::DelOp) {
row.m_exist = false; row.m_exist = false;
}
row.m_pending = Row::NoOp; row.m_pending = Row::NoOp;
} }
...@@ -2034,15 +2424,35 @@ Set::notpending(const Lst& lst) ...@@ -2034,15 +2424,35 @@ Set::notpending(const Lst& lst)
} }
void void
Set::calc(Par par, unsigned i) Set::dbdiscard(unsigned i)
{ {
const Tab& tab = m_tab; assert(m_row[i] != 0);
if (m_row[i] == 0)
m_row[i] = new Row(tab);
Row& row = *m_row[i]; Row& row = *m_row[i];
row.calc(par, i); LL5("dbdiscard " << i << ": " << row);
assert(row.m_dbrow != 0);
delete row.m_dbrow;
row.m_dbrow = 0;
} }
const Row&
Set::dbrow(unsigned i) const
{
assert(m_row[i] != 0);
Row& row = *m_row[i];
return row.dbrow();
}
void
Set::dbdiscard(const Lst& lst)
{
for (unsigned j = 0; j < lst.m_cnt; j++) {
unsigned i = lst.m_arr[j];
dbdiscard(i);
}
}
// operations
int int
Set::insrow(Par par, unsigned i) Set::insrow(Par par, unsigned i)
{ {
...@@ -2061,6 +2471,15 @@ Set::updrow(Par par, unsigned i) ...@@ -2061,6 +2471,15 @@ Set::updrow(Par par, unsigned i)
return 0; return 0;
} }
int
Set::updrow(Par par, const ITab& itab, unsigned i)
{
assert(m_row[i] != 0);
Row& row = *m_row[i];
CHK(row.updrow(par, itab) == 0);
return 0;
}
int int
Set::delrow(Par par, unsigned i) Set::delrow(Par par, unsigned i)
{ {
...@@ -2071,15 +2490,67 @@ Set::delrow(Par par, unsigned i) ...@@ -2071,15 +2490,67 @@ Set::delrow(Par par, unsigned i)
} }
int int
Set::selrow(Par par, unsigned i) Set::delrow(Par par, const ITab& itab, unsigned i)
{
assert(m_row[i] != 0);
Row& row = *m_row[i];
CHK(row.delrow(par, itab) == 0);
return 0;
}
int
Set::selrow(Par par, const Row& keyrow)
{ {
Con& con = par.con(); Con& con = par.con();
m_keyrow->calc(par, i); const Tab& tab = par.tab();
setkey(par, keyrow);
LL5("selrow " << tab.m_name << ": keyrow: " << keyrow);
CHK(m_keyrow->selrow(par) == 0); CHK(m_keyrow->selrow(par) == 0);
CHK(getval(par) == 0); CHK(getval(par) == 0);
return 0; return 0;
} }
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);
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 int
Set::setrow(Par par, unsigned i) Set::setrow(Par par, unsigned i)
{ {
...@@ -2114,7 +2585,7 @@ Set::getkey(Par par, unsigned* i) ...@@ -2114,7 +2585,7 @@ Set::getkey(Par par, unsigned* i)
} }
int int
Set::putval(unsigned i, bool force) Set::putval(unsigned i, bool force, unsigned n)
{ {
const Tab& tab = m_tab; const Tab& tab = m_tab;
if (m_row[i] == 0) if (m_row[i] == 0)
...@@ -2135,55 +2606,55 @@ Set::putval(unsigned i, bool force) ...@@ -2135,55 +2606,55 @@ Set::putval(unsigned i, bool force)
} }
if (! row.m_exist) if (! row.m_exist)
row.m_exist = true; row.m_exist = true;
if (n != ~0)
m_rowkey[n] = i;
return 0; return 0;
} }
// verify
int int
Set::verify(const Set& set2) const Set::verify(const Set& set2) const
{ {
const Tab& tab = m_tab; assert(&m_tab == &set2.m_tab && m_rows == set2.m_rows);
assert(&tab == &set2.m_tab && m_rows == set2.m_rows); LL4("verify set1 count=" << count() << " vs set2 count=" << set2.count());
LL3("verify set1 count=" << count() << " vs set2 count=" << set2.count());
for (unsigned i = 0; i < m_rows; i++) { for (unsigned i = 0; i < m_rows; i++) {
CHK(exist(i) == set2.exist(i)); bool ok = true;
if (! exist(i)) if (exist(i) != set2.exist(i)) {
continue; ok = false;
Row& row = *m_row[i]; } else if (exist(i)) {
Row& row2 = *set2.m_row[i]; if (dbrow(i).verify(set2.dbrow(i)) != 0)
CHK(row.verify(row2) == 0); ok = false;
}
if (! ok) {
LL1("verify failed: key=" << i << " row1=" << m_row[i] << " row2=" << set2.m_row[i]);
CHK(0 == 1);
}
} }
return 0; return 0;
} }
void int
Set::savepoint() Set::verifyorder(const ITab& itab, bool descending) const
{ {
const Tab& tab = m_tab; const Tab& tab = m_tab;
assert(m_saverow == 0); for (unsigned n = 0; n < m_rows; n++) {
m_saverow = new Row* [m_rows]; unsigned i2 = m_rowkey[n];
for (unsigned i = 0; i < m_rows; i++) { if (i2 == ~0)
if (m_row[i] == 0) break;
m_saverow[i] = 0; if (n == 0)
else { continue;
m_saverow[i] = new Row(tab); unsigned i1 = m_rowkey[n - 1];
m_saverow[i]->copy(*m_row[i]); assert(i1 < m_rows && i2 < m_rows);
} const Row& row1 = *m_row[i1];
const Row& row2 = *m_row[i2];
assert(row1.m_exist && row2.m_exist);
if (! descending)
CHK(row1.cmp(row2, itab) <= 0);
else
CHK(row1.cmp(row2, itab) >= 0);
} }
} return 0;
void
Set::commit()
{
delete [] m_saverow;
m_saverow = 0;
}
void
Set::rollback()
{
assert(m_saverow != 0);
m_row = m_saverow;
m_saverow = 0;
} }
static NdbOut& static NdbOut&
...@@ -2384,7 +2855,9 @@ BSet::filter(const Set& set, Set& set2) const ...@@ -2384,7 +2855,9 @@ BSet::filter(const Set& set, Set& set2) const
for (unsigned i = 0; i < set.m_rows; i++) { for (unsigned i = 0; i < set.m_rows; i++) {
if (! set.exist(i)) if (! set.exist(i))
continue; continue;
const Row& row = *set.m_row[i]; set.lock();
const Row& row = set.dbrow(i);
set.unlock();
if (! g_store_null_key) { if (! g_store_null_key) {
bool ok1 = false; bool ok1 = false;
for (unsigned k = 0; k < itab.m_icols; k++) { for (unsigned k = 0; k < itab.m_icols; k++) {
...@@ -2430,7 +2903,6 @@ BSet::filter(const Set& set, Set& set2) const ...@@ -2430,7 +2903,6 @@ BSet::filter(const Set& set, Set& set2) const
Row& row2 = *set2.m_row[i]; Row& row2 = *set2.m_row[i];
assert(! row2.m_exist); assert(! row2.m_exist);
row2.copy(row); row2.copy(row);
row2.m_exist = true;
} }
} }
...@@ -2451,15 +2923,16 @@ static int ...@@ -2451,15 +2923,16 @@ static int
pkinsert(Par par) pkinsert(Par par)
{ {
Con& con = par.con(); Con& con = par.con();
const Tab& tab = par.tab();
Set& set = par.set(); Set& set = par.set();
LL3("pkinsert"); LL3("pkinsert " << tab.m_name);
CHK(con.startTransaction() == 0); CHK(con.startTransaction() == 0);
Lst lst; Lst lst;
for (unsigned j = 0; j < par.m_rows; j++) { for (unsigned j = 0; j < par.m_rows; j++) {
unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
unsigned i = thrrow(par, j2); unsigned i = thrrow(par, j2);
set.lock(); set.lock();
if (set.exist(i) || set.pending(i)) { if (set.exist(i) || set.pending(i, Row::AnyOp)) {
set.unlock(); set.unlock();
continue; continue;
} }
...@@ -2473,7 +2946,7 @@ pkinsert(Par par) ...@@ -2473,7 +2946,7 @@ pkinsert(Par par)
CHK(con.execute(Commit, deadlock) == 0); CHK(con.execute(Commit, deadlock) == 0);
con.closeTransaction(); con.closeTransaction();
if (deadlock) { if (deadlock) {
LL1("pkinsert: stop on deadlock"); LL1("pkinsert: stop on deadlock [at 1]");
return 0; return 0;
} }
set.lock(); set.lock();
...@@ -2488,7 +2961,7 @@ pkinsert(Par par) ...@@ -2488,7 +2961,7 @@ pkinsert(Par par)
CHK(con.execute(Commit, deadlock) == 0); CHK(con.execute(Commit, deadlock) == 0);
con.closeTransaction(); con.closeTransaction();
if (deadlock) { if (deadlock) {
LL1("pkinsert: stop on deadlock"); LL1("pkinsert: stop on deadlock [at 2]");
return 0; return 0;
} }
set.lock(); set.lock();
...@@ -2504,8 +2977,9 @@ static int ...@@ -2504,8 +2977,9 @@ static int
pkupdate(Par par) pkupdate(Par par)
{ {
Con& con = par.con(); Con& con = par.con();
const Tab& tab = par.tab();
Set& set = par.set(); Set& set = par.set();
LL3("pkupdate"); LL3("pkupdate " << tab.m_name);
CHK(con.startTransaction() == 0); CHK(con.startTransaction() == 0);
Lst lst; Lst lst;
bool deadlock = false; bool deadlock = false;
...@@ -2513,10 +2987,11 @@ pkupdate(Par par) ...@@ -2513,10 +2987,11 @@ pkupdate(Par par)
unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
unsigned i = thrrow(par, j2); unsigned i = thrrow(par, j2);
set.lock(); set.lock();
if (! set.exist(i) || set.pending(i)) { if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
set.unlock(); set.unlock();
continue; continue;
} }
set.dbsave(i);
set.calc(par, i); set.calc(par, i);
CHK(set.updrow(par, i) == 0); CHK(set.updrow(par, i) == 0);
set.unlock(); set.unlock();
...@@ -2526,12 +3001,13 @@ pkupdate(Par par) ...@@ -2526,12 +3001,13 @@ pkupdate(Par par)
deadlock = par.m_deadlock; deadlock = par.m_deadlock;
CHK(con.execute(Commit, deadlock) == 0); CHK(con.execute(Commit, deadlock) == 0);
if (deadlock) { if (deadlock) {
LL1("pkupdate: stop on deadlock"); LL1("pkupdate: stop on deadlock [at 1]");
break; break;
} }
con.closeTransaction(); con.closeTransaction();
set.lock(); set.lock();
set.notpending(lst); set.notpending(lst);
set.dbdiscard(lst);
set.unlock(); set.unlock();
lst.reset(); lst.reset();
CHK(con.startTransaction() == 0); CHK(con.startTransaction() == 0);
...@@ -2541,10 +3017,11 @@ pkupdate(Par par) ...@@ -2541,10 +3017,11 @@ pkupdate(Par par)
deadlock = par.m_deadlock; deadlock = par.m_deadlock;
CHK(con.execute(Commit, deadlock) == 0); CHK(con.execute(Commit, deadlock) == 0);
if (deadlock) { if (deadlock) {
LL1("pkupdate: stop on deadlock"); LL1("pkupdate: stop on deadlock [at 1]");
} else { } else {
set.lock(); set.lock();
set.notpending(lst); set.notpending(lst);
set.dbdiscard(lst);
set.unlock(); set.unlock();
} }
} }
...@@ -2556,8 +3033,9 @@ static int ...@@ -2556,8 +3033,9 @@ static int
pkdelete(Par par) pkdelete(Par par)
{ {
Con& con = par.con(); Con& con = par.con();
const Tab& tab = par.tab();
Set& set = par.set(); Set& set = par.set();
LL3("pkdelete"); LL3("pkdelete " << tab.m_name);
CHK(con.startTransaction() == 0); CHK(con.startTransaction() == 0);
Lst lst; Lst lst;
bool deadlock = false; bool deadlock = false;
...@@ -2565,7 +3043,7 @@ pkdelete(Par par) ...@@ -2565,7 +3043,7 @@ pkdelete(Par par)
unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
unsigned i = thrrow(par, j2); unsigned i = thrrow(par, j2);
set.lock(); set.lock();
if (! set.exist(i) || set.pending(i)) { if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
set.unlock(); set.unlock();
continue; continue;
} }
...@@ -2577,7 +3055,7 @@ pkdelete(Par par) ...@@ -2577,7 +3055,7 @@ pkdelete(Par par)
deadlock = par.m_deadlock; deadlock = par.m_deadlock;
CHK(con.execute(Commit, deadlock) == 0); CHK(con.execute(Commit, deadlock) == 0);
if (deadlock) { if (deadlock) {
LL1("pkdelete: stop on deadlock"); LL1("pkdelete: stop on deadlock [at 1]");
break; break;
} }
con.closeTransaction(); con.closeTransaction();
...@@ -2592,7 +3070,7 @@ pkdelete(Par par) ...@@ -2592,7 +3070,7 @@ pkdelete(Par par)
deadlock = par.m_deadlock; deadlock = par.m_deadlock;
CHK(con.execute(Commit, deadlock) == 0); CHK(con.execute(Commit, deadlock) == 0);
if (deadlock) { if (deadlock) {
LL1("pkdelete: stop on deadlock"); LL1("pkdelete: stop on deadlock [at 2]");
} else { } else {
set.lock(); set.lock();
set.notpending(lst); set.notpending(lst);
...@@ -2609,19 +3087,19 @@ pkread(Par par) ...@@ -2609,19 +3087,19 @@ pkread(Par par)
Con& con = par.con(); Con& con = par.con();
const Tab& tab = par.tab(); const Tab& tab = par.tab();
Set& set = par.set(); Set& set = par.set();
LL3((par.m_verify ? "pkverify " : "pkread ") << tab.m_name); LL3("pkread " << tab.m_name << " verify=" << par.m_verify);
// expected // expected
const Set& set1 = set; const Set& set1 = set;
Set set2(tab, set.m_rows); Set set2(tab, set.m_rows);
for (unsigned i = 0; i < set.m_rows; i++) { for (unsigned i = 0; i < set.m_rows; i++) {
set.lock(); set.lock();
if (! set.exist(i) || set.pending(i)) { if (! set.exist(i)) {
set.unlock(); set.unlock();
continue; continue;
} }
set.unlock(); set.unlock();
CHK(con.startTransaction() == 0); CHK(con.startTransaction() == 0);
CHK(set2.selrow(par, i) == 0); CHK(set2.selrow(par, *set1.m_row[i]) == 0);
CHK(con.execute(Commit) == 0); CHK(con.execute(Commit) == 0);
unsigned i2 = (unsigned)-1; unsigned i2 = (unsigned)-1;
CHK(set2.getkey(par, &i2) == 0 && i == i2); CHK(set2.getkey(par, &i2) == 0 && i == i2);
...@@ -2659,6 +3137,146 @@ pkreadfast(Par par, unsigned count) ...@@ -2659,6 +3137,146 @@ pkreadfast(Par par, unsigned count)
return 0; return 0;
} }
// hash index operations
static int
hashindexupdate(Par par, const ITab& itab)
{
Con& con = par.con();
Set& set = par.set();
LL3("hashindexupdate " << itab.m_name);
CHK(con.startTransaction() == 0);
Lst lst;
bool deadlock = 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);
set.lock();
if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
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) == 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) == 0);
if (deadlock) {
LL1("hashindexupdate: stop on deadlock [at 1]");
} else {
set.lock();
set.notpending(lst);
set.dbdiscard(lst);
set.unlock();
}
}
con.closeTransaction();
return 0;
};
static int
hashindexdelete(Par par, const ITab& itab)
{
Con& con = par.con();
Set& set = par.set();
LL3("hashindexdelete " << itab.m_name);
CHK(con.startTransaction() == 0);
Lst lst;
bool deadlock = 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);
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) == 0);
if (deadlock) {
LL1("hashindexdelete: stop on deadlock [at 1]");
break;
}
con.closeTransaction();
set.lock();
set.notpending(lst);
set.unlock();
lst.reset();
CHK(con.startTransaction() == 0);
}
}
if (! deadlock && lst.cnt() != 0) {
deadlock = par.m_deadlock;
CHK(con.execute(Commit, deadlock) == 0);
if (deadlock) {
LL1("hashindexdelete: stop on deadlock [at 2]");
} else {
set.lock();
set.notpending(lst);
set.unlock();
}
}
con.closeTransaction();
return 0;
};
static int
hashindexread(Par par, const ITab& itab)
{
Con& con = par.con();
const Tab& tab = par.tab();
Set& set = par.set();
LL3("hashindexread " << itab.m_name << " verify=" << par.m_verify);
// expected
const Set& set1 = set;
Set set2(tab, set.m_rows);
for (unsigned i = 0; i < set.m_rows; i++) {
set.lock();
if (! set.exist(i)) {
set.unlock();
continue;
}
set.unlock();
CHK(con.startTransaction() == 0);
CHK(set2.selrow(par, itab, *set1.m_row[i]) == 0);
CHK(con.execute(Commit) == 0);
unsigned i2 = (unsigned)-1;
CHK(set2.getkey(par, &i2) == 0 && i == i2);
CHK(set2.putval(i, false) == 0);
LL4("row " << set2.count() << ": " << *set2.m_row[i]);
con.closeTransaction();
}
if (par.m_verify)
CHK(set1.verify(set2) == 0);
return 0;
}
// scan read // scan read
static int static int
...@@ -2691,14 +3309,14 @@ scanreadtable(Par par) ...@@ -2691,14 +3309,14 @@ scanreadtable(Par par)
} }
unsigned i = (unsigned)-1; unsigned i = (unsigned)-1;
CHK(set2.getkey(par, &i) == 0); CHK(set2.getkey(par, &i) == 0);
CHK(set2.putval(i, false) == 0); CHK(set2.putval(i, false, n) == 0);
LL4("row " << n << ": " << *set2.m_row[i]); LL4("row " << n << ": " << *set2.m_row[i]);
n++; n++;
} }
con.closeTransaction(); con.closeTransaction();
if (par.m_verify) if (par.m_verify)
CHK(set1.verify(set2) == 0); CHK(set1.verify(set2) == 0);
LL3("scanread " << tab.m_name << " rows=" << n); LL3("scanread " << tab.m_name << " done rows=" << n);
return 0; return 0;
} }
...@@ -2745,19 +3363,22 @@ scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc) ...@@ -2745,19 +3363,22 @@ scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc)
// prefer proper subset // prefer proper subset
if (0 < n && n < set.m_rows) if (0 < n && n < set.m_rows)
break; break;
if (urandom(5) == 0) if (urandom(3) == 0)
break; break;
set1.reset(); set1.reset();
} }
} else { } else {
bset.filter(set, set1); bset.filter(set, set1);
} }
LL3("scanread " << itab.m_name << " bounds=" << bset.m_bvals << " verify=" << par.m_verify); LL3("scanread " << itab.m_name << " bounds=" << bset << " verify=" << par.m_verify << " ordered=" << par.m_ordered << " descending=" << par.m_descending);
LL4("expect " << set1.count() << " rows"); LL4("expect " << set1.count() << " rows");
Set set2(tab, set.m_rows); Set set2(tab, set.m_rows);
CHK(con.startTransaction() == 0); CHK(con.startTransaction() == 0);
CHK(con.getNdbScanOperation(itab, tab) == 0); CHK(con.getNdbScanOperation(itab, tab) == 0);
if (! par.m_ordered)
CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0); CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0);
else
CHK(con.openScanOrdered(par.m_scanbat, par.m_scanpar, par.m_descending) == 0);
CHK(bset.setbnd(par) == 0); CHK(bset.setbnd(par) == 0);
set2.getval(par); set2.getval(par);
CHK(con.executeScan() == 0); CHK(con.executeScan() == 0);
...@@ -2775,15 +3396,17 @@ scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc) ...@@ -2775,15 +3396,17 @@ scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc)
} }
unsigned i = (unsigned)-1; unsigned i = (unsigned)-1;
CHK(set2.getkey(par, &i) == 0); CHK(set2.getkey(par, &i) == 0);
LL4("key " << i); CHK(set2.putval(i, par.m_dups, n) == 0);
CHK(set2.putval(i, par.m_dups) == 0); LL4("key " << i << " row " << n << ": " << *set2.m_row[i]);
LL4("row " << n << ": " << *set2.m_row[i]);
n++; n++;
} }
con.closeTransaction(); con.closeTransaction();
if (par.m_verify) if (par.m_verify) {
CHK(set1.verify(set2) == 0); CHK(set1.verify(set2) == 0);
LL3("scanread " << itab.m_name << " rows=" << n); if (par.m_ordered)
CHK(set2.verifyorder(itab, par.m_descending) == 0);
}
LL3("scanread " << itab.m_name << " done rows=" << n);
return 0; return 0;
} }
...@@ -2821,9 +3444,11 @@ scanreadindex(Par par, const ITab& itab) ...@@ -2821,9 +3444,11 @@ scanreadindex(Par par, const ITab& itab)
{ {
const Tab& tab = par.tab(); const Tab& tab = par.tab();
for (unsigned i = 0; i < par.m_subsubloop; i++) { for (unsigned i = 0; i < par.m_subsubloop; i++) {
if (itab.m_type == ITab::OrderedIndex) {
BSet bset(tab, itab, par.m_rows); BSet bset(tab, itab, par.m_rows);
CHK(scanreadindex(par, itab, bset, true) == 0); CHK(scanreadindex(par, itab, bset, true) == 0);
} }
}
return 0; return 0;
} }
...@@ -2835,7 +3460,11 @@ scanreadindex(Par par) ...@@ -2835,7 +3460,11 @@ scanreadindex(Par par)
if (tab.m_itab[i] == 0) if (tab.m_itab[i] == 0)
continue; continue;
const ITab& itab = *tab.m_itab[i]; const ITab& itab = *tab.m_itab[i];
if (itab.m_type == ITab::OrderedIndex) {
CHK(scanreadindex(par, itab) == 0); CHK(scanreadindex(par, itab) == 0);
} else {
CHK(hashindexread(par, itab) == 0);
}
} }
return 0; return 0;
} }
...@@ -2932,7 +3561,7 @@ scanupdatetable(Par par) ...@@ -2932,7 +3561,7 @@ scanupdatetable(Par par)
if (ret == 1) if (ret == 1)
break; break;
if (deadlock) { if (deadlock) {
LL1("scanupdatetable: stop on deadlock"); LL1("scanupdatetable: stop on deadlock [at 1]");
break; break;
} }
if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) { if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) {
...@@ -2944,13 +3573,14 @@ scanupdatetable(Par par) ...@@ -2944,13 +3573,14 @@ scanupdatetable(Par par)
CHK(set2.getkey(par, &i) == 0); CHK(set2.getkey(par, &i) == 0);
const Row& row = *set.m_row[i]; const Row& row = *set.m_row[i];
set.lock(); set.lock();
if (! set.exist(i) || set.pending(i)) { if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
LL4("scan update " << tab.m_name << ": skip: " << row); LL4("scan update " << tab.m_name << ": skip: " << row);
} else { } else {
CHKTRY(set2.putval(i, false) == 0, set.unlock()); CHKTRY(set2.putval(i, false) == 0, set.unlock());
CHKTRY(con.updateScanTuple(con2) == 0, set.unlock()); CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
Par par2 = par; Par par2 = par;
par2.m_con = &con2; par2.m_con = &con2;
set.dbsave(i);
set.calc(par, i); set.calc(par, i);
CHKTRY(set.setrow(par2, i) == 0, set.unlock()); CHKTRY(set.setrow(par2, i) == 0, set.unlock());
LL4("scan update " << tab.m_name << ": " << row); LL4("scan update " << tab.m_name << ": " << row);
...@@ -2961,12 +3591,13 @@ scanupdatetable(Par par) ...@@ -2961,12 +3591,13 @@ scanupdatetable(Par par)
deadlock = par.m_deadlock; deadlock = par.m_deadlock;
CHK(con2.execute(Commit, deadlock) == 0); CHK(con2.execute(Commit, deadlock) == 0);
if (deadlock) { if (deadlock) {
LL1("scanupdateindex: stop on deadlock"); LL1("scanupdatetable: stop on deadlock [at 2]");
goto out; goto out;
} }
con2.closeTransaction(); con2.closeTransaction();
set.lock(); set.lock();
set.notpending(lst); set.notpending(lst);
set.dbdiscard(lst);
set.unlock(); set.unlock();
count += lst.cnt(); count += lst.cnt();
lst.reset(); lst.reset();
...@@ -2977,12 +3608,13 @@ scanupdatetable(Par par) ...@@ -2977,12 +3608,13 @@ scanupdatetable(Par par)
deadlock = par.m_deadlock; deadlock = par.m_deadlock;
CHK(con2.execute(Commit, deadlock) == 0); CHK(con2.execute(Commit, deadlock) == 0);
if (deadlock) { if (deadlock) {
LL1("scanupdateindex: stop on deadlock"); LL1("scanupdatetable: stop on deadlock [at 3]");
goto out; goto out;
} }
con2.closeTransaction(); con2.closeTransaction();
set.lock(); set.lock();
set.notpending(lst); set.notpending(lst);
set.dbdiscard(lst);
set.unlock(); set.unlock();
count += lst.cnt(); count += lst.cnt();
lst.reset(); lst.reset();
...@@ -3009,7 +3641,10 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset) ...@@ -3009,7 +3641,10 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
Set set2(tab, set.m_rows); Set set2(tab, set.m_rows);
CHK(con.startTransaction() == 0); CHK(con.startTransaction() == 0);
CHK(con.getNdbScanOperation(itab, tab) == 0); CHK(con.getNdbScanOperation(itab, tab) == 0);
if (! par.m_ordered)
CHK(con.openScanExclusive(par.m_scanbat, par.m_scanpar) == 0); CHK(con.openScanExclusive(par.m_scanbat, par.m_scanpar) == 0);
else
CHK(con.openScanOrderedExclusive(par.m_scanbat, par.m_scanpar, par.m_descending) == 0);
CHK(bset.setbnd(par) == 0); CHK(bset.setbnd(par) == 0);
set2.getval(par); set2.getval(par);
CHK(con.executeScan() == 0); CHK(con.executeScan() == 0);
...@@ -3027,7 +3662,7 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset) ...@@ -3027,7 +3662,7 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
if (ret == 1) if (ret == 1)
break; break;
if (deadlock) { if (deadlock) {
LL1("scanupdateindex: stop on deadlock"); LL1("scanupdateindex: stop on deadlock [at 1]");
break; break;
} }
if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) { if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) {
...@@ -3039,13 +3674,14 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset) ...@@ -3039,13 +3674,14 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
CHK(set2.getkey(par, &i) == 0); CHK(set2.getkey(par, &i) == 0);
const Row& row = *set.m_row[i]; const Row& row = *set.m_row[i];
set.lock(); set.lock();
if (! set.exist(i) || set.pending(i)) { if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
LL4("scan update " << itab.m_name << ": skip: " << row); LL4("scan update " << itab.m_name << ": skip: " << row);
} else { } else {
CHKTRY(set2.putval(i, par.m_dups) == 0, set.unlock()); CHKTRY(set2.putval(i, par.m_dups) == 0, set.unlock());
CHKTRY(con.updateScanTuple(con2) == 0, set.unlock()); CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
Par par2 = par; Par par2 = par;
par2.m_con = &con2; par2.m_con = &con2;
set.dbsave(i);
set.calc(par, i); set.calc(par, i);
CHKTRY(set.setrow(par2, i) == 0, set.unlock()); CHKTRY(set.setrow(par2, i) == 0, set.unlock());
LL4("scan update " << itab.m_name << ": " << row); LL4("scan update " << itab.m_name << ": " << row);
...@@ -3056,12 +3692,13 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset) ...@@ -3056,12 +3692,13 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
deadlock = par.m_deadlock; deadlock = par.m_deadlock;
CHK(con2.execute(Commit, deadlock) == 0); CHK(con2.execute(Commit, deadlock) == 0);
if (deadlock) { if (deadlock) {
LL1("scanupdateindex: stop on deadlock"); LL1("scanupdateindex: stop on deadlock [at 2]");
goto out; goto out;
} }
con2.closeTransaction(); con2.closeTransaction();
set.lock(); set.lock();
set.notpending(lst); set.notpending(lst);
set.dbdiscard(lst);
set.unlock(); set.unlock();
count += lst.cnt(); count += lst.cnt();
lst.reset(); lst.reset();
...@@ -3072,12 +3709,13 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset) ...@@ -3072,12 +3709,13 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
deadlock = par.m_deadlock; deadlock = par.m_deadlock;
CHK(con2.execute(Commit, deadlock) == 0); CHK(con2.execute(Commit, deadlock) == 0);
if (deadlock) { if (deadlock) {
LL1("scanupdateindex: stop on deadlock"); LL1("scanupdateindex: stop on deadlock [at 3]");
goto out; goto out;
} }
con2.closeTransaction(); con2.closeTransaction();
set.lock(); set.lock();
set.notpending(lst); set.notpending(lst);
set.dbdiscard(lst);
set.unlock(); set.unlock();
count += lst.cnt(); count += lst.cnt();
lst.reset(); lst.reset();
...@@ -3097,9 +3735,13 @@ scanupdateindex(Par par, const ITab& itab) ...@@ -3097,9 +3735,13 @@ scanupdateindex(Par par, const ITab& itab)
{ {
const Tab& tab = par.tab(); const Tab& tab = par.tab();
for (unsigned i = 0; i < par.m_subsubloop; i++) { for (unsigned i = 0; i < par.m_subsubloop; i++) {
if (itab.m_type == ITab::OrderedIndex) {
BSet bset(tab, itab, par.m_rows); BSet bset(tab, itab, par.m_rows);
bset.calc(par); bset.calc(par);
CHK(scanupdateindex(par, itab, bset) == 0); CHK(scanupdateindex(par, itab, bset) == 0);
} else {
CHK(hashindexupdate(par, itab) == 0);
}
} }
return 0; return 0;
} }
...@@ -3151,8 +3793,12 @@ readverifyfull(Par par) ...@@ -3151,8 +3793,12 @@ readverifyfull(Par par)
unsigned i = par.m_no - 1; unsigned i = par.m_no - 1;
if (i < tab.m_itabs && tab.m_itab[i] != 0) { if (i < tab.m_itabs && tab.m_itab[i] != 0) {
const ITab& itab = *tab.m_itab[i]; const ITab& itab = *tab.m_itab[i];
if (itab.m_type == ITab::OrderedIndex) {
BSet bset(tab, itab, par.m_rows); BSet bset(tab, itab, par.m_rows);
CHK(scanreadindex(par, itab, bset, false) == 0); CHK(scanreadindex(par, itab, bset, false) == 0);
} else {
CHK(hashindexread(par, itab) == 0);
}
} }
} }
return 0; return 0;
...@@ -3162,6 +3808,11 @@ static int ...@@ -3162,6 +3808,11 @@ static int
readverifyindex(Par par) readverifyindex(Par par)
{ {
par.m_verify = true; par.m_verify = true;
unsigned sel = urandom(10);
if (sel < 9) {
par.m_ordered = true;
par.m_descending = (sel < 5);
}
CHK(scanreadindex(par) == 0); CHK(scanreadindex(par) == 0);
return 0; return 0;
} }
...@@ -3169,26 +3820,56 @@ readverifyindex(Par par) ...@@ -3169,26 +3820,56 @@ readverifyindex(Par par)
static int static int
pkops(Par par) pkops(Par par)
{ {
const Tab& tab = par.tab();
par.m_randomkey = true; par.m_randomkey = true;
for (unsigned i = 0; i < par.m_subsubloop; i++) { for (unsigned i = 0; i < par.m_subsubloop; i++) {
unsigned j = 0;
while (j < tab.m_itabs) {
if (tab.m_itab[j] != 0) {
const ITab& itab = *tab.m_itab[j];
if (itab.m_type == ITab::UniqueHashIndex && urandom(5) == 0)
break;
}
j++;
}
unsigned sel = urandom(10); unsigned sel = urandom(10);
if (par.m_slno % 2 == 0) { if (par.m_slno % 2 == 0) {
// favor insert // favor insert
if (sel < 8) { if (sel < 8) {
CHK(pkinsert(par) == 0); CHK(pkinsert(par) == 0);
} else if (sel < 9) { } else if (sel < 9) {
if (j == tab.m_itabs)
CHK(pkupdate(par) == 0); CHK(pkupdate(par) == 0);
else {
const ITab& itab = *tab.m_itab[j];
CHK(hashindexupdate(par, itab) == 0);
}
} else { } else {
if (j == tab.m_itabs)
CHK(pkdelete(par) == 0); CHK(pkdelete(par) == 0);
else {
const ITab& itab = *tab.m_itab[j];
CHK(hashindexdelete(par, itab) == 0);
}
} }
} else { } else {
// favor delete // favor delete
if (sel < 1) { if (sel < 1) {
CHK(pkinsert(par) == 0); CHK(pkinsert(par) == 0);
} else if (sel < 2) { } else if (sel < 2) {
if (j == tab.m_itabs)
CHK(pkupdate(par) == 0); CHK(pkupdate(par) == 0);
else {
const ITab& itab = *tab.m_itab[j];
CHK(hashindexupdate(par, itab) == 0);
}
} else { } else {
if (j == tab.m_itabs)
CHK(pkdelete(par) == 0); CHK(pkdelete(par) == 0);
else {
const ITab& itab = *tab.m_itab[j];
CHK(hashindexdelete(par, itab) == 0);
}
} }
} }
} }
...@@ -3208,6 +3889,10 @@ pkupdatescanread(Par par) ...@@ -3208,6 +3889,10 @@ pkupdatescanread(Par par)
CHK(scanreadtable(par) == 0); CHK(scanreadtable(par) == 0);
} else { } else {
par.m_verify = false; par.m_verify = false;
if (sel < 8) {
par.m_ordered = true;
par.m_descending = (sel < 7);
}
CHK(scanreadindex(par) == 0); CHK(scanreadindex(par) == 0);
} }
return 0; return 0;
...@@ -3227,6 +3912,10 @@ mixedoperations(Par par) ...@@ -3227,6 +3912,10 @@ mixedoperations(Par par)
} else if (sel < 6) { } else if (sel < 6) {
CHK(scanupdatetable(par) == 0); CHK(scanupdatetable(par) == 0);
} else { } else {
if (sel < 8) {
par.m_ordered = true;
par.m_descending = (sel < 7);
}
CHK(scanupdateindex(par) == 0); CHK(scanupdateindex(par) == 0);
} }
return 0; return 0;
...@@ -3720,7 +4409,7 @@ printtables() ...@@ -3720,7 +4409,7 @@ printtables()
{ {
Par par(g_opt); Par par(g_opt);
makebuiltintables(par); makebuiltintables(par);
ndbout << "builtin tables (index x0 is on table pk):" << endl; ndbout << "builtin tables (x0 on pk, x=ordered z=hash):" << endl;
for (unsigned j = 0; j < tabcount; j++) { for (unsigned j = 0; j < tabcount; j++) {
if (tablist[j] == 0) if (tablist[j] == 0)
continue; continue;
...@@ -3744,6 +4433,7 @@ runtest(Par par) ...@@ -3744,6 +4433,7 @@ runtest(Par par)
LL1("random seed: " << seed); LL1("random seed: " << seed);
srandom((unsigned)seed); srandom((unsigned)seed);
} else if (par.m_seed != 0) } else if (par.m_seed != 0)
LL1("random seed: " << par.m_seed);
srandom(par.m_seed); srandom(par.m_seed);
// cs // cs
assert(par.m_csname != 0); assert(par.m_csname != 0);
...@@ -3953,6 +4643,7 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535) ...@@ -3953,6 +4643,7 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535)
if (strcmp(arg, "-threads") == 0) { if (strcmp(arg, "-threads") == 0) {
if (++argv, --argc > 0) { if (++argv, --argc > 0) {
g_opt.m_threads = atoi(argv[0]); g_opt.m_threads = atoi(argv[0]);
if (1 <= g_opt.m_threads)
continue; continue;
} }
} }
...@@ -3970,7 +4661,7 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535) ...@@ -3970,7 +4661,7 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535)
printhelp(); printhelp();
goto wrongargs; goto wrongargs;
} }
ndbout << "testOIBasic: unknown option " << arg; ndbout << "testOIBasic: bad or unknown option " << arg;
goto usage; goto usage;
} }
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment