1
/* Copyright (C) 2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
* testOIBasic - ordered index test
20
#include <ndb_global.h>
25
#include <NdbTest.hpp>
27
#include <NdbCondition.h>
28
#include <NdbThread.h>
32
#include <NdbSqlUtil.hpp>
33
#include <ndb_version.h>
49
NdbDictionary::Object::FragmentType m_fragtype;
67
int m_v; // int for lint
79
m_fragtype(NdbDictionary::Object::FragUndefined),
103
static void printcases();
104
static void printtables();
111
<< "usage: testOIbasic [options]" << endl
112
<< " -batch N pk operations in batch [" << d.m_batch << "]" << endl
113
<< " -bound xyz use only these bound types 0-4 [" << d.m_bound << "]" << endl
114
<< " -case abc only given test cases (letters a-z)" << endl
115
<< " -collsp use strnncollsp instead of strnxfrm" << endl
116
<< " -cont on error continue to next test case [" << d.m_cont << "]" << endl
117
<< " -core core dump on error [" << d.m_core << "]" << endl
118
<< " -csname S charset or collation [" << d.m_csname << "]" << endl
119
<< " -die nnn exit immediately on NDB error code nnn" << endl
120
<< " -dups allow duplicate tuples from index scan [" << d.m_dups << "]" << endl
121
<< " -fragtype T fragment type single/small/medium/large" << endl
122
<< " -index xyz only given index numbers (digits 0-9)" << endl
123
<< " -loop N loop count full suite 0=forever [" << d.m_loop << "]" << endl
124
<< " -nologging create tables in no-logging mode" << endl
125
<< " -noverify skip index verifications" << endl
126
<< " -pctnull N pct NULL values in nullable column [" << d.m_pctnull << "]" << endl
127
<< " -rows N rows per thread [" << d.m_rows << "]" << endl
128
<< " -samples N samples for some timings (0=all) [" << d.m_samples << "]" << endl
129
<< " -scanbatch N scan batch 0=default [" << d.m_scanbatch << "]" << endl
130
<< " -scanpar N scan parallel 0=default [" << d.m_scanpar << "]" << endl
131
<< " -seed N srandom seed 0=loop number -1=random [" << d.m_seed << "]" << endl
132
<< " -skip abc skip given test cases (letters a-z)" << endl
133
<< " -sloop N level 2 (sub)loop count [" << d.m_sloop << "]" << endl
134
<< " -ssloop N level 3 (sub)loop count [" << d.m_ssloop << "]" << endl
135
<< " -table xyz only given table numbers (digits 0-9)" << endl
136
<< " -threads N number of threads [" << d.m_threads << "]" << endl
137
<< " -vN verbosity [" << d.m_v << "]" << endl
138
<< " -h or -help print this help text" << endl
144
// not yet configurable
145
static const bool g_store_null_key = true;
147
// compare NULL like normal value (NULL < not NULL, NULL == NULL)
148
static const bool g_compare_null = true;
150
static const char* hexstr = "0123456789abcdef";
159
uint i = random() % n;
168
int i = random() % n;
181
return urandom(100) < pct;
185
random_coprime(uint n)
187
uint prime[] = { 101, 211, 307, 401, 503, 601, 701, 809, 907 };
188
uint count = sizeof(prime) / sizeof(prime[0]);
192
uint i = urandom(count);
193
if (n % prime[i] != 0)
198
// random re-sequence of 0...(n-1)
214
m_start = urandom(n);
215
m_prime = random_coprime(n);
222
return (m_start + m_i++ * m_prime) % m_n;
225
// log and error macros
227
static NdbMutex *ndbout_mutex = NULL;
228
static const char* getthrprefix();
232
if ((n) > g_opt.m_v) break; \
233
if (g_opt.m_msglock) NdbMutex_Lock(ndbout_mutex); \
234
ndbout << getthrprefix(); \
236
ndbout << "line " << __LINE__ << ": "; \
237
ndbout << s << endl; \
238
if (g_opt.m_msglock) NdbMutex_Unlock(ndbout_mutex); \
241
#define LL0(s) LLN(0, s)
242
#define LL1(s) LLN(1, s)
243
#define LL2(s) LLN(2, s)
244
#define LL3(s) LLN(3, s)
245
#define LL4(s) LLN(4, s)
246
#define LL5(s) LLN(5, s)
248
#define HEX(x) hex << (x) << dec
250
// following check a condition and return -1 on failure
252
#undef CHK // simple check
253
#undef CHKTRY // check with action on fail
254
#undef CHKCON // print NDB API errors on failure
256
#define CHK(x) CHKTRY(x, ;)
258
#define CHKTRY(x, act) \
261
LL0("line " << __LINE__ << ": " << #x << " failed"); \
262
if (g_opt.m_core) abort(); \
267
#define CHKCON(x, con) \
270
LL0("line " << __LINE__ << ": " << #x << " failed"); \
271
(con).printerror(ndbout); \
272
if (g_opt.m_core) abort(); \
285
struct Par : public Opt {
288
Con& con() const { assert(m_con != 0); return *m_con; }
290
const Tab& tab() const { assert(m_tab != 0); return *m_tab; }
292
const ITab& itab() const { assert(m_itab != 0); return *m_itab; }
294
Set& set() const { assert(m_set != 0); return *m_set; }
296
Tmr& tmr() const { assert(m_tmr != 0); return *m_tmr; }
306
bool m_noindexkeyupdate;
309
// do verify after read
311
// errors to catch (see Con)
315
NdbOperation::LockMode m_lockmode;
320
// threads used by current test case
322
Par(const Opt& opt) :
337
m_noindexkeyupdate(false),
342
m_lockmode(NdbOperation::LM_Read),
353
usetable(Par par, uint i)
355
return par.m_table == 0 || strchr(par.m_table, '0' + i) != 0;
359
useindex(Par par, uint i)
361
return par.m_index == 0 || strchr(par.m_index, '0' + i) != 0;
365
thrrow(Par par, uint j)
367
return par.m_usedthreads * j + par.m_no;
371
isthrrow(Par par, uint i)
373
return i % par.m_usedthreads == par.m_no;
381
void off(uint cnt = 0);
383
const char* pct(const Tmr& t1);
384
const char* over(const Tmr& t1);
396
m_on = m_ms = m_cnt = m_time[0] = m_text[0] = 0;
403
m_on = NdbTick_CurrentMillisecond();
409
NDB_TICKS off = NdbTick_CurrentMillisecond();
410
assert(m_on != 0 && off >= m_on);
420
sprintf(m_time, "%u ms", m_ms);
422
sprintf(m_time, "%u ms per %u ( %u ms per 1000 )", m_ms, m_cnt, (1000 * m_ms) / m_cnt);
428
Tmr::pct(const Tmr& t1)
431
sprintf(m_text, "%u pct", (100 * m_ms) / t1.m_ms);
433
sprintf(m_text, "[cannot measure]");
439
Tmr::over(const Tmr& t1)
443
sprintf(m_text, "%u pct", (100 * (m_ms - t1.m_ms)) / t1.m_ms);
445
sprintf(m_text, "-%u pct", (100 * (t1.m_ms - m_ms)) / t1.m_ms);
447
sprintf(m_text, "[cannot measure]");
454
static const uint maxcsnumber = 512;
455
static const uint maxcharcount = 32;
456
static const uint maxcharsize = 4;
457
static const uint maxxmulsize = 8;
461
uchar m_bytes[maxcharsize];
462
uchar m_xbytes[maxxmulsize * maxcharsize];
469
memset(m_bytes, 0, sizeof(m_bytes));
470
memset(m_xbytes, 0, sizeof(m_xbytes));
474
// charset and random valid chars to use
479
Chs(CHARSET_INFO* cs);
484
operator<<(NdbOut& out, const Chs& chs);
486
Chs::Chs(CHARSET_INFO* cs) :
489
m_xmul = m_cs->strxfrm_multiply;
492
assert(m_xmul <= maxxmulsize);
493
m_chr = new Chr [maxcharcount];
499
while (i < maxcharcount) {
500
uchar* bytes = m_chr[i].m_bytes;
501
uchar* xbytes = m_chr[i].m_xbytes;
502
uint& size = m_chr[i].m_size;
504
size = m_cs->mbminlen + urandom(m_cs->mbmaxlen - m_cs->mbminlen + 1);
505
assert(m_cs->mbminlen <= size && size <= m_cs->mbmaxlen);
506
// prefer longer chars
507
if (size == m_cs->mbminlen && m_cs->mbminlen < m_cs->mbmaxlen && urandom(5) != 0)
509
for (uint j = 0; j < size; j++) {
510
bytes[j] = urandom(256);
514
const char* sbytes = (const char*)bytes;
515
if ((*cs->cset->well_formed_len)(cs, sbytes, sbytes + size, 1, ¬_used) != size) {
519
// check no proper prefix wellformed
521
for (uint j = 1; j < size; j++) {
522
if ((*cs->cset->well_formed_len)(cs, sbytes, sbytes + j, 1, ¬_used) == j) {
532
memset(xbytes, 0, sizeof(xbytes));
533
// currently returns buffer size always
534
int xlen = (*cs->coll->strnxfrm)(cs, xbytes, m_xmul * size, bytes, size);
535
// check we got something
537
for (uint j = 0; j < xlen; j++) {
538
if (xbytes[j] != 0) {
547
// check for duplicate (before normalize)
549
for (uint j = 0; j < i; j++) {
550
const Chr& chr = m_chr[j];
551
if (chr.m_size == size && memcmp(chr.m_bytes, bytes, size) == 0) {
562
bool disorder = true;
566
for (uint i = 1; i < maxcharcount; i++) {
567
uint len = sizeof(m_chr[i].m_xbytes);
568
if (memcmp(m_chr[i-1].m_xbytes, m_chr[i].m_xbytes, len) > 0) {
570
m_chr[i] = m_chr[i-1];
577
LL3("inited charset " << *this << " miss=" << miss1 << "," << miss2 << "," << miss3 << "," << miss4 << " bubbles=" << bubbles);
586
operator<<(NdbOut& out, const Chs& chs)
588
CHARSET_INFO* cs = chs.m_cs;
589
out << cs->name << "[" << cs->mbminlen << "-" << cs->mbmaxlen << "," << chs.m_xmul << "]";
593
static Chs* cslist[maxcsnumber];
598
for (uint i = 0; i < maxcsnumber; i++) {
612
uint n = urandom(maxcsnumber);
613
cs = get_charset(n, MYF(0));
615
// prefer complex charsets
616
if (cs->mbmaxlen != 1 || urandom(5) == 0)
621
if (cslist[cs->number] == 0)
622
cslist[cs->number] = new Chs(cs);
623
return cslist[cs->number];
626
// tables and indexes
628
// Col - table column
632
Unsigned = NdbDictionary::Column::Unsigned,
633
Char = NdbDictionary::Column::Char,
634
Varchar = NdbDictionary::Column::Varchar,
635
Longvarchar = NdbDictionary::Column::Longvarchar
637
const class Tab& m_tab;
643
uint m_bytelength; // multiplied by char width
644
uint m_attrsize; // base type size
645
uint m_headsize; // length bytes
646
uint m_bytesize; // full value size
649
Col(const class Tab& tab, uint num, const char* name, bool pk, Type type, uint length, bool nullable, const Chs* chs);
651
bool equal(const Col& col2) const;
652
void wellformed(const void* addr) const;
655
Col::Col(const class Tab& tab, uint num, const char* name, bool pk, Type type, uint length, bool nullable, const Chs* chs) :
658
m_name(strcpy(new char [strlen(name) + 1], name)),
662
m_bytelength(length * (chs == 0 ? 1 : chs->m_cs->mbmaxlen)),
664
type == Unsigned ? sizeof(Uint32) :
665
type == Char ? sizeof(char) :
666
type == Varchar ? sizeof(char) :
667
type == Longvarchar ? sizeof(char) : ~0),
669
type == Unsigned ? 0 :
671
type == Varchar ? 1 :
672
type == Longvarchar ? 2 : ~0),
673
m_bytesize(m_headsize + m_attrsize * m_bytelength),
674
m_nullable(nullable),
678
if (type == Varchar && m_bytelength > 255) {
679
m_type = Longvarchar;
691
Col::equal(const Col& col2) const
693
return m_type == col2.m_type && m_length == col2.m_length && m_chs == col2.m_chs;
697
Col::wellformed(const void* addr) const
704
CHARSET_INFO* cs = m_chs->m_cs;
705
const char* src = (const char*)addr;
706
uint len = m_bytelength;
708
assert((*cs->cset->well_formed_len)(cs, src, src + len, 0xffff, ¬_used) == len);
713
CHARSET_INFO* cs = m_chs->m_cs;
714
const uchar* src = (const uchar*)addr;
715
const char* ssrc = (const char*)src;
718
assert(len <= m_bytelength);
719
assert((*cs->cset->well_formed_len)(cs, ssrc + 1, ssrc + 1 + len, 0xffff, ¬_used) == len);
722
case Col::Longvarchar:
724
CHARSET_INFO* cs = m_chs->m_cs;
725
const uchar* src = (const uchar*)addr;
726
const char* ssrc = (const char*)src;
727
uint len = src[0] + (src[1] << 8);
729
assert(len <= m_bytelength);
730
assert((*cs->cset->well_formed_len)(cs, ssrc + 2, ssrc + 2 + len, 0xffff, ¬_used) == len);
740
operator<<(NdbOut& out, const Col& col)
742
out << "col[" << col.m_num << "] " << col.m_name;
743
switch (col.m_type) {
749
CHARSET_INFO* cs = col.m_chs->m_cs;
750
out << " char(" << col.m_length << "*" << cs->mbmaxlen << ";" << cs->name << ")";
755
CHARSET_INFO* cs = col.m_chs->m_cs;
756
out << " varchar(" << col.m_length << "*" << cs->mbmaxlen << ";" << cs->name << ")";
759
case Col::Longvarchar:
761
CHARSET_INFO* cs = col.m_chs->m_cs;
762
out << " longvarchar(" << col.m_length << "*" << cs->mbmaxlen << ";" << cs->name << ")";
766
out << "type" << (int)col.m_type;
770
out << (col.m_pk ? " pk" : "");
771
out << (col.m_nullable ? " nullable" : "");
775
// ICol - index column
778
const class ITab& m_itab;
781
ICol(const class ITab& itab, uint num, const Col& col);
785
ICol::ICol(const class ITab& itab, uint num, const Col& col) :
797
operator<<(NdbOut& out, const ICol& icol)
799
out << "icol[" << icol.m_num << "] " << icol.m_col;
807
OrderedIndex = NdbDictionary::Index::OrderedIndex,
808
UniqueHashIndex = NdbDictionary::Index::UniqueHashIndex
810
const class Tab& m_tab;
816
ITab(const class Tab& tab, const char* name, Type type, uint icols);
818
void icoladd(uint k, const ICol* icolptr);
821
ITab::ITab(const class Tab& tab, const char* name, Type type, uint icols) :
823
m_name(strcpy(new char [strlen(name) + 1], name)),
826
m_icol(new const ICol* [icols + 1]),
829
for (uint k = 0; k <= m_icols; k++)
836
for (uint i = 0; i < m_icols; i++)
842
ITab::icoladd(uint k, const ICol* icolptr)
844
assert(k == icolptr->m_num && k < m_icols && m_icol[k] == 0);
846
m_keymask |= (1 << icolptr->m_col.m_num);
850
operator<<(NdbOut& out, const ITab& itab)
852
out << "itab " << itab.m_name << " icols=" << itab.m_icols;
853
for (uint k = 0; k < itab.m_icols; k++) {
854
const ICol& icol = *itab.m_icol[k];
869
uint m_orderedindexes;
871
// pk must contain an Unsigned column
873
void coladd(uint k, Col* colptr);
874
void itabadd(uint j, ITab* itab);
875
Tab(const char* name, uint cols, uint itabs, uint keycol);
879
Tab::Tab(const char* name, uint cols, uint itabs, uint keycol) :
880
m_name(strcpy(new char [strlen(name) + 1], name)),
882
m_col(new const Col* [cols + 1]),
885
m_itab(new const ITab* [itabs + 1]),
890
for (uint k = 0; k <= cols; k++)
892
for (uint j = 0; j <= itabs; j++)
899
for (uint i = 0; i < m_cols; i++)
902
for (uint i = 0; i < m_itabs; i++)
908
Tab::coladd(uint k, Col* colptr)
910
assert(k == colptr->m_num && k < m_cols && m_col[k] == 0);
913
m_pkmask |= (1 << k);
917
Tab::itabadd(uint j, ITab* itabptr)
919
assert(j < m_itabs && m_itab[j] == 0 && itabptr != 0);
921
if (itabptr->m_type == ITab::OrderedIndex)
928
operator<<(NdbOut& out, const Tab& tab)
930
out << "tab " << tab.m_name << " cols=" << tab.m_cols;
931
for (uint k = 0; k < tab.m_cols; k++) {
932
const Col& col = *tab.m_col[k];
935
for (uint i = 0; i < tab.m_itabs; i++) {
936
if (tab.m_itab[i] == 0)
938
const ITab& itab = *tab.m_itab[i];
944
// make table structs
946
static const Tab** tablist = 0;
947
static uint tabcount = 0;
952
for (uint j = 0; j < tabcount; j++) {
953
const Tab* t = tablist[j];
956
assert(t->m_cols != 0 && t->m_col != 0);
957
for (uint k = 0; k < t->m_cols; k++) {
958
const Col* c = t->m_col[k];
959
assert(c != 0 && c->m_num == k);
960
assert(!(c->m_pk && c->m_nullable));
962
assert(t->m_col[t->m_cols] == 0);
964
assert(t->m_keycol < t->m_cols);
965
const Col* c = t->m_col[t->m_keycol];
966
assert(c->m_pk && c->m_type == Col::Unsigned);
968
assert(t->m_itabs != 0 && t->m_itab != 0);
969
for (uint i = 0; i < t->m_itabs; i++) {
970
const ITab* x = t->m_itab[i];
973
assert(x != 0 && x->m_icols != 0 && x->m_icol != 0);
974
for (uint k = 0; k < x->m_icols; k++) {
975
const ICol* c = x->m_icol[k];
976
assert(c != 0 && c->m_num == k && c->m_col.m_num < t->m_cols);
977
if (x->m_type == ITab::UniqueHashIndex) {
978
assert(!c->m_col.m_nullable);
982
assert(t->m_itab[t->m_itabs] == 0);
987
makebuiltintables(Par par)
989
LL2("makebuiltintables");
993
tablist = new const Tab* [tabcount];
994
for (uint j = 0; j < tabcount; j++) {
998
for (uint j = 0; j < tabcount; j++) {
1004
if (usetable(par, 0)) {
1005
Tab* t = new Tab("ti0", 5, 7, 0);
1006
// name - pk - type - length - nullable - cs
1007
t->coladd(0, new Col(*t, 0, "a", 1, Col::Unsigned, 1, 0, 0));
1008
t->coladd(1, new Col(*t, 1, "b", 0, Col::Unsigned, 1, 1, 0));
1009
t->coladd(2, new Col(*t, 2, "c", 0, Col::Unsigned, 1, 0, 0));
1010
t->coladd(3, new Col(*t, 3, "d", 0, Col::Unsigned, 1, 1, 0));
1011
t->coladd(4, new Col(*t, 4, "e", 0, Col::Unsigned, 1, 0, 0));
1012
if (useindex(par, 0)) {
1014
ITab* x = new ITab(*t, "ti0x0", ITab::OrderedIndex, 1);
1015
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
1018
if (useindex(par, 1)) {
1020
ITab* x = new ITab(*t, "ti0x1", ITab::OrderedIndex, 1);
1021
x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
1024
if (useindex(par, 2)) {
1026
ITab* x = new ITab(*t, "ti0x2", ITab::OrderedIndex, 2);
1027
x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
1028
x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
1031
if (useindex(par, 3)) {
1033
ITab* x = new ITab(*t, "ti0x3", ITab::OrderedIndex, 4);
1034
x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
1035
x->icoladd(1, new ICol(*x, 1, *t->m_col[4]));
1036
x->icoladd(2, new ICol(*x, 2, *t->m_col[2]));
1037
x->icoladd(3, new ICol(*x, 3, *t->m_col[3]));
1040
if (useindex(par, 4)) {
1042
ITab* x = new ITab(*t, "ti0z4", ITab::UniqueHashIndex, 2);
1043
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
1044
x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
1047
if (useindex(par, 5)) {
1049
ITab* x = new ITab(*t, "ti0z5", ITab::UniqueHashIndex, 2);
1050
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
1051
x->icoladd(1, new ICol(*x, 1, *t->m_col[4]));
1056
// ti1 - simple char fields
1057
if (usetable(par, 1)) {
1058
Tab* t = new Tab("ti1", 5, 7, 1);
1059
// name - pk - type - length - nullable - cs
1060
t->coladd(0, new Col(*t, 0, "a", 0, Col::Unsigned, 1, 0, 0));
1061
t->coladd(1, new Col(*t, 1, "b", 1, Col::Unsigned, 1, 0, 0));
1062
t->coladd(2, new Col(*t, 2, "c", 0, Col::Varchar, 20, 0, getcs(par)));
1063
t->coladd(3, new Col(*t, 3, "d", 0, Col::Char, 5, 0, getcs(par)));
1064
t->coladd(4, new Col(*t, 4, "e", 0, Col::Longvarchar, 5, 1, getcs(par)));
1065
if (useindex(par, 0)) {
1067
ITab* x = new ITab(*t, "ti1x0", ITab::OrderedIndex, 1);
1068
x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
1071
if (useindex(par, 1)) {
1073
ITab* x = new ITab(*t, "ti1x1", ITab::OrderedIndex, 2);
1074
x->icoladd(0, new ICol(*x, 0, *t->m_col[2]));
1075
x->icoladd(1, new ICol(*x, 1, *t->m_col[0]));
1078
if (useindex(par, 2)) {
1080
ITab* x = new ITab(*t, "ti1x2", ITab::OrderedIndex, 1);
1081
x->icoladd(0, new ICol(*x, 0, *t->m_col[3]));
1084
if (useindex(par, 3)) {
1086
ITab* x = new ITab(*t, "ti1x3", ITab::OrderedIndex, 4);
1087
x->icoladd(0, new ICol(*x, 0, *t->m_col[4]));
1088
x->icoladd(1, new ICol(*x, 1, *t->m_col[3]));
1089
x->icoladd(2, new ICol(*x, 2, *t->m_col[2]));
1090
x->icoladd(3, new ICol(*x, 3, *t->m_col[1]));
1093
if (useindex(par, 4)) {
1095
ITab* x = new ITab(*t, "ti1z4", ITab::UniqueHashIndex, 2);
1096
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
1097
x->icoladd(1, new ICol(*x, 1, *t->m_col[1]));
1100
if (useindex(par, 5)) {
1102
ITab* x = new ITab(*t, "ti1z5", ITab::UniqueHashIndex, 3);
1103
x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
1104
x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
1105
x->icoladd(2, new ICol(*x, 2, *t->m_col[3]));
1110
// ti2 - complex char fields
1111
if (usetable(par, 2)) {
1112
Tab* t = new Tab("ti2", 5, 7, 2);
1113
// name - pk - type - length - nullable - cs
1114
t->coladd(0, new Col(*t, 0, "a", 1, Col::Char, 31, 0, getcs(par)));
1115
t->coladd(1, new Col(*t, 1, "b", 0, Col::Char, 4, 1, getcs(par)));
1116
t->coladd(2, new Col(*t, 2, "c", 1, Col::Unsigned, 1, 0, 0));
1117
t->coladd(3, new Col(*t, 3, "d", 1, Col::Varchar, 128, 0, getcs(par)));
1118
t->coladd(4, new Col(*t, 4, "e", 0, Col::Varchar, 7, 0, getcs(par)));
1119
if (useindex(par, 0)) {
1121
ITab* x = new ITab(*t, "ti2x0", ITab::OrderedIndex, 3);
1122
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
1123
x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
1124
x->icoladd(2, new ICol(*x, 2, *t->m_col[3]));
1127
if (useindex(par, 1)) {
1129
ITab* x = new ITab(*t, "ti2x1", ITab::OrderedIndex, 5);
1130
x->icoladd(0, new ICol(*x, 0, *t->m_col[4]));
1131
x->icoladd(1, new ICol(*x, 1, *t->m_col[3]));
1132
x->icoladd(2, new ICol(*x, 2, *t->m_col[2]));
1133
x->icoladd(3, new ICol(*x, 3, *t->m_col[1]));
1134
x->icoladd(4, new ICol(*x, 4, *t->m_col[0]));
1137
if (useindex(par, 2)) {
1139
ITab* x = new ITab(*t, "ti2x2", ITab::OrderedIndex, 1);
1140
x->icoladd(0, new ICol(*x, 0, *t->m_col[3]));
1143
if (useindex(par, 3)) {
1145
ITab* x = new ITab(*t, "ti2x3", ITab::OrderedIndex, 1);
1146
x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
1149
if (useindex(par, 4)) {
1151
ITab* x = new ITab(*t, "ti2z4", ITab::UniqueHashIndex, 2);
1152
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
1153
x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
1156
if (useindex(par, 5)) {
1158
ITab* x = new ITab(*t, "ti2z5", ITab::UniqueHashIndex, 4);
1159
x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
1160
x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
1161
x->icoladd(2, new ICol(*x, 2, *t->m_col[3]));
1162
x->icoladd(3, new ICol(*x, 3, *t->m_col[4]));
1172
static Ndb_cluster_connection* g_ncc = 0;
1176
NdbDictionary::Dictionary* m_dic;
1177
NdbTransaction* m_tx;
1180
NdbIndexOperation* m_indexop;
1181
NdbScanOperation* m_scanop;
1182
NdbIndexScanOperation* m_indexscanop;
1183
NdbScanFilter* m_scanfilter;
1184
enum ScanMode { ScanNo = 0, Committed, Latest, Exclusive };
1185
ScanMode m_scanmode;
1193
char m_errname[100];
1195
m_ndb(0), m_dic(0), m_tx(0), m_txid(0), m_op(0), m_indexop(0),
1196
m_scanop(0), m_indexscanop(0), m_scanfilter(0),
1197
m_scanmode(ScanNo), m_errtype(ErrNone) {}
1203
void connect(const Con& con);
1205
int startTransaction();
1206
int getNdbOperation(const Tab& tab);
1207
int getNdbIndexOperation1(const ITab& itab, const Tab& tab);
1208
int getNdbIndexOperation(const ITab& itab, const Tab& tab);
1209
int getNdbScanOperation(const Tab& tab);
1210
int getNdbIndexScanOperation1(const ITab& itab, const Tab& tab);
1211
int getNdbIndexScanOperation(const ITab& itab, const Tab& tab);
1212
int getNdbScanFilter();
1213
int equal(int num, const char* addr);
1214
int getValue(int num, NdbRecAttr*& rec);
1215
int setValue(int num, const char* addr);
1216
int setBound(int num, int type, const void* value);
1217
int beginFilter(int group);
1219
int setFilter(int num, int cond, const void* value, uint len);
1220
int execute(ExecType et);
1221
int execute(ExecType et, uint& err);
1222
int readTuple(Par par);
1223
int readTuples(Par par);
1224
int readIndexTuples(Par par);
1226
int nextScanResult(bool fetchAllowed);
1227
int nextScanResult(bool fetchAllowed, uint& err);
1228
int updateScanTuple(Con& con2);
1229
int deleteScanTuple(Con& con2);
1231
void closeTransaction();
1232
const char* errname(uint err);
1233
void printerror(NdbOut& out);
1240
m_ndb = new Ndb(g_ncc, "TEST_DB");
1241
CHKCON(m_ndb->init() == 0, *this);
1242
CHKCON(m_ndb->waitUntilReady(30) == 0, *this);
1243
m_tx = 0, m_txid = 0, m_op = 0;
1248
Con::connect(const Con& con)
1258
m_ndb = 0, m_dic = 0, m_tx = 0, m_txid = 0, m_op = 0;
1262
Con::startTransaction()
1267
CHKCON((m_tx = m_ndb->startTransaction()) != 0, *this);
1268
m_txid = m_tx->getTransactionId();
1273
Con::getNdbOperation(const Tab& tab)
1276
CHKCON((m_op = m_tx->getNdbOperation(tab.m_name)) != 0, *this);
1281
Con::getNdbIndexOperation1(const ITab& itab, const Tab& tab)
1284
CHKCON((m_op = m_indexop = m_tx->getNdbIndexOperation(itab.m_name, tab.m_name)) != 0, *this);
1289
Con::getNdbIndexOperation(const ITab& itab, const Tab& tab)
1294
if (getNdbIndexOperation1(itab, tab) == 0)
1297
NdbSleep_MilliSleep(100);
1303
Con::getNdbScanOperation(const Tab& tab)
1306
CHKCON((m_op = m_scanop = m_tx->getNdbScanOperation(tab.m_name)) != 0, *this);
1311
Con::getNdbIndexScanOperation1(const ITab& itab, const Tab& tab)
1314
CHKCON((m_op = m_scanop = m_indexscanop = m_tx->getNdbIndexScanOperation(itab.m_name, tab.m_name)) != 0, *this);
1319
Con::getNdbIndexScanOperation(const ITab& itab, const Tab& tab)
1324
if (getNdbIndexScanOperation1(itab, tab) == 0)
1327
NdbSleep_MilliSleep(100);
1333
Con::getNdbScanFilter()
1335
assert(m_tx != 0 && m_scanop != 0);
1336
delete m_scanfilter;
1337
m_scanfilter = new NdbScanFilter(m_scanop);
1342
Con::equal(int num, const char* addr)
1344
assert(m_tx != 0 && m_op != 0);
1345
CHKCON(m_op->equal(num, addr) == 0, *this);
1350
Con::getValue(int num, NdbRecAttr*& rec)
1352
assert(m_tx != 0 && m_op != 0);
1353
CHKCON((rec = m_op->getValue(num, 0)) != 0, *this);
1358
Con::setValue(int num, const char* addr)
1360
assert(m_tx != 0 && m_op != 0);
1361
CHKCON(m_op->setValue(num, addr) == 0, *this);
1366
Con::setBound(int num, int type, const void* value)
1368
assert(m_tx != 0 && m_indexscanop != 0);
1369
CHKCON(m_indexscanop->setBound(num, type, value) == 0, *this);
1374
Con::beginFilter(int group)
1376
assert(m_tx != 0 && m_scanfilter != 0);
1377
CHKCON(m_scanfilter->begin((NdbScanFilter::Group)group) == 0, *this);
1384
assert(m_tx != 0 && m_scanfilter != 0);
1385
CHKCON(m_scanfilter->end() == 0, *this);
1390
Con::setFilter(int num, int cond, const void* value, uint len)
1392
assert(m_tx != 0 && m_scanfilter != 0);
1393
CHKCON(m_scanfilter->cmp((NdbScanFilter::BinaryCondition)cond, num, value, len) == 0, *this);
1398
Con::execute(ExecType et)
1401
CHKCON(m_tx->execute(et) == 0, *this);
1406
Con::execute(ExecType et, uint& err)
1408
int ret = execute(et);
1409
// err in: errors to catch, out: error caught
1410
const uint errin = err;
1413
if (m_errtype == ErrDeadlock && (errin & ErrDeadlock)) {
1414
LL3("caught deadlock");
1418
if (m_errtype == ErrNospace && (errin & ErrNospace)) {
1419
LL3("caught nospace");
1429
Con::readTuple(Par par)
1431
assert(m_tx != 0 && m_op != 0);
1432
NdbOperation::LockMode lm = par.m_lockmode;
1433
CHKCON(m_op->readTuple(lm) == 0, *this);
1438
Con::readTuples(Par par)
1440
assert(m_tx != 0 && m_scanop != 0);
1443
scan_flags |= NdbScanOperation::SF_TupScan;
1444
CHKCON(m_scanop->readTuples(par.m_lockmode, scan_flags, par.m_scanpar, par.m_scanbatch) == 0, *this);
1449
Con::readIndexTuples(Par par)
1451
assert(m_tx != 0 && m_indexscanop != 0);
1454
scan_flags |= NdbScanOperation::SF_OrderBy;
1455
if (par.m_descending)
1456
scan_flags |= NdbScanOperation::SF_Descending;
1457
CHKCON(m_indexscanop->readTuples(par.m_lockmode, scan_flags, par.m_scanpar, par.m_scanbatch) == 0, *this);
1464
CHKCON(m_tx->execute(NoCommit) == 0, *this);
1469
Con::nextScanResult(bool fetchAllowed)
1472
assert(m_scanop != 0);
1473
CHKCON((ret = m_scanop->nextResult(fetchAllowed)) != -1, *this);
1474
assert(ret == 0 || ret == 1 || (!fetchAllowed && ret == 2));
1479
Con::nextScanResult(bool fetchAllowed, uint& err)
1481
int ret = nextScanResult(fetchAllowed);
1482
// err in: errors to catch, out: error caught
1483
const uint errin = err;
1486
if (m_errtype == ErrDeadlock && (errin & ErrDeadlock)) {
1487
LL3("caught deadlock");
1492
CHK(ret == 0 || ret == 1 || (!fetchAllowed && ret == 2));
1497
Con::updateScanTuple(Con& con2)
1499
assert(con2.m_tx != 0);
1500
CHKCON((con2.m_op = m_scanop->updateCurrentTuple(con2.m_tx)) != 0, *this);
1501
con2.m_txid = m_txid; // in the kernel
1506
Con::deleteScanTuple(Con& con2)
1508
assert(con2.m_tx != 0);
1509
CHKCON(m_scanop->deleteCurrentTuple(con2.m_tx) == 0, *this);
1510
con2.m_txid = m_txid; // in the kernel
1517
assert(m_scanop != 0);
1519
m_scanop = 0, m_indexscanop = 0;
1524
Con::closeTransaction()
1526
assert(m_ndb != 0 && m_tx != 0);
1527
m_ndb->closeTransaction(m_tx);
1528
m_tx = 0, m_txid = 0, m_op = 0;
1529
m_scanop = 0, m_indexscanop = 0;
1533
Con::errname(uint err)
1535
sprintf(m_errname, "0x%x", err);
1536
if (err & ErrDeadlock)
1537
strcat(m_errname, ",deadlock");
1538
if (err & ErrNospace)
1539
strcat(m_errname, ",nospace");
1544
Con::printerror(NdbOut& out)
1546
m_errtype = ErrOther;
1551
if ((code = m_ndb->getNdbError().code) != 0) {
1552
LL0(++any << " ndb: error " << m_ndb->getNdbError());
1553
die += (code == g_opt.m_die);
1555
if (m_dic && (code = m_dic->getNdbError().code) != 0) {
1556
LL0(++any << " dic: error " << m_dic->getNdbError());
1557
die += (code == g_opt.m_die);
1560
if ((code = m_tx->getNdbError().code) != 0) {
1561
LL0(++any << " con: error " << m_tx->getNdbError());
1562
die += (code == g_opt.m_die);
1563
// 631 is new, occurs only on 4 db nodes, needs to be checked out
1564
if (code == 266 || code == 274 || code == 296 || code == 297 || code == 499 || code == 631)
1565
m_errtype = ErrDeadlock;
1566
if (code == 826 || code == 827 || code == 902)
1567
m_errtype = ErrNospace;
1569
if (m_op && m_op->getNdbError().code != 0) {
1570
LL0(++any << " op : error " << m_op->getNdbError());
1571
die += (code == g_opt.m_die);
1576
LL0("failed but no NDB error code");
1585
// dictionary operations
1588
invalidateindex(Par par, const ITab& itab)
1590
Con& con = par.con();
1591
const Tab& tab = par.tab();
1592
con.m_ndb->getDictionary()->invalidateIndex(itab.m_name, tab.m_name);
1597
invalidateindex(Par par)
1599
Con& con = par.con();
1600
const Tab& tab = par.tab();
1601
for (uint i = 0; i < tab.m_itabs; i++) {
1602
if (tab.m_itab[i] == 0)
1604
const ITab& itab = *tab.m_itab[i];
1605
invalidateindex(par, itab);
1611
invalidatetable(Par par)
1613
Con& con = par.con();
1614
const Tab& tab = par.tab();
1615
invalidateindex(par);
1616
con.m_ndb->getDictionary()->invalidateTable(tab.m_name);
1623
Con& con = par.con();
1624
const Tab& tab = par.tab();
1625
con.m_dic = con.m_ndb->getDictionary();
1626
if (con.m_dic->getTable(tab.m_name) == 0) {
1627
// how to check for error
1628
LL4("no table " << tab.m_name);
1630
LL3("drop table " << tab.m_name);
1631
CHKCON(con.m_dic->dropTable(tab.m_name) == 0, con);
1638
createtable(Par par)
1640
Con& con = par.con();
1641
const Tab& tab = par.tab();
1642
LL3("create table " << tab.m_name);
1644
NdbDictionary::Table t(tab.m_name);
1645
if (par.m_fragtype != NdbDictionary::Object::FragUndefined) {
1646
t.setFragmentType(par.m_fragtype);
1648
if (par.m_nologging) {
1649
t.setLogging(false);
1651
for (uint k = 0; k < tab.m_cols; k++) {
1652
const Col& col = *tab.m_col[k];
1653
NdbDictionary::Column c(col.m_name);
1654
c.setType((NdbDictionary::Column::Type)col.m_type);
1655
c.setLength(col.m_bytelength); // for char NDB API uses length in bytes
1656
c.setPrimaryKey(col.m_pk);
1657
c.setNullable(col.m_nullable);
1659
c.setCharset(col.m_chs->m_cs);
1662
con.m_dic = con.m_ndb->getDictionary();
1663
CHKCON(con.m_dic->createTable(t) == 0, con);
1669
dropindex(Par par, const ITab& itab)
1671
Con& con = par.con();
1672
const Tab& tab = par.tab();
1673
con.m_dic = con.m_ndb->getDictionary();
1674
if (con.m_dic->getIndex(itab.m_name, tab.m_name) == 0) {
1675
// how to check for error
1676
LL4("no index " << itab.m_name);
1678
LL3("drop index " << itab.m_name);
1679
CHKCON(con.m_dic->dropIndex(itab.m_name, tab.m_name) == 0, con);
1688
const Tab& tab = par.tab();
1689
for (uint i = 0; i < tab.m_itabs; i++) {
1690
if (tab.m_itab[i] == 0)
1692
const ITab& itab = *tab.m_itab[i];
1693
CHK(dropindex(par, itab) == 0);
1699
createindex(Par par, const ITab& itab)
1701
Con& con = par.con();
1702
const Tab& tab = par.tab();
1703
LL3("create index " << itab.m_name);
1705
NdbDictionary::Index x(itab.m_name);
1706
x.setTable(tab.m_name);
1707
x.setType((NdbDictionary::Index::Type)itab.m_type);
1708
if (par.m_nologging || itab.m_type == ITab::OrderedIndex) {
1709
x.setLogging(false);
1711
for (uint k = 0; k < itab.m_icols; k++) {
1712
const ICol& icol = *itab.m_icol[k];
1713
const Col& col = icol.m_col;
1714
x.addColumnName(col.m_name);
1716
con.m_dic = con.m_ndb->getDictionary();
1717
CHKCON(con.m_dic->createIndex(x) == 0, con);
1723
createindex(Par par)
1725
const Tab& tab = par.tab();
1726
for (uint i = 0; i < tab.m_itabs; i++) {
1727
if (tab.m_itab[i] == 0)
1729
const ITab& itab = *tab.m_itab[i];
1730
CHK(createindex(par, itab) == 0);
1737
// Val - typed column value
1745
uchar* m_longvarchar;
1749
Val(const Col& col);
1751
void copy(const Val& val2);
1752
void copy(const void* addr);
1753
const void* dataaddr() const;
1754
void calc(Par par, uint i);
1755
void calckey(Par par, uint i);
1756
void calckeychars(Par par, uint i, uint& n, uchar* buf);
1757
void calcnokey(Par par);
1758
void calcnokeychars(Par par, uint& n, uchar* buf);
1760
int setval(Par par) const;
1761
int setval(Par par, const ICol& icol) const;
1763
int cmp(Par par, const Val& val2) const;
1764
int cmpchars(Par par, const uchar* buf1, uint len1, const uchar* buf2, uint len2) const;
1765
int verify(Par par, const Val& val2) const;
1767
Val& operator=(const Val& val2);
1771
operator<<(NdbOut& out, const Val& val);
1775
Val::Val(const Col& col) :
1778
switch (col.m_type) {
1780
m_uint32 = 0x7e7e7e7e;
1783
m_char = new uchar [col.m_bytelength];
1784
memset(m_char, 0x7e, col.m_bytelength);
1787
m_varchar = new uchar [1 + col.m_bytelength];
1788
memset(m_char, 0x7e, 1 + col.m_bytelength);
1790
case Col::Longvarchar:
1791
m_longvarchar = new uchar [2 + col.m_bytelength];
1792
memset(m_char, 0x7e, 2 + col.m_bytelength);
1802
const Col& col = m_col;
1803
switch (col.m_type) {
1810
delete [] m_varchar;
1812
case Col::Longvarchar:
1813
delete [] m_longvarchar;
1822
Val::copy(const Val& val2)
1824
const Col& col = m_col;
1825
const Col& col2 = val2.m_col;
1826
assert(col.m_type == col2.m_type && col.m_length == col2.m_length);
1831
copy(val2.dataaddr());
1835
Val::copy(const void* addr)
1837
const Col& col = m_col;
1838
switch (col.m_type) {
1840
m_uint32 = *(const Uint32*)addr;
1843
memcpy(m_char, addr, col.m_bytelength);
1846
memcpy(m_varchar, addr, 1 + col.m_bytelength);
1848
case Col::Longvarchar:
1849
memcpy(m_longvarchar, addr, 2 + col.m_bytelength);
1859
Val::dataaddr() const
1861
const Col& col = m_col;
1862
switch (col.m_type) {
1869
case Col::Longvarchar:
1870
return m_longvarchar;
1879
Val::calc(Par par, uint i)
1881
const Col& col = m_col;
1882
col.m_pk ? calckey(par, i) : calcnokey(par);
1884
col.wellformed(dataaddr());
1888
Val::calckey(Par par, uint i)
1890
const Col& col = m_col;
1892
switch (col.m_type) {
1898
const Chs* chs = col.m_chs;
1899
CHARSET_INFO* cs = chs->m_cs;
1901
calckeychars(par, i, n, m_char);
1902
// extend by appropriate space
1903
(*cs->cset->fill)(cs, (char*)&m_char[n], col.m_bytelength - n, 0x20);
1909
calckeychars(par, i, n, m_varchar + 1);
1910
// set length and pad with nulls
1912
memset(&m_varchar[1 + n], 0, col.m_bytelength - n);
1915
case Col::Longvarchar:
1918
calckeychars(par, i, n, m_longvarchar + 2);
1919
// set length and pad with nulls
1920
m_longvarchar[0] = (n & 0xff);
1921
m_longvarchar[1] = (n >> 8);
1922
memset(&m_longvarchar[2 + n], 0, col.m_bytelength - n);
1932
Val::calckeychars(Par par, uint i, uint& n, uchar* buf)
1934
const Col& col = m_col;
1935
const Chs* chs = col.m_chs;
1936
CHARSET_INFO* cs = chs->m_cs;
1939
while (len < col.m_length) {
1940
if (i % (1 + n) == 0) {
1943
const Chr& chr = chs->m_chr[i % maxcharcount];
1944
assert(n + chr.m_size <= col.m_bytelength);
1945
memcpy(buf + n, chr.m_bytes, chr.m_size);
1952
Val::calcnokey(Par par)
1954
const Col& col = m_col;
1956
if (col.m_nullable && urandom(100) < par.m_pctnull) {
1960
int r = irandom((par.m_pctrange * par.m_range) / 100);
1961
if (par.m_bdir != 0 && urandom(10) != 0) {
1962
if (r < 0 && par.m_bdir > 0 || r > 0 && par.m_bdir < 0)
1965
uint v = par.m_range + r;
1966
switch (col.m_type) {
1972
const Chs* chs = col.m_chs;
1973
CHARSET_INFO* cs = chs->m_cs;
1975
calcnokeychars(par, n, m_char);
1976
// extend by appropriate space
1977
(*cs->cset->fill)(cs, (char*)&m_char[n], col.m_bytelength - n, 0x20);
1983
calcnokeychars(par, n, m_varchar + 1);
1984
// set length and pad with nulls
1986
memset(&m_varchar[1 + n], 0, col.m_bytelength - n);
1989
case Col::Longvarchar:
1992
calcnokeychars(par, n, m_longvarchar + 2);
1993
// set length and pad with nulls
1994
m_longvarchar[0] = (n & 0xff);
1995
m_longvarchar[1] = (n >> 8);
1996
memset(&m_longvarchar[2 + n], 0, col.m_bytelength - n);
2006
Val::calcnokeychars(Par par, uint& n, uchar* buf)
2008
const Col& col = m_col;
2009
const Chs* chs = col.m_chs;
2010
CHARSET_INFO* cs = chs->m_cs;
2013
while (len < col.m_length) {
2014
if (urandom(1 + col.m_bytelength) == 0) {
2017
uint half = maxcharcount / 2;
2018
int r = irandom((par.m_pctrange * half) / 100);
2019
if (par.m_bdir != 0 && urandom(10) != 0) {
2020
if (r < 0 && par.m_bdir > 0 || r > 0 && par.m_bdir < 0)
2024
assert(i < maxcharcount);
2025
const Chr& chr = chs->m_chr[i];
2026
assert(n + chr.m_size <= col.m_bytelength);
2027
memcpy(buf + n, chr.m_bytes, chr.m_size);
2036
Val::setval(Par par) const
2038
Con& con = par.con();
2039
const Col& col = m_col;
2042
const char* addr = (const char*)dataaddr();
2043
LL5("setval pk [" << col << "] " << *this);
2044
CHK(con.equal(col.m_num, addr) == 0);
2046
const char* addr = !m_null ? (const char*)dataaddr() : 0;
2047
LL5("setval non-pk [" << col << "] " << *this);
2048
CHK(con.setValue(col.m_num, addr) == 0);
2054
Val::setval(Par par, const ICol& icol) const
2056
Con& con = par.con();
2058
const char* addr = (const char*)dataaddr();
2059
LL5("setval key [" << icol << "] " << *this);
2060
CHK(con.equal(icol.m_num, addr) == 0);
2067
Val::cmp(Par par, const Val& val2) const
2069
const Col& col = m_col;
2070
const Col& col2 = val2.m_col;
2071
assert(col.equal(col2));
2072
if (m_null || val2.m_null) {
2079
// verify data formats
2080
col.wellformed(dataaddr());
2081
col.wellformed(val2.dataaddr());
2083
switch (col.m_type) {
2086
if (m_uint32 < val2.m_uint32)
2088
if (m_uint32 > val2.m_uint32)
2095
uint len = col.m_bytelength;
2096
return cmpchars(par, m_char, len, val2.m_char, len);
2101
uint len1 = m_varchar[0];
2102
uint len2 = val2.m_varchar[0];
2103
return cmpchars(par, m_varchar + 1, len1, val2.m_varchar + 1, len2);
2106
case Col::Longvarchar:
2108
uint len1 = m_longvarchar[0] + (m_longvarchar[1] << 8);
2109
uint len2 = val2.m_longvarchar[0] + (val2.m_longvarchar[1] << 8);
2110
return cmpchars(par, m_longvarchar + 2, len1, val2.m_longvarchar + 2, len2);
2121
Val::cmpchars(Par par, const uchar* buf1, uint len1, const uchar* buf2, uint len2) const
2123
const Col& col = m_col;
2124
const Chs* chs = col.m_chs;
2125
CHARSET_INFO* cs = chs->m_cs;
2127
if (!par.m_collsp) {
2128
uchar x1[maxxmulsize * 8000];
2129
uchar x2[maxxmulsize * 8000];
2130
// make strxfrm pad both to same length
2131
uint len = maxxmulsize * col.m_bytelength;
2132
int n1 = NdbSqlUtil::strnxfrm_bug7284(cs, x1, chs->m_xmul * len, buf1, len1);
2133
int n2 = NdbSqlUtil::strnxfrm_bug7284(cs, x2, chs->m_xmul * len, buf2, len2);
2134
assert(n1 != -1 && n1 == n2);
2135
k = memcmp(x1, x2, n1);
2137
k = (*cs->coll->strnncollsp)(cs, buf1, len1, buf2, len2, false);
2139
return k < 0 ? -1 : k > 0 ? +1 : 0;
2143
Val::verify(Par par, const Val& val2) const
2145
CHK(cmp(par, val2) == 0);
2152
printstring(NdbOut& out, const uchar* str, uint len, bool showlen)
2158
sprintf(p, "%u:", len);
2161
for (uint i = 0; i < len; i++) {
2166
} else if (0x20 <= c && c <= 0x7e) {
2170
*p++ = hexstr[c >> 4];
2171
*p++ = hexstr[c & 15];
2180
operator<<(NdbOut& out, const Val& val)
2182
const Col& col = val.m_col;
2187
switch (col.m_type) {
2189
out << val.m_uint32;
2193
uint len = col.m_bytelength;
2194
printstring(out, val.m_char, len, false);
2199
uint len = val.m_varchar[0];
2200
printstring(out, val.m_varchar + 1, len, true);
2203
case Col::Longvarchar:
2205
uint len = val.m_longvarchar[0] + (val.m_longvarchar[1] << 8);
2206
printstring(out, val.m_longvarchar + 2, len, true);
2210
out << "type" << col.m_type;
2217
// Row - table tuple
2237
OpREAD = 16 | 32 | 64
2244
Row(const Tab& tab);
2246
void copy(const Row& row2, bool copy_bi);
2247
void copyval(const Row& row2, uint colmask = ~0);
2248
void calc(Par par, uint i, uint colmask = ~0);
2250
int setval(Par par, uint colmask = ~0);
2251
int setval(Par par, const ITab& itab);
2252
int insrow(Par par);
2253
int updrow(Par par);
2254
int updrow(Par par, const ITab& itab);
2255
int delrow(Par par);
2256
int delrow(Par par, const ITab& itab);
2257
int selrow(Par par);
2258
int selrow(Par par, const ITab& itab);
2259
int setrow(Par par);
2261
int cmp(Par par, const Row& row2) const;
2262
int cmp(Par par, const Row& row2, const ITab& itab) const;
2263
int verify(Par par, const Row& row2, bool pkonly) const;
2265
Row& operator=(const Row& row2);
2269
operator<<(NdbOut& out, const Row* rowp);
2272
operator<<(NdbOut& out, const Row& row);
2276
Row::Row(const Tab& tab) :
2279
m_val = new Val* [tab.m_cols];
2280
for (uint k = 0; k < tab.m_cols; k++) {
2281
const Col& col = *tab.m_col[k];
2282
m_val[k] = new Val(col);
2292
const Tab& tab = m_tab;
2293
for (uint k = 0; k < tab.m_cols; k++) {
2301
Row::copy(const Row& row2, bool copy_bi)
2303
const Tab& tab = m_tab;
2307
m_txid = row2.m_txid;
2309
if (copy_bi && row2.m_bi != 0) {
2310
m_bi = new Row(tab);
2311
m_bi->copy(*row2.m_bi, copy_bi);
2316
Row::copyval(const Row& row2, uint colmask)
2318
const Tab& tab = m_tab;
2319
assert(&tab == &row2.m_tab);
2320
for (uint k = 0; k < tab.m_cols; k++) {
2321
Val& val = *m_val[k];
2322
const Val& val2 = *row2.m_val[k];
2323
if ((1 << k) & colmask)
2329
Row::calc(Par par, uint i, uint colmask)
2331
const Tab& tab = m_tab;
2332
for (uint k = 0; k < tab.m_cols; k++) {
2333
if ((1 << k) & colmask) {
2334
Val& val = *m_val[k];
2343
Row::setval(Par par, uint colmask)
2345
const Tab& tab = m_tab;
2346
Rsq rsq(tab.m_cols);
2347
for (uint k = 0; k < tab.m_cols; k++) {
2348
uint k2 = rsq.next();
2349
if ((1 << k2) & colmask) {
2350
const Val& val = *m_val[k2];
2351
CHK(val.setval(par) == 0);
2358
Row::setval(Par par, const ITab& itab)
2360
Con& con = par.con();
2361
Rsq rsq(itab.m_icols);
2362
for (uint k = 0; k < itab.m_icols; k++) {
2363
uint k2 = rsq.next();
2364
const ICol& icol = *itab.m_icol[k2];
2365
const Col& col = icol.m_col;
2367
const Val& val = *m_val[m];
2368
CHK(val.setval(par, icol) == 0);
2374
Row::insrow(Par par)
2376
Con& con = par.con();
2377
const Tab& tab = m_tab;
2378
CHK(con.getNdbOperation(tab) == 0);
2379
CHKCON(con.m_op->insertTuple() == 0, con);
2380
CHK(setval(par, tab.m_pkmask) == 0);
2381
CHK(setval(par, ~tab.m_pkmask) == 0);
2382
assert(m_st == StUndef);
2385
m_txid = con.m_txid;
2390
Row::updrow(Par par)
2392
Con& con = par.con();
2393
const Tab& tab = m_tab;
2394
CHK(con.getNdbOperation(tab) == 0);
2395
CHKCON(con.m_op->updateTuple() == 0, con);
2396
CHK(setval(par, tab.m_pkmask) == 0);
2397
CHK(setval(par, ~tab.m_pkmask) == 0);
2398
assert(m_st == StUndef);
2401
m_txid = con.m_txid;
2406
Row::updrow(Par par, const ITab& itab)
2408
Con& con = par.con();
2409
const Tab& tab = m_tab;
2410
assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab);
2411
CHK(con.getNdbIndexOperation(itab, tab) == 0);
2412
CHKCON(con.m_op->updateTuple() == 0, con);
2413
CHK(setval(par, itab) == 0);
2414
CHK(setval(par, ~tab.m_pkmask) == 0);
2415
assert(m_st == StUndef);
2418
m_txid = con.m_txid;
2423
Row::delrow(Par par)
2425
Con& con = par.con();
2426
const Tab& tab = m_tab;
2427
CHK(con.getNdbOperation(m_tab) == 0);
2428
CHKCON(con.m_op->deleteTuple() == 0, con);
2429
CHK(setval(par, tab.m_pkmask) == 0);
2430
assert(m_st == StUndef);
2433
m_txid = con.m_txid;
2438
Row::delrow(Par par, const ITab& itab)
2440
Con& con = par.con();
2441
const Tab& tab = m_tab;
2442
assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab);
2443
CHK(con.getNdbIndexOperation(itab, tab) == 0);
2444
CHKCON(con.m_op->deleteTuple() == 0, con);
2445
CHK(setval(par, itab) == 0);
2446
assert(m_st == StUndef);
2449
m_txid = con.m_txid;
2454
Row::selrow(Par par)
2456
Con& con = par.con();
2457
const Tab& tab = m_tab;
2458
CHK(con.getNdbOperation(m_tab) == 0);
2459
CHKCON(con.readTuple(par) == 0, con);
2460
CHK(setval(par, tab.m_pkmask) == 0);
2466
Row::selrow(Par par, const ITab& itab)
2468
Con& con = par.con();
2469
const Tab& tab = m_tab;
2470
assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab);
2471
CHK(con.getNdbIndexOperation(itab, tab) == 0);
2472
CHKCON(con.readTuple(par) == 0, con);
2473
CHK(setval(par, itab) == 0);
2479
Row::setrow(Par par)
2481
Con& con = par.con();
2482
const Tab& tab = m_tab;
2483
CHK(setval(par, ~tab.m_pkmask) == 0);
2484
assert(m_st == StUndef);
2487
m_txid = con.m_txid;
2494
Row::cmp(Par par, const Row& row2) const
2496
const Tab& tab = m_tab;
2497
assert(&tab == &row2.m_tab);
2499
for (uint k = 0; k < tab.m_cols; k++) {
2500
const Val& val = *m_val[k];
2501
const Val& val2 = *row2.m_val[k];
2502
if ((c = val.cmp(par, val2)) != 0)
2509
Row::cmp(Par par, const Row& row2, const ITab& itab) const
2511
const Tab& tab = m_tab;
2513
for (uint i = 0; i < itab.m_icols; i++) {
2514
const ICol& icol = *itab.m_icol[i];
2515
const Col& col = icol.m_col;
2517
assert(k < tab.m_cols);
2518
const Val& val = *m_val[k];
2519
const Val& val2 = *row2.m_val[k];
2520
if ((c = val.cmp(par, val2)) != 0)
2527
Row::verify(Par par, const Row& row2, bool pkonly) const
2529
const Tab& tab = m_tab;
2530
const Row& row1 = *this;
2531
assert(&row1.m_tab == &row2.m_tab);
2532
for (uint k = 0; k < tab.m_cols; k++) {
2533
const Col& col = row1.m_val[k]->m_col;
2534
if (!pkonly || col.m_pk) {
2535
const Val& val1 = *row1.m_val[k];
2536
const Val& val2 = *row2.m_val[k];
2537
CHK(val1.verify(par, val2) == 0);
2546
operator<<(NdbOut& out, const Row::St st)
2548
if (st == Row::StUndef)
2550
else if (st == Row::StDefine)
2552
else if (st == Row::StPrepare)
2554
else if (st == Row::StCommit)
2562
operator<<(NdbOut& out, const Row::Op op)
2564
if (op == Row::OpNone)
2566
else if (op == Row::OpIns)
2568
else if (op == Row::OpUpd)
2570
else if (op == Row::OpDel)
2572
else if (op == Row::OpRead)
2574
else if (op == Row::OpReadEx)
2576
else if (op == Row::OpReadCom)
2584
operator<<(NdbOut& out, const Row* rowp)
2594
operator<<(NdbOut& out, const Row& row)
2596
const Tab& tab = row.m_tab;
2598
for (uint i = 0; i < tab.m_cols; i++) {
2601
out << *row.m_val[i];
2603
out << " " << row.m_st;
2604
out << " " << row.m_op;
2605
out << " " << HEX(row.m_txid);
2607
out << " " << row.m_bi;
2612
// Set - set of table tuples
2618
uint* m_rowkey; // maps row number (from 0) in scan to tuple key
2622
Set(const Tab& tab, uint rows);
2625
bool compat(Par par, uint i, const Row::Op op) const;
2627
void copyval(uint i, uint colmask = ~0); // from bi
2628
void calc(Par par, uint i, uint colmask = ~0);
2630
const Row* getrow(uint i, bool dirty = false) const;
2632
void post(Par par, ExecType et);
2634
int insrow(Par par, uint i);
2635
int updrow(Par par, uint i);
2636
int updrow(Par par, const ITab& itab, uint i);
2637
int delrow(Par par, uint i);
2638
int delrow(Par par, const ITab& itab, uint i);
2639
int selrow(Par par, const Row& keyrow);
2640
int selrow(Par par, const ITab& itab, const Row& keyrow);
2641
int setrow(Par par, uint i);
2642
int getval(Par par);
2643
int getkey(Par par, uint* i);
2644
int putval(uint i, bool force, uint n = ~0);
2646
void sort(Par par, const ITab& itab);
2647
int verify(Par par, const Set& set2, bool pkonly, bool dirty = false) const;
2648
int verifyorder(Par par, const ITab& itab, bool descending) const;
2649
// protect structure
2652
NdbMutex_Lock(m_mutex);
2654
void unlock() const {
2655
NdbMutex_Unlock(m_mutex);
2658
void sort(Par par, const ITab& itab, uint lo, uint hi);
2659
Set& operator=(const Set& set2);
2664
Set::Set(const Tab& tab, uint rows) :
2668
m_row = new Row* [m_rows];
2669
for (uint i = 0; i < m_rows; i++) {
2672
m_rowkey = new uint [m_rows];
2673
for (uint n = 0; n < m_rows; n++) {
2676
m_keyrow = new Row(tab);
2677
m_rec = new NdbRecAttr* [tab.m_cols];
2678
for (uint k = 0; k < tab.m_cols; k++) {
2681
m_mutex = NdbMutex_Create();
2682
assert(m_mutex != 0);
2687
for (uint i = 0; i < m_rows; i++) {
2694
NdbMutex_Destroy(m_mutex);
2700
for (uint i = 0; i < m_rows; i++) {
2707
Set::compat(Par par, uint i, const Row::Op op) const
2709
Con& con = par.con();
2713
const Row* rowp = getrow(i);
2715
ret = op == Row::OpIns;
2719
const Row& row = *rowp;
2720
if (!(op & Row::OpREAD)) {
2721
if (row.m_st == Row::StDefine || row.m_st == Row::StPrepare) {
2722
assert(row.m_op & Row::OpDML);
2723
assert(row.m_txid != 0);
2724
if (con.m_txid != row.m_txid) {
2729
if (row.m_op != Row::OpDel) {
2730
ret = op == Row::OpUpd || op == Row::OpDel;
2734
ret = op == Row::OpIns;
2738
if (row.m_st == Row::StCommit) {
2739
assert(row.m_op == Row::OpNone);
2740
assert(row.m_txid == 0);
2741
ret = op == Row::OpUpd || op == Row::OpDel;
2746
if (op & Row::OpREAD) {
2748
con.m_txid != row.m_txid &&
2749
par.m_lockmode == NdbOperation::LM_CommittedRead;
2750
const Row* rowp2 = getrow(i, dirty);
2751
if (rowp2 == 0 || rowp2->m_op == Row::OpDel) {
2761
LL4("compat ret=" << ret << " place=" << place);
2762
assert(ret == false || ret == true);
2769
const Tab& tab = m_tab;
2772
m_row[i] = new Row(tab);
2773
Row& row = *m_row[i];
2780
Set::copyval(uint i, uint colmask)
2782
assert(m_row[i] != 0);
2783
Row& row = *m_row[i];
2784
assert(row.m_bi != 0);
2785
row.copyval(*row.m_bi, colmask);
2789
Set::calc(Par par, uint i, uint colmask)
2791
assert(m_row[i] != 0);
2792
Row& row = *m_row[i];
2793
row.calc(par, i, colmask);
2800
for (uint i = 0; i < m_rows; i++) {
2808
Set::getrow(uint i, bool dirty) const
2811
const Row* rowp = m_row[i];
2814
bool b1 = rowp->m_op == Row::OpNone;
2815
bool b2 = rowp->m_st == Row::StCommit;
2818
assert(rowp->m_bi == 0);
2830
Set::post(Par par, ExecType et)
2833
Con& con = par.con();
2834
assert(con.m_txid != 0);
2836
for (i = 0; i < m_rows; i++) {
2837
Row* rowp = m_row[i];
2839
LL5("skip " << i << " " << rowp);
2842
if (rowp->m_st == Row::StCommit) {
2843
assert(rowp->m_op == Row::OpNone);
2844
assert(rowp->m_txid == 0);
2845
assert(rowp->m_bi == 0);
2846
LL5("skip committed " << i << " " << rowp);
2849
assert(rowp->m_st == Row::StDefine || rowp->m_st == Row::StPrepare);
2850
assert(rowp->m_txid != 0);
2851
if (con.m_txid != rowp->m_txid) {
2852
LL5("skip txid " << i << " " << HEX(con.m_txid) << " " << rowp);
2856
assert(rowp->m_op & Row::OpDML);
2857
LL4("post BEFORE " << rowp);
2858
if (et == NoCommit) {
2859
if (rowp->m_st == Row::StDefine) {
2860
rowp->m_st = Row::StPrepare;
2861
Row* bi = rowp->m_bi;
2862
while (bi != 0 && bi->m_st == Row::StDefine) {
2863
bi->m_st = Row::StPrepare;
2867
} else if (et == Commit) {
2868
if (rowp->m_op != Row::OpDel) {
2869
rowp->m_st = Row::StCommit;
2870
rowp->m_op = Row::OpNone;
2878
} else if (et == Rollback) {
2879
while (rowp != 0 && rowp->m_st != Row::StCommit) {
2889
LL4("post AFTER " << rowp);
2896
Set::insrow(Par par, uint i)
2898
assert(m_row[i] != 0);
2899
Row& row = *m_row[i];
2900
CHK(row.insrow(par) == 0);
2905
Set::updrow(Par par, uint i)
2907
assert(m_row[i] != 0);
2908
Row& row = *m_row[i];
2909
CHK(row.updrow(par) == 0);
2914
Set::updrow(Par par, const ITab& itab, uint i)
2916
assert(m_row[i] != 0);
2917
Row& row = *m_row[i];
2918
CHK(row.updrow(par, itab) == 0);
2923
Set::delrow(Par par, uint i)
2925
assert(m_row[i] != 0);
2926
Row& row = *m_row[i];
2927
CHK(row.delrow(par) == 0);
2932
Set::delrow(Par par, const ITab& itab, uint i)
2934
assert(m_row[i] != 0);
2935
Row& row = *m_row[i];
2936
CHK(row.delrow(par, itab) == 0);
2941
Set::selrow(Par par, const Row& keyrow)
2943
Con& con = par.con();
2944
const Tab& tab = par.tab();
2945
LL5("selrow " << tab.m_name << " keyrow " << keyrow);
2946
m_keyrow->copyval(keyrow, tab.m_pkmask);
2947
CHK(m_keyrow->selrow(par) == 0);
2948
CHK(getval(par) == 0);
2953
Set::selrow(Par par, const ITab& itab, const Row& keyrow)
2955
Con& con = par.con();
2956
LL5("selrow " << itab.m_name << " keyrow " << keyrow);
2957
m_keyrow->copyval(keyrow, itab.m_keymask);
2958
CHK(m_keyrow->selrow(par, itab) == 0);
2959
CHK(getval(par) == 0);
2964
Set::setrow(Par par, uint i)
2966
Con& con = par.con();
2967
assert(m_row[i] != 0);
2968
CHK(m_row[i]->setrow(par) == 0);
2973
Set::getval(Par par)
2975
Con& con = par.con();
2976
const Tab& tab = m_tab;
2977
Rsq rsq1(tab.m_cols);
2978
for (uint k = 0; k < tab.m_cols; k++) {
2979
uint k2 = rsq1.next();
2980
CHK(con.getValue(k2, m_rec[k2]) == 0);
2986
Set::getkey(Par par, uint* i)
2988
const Tab& tab = m_tab;
2989
uint k = tab.m_keycol;
2990
assert(m_rec[k] != 0);
2991
const char* aRef = m_rec[k]->aRef();
2992
Uint32 key = *(const Uint32*)aRef;
2993
LL5("getkey: " << key);
3000
Set::putval(uint i, bool force, uint n)
3002
const Tab& tab = m_tab;
3003
LL4("putval key=" << i << " row=" << n << " old=" << m_row[i]);
3004
if (m_row[i] != 0) {
3009
m_row[i] = new Row(tab);
3010
Row& row = *m_row[i];
3011
for (uint k = 0; k < tab.m_cols; k++) {
3012
Val& val = *row.m_val[k];
3013
NdbRecAttr* rec = m_rec[k];
3015
if (rec->isNULL()) {
3019
const char* aRef = m_rec[k]->aRef();
3031
Set::sort(Par par, const ITab& itab)
3034
sort(par, itab, 0, m_rows - 1);
3038
Set::sort(Par par, const ITab& itab, uint lo, uint hi)
3040
assert(lo < m_rows && hi < m_rows && lo <= hi);
3041
Row* const p = m_row[lo];
3045
while (i < j && m_row[j]->cmp(par, *p, itab) >= 0)
3048
m_row[i] = m_row[j];
3051
while (i < j && m_row[i]->cmp(par, *p, itab) <= 0)
3054
m_row[j] = m_row[i];
3060
sort(par, itab, lo, i - 1);
3062
sort(par, itab, i + 1, hi);
3066
* set1 (self) is from dml and can contain un-committed operations.
3067
* set2 is from read and contains no operations. "dirty" applies
3068
* to set1: false = use latest row, true = use committed row.
3071
Set::verify(Par par, const Set& set2, bool pkonly, bool dirty) const
3073
const Set& set1 = *this;
3074
assert(&set1.m_tab == &set2.m_tab && set1.m_rows == set2.m_rows);
3075
LL3("verify dirty:" << dirty);
3076
for (uint i = 0; i < set1.m_rows; i++) {
3077
// the row versions we actually compare
3078
const Row* row1p = set1.getrow(i, dirty);
3079
const Row* row2p = set2.getrow(i);
3088
Row::Op op1 = row1p->m_op;
3089
if (op1 != Row::OpDel) {
3093
} else if (row1p->verify(par, *row2p, pkonly) == -1) {
3097
} else if (row2p != 0) {
3103
LL1("verify " << i << " failed at " << place);
3104
LL1("row1 " << row1p);
3105
LL1("row2 " << row2p);
3113
Set::verifyorder(Par par, const ITab& itab, bool descending) const
3115
const Tab& tab = m_tab;
3116
for (uint n = 0; n < m_rows; n++) {
3117
uint i2 = m_rowkey[n];
3122
uint i1 = m_rowkey[n - 1];
3123
assert(m_row[i1] != 0 && m_row[i2] != 0);
3124
const Row& row1 = *m_row[i1];
3125
const Row& row2 = *m_row[i2];
3127
CHK(row1.cmp(par, row2, itab) <= 0);
3129
CHK(row1.cmp(par, row2, itab) >= 0);
3137
operator<<(NdbOut& out, const Set& set)
3139
for (uint i = 0; i < set.m_rows; i++) {
3140
const Row& row = *set.m_row[i];
3148
// BVal - range scan bound
3150
struct BVal : public Val {
3153
BVal(const ICol& icol);
3154
int setbnd(Par par) const;
3155
int setflt(Par par) const;
3158
BVal::BVal(const ICol& icol) :
3165
BVal::setbnd(Par par) const
3167
Con& con = par.con();
3168
assert(g_compare_null || !m_null);
3169
const char* addr = !m_null ? (const char*)dataaddr() : 0;
3170
const ICol& icol = m_icol;
3171
CHK(con.setBound(icol.m_num, m_type, addr) == 0);
3176
BVal::setflt(Par par) const
3178
static uint index_bound_to_filter_bound[5] = {
3179
NdbScanFilter::COND_GE,
3180
NdbScanFilter::COND_GT,
3181
NdbScanFilter::COND_LE,
3182
NdbScanFilter::COND_LT,
3183
NdbScanFilter::COND_EQ
3185
Con& con = par.con();
3186
assert(g_compare_null || !m_null);
3187
const char* addr = !m_null ? (const char*)dataaddr() : 0;
3188
const ICol& icol = m_icol;
3189
const Col& col = icol.m_col;
3190
uint length = col.m_bytesize;
3191
uint cond = index_bound_to_filter_bound[m_type];
3192
CHK(con.setFilter(col.m_num, cond, addr, length) == 0);
3197
operator<<(NdbOut& out, const BVal& bval)
3199
const ICol& icol = bval.m_icol;
3200
const Col& col = icol.m_col;
3201
const Val& val = bval;
3202
out << "type=" << bval.m_type;
3203
out << " icol=" << icol.m_num;
3204
out << " col=" << col.m_num << "," << col.m_name;
3205
out << " value=" << val;
3209
// BSet - set of bounds
3217
BSet(const Tab& tab, const ITab& itab);
3221
void calcpk(Par par, uint i);
3222
int setbnd(Par par) const;
3223
int setflt(Par par) const;
3224
void filter(Par par, const Set& set, Set& set2) const;
3227
BSet::BSet(const Tab& tab, const ITab& itab) :
3230
m_alloc(2 * itab.m_icols),
3233
m_bval = new BVal* [m_alloc];
3234
for (uint i = 0; i < m_alloc; i++) {
3247
while (m_bvals > 0) {
3257
const ITab& itab = m_itab;
3258
par.m_pctrange = par.m_pctbrange;
3260
for (uint k = 0; k < itab.m_icols; k++) {
3261
const ICol& icol = *itab.m_icol[k];
3262
const Col& col = icol.m_col;
3263
for (uint i = 0; i <= 1; i++) {
3264
if (m_bvals == 0 && urandom(100) == 0)
3266
if (m_bvals != 0 && urandom(3) == 0)
3268
assert(m_bvals < m_alloc);
3269
BVal& bval = *new BVal(icol);
3270
m_bval[m_bvals++] = &bval;
3271
bval.m_null = false;
3274
// equality bound only on i==0
3275
sel = urandom(5 - i);
3276
} while (strchr(par.m_bound, '0' + sel) == 0);
3278
bval.m_type = 0 | (1 << i);
3280
bval.m_type = 1 | (1 << i);
3283
if (k + 1 < itab.m_icols)
3285
if (!g_compare_null)
3287
if (bval.m_type == 0 || bval.m_type == 1)
3289
if (bval.m_type == 2 || bval.m_type == 3)
3292
bval.calcnokey(par);
3294
assert(m_bvals >= 2);
3295
const BVal& bv1 = *m_bval[m_bvals - 2];
3296
const BVal& bv2 = *m_bval[m_bvals - 1];
3297
if (bv1.cmp(par, bv2) > 0 && urandom(100) != 0)
3301
// equality bound only once
3302
if (bval.m_type == 4)
3309
BSet::calcpk(Par par, uint i)
3311
const ITab& itab = m_itab;
3313
for (uint k = 0; k < itab.m_icols; k++) {
3314
const ICol& icol = *itab.m_icol[k];
3315
const Col& col = icol.m_col;
3317
assert(m_bvals < m_alloc);
3318
BVal& bval = *new BVal(icol);
3319
m_bval[m_bvals++] = &bval;
3326
BSet::setbnd(Par par) const
3330
for (uint j = 0; j < m_bvals; j++) {
3331
uint j2 = rsq1.next();
3332
const BVal& bval = *m_bval[j2];
3333
CHK(bval.setbnd(par) == 0);
3336
if (urandom(5) == 0) {
3337
uint j3 = urandom(m_bvals);
3338
const BVal& bval = *m_bval[j3];
3339
CHK(bval.setbnd(par) == 0);
3346
BSet::setflt(Par par) const
3348
Con& con = par.con();
3349
CHK(con.getNdbScanFilter() == 0);
3350
CHK(con.beginFilter(NdbScanFilter::AND) == 0);
3353
for (uint j = 0; j < m_bvals; j++) {
3354
uint j2 = rsq1.next();
3355
const BVal& bval = *m_bval[j2];
3356
CHK(bval.setflt(par) == 0);
3359
if (urandom(5) == 0) {
3360
uint j3 = urandom(m_bvals);
3361
const BVal& bval = *m_bval[j3];
3362
CHK(bval.setflt(par) == 0);
3365
CHK(con.endFilter() == 0);
3370
BSet::filter(Par par, const Set& set, Set& set2) const
3372
const Tab& tab = m_tab;
3373
const ITab& itab = m_itab;
3374
assert(&tab == &set2.m_tab && set.m_rows == set2.m_rows);
3375
assert(set2.count() == 0);
3376
for (uint i = 0; i < set.m_rows; i++) {
3379
if (set.m_row[i] == 0) {
3382
const Row& row = *set.m_row[i];
3383
if (!g_store_null_key) {
3385
for (uint k = 0; k < itab.m_icols; k++) {
3386
const ICol& icol = *itab.m_icol[k];
3387
const Col& col = icol.m_col;
3388
const Val& val = *row.m_val[col.m_num];
3398
for (uint j = 0; j < m_bvals; j++) {
3399
const BVal& bval = *m_bval[j];
3400
const ICol& icol = bval.m_icol;
3401
const Col& col = icol.m_col;
3402
const Val& val = *row.m_val[col.m_num];
3403
int ret = bval.cmp(par, val);
3404
LL5("cmp: ret=" << ret << " " << bval << " vs " << val);
3405
if (bval.m_type == 0)
3407
else if (bval.m_type == 1)
3409
else if (bval.m_type == 2)
3411
else if (bval.m_type == 3)
3413
else if (bval.m_type == 4)
3423
assert(set2.m_row[i] == 0);
3424
set2.m_row[i] = new Row(tab);
3425
Row& row2 = *set2.m_row[i];
3426
row2.copy(row, true);
3433
operator<<(NdbOut& out, const BSet& bset)
3435
out << "bounds=" << bset.m_bvals;
3436
for (uint j = 0; j < bset.m_bvals; j++) {
3437
const BVal& bval = *bset.m_bval[j];
3438
out << " [bound " << j << ": " << bval << "]";
3448
Con& con = par.con();
3449
const Tab& tab = par.tab();
3450
Set& set = par.set();
3451
LL3("pkinsert " << tab.m_name);
3452
CHK(con.startTransaction() == 0);
3454
for (uint j = 0; j < par.m_rows; j++) {
3455
uint j2 = !par.m_randomkey ? j : urandom(par.m_rows);
3456
uint i = thrrow(par, j2);
3458
if (!set.compat(par, i, Row::OpIns)) {
3459
LL3("pkinsert SKIP " << i << " " << set.getrow(i));
3464
CHK(set.insrow(par, i) == 0);
3466
LL4("pkinsert key=" << i << " " << set.getrow(i));
3469
bool lastbatch = (batch != 0 && j + 1 == par.m_rows);
3470
if (batch == par.m_batch || lastbatch) {
3471
uint err = par.m_catcherr;
3472
ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback;
3473
CHK(con.execute(et, err) == 0);
3475
set.post(par, !err ? et : Rollback);
3478
LL1("pkinsert key=" << i << " stop on " << con.errname(err));
3483
con.closeTransaction();
3484
CHK(con.startTransaction() == 0);
3488
con.closeTransaction();
3495
Con& con = par.con();
3496
const Tab& tab = par.tab();
3497
Set& set = par.set();
3498
LL3("pkupdate " << tab.m_name);
3499
CHK(con.startTransaction() == 0);
3501
for (uint j = 0; j < par.m_rows; j++) {
3502
uint j2 = !par.m_randomkey ? j : urandom(par.m_rows);
3503
uint i = thrrow(par, j2);
3505
if (!set.compat(par, i, Row::OpUpd)) {
3506
LL3("pkupdate SKIP " << i << " " << set.getrow(i));
3510
set.copyval(i, tab.m_pkmask);
3511
set.calc(par, i, ~tab.m_pkmask);
3512
CHK(set.updrow(par, i) == 0);
3514
LL4("pkupdate key=" << i << " " << set.getrow(i));
3517
bool lastbatch = (batch != 0 && j + 1 == par.m_rows);
3518
if (batch == par.m_batch || lastbatch) {
3519
uint err = par.m_catcherr;
3520
ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback;
3521
CHK(con.execute(et, err) == 0);
3523
set.post(par, !err ? et : Rollback);
3526
LL1("pkupdate key=" << i << ": stop on " << con.errname(err));
3531
con.closeTransaction();
3532
CHK(con.startTransaction() == 0);
3536
con.closeTransaction();
3543
Con& con = par.con();
3544
const Tab& tab = par.tab();
3545
Set& set = par.set();
3546
LL3("pkdelete " << tab.m_name);
3547
CHK(con.startTransaction() == 0);
3549
for (uint j = 0; j < par.m_rows; j++) {
3550
uint j2 = !par.m_randomkey ? j : urandom(par.m_rows);
3551
uint i = thrrow(par, j2);
3553
if (!set.compat(par, i, Row::OpDel)) {
3554
LL3("pkdelete SKIP " << i << " " << set.getrow(i));
3558
set.copyval(i, tab.m_pkmask);
3559
CHK(set.delrow(par, i) == 0);
3561
LL4("pkdelete key=" << i << " " << set.getrow(i));
3564
bool lastbatch = (batch != 0 && j + 1 == par.m_rows);
3565
if (batch == par.m_batch || lastbatch) {
3566
uint err = par.m_catcherr;
3567
ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback;
3568
CHK(con.execute(et, err) == 0);
3570
set.post(par, !err ? et : Rollback);
3573
LL1("pkdelete key=" << i << " stop on " << con.errname(err));
3578
con.closeTransaction();
3579
CHK(con.startTransaction() == 0);
3583
con.closeTransaction();
3590
Con& con = par.con();
3591
const Tab& tab = par.tab();
3592
Set& set = par.set();
3593
LL3("pkread " << tab.m_name << " verify=" << par.m_verify);
3595
const Set& set1 = set;
3596
Set set2(tab, set.m_rows);
3597
for (uint i = 0; i < set.m_rows; i++) {
3600
if (!set.compat(par, i, Row::OpREAD)) {
3601
LL3("pkread SKIP " << i << " " << set.getrow(i));
3606
CHK(con.startTransaction() == 0);
3607
CHK(set2.selrow(par, *set1.m_row[i]) == 0);
3608
CHK(con.execute(Commit) == 0);
3610
CHK(set2.getkey(par, &i2) == 0 && i == i2);
3611
CHK(set2.putval(i, false) == 0);
3612
LL4("row " << set2.count() << " " << set2.getrow(i));
3613
con.closeTransaction();
3616
CHK(set1.verify(par, set2, false) == 0);
3621
pkreadfast(Par par, uint count)
3623
Con& con = par.con();
3624
const Tab& tab = par.tab();
3625
const Set& set = par.set();
3626
LL3("pkfast " << tab.m_name);
3628
// not batched on purpose
3629
for (uint j = 0; j < count; j++) {
3630
uint i = urandom(set.m_rows);
3631
assert(set.compat(par, i, Row::OpREAD));
3632
CHK(con.startTransaction() == 0);
3634
keyrow.calc(par, i);
3635
CHK(keyrow.selrow(par) == 0);
3638
CHK(con.getValue((Uint32)0, rec) == 0);
3639
CHK(con.execute(Commit) == 0);
3640
con.closeTransaction();
3645
// hash index operations
3648
hashindexupdate(Par par, const ITab& itab)
3650
Con& con = par.con();
3651
const Tab& tab = par.tab();
3652
Set& set = par.set();
3653
LL3("hashindexupdate " << itab.m_name);
3654
CHK(con.startTransaction() == 0);
3656
for (uint j = 0; j < par.m_rows; j++) {
3657
uint j2 = !par.m_randomkey ? j : urandom(par.m_rows);
3658
uint i = thrrow(par, j2);
3660
if (!set.compat(par, i, Row::OpUpd)) {
3661
LL3("hashindexupdate SKIP " << i << " " << set.getrow(i));
3664
// table pk and index key are not updated
3666
uint keymask = tab.m_pkmask | itab.m_keymask;
3667
set.copyval(i, keymask);
3668
set.calc(par, i, ~keymask);
3669
CHK(set.updrow(par, itab, i) == 0);
3671
LL4("hashindexupdate " << i << " " << set.getrow(i));
3674
bool lastbatch = (batch != 0 && j + 1 == par.m_rows);
3675
if (batch == par.m_batch || lastbatch) {
3676
uint err = par.m_catcherr;
3677
ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback;
3678
CHK(con.execute(et, err) == 0);
3680
set.post(par, !err ? et : Rollback);
3683
LL1("hashindexupdate " << i << " stop on " << con.errname(err));
3688
con.closeTransaction();
3689
CHK(con.startTransaction() == 0);
3693
con.closeTransaction();
3698
hashindexdelete(Par par, const ITab& itab)
3700
Con& con = par.con();
3701
Set& set = par.set();
3702
LL3("hashindexdelete " << itab.m_name);
3703
CHK(con.startTransaction() == 0);
3705
for (uint j = 0; j < par.m_rows; j++) {
3706
uint j2 = !par.m_randomkey ? j : urandom(par.m_rows);
3707
uint i = thrrow(par, j2);
3709
if (!set.compat(par, i, Row::OpDel)) {
3710
LL3("hashindexdelete SKIP " << i << " " << set.getrow(i));
3714
set.copyval(i, itab.m_keymask);
3715
CHK(set.delrow(par, itab, i) == 0);
3717
LL4("hashindexdelete " << i << " " << set.getrow(i));
3720
bool lastbatch = (batch != 0 && j + 1 == par.m_rows);
3721
if (batch == par.m_batch || lastbatch) {
3722
uint err = par.m_catcherr;
3723
ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback;
3724
CHK(con.execute(et, err) == 0);
3726
set.post(par, !err ? et : Rollback);
3729
LL1("hashindexdelete " << i << " stop on " << con.errname(err));
3734
con.closeTransaction();
3735
CHK(con.startTransaction() == 0);
3739
con.closeTransaction();
3744
hashindexread(Par par, const ITab& itab)
3746
Con& con = par.con();
3747
const Tab& tab = par.tab();
3748
Set& set = par.set();
3749
LL3("hashindexread " << itab.m_name << " verify=" << par.m_verify);
3751
const Set& set1 = set;
3752
Set set2(tab, set.m_rows);
3753
for (uint i = 0; i < set.m_rows; i++) {
3756
if (!set.compat(par, i, Row::OpREAD)) {
3757
LL3("hashindexread SKIP " << i << " " << set.getrow(i));
3762
CHK(con.startTransaction() == 0);
3763
CHK(set2.selrow(par, itab, *set1.m_row[i]) == 0);
3764
CHK(con.execute(Commit) == 0);
3766
CHK(set2.getkey(par, &i2) == 0 && i == i2);
3767
CHK(set2.putval(i, false) == 0);
3768
LL4("row " << set2.count() << " " << *set2.m_row[i]);
3769
con.closeTransaction();
3772
CHK(set1.verify(par, set2, false) == 0);
3779
scanreadtable(Par par)
3781
Con& con = par.con();
3782
const Tab& tab = par.tab();
3783
const Set& set = par.set();
3785
const Set& set1 = set;
3786
LL3("scanreadtable " << tab.m_name << " lockmode=" << par.m_lockmode << " tupscan=" << par.m_tupscan << " expect=" << set1.count() << " verify=" << par.m_verify);
3787
Set set2(tab, set.m_rows);
3788
CHK(con.startTransaction() == 0);
3789
CHK(con.getNdbScanOperation(tab) == 0);
3790
CHK(con.readTuples(par) == 0);
3792
CHK(con.executeScan() == 0);
3796
uint err = par.m_catcherr;
3797
CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1);
3801
LL1("scanreadtable stop on " << con.errname(err));
3805
CHK(set2.getkey(par, &i) == 0);
3806
CHK(set2.putval(i, false, n) == 0);
3807
LL4("row " << n << " " << *set2.m_row[i]);
3810
con.closeTransaction();
3812
CHK(set1.verify(par, set2, false) == 0);
3813
LL3("scanreadtable " << tab.m_name << " done rows=" << n);
3818
scanreadtablefast(Par par, uint countcheck)
3820
Con& con = par.con();
3821
const Tab& tab = par.tab();
3822
const Set& set = par.set();
3823
LL3("scanfast " << tab.m_name);
3824
CHK(con.startTransaction() == 0);
3825
CHK(con.getNdbScanOperation(tab) == 0);
3826
CHK(con.readTuples(par) == 0);
3829
CHK(con.getValue((Uint32)0, rec) == 0);
3830
CHK(con.executeScan() == 0);
3834
CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
3839
con.closeTransaction();
3840
CHK(count == countcheck);
3844
// try to get interesting bounds
3846
calcscanbounds(Par par, const ITab& itab, BSet& bset, const Set& set, Set& set1)
3850
bset.filter(par, set, set1);
3851
uint n = set1.count();
3852
// prefer proper subset
3853
if (0 < n && n < set.m_rows)
3855
if (urandom(5) == 0)
3862
scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc)
3864
Con& con = par.con();
3865
const Tab& tab = par.tab();
3866
const Set& set = par.set();
3867
Set set1(tab, set.m_rows);
3869
calcscanbounds(par, itab, bset, set, set1);
3871
bset.filter(par, set, set1);
3873
LL3("scanreadindex " << itab.m_name << " " << bset << " lockmode=" << par.m_lockmode << " expect=" << set1.count() << " ordered=" << par.m_ordered << " descending=" << par.m_descending << " verify=" << par.m_verify);
3874
Set set2(tab, set.m_rows);
3875
CHK(con.startTransaction() == 0);
3876
CHK(con.getNdbIndexScanOperation(itab, tab) == 0);
3877
CHK(con.readIndexTuples(par) == 0);
3878
CHK(bset.setbnd(par) == 0);
3880
CHK(con.executeScan() == 0);
3884
uint err = par.m_catcherr;
3885
CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1);
3889
LL1("scanreadindex stop on " << con.errname(err));
3893
CHK(set2.getkey(par, &i) == 0);
3894
CHK(set2.putval(i, par.m_dups, n) == 0);
3895
LL4("key " << i << " row " << n << " " << *set2.m_row[i]);
3898
con.closeTransaction();
3900
CHK(set1.verify(par, set2, false) == 0);
3902
CHK(set2.verifyorder(par, itab, par.m_descending) == 0);
3904
LL3("scanreadindex " << itab.m_name << " done rows=" << n);
3909
scanreadindexfast(Par par, const ITab& itab, const BSet& bset, uint countcheck)
3911
Con& con = par.con();
3912
const Tab& tab = par.tab();
3913
const Set& set = par.set();
3914
LL3("scanfast " << itab.m_name << " " << bset);
3916
CHK(con.startTransaction() == 0);
3917
CHK(con.getNdbIndexScanOperation(itab, tab) == 0);
3918
CHK(con.readIndexTuples(par) == 0);
3919
CHK(bset.setbnd(par) == 0);
3922
CHK(con.getValue((Uint32)0, rec) == 0);
3923
CHK(con.executeScan() == 0);
3927
CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
3932
con.closeTransaction();
3933
CHK(count == countcheck);
3938
scanreadfilter(Par par, const ITab& itab, BSet& bset, bool calc)
3940
Con& con = par.con();
3941
const Tab& tab = par.tab();
3942
const Set& set = par.set();
3943
Set set1(tab, set.m_rows);
3945
calcscanbounds(par, itab, bset, set, set1);
3947
bset.filter(par, set, set1);
3949
LL3("scanfilter " << itab.m_name << " " << bset << " lockmode=" << par.m_lockmode << " expect=" << set1.count() << " verify=" << par.m_verify);
3950
Set set2(tab, set.m_rows);
3951
CHK(con.startTransaction() == 0);
3952
CHK(con.getNdbScanOperation(tab) == 0);
3953
CHK(con.readTuples(par) == 0);
3954
CHK(bset.setflt(par) == 0);
3956
CHK(con.executeScan() == 0);
3960
uint err = par.m_catcherr;
3961
CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1);
3965
LL1("scanfilter stop on " << con.errname(err));
3969
CHK(set2.getkey(par, &i) == 0);
3970
CHK(set2.putval(i, par.m_dups, n) == 0);
3971
LL4("key " << i << " row " << n << " " << *set2.m_row[i]);
3974
con.closeTransaction();
3976
CHK(set1.verify(par, set2, false) == 0);
3978
LL3("scanfilter " << itab.m_name << " done rows=" << n);
3983
scanreadindex(Par par, const ITab& itab)
3985
const Tab& tab = par.tab();
3986
for (uint i = 0; i < par.m_ssloop; i++) {
3987
if (itab.m_type == ITab::OrderedIndex) {
3988
BSet bset(tab, itab);
3989
CHK(scanreadfilter(par, itab, bset, true) == 0);
3990
CHK(scanreadindex(par, itab, bset, true) == 0);
3997
scanreadindex(Par par)
3999
const Tab& tab = par.tab();
4000
for (uint i = 0; i < tab.m_itabs; i++) {
4001
if (tab.m_itab[i] == 0)
4003
const ITab& itab = *tab.m_itab[i];
4004
if (itab.m_type == ITab::OrderedIndex) {
4005
CHK(scanreadindex(par, itab) == 0);
4007
CHK(hashindexread(par, itab) == 0);
4014
scanreadall(Par par)
4016
CHK(scanreadtable(par) == 0);
4017
CHK(scanreadindex(par) == 0);
4024
timescantable(Par par)
4027
CHK(scanreadtablefast(par, par.m_totrows) == 0);
4028
par.tmr().off(par.set().m_rows);
4033
timescanpkindex(Par par)
4035
const Tab& tab = par.tab();
4036
const ITab& itab = *tab.m_itab[0]; // 1st index is on PK
4037
BSet bset(tab, itab);
4039
CHK(scanreadindexfast(par, itab, bset, par.m_totrows) == 0);
4040
par.tmr().off(par.set().m_rows);
4045
timepkreadtable(Par par)
4048
uint count = par.m_samples;
4050
count = par.m_totrows;
4051
CHK(pkreadfast(par, count) == 0);
4052
par.tmr().off(count);
4057
timepkreadindex(Par par)
4059
const Tab& tab = par.tab();
4060
const ITab& itab = *tab.m_itab[0]; // 1st index is on PK
4061
BSet bset(tab, itab);
4062
uint count = par.m_samples;
4064
count = par.m_totrows;
4066
for (uint j = 0; j < count; j++) {
4067
uint i = urandom(par.m_totrows);
4068
bset.calcpk(par, i);
4069
CHK(scanreadindexfast(par, itab, bset, 1) == 0);
4071
par.tmr().off(count);
4078
scanupdatetable(Par par)
4080
Con& con = par.con();
4081
const Tab& tab = par.tab();
4082
Set& set = par.set();
4083
LL3("scanupdatetable " << tab.m_name);
4084
Set set2(tab, set.m_rows);
4085
par.m_lockmode = NdbOperation::LM_Exclusive;
4086
CHK(con.startTransaction() == 0);
4087
CHK(con.getNdbScanOperation(tab) == 0);
4088
CHK(con.readTuples(par) == 0);
4090
CHK(con.executeScan() == 0);
4095
CHK(con2.startTransaction() == 0);
4099
uint32 err = par.m_catcherr;
4100
CHK((ret = con.nextScanResult(true, err)) != -1);
4104
LL1("scanupdatetable [scan] stop on " << con.errname(err));
4107
if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) {
4113
CHK(set2.getkey(par, &i) == 0);
4115
if (!set.compat(par, i, Row::OpUpd)) {
4116
LL3("scanupdatetable SKIP " << i << " " << set.getrow(i));
4118
CHKTRY(set2.putval(i, false) == 0, set.unlock());
4119
CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
4123
set.calc(par, i, ~tab.m_pkmask);
4124
CHKTRY(set.setrow(par2, i) == 0, set.unlock());
4125
LL4("scanupdatetable " << i << " " << set.getrow(i));
4129
CHK((ret = con.nextScanResult(false)) != -1);
4130
bool lastbatch = (batch != 0 && ret != 0);
4131
if (batch == par.m_batch || lastbatch) {
4132
uint err = par.m_catcherr;
4133
ExecType et = Commit;
4134
CHK(con2.execute(et, err) == 0);
4136
set.post(par, !err ? et : Rollback);
4139
LL1("scanupdatetable [update] stop on " << con2.errname(err));
4142
LL4("scanupdatetable committed batch");
4145
con2.closeTransaction();
4146
CHK(con2.startTransaction() == 0);
4153
con2.closeTransaction();
4154
LL3("scanupdatetable " << tab.m_name << " rows updated=" << count);
4155
con.closeTransaction();
4160
scanupdateindex(Par par, const ITab& itab, BSet& bset, bool calc)
4162
Con& con = par.con();
4163
const Tab& tab = par.tab();
4164
Set& set = par.set();
4166
Set set1(tab, set.m_rows);
4168
calcscanbounds(par, itab, bset, set, set1);
4170
bset.filter(par, set, set1);
4172
LL3("scanupdateindex " << itab.m_name << " " << bset << " expect=" << set1.count() << " ordered=" << par.m_ordered << " descending=" << par.m_descending << " verify=" << par.m_verify);
4173
Set set2(tab, set.m_rows);
4174
par.m_lockmode = NdbOperation::LM_Exclusive;
4175
CHK(con.startTransaction() == 0);
4176
CHK(con.getNdbIndexScanOperation(itab, tab) == 0);
4177
CHK(con.readTuples(par) == 0);
4178
CHK(bset.setbnd(par) == 0);
4180
CHK(con.executeScan() == 0);
4185
CHK(con2.startTransaction() == 0);
4189
uint err = par.m_catcherr;
4190
CHK((ret = con.nextScanResult(true, err)) != -1);
4194
LL1("scanupdateindex [scan] stop on " << con.errname(err));
4197
if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) {
4203
CHK(set2.getkey(par, &i) == 0);
4205
if (!set.compat(par, i, Row::OpUpd)) {
4206
LL4("scanupdateindex SKIP " << set.getrow(i));
4208
CHKTRY(set2.putval(i, par.m_dups) == 0, set.unlock());
4209
CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
4213
uint colmask = !par.m_noindexkeyupdate ? ~0 : ~itab.m_keymask;
4214
set.calc(par, i, colmask);
4215
CHKTRY(set.setrow(par2, i) == 0, set.unlock());
4216
LL4("scanupdateindex " << i << " " << set.getrow(i));
4220
CHK((ret = con.nextScanResult(false)) != -1);
4221
bool lastbatch = (batch != 0 && ret != 0);
4222
if (batch == par.m_batch || lastbatch) {
4223
uint err = par.m_catcherr;
4224
ExecType et = Commit;
4225
CHK(con2.execute(et, err) == 0);
4227
set.post(par, !err ? et : Rollback);
4230
LL1("scanupdateindex [update] stop on " << con2.errname(err));
4233
LL4("scanupdateindex committed batch");
4236
con2.closeTransaction();
4237
CHK(con2.startTransaction() == 0);
4244
con2.closeTransaction();
4246
CHK(set1.verify(par, set2, true) == 0);
4248
CHK(set2.verifyorder(par, itab, par.m_descending) == 0);
4250
LL3("scanupdateindex " << itab.m_name << " rows updated=" << count);
4251
con.closeTransaction();
4256
scanupdateindex(Par par, const ITab& itab)
4258
const Tab& tab = par.tab();
4259
for (uint i = 0; i < par.m_ssloop; i++) {
4260
if (itab.m_type == ITab::OrderedIndex) {
4261
BSet bset(tab, itab);
4262
CHK(scanupdateindex(par, itab, bset, true) == 0);
4264
CHK(hashindexupdate(par, itab) == 0);
4271
scanupdateindex(Par par)
4273
const Tab& tab = par.tab();
4274
for (uint i = 0; i < tab.m_itabs; i++) {
4275
if (tab.m_itab[i] == 0)
4277
const ITab& itab = *tab.m_itab[i];
4278
CHK(scanupdateindex(par, itab) == 0);
4284
scanupdateall(Par par)
4286
CHK(scanupdatetable(par) == 0);
4287
CHK(scanupdateindex(par) == 0);
4291
// medium level routines
4294
readverifyfull(Par par)
4298
par.m_verify = true;
4299
if (par.m_abortpct != 0) {
4300
LL2("skip verify in this version"); // implement in 5.0 version
4301
par.m_verify = false;
4303
par.m_lockmode = NdbOperation::LM_CommittedRead;
4304
const Tab& tab = par.tab();
4305
if (par.m_no == 0) {
4306
// thread 0 scans table
4307
CHK(scanreadtable(par) == 0);
4308
// once more via tup scan
4309
par.m_tupscan = true;
4310
CHK(scanreadtable(par) == 0);
4312
// each thread scans different indexes
4313
for (uint i = 0; i < tab.m_itabs; i++) {
4314
if (i % par.m_usedthreads != par.m_no)
4316
if (tab.m_itab[i] == 0)
4318
const ITab& itab = *tab.m_itab[i];
4319
if (itab.m_type == ITab::OrderedIndex) {
4320
BSet bset(tab, itab);
4321
CHK(scanreadindex(par, itab, bset, false) == 0);
4323
CHK(hashindexread(par, itab) == 0);
4330
readverifyindex(Par par)
4334
par.m_verify = true;
4335
par.m_lockmode = NdbOperation::LM_CommittedRead;
4336
uint sel = urandom(10);
4338
par.m_ordered = true;
4339
par.m_descending = (sel < 5);
4341
CHK(scanreadindex(par) == 0);
4348
const Tab& tab = par.tab();
4349
par.m_randomkey = true;
4350
for (uint i = 0; i < par.m_ssloop; i++) {
4352
while (j < tab.m_itabs) {
4353
if (tab.m_itab[j] != 0) {
4354
const ITab& itab = *tab.m_itab[j];
4355
if (itab.m_type == ITab::UniqueHashIndex && urandom(5) == 0)
4360
uint sel = urandom(10);
4361
if (par.m_slno % 2 == 0) {
4364
CHK(pkinsert(par) == 0);
4365
} else if (sel < 9) {
4366
if (j == tab.m_itabs)
4367
CHK(pkupdate(par) == 0);
4369
const ITab& itab = *tab.m_itab[j];
4370
CHK(hashindexupdate(par, itab) == 0);
4373
if (j == tab.m_itabs)
4374
CHK(pkdelete(par) == 0);
4376
const ITab& itab = *tab.m_itab[j];
4377
CHK(hashindexdelete(par, itab) == 0);
4383
CHK(pkinsert(par) == 0);
4384
} else if (sel < 2) {
4385
if (j == tab.m_itabs)
4386
CHK(pkupdate(par) == 0);
4388
const ITab& itab = *tab.m_itab[j];
4389
CHK(hashindexupdate(par, itab) == 0);
4392
if (j == tab.m_itabs)
4393
CHK(pkdelete(par) == 0);
4395
const ITab& itab = *tab.m_itab[j];
4396
CHK(hashindexdelete(par, itab) == 0);
4405
pkupdatescanread(Par par)
4408
par.m_catcherr |= Con::ErrDeadlock;
4409
uint sel = urandom(10);
4411
CHK(pkupdate(par) == 0);
4412
} else if (sel < 6) {
4413
par.m_verify = false;
4414
CHK(scanreadtable(par) == 0);
4416
par.m_verify = false;
4418
par.m_ordered = true;
4419
par.m_descending = (sel < 7);
4421
CHK(scanreadindex(par) == 0);
4427
mixedoperations(Par par)
4430
par.m_catcherr |= Con::ErrDeadlock;
4431
par.m_scanstop = par.m_totrows; // randomly close scans
4432
uint sel = urandom(10);
4434
CHK(pkdelete(par) == 0);
4435
} else if (sel < 4) {
4436
CHK(pkupdate(par) == 0);
4437
} else if (sel < 6) {
4438
CHK(scanupdatetable(par) == 0);
4441
par.m_ordered = true;
4442
par.m_descending = (sel < 7);
4444
CHK(scanupdateindex(par) == 0);
4450
parallelorderedupdate(Par par)
4452
const Tab& tab = par.tab();
4454
for (uint i = 0; i < tab.m_itabs; i++) {
4455
if (tab.m_itab[i] == 0)
4457
const ITab& itab = *tab.m_itab[i];
4458
if (itab.m_type != ITab::OrderedIndex)
4460
// cannot sync threads yet except via subloop
4461
if (k++ == par.m_slno % tab.m_orderedindexes) {
4462
LL3("parallelorderedupdate: " << itab.m_name);
4463
par.m_noindexkeyupdate = true;
4464
par.m_ordered = true;
4465
par.m_descending = (par.m_slno != 0);
4467
par.m_verify = true;
4468
BSet bset(tab, itab); // empty bounds
4469
// prefer empty bounds
4470
uint sel = urandom(10);
4471
CHK(scanupdateindex(par, itab, bset, sel < 2) == 0);
4478
pkupdateindexbuild(Par par)
4480
if (par.m_no == 0) {
4481
CHK(createindex(par) == 0);
4483
par.m_randomkey = true;
4484
CHK(pkupdate(par) == 0);
4489
// savepoint tests (single thread for now)
4492
enum Res { Committed, Latest, Deadlock };
4493
bool m_same; // same transaction
4494
NdbOperation::LockMode m_lm;
4498
static Spt sptlist[] = {
4499
{ 1, NdbOperation::LM_Read, Spt::Latest },
4500
{ 1, NdbOperation::LM_Exclusive, Spt::Latest },
4501
{ 1, NdbOperation::LM_CommittedRead, Spt::Latest },
4502
{ 0, NdbOperation::LM_Read, Spt::Deadlock },
4503
{ 0, NdbOperation::LM_Exclusive, Spt::Deadlock },
4504
{ 0, NdbOperation::LM_CommittedRead, Spt::Committed }
4506
static uint sptcount = sizeof(sptlist)/sizeof(sptlist[0]);
4509
savepointreadpk(Par par, Spt spt)
4511
LL3("savepointreadpk");
4512
Con& con = par.con();
4513
const Tab& tab = par.tab();
4514
Set& set = par.set();
4515
const Set& set1 = set;
4516
Set set2(tab, set.m_rows);
4518
for (uint i = 0; i < set.m_rows; i++) {
4520
if (!set.compat(par, i, Row::OpREAD)) {
4521
LL4("savepointreadpk SKIP " << i << " " << set.getrow(i));
4526
CHK(set2.selrow(par, *set1.m_row[i]) == 0);
4527
uint err = par.m_catcherr | Con::ErrDeadlock;
4528
ExecType et = NoCommit;
4529
CHK(con.execute(et, err) == 0);
4531
if (err & Con::ErrDeadlock) {
4532
CHK(spt.m_res == Spt::Deadlock);
4533
// all rows have same behaviour
4536
LL1("savepointreadpk stop on " << con.errname(err));
4540
CHK(set2.getkey(par, &i2) == 0 && i == i2);
4541
CHK(set2.putval(i, false) == 0);
4542
LL4("row " << set2.count() << " " << set2.getrow(i));
4545
bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead);
4546
if (spt.m_res != Spt::Deadlock)
4547
CHK(set1.verify(par, set2, false, dirty) == 0);
4552
savepointreadhashindex(Par par, Spt spt)
4554
if (spt.m_lm == NdbOperation::LM_CommittedRead && !spt.m_same) {
4555
LL1("skip hash index dirty read");
4558
LL3("savepointreadhashindex");
4559
Con& con = par.con();
4560
const Tab& tab = par.tab();
4561
const ITab& itab = par.itab();
4562
Set& set = par.set();
4563
const Set& set1 = set;
4564
Set set2(tab, set.m_rows);
4566
for (uint i = 0; i < set.m_rows; i++) {
4568
if (!set.compat(par, i, Row::OpREAD)) {
4569
LL3("savepointreadhashindex SKIP " << i << " " << set.getrow(i));
4574
CHK(set2.selrow(par, itab, *set1.m_row[i]) == 0);
4575
uint err = par.m_catcherr | Con::ErrDeadlock;
4576
ExecType et = NoCommit;
4577
CHK(con.execute(et, err) == 0);
4579
if (err & Con::ErrDeadlock) {
4580
CHK(spt.m_res == Spt::Deadlock);
4581
// all rows have same behaviour
4584
LL1("savepointreadhashindex stop on " << con.errname(err));
4588
CHK(set2.getkey(par, &i2) == 0 && i == i2);
4589
CHK(set2.putval(i, false) == 0);
4590
LL4("row " << set2.count() << " " << *set2.m_row[i]);
4593
bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead);
4594
if (spt.m_res != Spt::Deadlock)
4595
CHK(set1.verify(par, set2, false, dirty) == 0);
4600
savepointscantable(Par par, Spt spt)
4602
LL3("savepointscantable");
4603
Con& con = par.con();
4604
const Tab& tab = par.tab();
4605
const Set& set = par.set();
4606
const Set& set1 = set; // not modifying current set
4607
Set set2(tab, set.m_rows); // scan result
4608
CHK(con.getNdbScanOperation(tab) == 0);
4609
CHK(con.readTuples(par) == 0);
4610
set2.getval(par); // getValue all columns
4611
CHK(con.executeScan() == 0);
4612
bool deadlock = false;
4616
uint err = par.m_catcherr | Con::ErrDeadlock;
4617
CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1);
4621
if (err & Con::ErrDeadlock) {
4622
CHK(spt.m_res == Spt::Deadlock);
4623
// all rows have same behaviour
4627
LL1("savepointscantable stop on " << con.errname(err));
4630
CHK(spt.m_res != Spt::Deadlock);
4632
CHK(set2.getkey(par, &i) == 0);
4633
CHK(set2.putval(i, false, n) == 0);
4634
LL4("row " << n << " key " << i << " " << set2.getrow(i));
4637
if (set1.m_rows > 0) {
4639
CHK(spt.m_res != Spt::Deadlock);
4641
CHK(spt.m_res == Spt::Deadlock);
4643
LL2("savepointscantable " << n << " rows");
4644
bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead);
4645
if (spt.m_res != Spt::Deadlock)
4646
CHK(set1.verify(par, set2, false, dirty) == 0);
4651
savepointscanindex(Par par, Spt spt)
4653
LL3("savepointscanindex");
4654
Con& con = par.con();
4655
const Tab& tab = par.tab();
4656
const ITab& itab = par.itab();
4657
const Set& set = par.set();
4658
const Set& set1 = set;
4659
Set set2(tab, set.m_rows);
4660
CHK(con.getNdbIndexScanOperation(itab, tab) == 0);
4661
CHK(con.readIndexTuples(par) == 0);
4663
CHK(con.executeScan() == 0);
4664
bool deadlock = false;
4668
uint err = par.m_catcherr | Con::ErrDeadlock;
4669
CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1);
4673
if (err & Con::ErrDeadlock) {
4674
CHK(spt.m_res == Spt::Deadlock);
4675
// all rows have same behaviour
4679
LL1("savepointscanindex stop on " << con.errname(err));
4682
CHK(spt.m_res != Spt::Deadlock);
4684
CHK(set2.getkey(par, &i) == 0);
4685
CHK(set2.putval(i, par.m_dups, n) == 0);
4686
LL4("row " << n << " key " << i << " " << set2.getrow(i));
4689
if (set1.m_rows > 0) {
4691
CHK(spt.m_res != Spt::Deadlock);
4693
CHK(spt.m_res == Spt::Deadlock);
4695
LL2("savepointscanindex " << n << " rows");
4696
bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead);
4697
if (spt.m_res != Spt::Deadlock)
4698
CHK(set1.verify(par, set2, false, dirty) == 0);
4702
typedef int (*SptFun)(Par, Spt);
4705
savepointtest(Par par, Spt spt, SptFun fun)
4707
Con& con = par.con();
4711
con2.connect(con); // copy ndb reference
4713
CHK(con2.startTransaction() == 0);
4715
par2.m_lockmode = spt.m_lm;
4716
CHK((*fun)(par2, spt) == 0);
4718
con2.closeTransaction();
4724
savepointtest(Par par, const char* op)
4726
Con& con = par.con();
4727
const Tab& tab = par.tab();
4728
Set& set = par.set();
4729
LL2("savepointtest op=\"" << op << "\"");
4730
CHK(con.startTransaction() == 0);
4733
while ((c = *p++) != 0) {
4735
for (j = 0; j < par.m_rows; j++) {
4736
uint i = thrrow(par, j);
4738
ExecType et = Commit;
4739
CHK(con.execute(et) == 0);
4743
CHK(con.startTransaction() == 0);
4749
CHK(set.insrow(par, i) == 0);
4750
} else if (c == 'u') {
4751
set.copyval(i, tab.m_pkmask);
4752
set.calc(par, i, ~tab.m_pkmask);
4753
CHK(set.updrow(par, i) == 0);
4754
} else if (c == 'd') {
4755
set.copyval(i, tab.m_pkmask);
4756
CHK(set.delrow(par, i) == 0);
4765
ExecType et = NoCommit;
4766
CHK(con.execute(et) == 0);
4771
for (uint k = 0; k < sptcount; k++) {
4772
Spt spt = sptlist[k];
4773
LL2("spt lm=" << spt.m_lm << " same=" << spt.m_same);
4774
CHK(savepointtest(par, spt, &savepointreadpk) == 0);
4775
CHK(savepointtest(par, spt, &savepointscantable) == 0);
4776
for (uint i = 0; i < tab.m_itabs; i++) {
4777
if (tab.m_itab[i] == 0)
4779
const ITab& itab = *tab.m_itab[i];
4781
if (itab.m_type == ITab::OrderedIndex)
4782
CHK(savepointtest(par, spt, &savepointscanindex) == 0);
4784
CHK(savepointtest(par, spt, &savepointreadhashindex) == 0);
4789
ExecType et = Rollback;
4790
CHK(con.execute(et) == 0);
4795
con.closeTransaction();
4800
savepointtest(Par par)
4802
assert(par.m_usedthreads == 1);
4803
const char* oplist[] = {
4804
// each based on previous and "c" not last
4813
for (i = 0; oplist[i] != 0; i++) {
4814
CHK(savepointtest(par, oplist[i]) == 0);
4820
halloweentest(Par par, const ITab& itab)
4822
LL2("halloweentest " << itab.m_name);
4823
Con& con = par.con();
4824
const Tab& tab = par.tab();
4825
Set& set = par.set();
4826
CHK(con.startTransaction() == 0);
4831
CHK(set.insrow(par, i) == 0);
4832
CHK(con.execute(NoCommit) == 0);
4833
// scan via index until Set m_rows reached
4837
par.m_lockmode = // makes no difference
4838
scancount % 2 == 0 ? NdbOperation::LM_CommittedRead :
4839
NdbOperation::LM_Read;
4840
Set set1(tab, set.m_rows); // expected scan result
4841
Set set2(tab, set.m_rows); // actual scan result
4842
BSet bset(tab, itab);
4843
calcscanbounds(par, itab, bset, set, set1);
4844
CHK(con.getNdbIndexScanOperation(itab, tab) == 0);
4845
CHK(con.readIndexTuples(par) == 0);
4846
CHK(bset.setbnd(par) == 0);
4848
CHK(con.executeScan() == 0);
4849
const uint savepoint = i;
4850
LL3("scancount=" << scancount << " savepoint=" << savepoint);
4854
CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
4858
CHK(set2.getkey(par, &k) == 0);
4859
CHK(set2.putval(k, false, n) == 0);
4860
LL3("row=" << n << " key=" << k);
4861
CHK(k <= savepoint);
4862
if (++i == set.m_rows) {
4868
CHK(set.insrow(par, i) == 0);
4869
CHK(con.execute(NoCommit) == 0);
4873
LL3("scanrows=" << n);
4875
CHK(set1.verify(par, set2, false) == 0);
4879
CHK(con.execute(Commit) == 0);
4880
set.post(par, Commit);
4881
assert(set.count() == set.m_rows);
4882
CHK(pkdelete(par) == 0);
4887
halloweentest(Par par)
4889
assert(par.m_usedthreads == 1);
4890
const Tab& tab = par.tab();
4891
for (uint i = 0; i < tab.m_itabs; i++) {
4892
if (tab.m_itab[i] == 0)
4894
const ITab& itab = *tab.m_itab[i];
4895
if (itab.m_type == ITab::OrderedIndex)
4896
CHK(halloweentest(par, itab) == 0);
4903
typedef int (*TFunc)(Par par);
4904
enum TMode { ST = 1, MT = 2 };
4906
extern "C" { static void* runthread(void* arg); }
4909
enum State { Wait, Start, Stop, Exit };
4913
NdbThread* m_thread;
4915
NdbCondition* m_cond;
4919
char m_tmp[20]; // used for debug msg prefix
4920
Thr(Par par, uint n);
4928
NdbMutex_Lock(m_mutex);
4931
NdbMutex_Unlock(m_mutex);
4934
NdbCondition_Wait(m_cond, m_mutex);
4937
NdbCondition_Signal(m_cond);
4940
NdbThread_WaitFor(m_thread, &m_status);
4945
Thr::Thr(Par par, uint n) :
4957
sprintf(buf, "thr%03u", par.m_no);
4958
const char* name = strcpy(new char[10], buf);
4960
m_mutex = NdbMutex_Create();
4961
m_cond = NdbCondition_Create();
4962
assert(m_mutex != 0 && m_cond != 0);
4964
const uint stacksize = 256 * 1024;
4965
const NDB_THREAD_PRIO prio = NDB_THREAD_PRIO_LOW;
4966
m_thread = NdbThread_Create(runthread, (void**)this, stacksize, name, prio);
4971
if (m_thread != 0) {
4972
NdbThread_Destroy(&m_thread);
4976
NdbCondition_Destroy(m_cond);
4980
NdbMutex_Destroy(m_mutex);
4986
runthread(void* arg)
4988
Thr& thr = *(Thr*)arg;
4989
thr.m_id = pthread_self();
4990
if (thr.run() < 0) {
4991
LL1("exit on error");
5003
CHK(con.connect() == 0);
5008
while (m_state != Start && m_state != Exit) {
5012
if (m_state == Exit) {
5018
assert(m_state == Start);
5019
m_ret = (*m_func)(m_par);
5026
LL1("continue running due to -cont");
5048
while (m_state != Stop)
5065
static Thr** g_thrlist = 0;
5070
if (g_thrlist != 0) {
5071
pthread_t id = pthread_self();
5072
for (uint n = 0; n < g_opt.m_threads; n++) {
5073
if (g_thrlist[n] != 0) {
5074
Thr& thr = *g_thrlist[n];
5075
if (pthread_equal(thr.m_id, id))
5083
// for debug messages (par.m_no not available)
5087
Thr* thrp = getthr();
5090
uint n = thr.m_par.m_no;
5092
g_opt.m_threads < 10 ? 1 :
5093
g_opt.m_threads < 100 ? 2 : 3;
5094
sprintf(thr.m_tmp, "[%0*u] ", m, n);
5101
runstep(Par par, const char* fname, TFunc func, uint mode)
5103
LL2("step: " << fname);
5104
const int threads = (mode & ST ? 1 : par.m_usedthreads);
5106
for (n = 0; n < threads; n++) {
5108
Thr& thr = *g_thrlist[n];
5109
Par oldpar = thr.m_par;
5110
// update parameters
5112
thr.m_par.m_no = oldpar.m_no;
5113
thr.m_par.m_con = oldpar.m_con;
5118
for (n = threads - 1; n >= 0; n--) {
5120
Thr& thr = *g_thrlist[n];
5129
#define RUNSTEP(par, func, mode) \
5130
CHK(runstep(par, #func, func, mode) == 0)
5132
#define SUBLOOP(par) \
5133
"sloop: " << par.m_lno << "/" << par.m_currcase << "/" << \
5134
par.m_tab->m_name << "/" << par.m_slno
5139
RUNSTEP(par, droptable, ST);
5140
RUNSTEP(par, createtable, ST);
5141
RUNSTEP(par, invalidatetable, MT);
5142
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5144
if (par.m_slno % 3 == 0) {
5145
RUNSTEP(par, createindex, ST);
5146
RUNSTEP(par, invalidateindex, MT);
5147
RUNSTEP(par, pkinsert, MT);
5148
RUNSTEP(par, pkupdate, MT);
5149
} else if (par.m_slno % 3 == 1) {
5150
RUNSTEP(par, pkinsert, MT);
5151
RUNSTEP(par, createindex, ST);
5152
RUNSTEP(par, invalidateindex, MT);
5153
RUNSTEP(par, pkupdate, MT);
5155
RUNSTEP(par, pkinsert, MT);
5156
RUNSTEP(par, pkupdate, MT);
5157
RUNSTEP(par, createindex, ST);
5158
RUNSTEP(par, invalidateindex, MT);
5160
RUNSTEP(par, readverifyfull, MT);
5162
if (par.m_slno + 1 < par.m_sloop) {
5163
RUNSTEP(par, pkdelete, MT);
5164
RUNSTEP(par, readverifyfull, MT);
5165
RUNSTEP(par, dropindex, ST);
5174
RUNSTEP(par, droptable, ST);
5175
RUNSTEP(par, createtable, ST);
5176
RUNSTEP(par, invalidatetable, MT);
5177
RUNSTEP(par, createindex, ST);
5178
RUNSTEP(par, invalidateindex, MT);
5179
RUNSTEP(par, pkinsert, MT);
5180
RUNSTEP(par, readverifyfull, MT);
5181
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5183
RUNSTEP(par, readverifyindex, MT);
5192
RUNSTEP(par, droptable, ST);
5193
RUNSTEP(par, createtable, ST);
5194
RUNSTEP(par, invalidatetable, MT);
5195
RUNSTEP(par, createindex, ST);
5196
RUNSTEP(par, invalidateindex, MT);
5197
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5199
RUNSTEP(par, pkops, MT);
5200
LL2("rows=" << par.set().count());
5201
RUNSTEP(par, readverifyfull, MT);
5209
RUNSTEP(par, droptable, ST);
5210
RUNSTEP(par, createtable, ST);
5211
RUNSTEP(par, invalidatetable, MT);
5212
RUNSTEP(par, pkinsert, MT);
5213
RUNSTEP(par, createindex, ST);
5214
RUNSTEP(par, invalidateindex, MT);
5215
RUNSTEP(par, readverifyfull, MT);
5216
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5218
RUNSTEP(par, pkupdatescanread, MT);
5219
RUNSTEP(par, readverifyfull, MT);
5221
RUNSTEP(par, pkdelete, MT);
5222
RUNSTEP(par, readverifyfull, MT);
5229
RUNSTEP(par, droptable, ST);
5230
RUNSTEP(par, createtable, ST);
5231
RUNSTEP(par, invalidatetable, MT);
5232
RUNSTEP(par, pkinsert, MT);
5233
RUNSTEP(par, createindex, ST);
5234
RUNSTEP(par, invalidateindex, MT);
5235
RUNSTEP(par, readverifyfull, MT);
5236
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5238
RUNSTEP(par, mixedoperations, MT);
5239
RUNSTEP(par, readverifyfull, MT);
5247
RUNSTEP(par, droptable, ST);
5248
RUNSTEP(par, createtable, ST);
5249
RUNSTEP(par, invalidatetable, MT);
5250
RUNSTEP(par, pkinsert, MT);
5251
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5253
RUNSTEP(par, pkupdateindexbuild, MT);
5254
RUNSTEP(par, invalidateindex, MT);
5255
RUNSTEP(par, readverifyfull, MT);
5256
RUNSTEP(par, dropindex, ST);
5264
par.m_abortpct = 50;
5265
RUNSTEP(par, droptable, ST);
5266
RUNSTEP(par, createtable, ST);
5267
RUNSTEP(par, invalidatetable, MT);
5268
RUNSTEP(par, pkinsert, MT);
5269
RUNSTEP(par, createindex, ST);
5270
RUNSTEP(par, invalidateindex, MT);
5271
RUNSTEP(par, readverifyfull, MT);
5272
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5274
RUNSTEP(par, mixedoperations, MT);
5275
RUNSTEP(par, readverifyfull, MT);
5283
RUNSTEP(par, droptable, ST);
5284
RUNSTEP(par, createtable, ST);
5285
RUNSTEP(par, invalidatetable, MT);
5286
RUNSTEP(par, pkinsert, MT);
5287
RUNSTEP(par, createindex, ST);
5288
RUNSTEP(par, invalidateindex, MT);
5289
RUNSTEP(par, readverifyfull, MT);
5290
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5292
RUNSTEP(par, parallelorderedupdate, MT);
5293
RUNSTEP(par, readverifyfull, MT);
5301
RUNSTEP(par, droptable, ST);
5302
RUNSTEP(par, createtable, ST);
5303
RUNSTEP(par, invalidatetable, MT);
5304
RUNSTEP(par, createindex, ST);
5305
RUNSTEP(par, invalidateindex, MT);
5306
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5308
RUNSTEP(par, savepointtest, MT);
5309
RUNSTEP(par, readverifyfull, MT);
5317
RUNSTEP(par, droptable, ST);
5318
RUNSTEP(par, createtable, ST);
5319
RUNSTEP(par, invalidatetable, MT);
5320
RUNSTEP(par, createindex, ST);
5321
RUNSTEP(par, invalidateindex, MT);
5322
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5324
RUNSTEP(par, halloweentest, MT);
5333
RUNSTEP(par, droptable, ST);
5334
RUNSTEP(par, createtable, ST);
5335
RUNSTEP(par, invalidatetable, MT);
5336
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5338
RUNSTEP(par, pkinsert, MT);
5340
RUNSTEP(par, createindex, ST);
5341
t1.off(par.m_totrows);
5342
RUNSTEP(par, invalidateindex, MT);
5343
RUNSTEP(par, dropindex, ST);
5345
LL1("build index - " << t1.time());
5353
RUNSTEP(par, droptable, ST);
5354
RUNSTEP(par, createtable, ST);
5355
RUNSTEP(par, invalidatetable, MT);
5356
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5358
RUNSTEP(par, pkinsert, MT);
5360
RUNSTEP(par, pkupdate, MT);
5361
t1.off(par.m_totrows);
5362
RUNSTEP(par, createindex, ST);
5363
RUNSTEP(par, invalidateindex, MT);
5365
RUNSTEP(par, pkupdate, MT);
5366
t2.off(par.m_totrows);
5367
RUNSTEP(par, dropindex, ST);
5369
LL1("update - " << t1.time());
5370
LL1("update indexed - " << t2.time());
5371
LL1("overhead - " << t2.over(t1));
5378
if (par.tab().m_itab[0] == 0) {
5379
LL1("ttimescan - no index 0, skipped");
5383
RUNSTEP(par, droptable, ST);
5384
RUNSTEP(par, createtable, ST);
5385
RUNSTEP(par, invalidatetable, MT);
5386
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5388
RUNSTEP(par, pkinsert, MT);
5389
RUNSTEP(par, createindex, ST);
5391
RUNSTEP(par, timescantable, ST);
5393
RUNSTEP(par, timescanpkindex, ST);
5394
RUNSTEP(par, dropindex, ST);
5396
LL1("full scan table - " << t1.time());
5397
LL1("full scan PK index - " << t2.time());
5398
LL1("overhead - " << t2.over(t1));
5403
ttimepkread(Par par)
5405
if (par.tab().m_itab[0] == 0) {
5406
LL1("ttimescan - no index 0, skipped");
5410
RUNSTEP(par, droptable, ST);
5411
RUNSTEP(par, createtable, ST);
5412
RUNSTEP(par, invalidatetable, MT);
5413
for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) {
5415
RUNSTEP(par, pkinsert, MT);
5416
RUNSTEP(par, createindex, ST);
5418
RUNSTEP(par, timepkreadtable, ST);
5420
RUNSTEP(par, timepkreadindex, ST);
5421
RUNSTEP(par, dropindex, ST);
5423
LL1("pk read table - " << t1.time());
5424
LL1("pk read PK index - " << t2.time());
5425
LL1("overhead - " << t2.over(t1));
5432
RUNSTEP(par, droptable, ST);
5440
TCase(const char* name, TFunc func, const char* desc) :
5449
TCase("a", tbuild, "index build"),
5450
TCase("b", tindexscan, "index scans"),
5451
TCase("c", tpkops, "pk operations"),
5452
TCase("d", tpkopsread, "pk operations and scan reads"),
5453
TCase("e", tmixedops, "pk operations and scan operations"),
5454
TCase("f", tbusybuild, "pk operations and index build"),
5455
TCase("g", trollback, "operations with random rollbacks"),
5456
TCase("h", tparupdate, "parallel ordered update bug#20446"),
5457
TCase("i", tsavepoint, "savepoint test locking bug#31477"),
5458
TCase("j", thalloween, "savepoint test halloween problem"),
5459
TCase("t", ttimebuild, "time index build"),
5460
TCase("u", ttimemaint, "time index maintenance"),
5461
TCase("v", ttimescan, "time full scan table vs index on pk"),
5462
TCase("w", ttimepkread, "time pk read table vs index on pk"),
5463
TCase("z", tdrop, "drop test tables")
5467
tcasecount = sizeof(tcaselist) / sizeof(tcaselist[0]);
5472
ndbout << "test cases:" << endl;
5473
for (uint i = 0; i < tcasecount; i++) {
5474
const TCase& tcase = tcaselist[i];
5475
ndbout << " " << tcase.m_name << " - " << tcase.m_desc << endl;
5483
makebuiltintables(par);
5484
ndbout << "tables and indexes (x=ordered z=hash x0=on pk):" << endl;
5485
for (uint j = 0; j < tabcount; j++) {
5486
if (tablist[j] == 0)
5488
const Tab& tab = *tablist[j];
5489
const char* tname = tab.m_name;
5490
ndbout << " " << tname;
5491
for (uint i = 0; i < tab.m_itabs; i++) {
5492
if (tab.m_itab[i] == 0)
5494
const ITab& itab = *tab.m_itab[i];
5495
const char* iname = itab.m_name;
5496
if (strncmp(tname, iname, strlen(tname)) == 0)
5497
iname += strlen(tname);
5498
ndbout << " " << iname;
5500
for (uint k = 0; k < itab.m_icols; k++) {
5503
const ICol& icol = *itab.m_icol[k];
5504
const Col& col = icol.m_col;
5505
ndbout << col.m_name;
5514
setcasepar(Par& par)
5517
const char* c = par.m_currcase;
5521
if (par.m_usedthreads > 1) {
5522
par.m_usedthreads = 1;
5523
LL1("case " << c << " reduce threads to " << par.m_usedthreads);
5525
const uint rows = 100;
5526
if (par.m_rows > rows) {
5528
LL1("case " << c << " reduce rows to " << rows);
5534
if (par.m_usedthreads > 1) {
5535
par.m_usedthreads = 1;
5536
LL1("case " << c << " reduce threads to " << par.m_usedthreads);
5550
if (par.m_seed == -1) {
5551
// good enough for daily run
5552
ushort seed = (ushort)getpid();
5553
LL0("random seed: " << seed);
5554
srandom((uint)seed);
5555
} else if (par.m_seed != 0) {
5556
LL0("random seed: " << par.m_seed);
5557
srandom(par.m_seed);
5559
LL0("random seed: loop number");
5562
assert(par.m_csname != 0);
5563
if (strcmp(par.m_csname, "random") != 0) {
5565
CHK((cs = get_charset_by_name(par.m_csname, MYF(0))) != 0 || (cs = get_charset_by_csname(par.m_csname, MY_CS_PRIMARY, MYF(0))) != 0);
5570
CHK(con.connect() == 0);
5572
par.m_catcherr |= Con::ErrNospace;
5574
g_thrlist = new Thr* [par.m_threads];
5576
for (n = 0; n < par.m_threads; n++) {
5579
for (n = 0; n < par.m_threads; n++) {
5580
g_thrlist[n] = new Thr(par, n);
5581
Thr& thr = *g_thrlist[n];
5582
assert(thr.m_thread != 0);
5584
for (par.m_lno = 0; par.m_loop == 0 || par.m_lno < par.m_loop; par.m_lno++) {
5585
LL1("loop: " << par.m_lno);
5586
if (par.m_seed == 0) {
5587
LL1("random seed: " << par.m_lno);
5590
for (uint i = 0; i < tcasecount; i++) {
5591
const TCase& tcase = tcaselist[i];
5592
if (par.m_case != 0 && strchr(par.m_case, tcase.m_name[0]) == 0 ||
5593
par.m_skip != 0 && strchr(par.m_skip, tcase.m_name[0]) != 0) {
5596
sprintf(par.m_currcase, "%c", tcase.m_name[0]);
5597
par.m_usedthreads = par.m_threads;
5598
if (!setcasepar(par)) {
5599
LL1("case " << tcase.m_name << " cannot run with given options");
5602
par.m_totrows = par.m_usedthreads * par.m_rows;
5603
makebuiltintables(par);
5604
LL1("case: " << par.m_lno << "/" << tcase.m_name << " - " << tcase.m_desc);
5605
for (uint j = 0; j < tabcount; j++) {
5606
if (tablist[j] == 0)
5608
const Tab& tab = *tablist[j];
5610
par.m_set = new Set(tab, par.m_totrows);
5611
LL1("table: " << par.m_lno << "/" << tcase.m_name << "/" << tab.m_name);
5612
int ret = tcase.m_func(par);
5619
LL1("continue to next case due to -cont");
5625
for (n = 0; n < par.m_threads; n++) {
5626
Thr& thr = *g_thrlist[n];
5629
for (n = 0; n < par.m_threads; n++) {
5630
Thr& thr = *g_thrlist[n];
5634
delete [] g_thrlist;
5640
static const char* g_progname = "testOIBasic";
5643
main(int argc, char** argv)
5647
ndbout << g_progname;
5648
for (i = 1; i < argc; i++)
5649
ndbout << " " << argv[i];
5651
ndbout_mutex = NdbMutex_Create();
5652
while (++argv, --argc > 0) {
5653
const char* arg = argv[0];
5655
ndbout << "testOIBasic: unknown argument " << arg;
5658
if (strcmp(arg, "-batch") == 0) {
5659
if (++argv, --argc > 0) {
5660
g_opt.m_batch = atoi(argv[0]);
5664
if (strcmp(arg, "-bound") == 0) {
5665
if (++argv, --argc > 0) {
5666
const char* p = argv[0];
5667
if (strlen(p) != 0 && strlen(p) == strspn(p, "01234")) {
5668
g_opt.m_bound = strdup(p);
5673
if (strcmp(arg, "-case") == 0) {
5674
if (++argv, --argc > 0) {
5675
g_opt.m_case = strdup(argv[0]);
5679
if (strcmp(arg, "-collsp") == 0) {
5680
g_opt.m_collsp = true;
5683
if (strcmp(arg, "-cont") == 0) {
5684
g_opt.m_cont = true;
5687
if (strcmp(arg, "-core") == 0) {
5688
g_opt.m_core = true;
5691
if (strcmp(arg, "-csname") == 0) {
5692
if (++argv, --argc > 0) {
5693
g_opt.m_csname = strdup(argv[0]);
5697
if (strcmp(arg, "-die") == 0) {
5698
if (++argv, --argc > 0) {
5699
g_opt.m_die = atoi(argv[0]);
5703
if (strcmp(arg, "-dups") == 0) {
5704
g_opt.m_dups = true;
5707
if (strcmp(arg, "-fragtype") == 0) {
5708
if (++argv, --argc > 0) {
5709
if (strcmp(argv[0], "single") == 0) {
5710
g_opt.m_fragtype = NdbDictionary::Object::FragSingle;
5713
if (strcmp(argv[0], "small") == 0) {
5714
g_opt.m_fragtype = NdbDictionary::Object::FragAllSmall;
5717
if (strcmp(argv[0], "medium") == 0) {
5718
g_opt.m_fragtype = NdbDictionary::Object::FragAllMedium;
5721
if (strcmp(argv[0], "large") == 0) {
5722
g_opt.m_fragtype = NdbDictionary::Object::FragAllLarge;
5727
if (strcmp(arg, "-index") == 0) {
5728
if (++argv, --argc > 0) {
5729
g_opt.m_index = strdup(argv[0]);
5733
if (strcmp(arg, "-loop") == 0) {
5734
if (++argv, --argc > 0) {
5735
g_opt.m_loop = atoi(argv[0]);
5739
if (strcmp(arg, "-nologging") == 0) {
5740
g_opt.m_nologging = true;
5743
if (strcmp(arg, "-noverify") == 0) {
5744
g_opt.m_noverify = true;
5747
if (strcmp(arg, "-pctnull") == 0) {
5748
if (++argv, --argc > 0) {
5749
g_opt.m_pctnull = atoi(argv[0]);
5753
if (strcmp(arg, "-rows") == 0) {
5754
if (++argv, --argc > 0) {
5755
g_opt.m_rows = atoi(argv[0]);
5759
if (strcmp(arg, "-samples") == 0) {
5760
if (++argv, --argc > 0) {
5761
g_opt.m_samples = atoi(argv[0]);
5765
if (strcmp(arg, "-scanbatch") == 0) {
5766
if (++argv, --argc > 0) {
5767
g_opt.m_scanbatch = atoi(argv[0]);
5771
if (strcmp(arg, "-scanpar") == 0) {
5772
if (++argv, --argc > 0) {
5773
g_opt.m_scanpar = atoi(argv[0]);
5777
if (strcmp(arg, "-seed") == 0) {
5778
if (++argv, --argc > 0) {
5779
g_opt.m_seed = atoi(argv[0]);
5783
if (strcmp(arg, "-skip") == 0) {
5784
if (++argv, --argc > 0) {
5785
g_opt.m_skip = strdup(argv[0]);
5789
if (strcmp(arg, "-sloop") == 0) {
5790
if (++argv, --argc > 0) {
5791
g_opt.m_sloop = atoi(argv[0]);
5795
if (strcmp(arg, "-ssloop") == 0) {
5796
if (++argv, --argc > 0) {
5797
g_opt.m_ssloop = atoi(argv[0]);
5801
if (strcmp(arg, "-table") == 0) {
5802
if (++argv, --argc > 0) {
5803
g_opt.m_table = strdup(argv[0]);
5807
if (strcmp(arg, "-threads") == 0) {
5808
if (++argv, --argc > 0) {
5809
g_opt.m_threads = atoi(argv[0]);
5810
if (1 <= g_opt.m_threads)
5814
if (strcmp(arg, "-v") == 0) {
5815
if (++argv, --argc > 0) {
5816
g_opt.m_v = atoi(argv[0]);
5820
if (strncmp(arg, "-v", 2) == 0 && isdigit(arg[2])) {
5821
g_opt.m_v = atoi(&arg[2]);
5824
if (strcmp(arg, "-h") == 0 || strcmp(arg, "-help") == 0) {
5828
ndbout << "testOIBasic: bad or unknown option " << arg;
5833
g_ncc = new Ndb_cluster_connection();
5834
if (g_ncc->connect(30) != 0 || runtest(par) < 0)
5840
return NDBT_ProgramExit(NDBT_OK);
5842
return NDBT_ProgramExit(NDBT_FAILED);
5844
ndbout << " (use -h for help)" << endl;
5846
return NDBT_ProgramExit(NDBT_WRONGARGS);
5849
// vim: set sw=2 et: