testOIBasic.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:77k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /*
  14.  * testOIBasic - ordered index test
  15.  */
  16. #include <ndb_global.h>
  17. #include <NdbMain.h>
  18. #include <NdbOut.hpp>
  19. #include <NdbApi.hpp>
  20. #include <NdbTest.hpp>
  21. #include <NdbMutex.h>
  22. #include <NdbCondition.h>
  23. #include <NdbThread.h>
  24. #include <NdbTick.h>
  25. #include <my_sys.h>
  26. // options
  27. struct Opt {
  28.   // common options
  29.   unsigned m_batch;
  30.   const char* m_bound;
  31.   const char* m_case;
  32.   bool m_core;
  33.   const char* m_csname;
  34.   CHARSET_INFO* m_cs;
  35.   int m_die;
  36.   bool m_dups;
  37.   NdbDictionary::Object::FragmentType m_fragtype;
  38.   unsigned m_subsubloop;
  39.   const char* m_index;
  40.   unsigned m_loop;
  41.   bool m_msglock;
  42.   bool m_nologging;
  43.   bool m_noverify;
  44.   unsigned m_pctnull;
  45.   unsigned m_rows;
  46.   unsigned m_samples;
  47.   unsigned m_scanbat;
  48.   unsigned m_scanpar;
  49.   unsigned m_scanstop;
  50.   unsigned m_seed;
  51.   unsigned m_subloop;
  52.   const char* m_table;
  53.   unsigned m_threads;
  54.   int m_v;
  55.   Opt() :
  56.     m_batch(32),
  57.     m_bound("01234"),
  58.     m_case(0),
  59.     m_core(false),
  60.     m_csname("latin1_bin"),
  61.     m_cs(0),
  62.     m_die(0),
  63.     m_dups(false),
  64.     m_fragtype(NdbDictionary::Object::FragUndefined),
  65.     m_subsubloop(4),
  66.     m_index(0),
  67.     m_loop(1),
  68.     m_msglock(true),
  69.     m_nologging(false),
  70.     m_noverify(false),
  71.     m_pctnull(10),
  72.     m_rows(1000),
  73.     m_samples(0),
  74.     m_scanbat(0),
  75.     m_scanpar(0),
  76.     m_scanstop(0),
  77.     m_seed(0),
  78.     m_subloop(4),
  79.     m_table(0),
  80.     m_threads(10),
  81.     m_v(1) {
  82.   }
  83. };
  84. static Opt g_opt;
  85. static void printcases();
  86. static void printtables();
  87. static void
  88. printhelp()
  89. {
  90.   Opt d;
  91.   ndbout
  92.     << "usage: testOIbasic [options]" << endl
  93.     << "  -batch N      pk operations in batch [" << d.m_batch << "]" << endl
  94.     << "  -bound xyz    use only these bound types 0-4 [" << d.m_bound << "]" << endl
  95.     << "  -case abc     only given test cases (letters a-z)" << endl
  96.     << "  -core         core dump on error [" << d.m_core << "]" << endl
  97.     << "  -csname S     charset (collation) of non-pk char column [" << d.m_csname << "]" << endl
  98.     << "  -die nnn      exit immediately on NDB error code nnn" << endl
  99.     << "  -dups         allow duplicate tuples from index scan [" << d.m_dups << "]" << endl
  100.     << "  -fragtype T   fragment type single/small/medium/large" << endl
  101.     << "  -index xyz    only given index numbers (digits 1-9)" << endl
  102.     << "  -loop N       loop count full suite 0=forever [" << d.m_loop << "]" << endl
  103.     << "  -nologging    create tables in no-logging mode" << endl
  104.     << "  -noverify     skip index verifications" << endl
  105.     << "  -pctnull N    pct NULL values in nullable column [" << d.m_pctnull << "]" << endl
  106.     << "  -rows N       rows per thread [" << d.m_rows << "]" << endl
  107.     << "  -samples N    samples for some timings (0=all) [" << d.m_samples << "]" << endl
  108.     << "  -scanbat N    scan batch per fragment (ignored by ndb api) [" << d.m_scanbat << "]" << endl
  109.     << "  -scanpar N    scan parallelism [" << d.m_scanpar << "]" << endl
  110.     << "  -seed N       srandom seed 0=loop number[" << d.m_seed << "]" << endl
  111.     << "  -subloop N    subtest loop count [" << d.m_subloop << "]" << endl
  112.     << "  -table xyz    only given table numbers (digits 1-9)" << endl
  113.     << "  -threads N    number of threads [" << d.m_threads << "]" << endl
  114.     << "  -vN           verbosity [" << d.m_v << "]" << endl
  115.     << "  -h or -help   print this help text" << endl
  116.     ;
  117.   printcases();
  118.   printtables();
  119. }
  120. // not yet configurable
  121. static const bool g_store_null_key = true;
  122. // compare NULL like normal value (NULL < not NULL, NULL == NULL)
  123. static const bool g_compare_null = true;
  124. // log and error macros
  125. static NdbMutex *ndbout_mutex= NULL;
  126. static unsigned getthrno();
  127. static const char*
  128. getthrstr()
  129. {
  130.   static char buf[20];
  131.   unsigned n = getthrno();
  132.   if (n == (unsigned)-1)
  133.     strcpy(buf, "");
  134.   else {
  135.     unsigned m =
  136.       g_opt.m_threads < 10 ? 1 :
  137.       g_opt.m_threads < 100 ? 2 : 3;
  138.     sprintf(buf, "[%0*u] ", m, n);
  139.   }
  140.   return buf;
  141. }
  142. #define LLN(n, s) 
  143.   do { 
  144.     if ((n) > g_opt.m_v) break; 
  145.     if (g_opt.m_msglock) NdbMutex_Lock(ndbout_mutex); 
  146.     ndbout << getthrstr() << s << endl; 
  147.     if (g_opt.m_msglock) NdbMutex_Unlock(ndbout_mutex); 
  148.   } while(0)
  149. #define LL0(s) LLN(0, s)
  150. #define LL1(s) LLN(1, s)
  151. #define LL2(s) LLN(2, s)
  152. #define LL3(s) LLN(3, s)
  153. #define LL4(s) LLN(4, s)
  154. #define LL5(s) LLN(5, s)
  155. // following check a condition and return -1 on failure
  156. #undef CHK      // simple check
  157. #undef CHKTRY   // check with action on fail
  158. #undef CHKCON   // print NDB API errors on failure
  159. #define CHK(x)  CHKTRY(x, ;)
  160. #define CHKTRY(x, act) 
  161.   do { 
  162.     if (x) break; 
  163.     LL0("line " << __LINE__ << ": " << #x << " failed"); 
  164.     if (g_opt.m_core) abort(); 
  165.     act; 
  166.     return -1; 
  167.   } while (0)
  168. #define CHKCON(x, con) 
  169.   do { 
  170.     if (x) break; 
  171.     LL0("line " << __LINE__ << ": " << #x << " failed"); 
  172.     (con).printerror(ndbout); 
  173.     if (g_opt.m_core) abort(); 
  174.     return -1; 
  175.   } while (0)
  176. // method parameters base class
  177. class Thr;
  178. class Con;
  179. class Tab;
  180. class Set;
  181. class Tmr;
  182. struct Par : public Opt {
  183.   unsigned m_no;
  184.   Con* m_con;
  185.   Con& con() const { assert(m_con != 0); return *m_con; }
  186.   const Tab* m_tab;
  187.   const Tab& tab() const { assert(m_tab != 0); return *m_tab; }
  188.   Set* m_set;
  189.   Set& set() const { assert(m_set != 0); return *m_set; }
  190.   Tmr* m_tmr;
  191.   Tmr& tmr() const { assert(m_tmr != 0); return *m_tmr; }
  192.   unsigned m_lno;
  193.   unsigned m_slno;
  194.   unsigned m_totrows;
  195.   // value calculation
  196.   unsigned m_range;
  197.   unsigned m_pctrange;
  198.   // choice of key
  199.   bool m_randomkey;
  200.   // do verify after read
  201.   bool m_verify;
  202.   // deadlock possible
  203.   bool m_deadlock;
  204.   // abort percentabge
  205.   unsigned m_abortpct;
  206.   // timer location
  207.   Par(const Opt& opt) :
  208.     Opt(opt),
  209.     m_no(0),
  210.     m_con(0),
  211.     m_tab(0),
  212.     m_set(0),
  213.     m_tmr(0),
  214.     m_lno(0),
  215.     m_slno(0),
  216.     m_totrows(m_threads * m_rows),
  217.     m_range(m_rows),
  218.     m_pctrange(0),
  219.     m_randomkey(false),
  220.     m_verify(false),
  221.     m_deadlock(false),
  222.     m_abortpct(0) {
  223.   }
  224. };
  225. static bool
  226. usetable(unsigned i)
  227. {
  228.   return g_opt.m_table == 0 || strchr(g_opt.m_table, '1' + i) != 0;
  229. }
  230. static bool
  231. useindex(unsigned i)
  232. {
  233.   return g_opt.m_index == 0 || strchr(g_opt.m_index, '1' + i) != 0;
  234. }
  235. static unsigned
  236. thrrow(Par par, unsigned j)
  237. {
  238.   return par.m_threads * j + par.m_no;
  239. }
  240. static bool
  241. isthrrow(Par par, unsigned i)
  242. {
  243.   return i % par.m_threads == par.m_no;
  244. }
  245. // timer
  246. struct Tmr {
  247.   void clr();
  248.   void on();
  249.   void off(unsigned cnt = 0);
  250.   const char* time();
  251.   const char* pct(const Tmr& t1);
  252.   const char* over(const Tmr& t1);
  253.   NDB_TICKS m_on;
  254.   unsigned m_ms;
  255.   unsigned m_cnt;
  256.   char m_time[100];
  257.   char m_text[100];
  258.   Tmr() { clr(); }
  259. };
  260. void
  261. Tmr::clr()
  262. {
  263.   m_on = m_ms = m_cnt = m_time[0] = m_text[0] = 0;
  264. }
  265. void
  266. Tmr::on()
  267. {
  268.   assert(m_on == 0);
  269.   m_on = NdbTick_CurrentMillisecond();
  270. }
  271. void
  272. Tmr::off(unsigned cnt)
  273. {
  274.   NDB_TICKS off = NdbTick_CurrentMillisecond();
  275.   assert(m_on != 0 && off >= m_on);
  276.   m_ms += off - m_on;
  277.   m_cnt += cnt;
  278.   m_on = 0;
  279. }
  280. const char*
  281. Tmr::time()
  282. {
  283.   if (m_cnt == 0) {
  284.     sprintf(m_time, "%u ms", m_ms);
  285.   } else {
  286.     sprintf(m_time, "%u ms per %u ( %u ms per 1000 )", m_ms, m_cnt, (1000 * m_ms) / m_cnt);
  287.   }
  288.   return m_time;
  289. }
  290. const char*
  291. Tmr::pct(const Tmr& t1)
  292. {
  293.   if (0 < t1.m_ms) {
  294.     sprintf(m_text, "%u pct", (100 * m_ms) / t1.m_ms);
  295.   } else {
  296.     sprintf(m_text, "[cannot measure]");
  297.   }
  298.   return m_text;
  299. }
  300. const char*
  301. Tmr::over(const Tmr& t1)
  302. {
  303.   if (0 < t1.m_ms) {
  304.     if (t1.m_ms <= m_ms)
  305.       sprintf(m_text, "%u pct", (100 * (m_ms - t1.m_ms)) / t1.m_ms);
  306.     else
  307.       sprintf(m_text, "-%u pct", (100 * (t1.m_ms - m_ms)) / t1.m_ms);
  308.   } else {
  309.     sprintf(m_text, "[cannot measure]");
  310.   }
  311.   return m_text;
  312. }
  313. // list of ints
  314. struct Lst {
  315.   Lst();
  316.   unsigned m_arr[1000];
  317.   unsigned m_cnt;
  318.   void push(unsigned i);
  319.   unsigned cnt() const;
  320.   void reset();
  321. };
  322. Lst::Lst() :
  323.   m_cnt(0)
  324. {
  325. }
  326. void
  327. Lst::push(unsigned i)
  328. {
  329.   assert(m_cnt < sizeof(m_arr)/sizeof(m_arr[0]));
  330.   m_arr[m_cnt++] = i;
  331. }
  332. unsigned
  333. Lst::cnt() const
  334. {
  335.   return m_cnt;
  336. }
  337. void
  338. Lst::reset()
  339. {
  340.   m_cnt = 0;
  341. }
  342. // tables and indexes
  343. // Col - table column
  344. struct Col {
  345.   unsigned m_num;
  346.   const char* m_name;
  347.   bool m_pk;
  348.   NdbDictionary::Column::Type m_type;
  349.   unsigned m_length;
  350.   bool m_nullable;
  351.   void verify(const void* addr) const;
  352. };
  353. void
  354. Col::verify(const void* addr) const
  355. {
  356.   switch (m_type) {
  357.   case NdbDictionary::Column::Unsigned:
  358.     break;
  359.   case NdbDictionary::Column::Varchar:
  360.     {
  361.       const unsigned char* p = (const unsigned char*)addr;
  362.       unsigned n = (p[0] << 8) | p[1];
  363.       assert(n <= m_length);
  364.       unsigned i;
  365.       for (i = 0; i < n; i++) {
  366.         assert(p[2 + i] != 0);
  367.       }
  368.       for (i = n; i < m_length; i++) {
  369.         assert(p[2 + i] == 0);
  370.       }
  371.     }
  372.     break;
  373.   default:
  374.     assert(false);
  375.     break;
  376.   }
  377. }
  378. static NdbOut&
  379. operator<<(NdbOut& out, const Col& col)
  380. {
  381.   out << "col " << col.m_num;
  382.   out << " " << col.m_name;
  383.   switch (col.m_type) {
  384.   case NdbDictionary::Column::Unsigned:
  385.     out << " unsigned";
  386.     break;
  387.   case NdbDictionary::Column::Varchar:
  388.     out << " varchar(" << col.m_length << ")";
  389.     break;
  390.   default:
  391.     out << "type" << (int)col.m_type;
  392.     assert(false);
  393.     break;
  394.   }
  395.   out << (col.m_pk ? " pk" : "");
  396.   out << (col.m_nullable ? " nullable" : "");
  397.   return out;
  398. }
  399. // ICol - index column
  400. struct ICol {
  401.   unsigned m_num;
  402.   struct Col m_col;
  403. };
  404. // ITab - index
  405. struct ITab {
  406.   const char* m_name;
  407.   unsigned m_icols;
  408.   const ICol* m_icol;
  409. };
  410. static NdbOut&
  411. operator<<(NdbOut& out, const ITab& itab)
  412. {
  413.   out << "itab " << itab.m_name << " " << itab.m_icols;
  414.   for (unsigned k = 0; k < itab.m_icols; k++) {
  415.     out << endl;
  416.     out << "icol " << k << " " << itab.m_icol[k].m_col;
  417.   }
  418.   return out;
  419. }
  420. // Tab - table
  421. struct Tab {
  422.   const char* m_name;
  423.   unsigned m_cols;
  424.   const Col* m_col;
  425.   unsigned m_itabs;
  426.   const ITab* m_itab;
  427. };
  428. static NdbOut&
  429. operator<<(NdbOut& out, const Tab& tab)
  430. {
  431.   out << "tab " << tab.m_name << " " << tab.m_cols;
  432.   for (unsigned k = 0; k < tab.m_cols; k++) {
  433.     out << endl;
  434.     out << tab.m_col[k];
  435.   }
  436.   for (unsigned i = 0; i < tab.m_itabs; i++) {
  437.     if (! useindex(i))
  438.       continue;
  439.     out << endl;
  440.     out << tab.m_itab[i];
  441.   }
  442.   return out;
  443. }
  444. // tt1 + tt1x1 tt1x2 tt1x3 tt1x4 tt1x5
  445. static const Col
  446. tt1col[] = {
  447.   { 0, "A", 1, NdbDictionary::Column::Unsigned, 1, 0 },
  448.   { 1, "B", 0, NdbDictionary::Column::Unsigned, 1, 1 },
  449.   { 2, "C", 0, NdbDictionary::Column::Unsigned, 1, 1 },
  450.   { 3, "D", 0, NdbDictionary::Column::Unsigned, 1, 1 },
  451.   { 4, "E", 0, NdbDictionary::Column::Unsigned, 1, 1 }
  452. };
  453. static const ICol
  454. tt1x1col[] = {
  455.   { 0, tt1col[0] }
  456. };
  457. static const ICol
  458. tt1x2col[] = {
  459.   { 0, tt1col[1] }
  460. };
  461. static const ICol
  462. tt1x3col[] = {
  463.   { 0, tt1col[1] },
  464.   { 1, tt1col[2] }
  465. };
  466. static const ICol
  467. tt1x4col[] = {
  468.   { 0, tt1col[3] },
  469.   { 1, tt1col[2] },
  470.   { 2, tt1col[1] }
  471. };
  472. static const ICol
  473. tt1x5col[] = {
  474.   { 0, tt1col[1] },
  475.   { 1, tt1col[4] },
  476.   { 2, tt1col[2] },
  477.   { 3, tt1col[3] }
  478. };
  479. static const ITab
  480. tt1x1 = {
  481.   "TT1X1", 1, tt1x1col
  482. };
  483. static const ITab
  484. tt1x2 = {
  485.   "TT1X2", 1, tt1x2col
  486. };
  487. static const ITab
  488. tt1x3 = {
  489.   "TT1X3", 2, tt1x3col
  490. };
  491. static const ITab
  492. tt1x4 = {
  493.   "TT1X4", 3, tt1x4col
  494. };
  495. static const ITab
  496. tt1x5 = {
  497.   "TT1X5", 4, tt1x5col
  498. };
  499. static const ITab
  500. tt1itab[] = {
  501.   tt1x1,
  502.   tt1x2,
  503.   tt1x3,
  504.   tt1x4,
  505.   tt1x5
  506. };
  507. static const Tab
  508. tt1 = {
  509.   "TT1", 5, tt1col, 5, tt1itab
  510. };
  511. // tt2 + tt2x1 tt2x2 tt2x3 tt2x4 tt2x5
  512. static const Col
  513. tt2col[] = {
  514.   { 0, "A", 1, NdbDictionary::Column::Unsigned, 1, 0 },
  515.   { 1, "B", 0, NdbDictionary::Column::Unsigned, 1, 1 },
  516.   { 2, "C", 0, NdbDictionary::Column::Varchar, 20, 1 },
  517.   { 3, "D", 0, NdbDictionary::Column::Varchar, 5, 1 },
  518.   { 4, "E", 0, NdbDictionary::Column::Varchar, 5, 1 }
  519. };
  520. static const ICol
  521. tt2x1col[] = {
  522.   { 0, tt2col[0] }
  523. };
  524. static const ICol
  525. tt2x2col[] = {
  526.   { 0, tt2col[1] },
  527.   { 1, tt2col[2] }
  528. };
  529. static const ICol
  530. tt2x3col[] = {
  531.   { 0, tt2col[2] },
  532.   { 1, tt2col[1] }
  533. };
  534. static const ICol
  535. tt2x4col[] = {
  536.   { 0, tt2col[3] },
  537.   { 1, tt2col[4] }
  538. };
  539. static const ICol
  540. tt2x5col[] = {
  541.   { 0, tt2col[4] },
  542.   { 1, tt2col[3] },
  543.   { 2, tt2col[2] },
  544.   { 3, tt2col[1] }
  545. };
  546. static const ITab
  547. tt2x1 = {
  548.   "TT2X1", 1, tt2x1col
  549. };
  550. static const ITab
  551. tt2x2 = {
  552.   "TT2X2", 2, tt2x2col
  553. };
  554. static const ITab
  555. tt2x3 = {
  556.   "TT2X3", 2, tt2x3col
  557. };
  558. static const ITab
  559. tt2x4 = {
  560.   "TT2X4", 2, tt2x4col
  561. };
  562. static const ITab
  563. tt2x5 = {
  564.   "TT2X5", 4, tt2x5col
  565. };
  566. static const ITab
  567. tt2itab[] = {
  568.   tt2x1,
  569.   tt2x2,
  570.   tt2x3,
  571.   tt2x4,
  572.   tt2x5
  573. };
  574. static const Tab
  575. tt2 = {
  576.   "TT2", 5, tt2col, 5, tt2itab
  577. };
  578. // all tables
  579. static const Tab
  580. tablist[] = {
  581.   tt1,
  582.   tt2
  583. };
  584. static const unsigned
  585. tabcount = sizeof(tablist) / sizeof(tablist[0]);
  586. // connections
  587. static Ndb_cluster_connection* g_ncc = 0;
  588. struct Con {
  589.   Ndb* m_ndb;
  590.   NdbDictionary::Dictionary* m_dic;
  591.   NdbConnection* m_tx;
  592.   NdbOperation* m_op;
  593.   NdbScanOperation* m_scanop;
  594.   NdbIndexScanOperation* m_indexscanop;
  595.   NdbResultSet* m_resultset;
  596.   enum ScanMode { ScanNo = 0, Committed, Latest, Exclusive };
  597.   ScanMode m_scanmode;
  598.   enum ErrType { ErrNone = 0, ErrDeadlock, ErrNospace, ErrOther };
  599.   ErrType m_errtype;
  600.   Con() :
  601.     m_ndb(0), m_dic(0), m_tx(0), m_op(0),
  602.     m_scanop(0), m_indexscanop(0), m_resultset(0), m_scanmode(ScanNo), m_errtype(ErrNone) {}
  603.   ~Con() {
  604.     if (m_tx != 0)
  605.       closeTransaction();
  606.   }
  607.   int connect();
  608.   void connect(const Con& con);
  609.   void disconnect();
  610.   int startTransaction();
  611.   int getNdbOperation(const Tab& tab);
  612.   int getNdbScanOperation(const Tab& tab);
  613.   int getNdbScanOperation(const ITab& itab, const Tab& tab);
  614.   int equal(int num, const char* addr);
  615.   int getValue(int num, NdbRecAttr*& rec);
  616.   int setValue(int num, const char* addr);
  617.   int setBound(int num, int type, const void* value);
  618.   int execute(ExecType t);
  619.   int execute(ExecType t, bool& deadlock, bool& nospace);
  620.   int openScanRead(unsigned scanbat, unsigned scanpar);
  621.   int openScanExclusive(unsigned scanbat, unsigned scanpar);
  622.   int executeScan();
  623.   int nextScanResult(bool fetchAllowed);
  624.   int nextScanResult(bool fetchAllowed, bool& deadlock);
  625.   int updateScanTuple(Con& con2);
  626.   int deleteScanTuple(Con& con2);
  627.   void closeScan();
  628.   void closeTransaction();
  629.   void printerror(NdbOut& out);
  630. };
  631. int
  632. Con::connect()
  633. {
  634.   assert(m_ndb == 0);
  635.   m_ndb = new Ndb(g_ncc, "TEST_DB");
  636.   CHKCON(m_ndb->init() == 0, *this);
  637.   CHKCON(m_ndb->waitUntilReady(30) == 0, *this);
  638.   m_tx = 0, m_op = 0;
  639.   return 0;
  640. }
  641. void
  642. Con::connect(const Con& con)
  643. {
  644.   assert(m_ndb == 0);
  645.   m_ndb = con.m_ndb;
  646. }
  647. void
  648. Con::disconnect()
  649. {
  650.   delete m_ndb;
  651.   m_ndb = 0, m_dic = 0, m_tx = 0, m_op = 0;
  652. }
  653. int
  654. Con::startTransaction()
  655. {
  656.   assert(m_ndb != 0);
  657.   if (m_tx != 0)
  658.     closeTransaction();
  659.   CHKCON((m_tx = m_ndb->startTransaction()) != 0, *this);
  660.   return 0;
  661. }
  662. int
  663. Con::getNdbOperation(const Tab& tab)
  664. {
  665.   assert(m_tx != 0);
  666.   CHKCON((m_op = m_tx->getNdbOperation(tab.m_name)) != 0, *this);
  667.   return 0;
  668. }
  669. int
  670. Con::getNdbScanOperation(const Tab& tab)
  671. {
  672.   assert(m_tx != 0);
  673.   CHKCON((m_op = m_scanop = m_tx->getNdbScanOperation(tab.m_name)) != 0, *this);
  674.   return 0;
  675. }
  676. int
  677. Con::getNdbScanOperation(const ITab& itab, const Tab& tab)
  678. {
  679.   assert(m_tx != 0);
  680.   CHKCON((m_op = m_scanop = m_indexscanop = m_tx->getNdbIndexScanOperation(itab.m_name, tab.m_name)) != 0, *this);
  681.   return 0;
  682. }
  683. int
  684. Con::equal(int num, const char* addr)
  685. {
  686.   assert(m_tx != 0 && m_op != 0);
  687.   CHKCON(m_op->equal(num, addr) == 0, *this);
  688.   return 0;
  689. }
  690. int
  691. Con::getValue(int num, NdbRecAttr*& rec)
  692. {
  693.   assert(m_tx != 0 && m_op != 0);
  694.   CHKCON((rec = m_op->getValue(num, 0)) != 0, *this);
  695.   return 0;
  696. }
  697. int
  698. Con::setValue(int num, const char* addr)
  699. {
  700.   assert(m_tx != 0 && m_op != 0);
  701.   CHKCON(m_op->setValue(num, addr) == 0, *this);
  702.   return 0;
  703. }
  704. int
  705. Con::setBound(int num, int type, const void* value)
  706. {
  707.   assert(m_tx != 0 && m_op != 0);
  708.   CHKCON(m_indexscanop->setBound(num, type, value) == 0, *this);
  709.   return 0;
  710. }
  711. int
  712. Con::execute(ExecType t)
  713. {
  714.   assert(m_tx != 0);
  715.   CHKCON(m_tx->execute(t) == 0, *this);
  716.   return 0;
  717. }
  718. int
  719. Con::execute(ExecType t, bool& deadlock, bool& nospace)
  720. {
  721.   int ret = execute(t);
  722.   if (ret != 0 && deadlock && m_errtype == ErrDeadlock) {
  723.     LL3("caught deadlock");
  724.     ret = 0;
  725.   } else {
  726.     deadlock = false;
  727.   }
  728.   if (ret != 0 && nospace && m_errtype == ErrNospace) {
  729.     LL3("caught nospace");
  730.     ret = 0;
  731.   } else {
  732.     nospace = false;
  733.   }
  734.   CHK(ret == 0);
  735.   return 0;
  736. }
  737. int
  738. Con::openScanRead(unsigned scanbat, unsigned scanpar)
  739. {
  740.   assert(m_tx != 0 && m_op != 0);
  741.   NdbOperation::LockMode lm = NdbOperation::LM_Read;
  742.   CHKCON((m_resultset = m_scanop->readTuples(lm, scanbat, scanpar)) != 0, *this);
  743.   return 0;
  744. }
  745. int
  746. Con::openScanExclusive(unsigned scanbat, unsigned scanpar)
  747. {
  748.   assert(m_tx != 0 && m_op != 0);
  749.   NdbOperation::LockMode lm = NdbOperation::LM_Exclusive;
  750.   CHKCON((m_resultset = m_scanop->readTuples(lm, scanbat, scanpar)) != 0, *this);
  751.   return 0;
  752. }
  753. int
  754. Con::executeScan()
  755. {
  756.   CHKCON(m_tx->execute(NoCommit) == 0, *this);
  757.   return 0;
  758. }
  759. int
  760. Con::nextScanResult(bool fetchAllowed)
  761. {
  762.   int ret;
  763.   assert(m_resultset != 0);
  764.   CHKCON((ret = m_resultset->nextResult(fetchAllowed)) != -1, *this);
  765.   assert(ret == 0 || ret == 1 || (! fetchAllowed && ret == 2));
  766.   return ret;
  767. }
  768. int
  769. Con::nextScanResult(bool fetchAllowed, bool& deadlock)
  770. {
  771.   int ret = nextScanResult(fetchAllowed);
  772.   if (ret == -1) {
  773.     if (deadlock && m_errtype == ErrDeadlock) {
  774.       LL3("caught deadlock");
  775.       ret = 0;
  776.     }
  777.   } else {
  778.     deadlock = false;
  779.   }
  780.   CHK(ret == 0 || ret == 1 || (! fetchAllowed && ret == 2));
  781.   return ret;
  782. }
  783. int
  784. Con::updateScanTuple(Con& con2)
  785. {
  786.   assert(con2.m_tx != 0);
  787.   CHKCON((con2.m_op = m_resultset->updateTuple(con2.m_tx)) != 0, *this);
  788.   return 0;
  789. }
  790. int
  791. Con::deleteScanTuple(Con& con2)
  792. {
  793.   assert(con2.m_tx != 0);
  794.   CHKCON(m_resultset->deleteTuple(con2.m_tx) == 0, *this);
  795.   return 0;
  796. }
  797. void
  798. Con::closeScan()
  799. {
  800.   assert(m_resultset != 0);
  801.   m_resultset->close();
  802.   m_scanop = 0, m_indexscanop = 0, m_resultset = 0;
  803. }
  804. void
  805. Con::closeTransaction()
  806. {
  807.   assert(m_ndb != 0 && m_tx != 0);
  808.   m_ndb->closeTransaction(m_tx);
  809.   m_tx = 0, m_op = 0;
  810.   m_scanop = 0, m_indexscanop = 0, m_resultset = 0;
  811. }
  812. void
  813. Con::printerror(NdbOut& out)
  814. {
  815.   m_errtype = ErrOther;
  816.   unsigned any = 0;
  817.   int code;
  818.   int die = 0;
  819.   if (m_ndb) {
  820.     if ((code = m_ndb->getNdbError().code) != 0) {
  821.       LL0(++any << " ndb: error " << m_ndb->getNdbError());
  822.       die += (code == g_opt.m_die);
  823.     }
  824.     if (m_dic && (code = m_dic->getNdbError().code) != 0) {
  825.       LL0(++any << " dic: error " << m_dic->getNdbError());
  826.       die += (code == g_opt.m_die);
  827.     }
  828.     if (m_tx) {
  829.       if ((code = m_tx->getNdbError().code) != 0) {
  830.         LL0(++any << " con: error " << m_tx->getNdbError());
  831.         die += (code == g_opt.m_die);
  832.         if (code == 266 || code == 274 || code == 296 || code == 297 || code == 499)
  833.           m_errtype = ErrDeadlock;
  834.         if (code == 826 || code == 827 || code == 902)
  835.           m_errtype = ErrNospace;
  836.       }
  837.       if (m_op && m_op->getNdbError().code != 0) {
  838.         LL0(++any << " op : error " << m_op->getNdbError());
  839.         die += (code == g_opt.m_die);
  840.       }
  841.     }
  842.   }
  843.   if (! any) {
  844.     LL0("failed but no NDB error code");
  845.   }
  846.   if (die) {
  847.     if (g_opt.m_core)
  848.       abort();
  849.     exit(1);
  850.   }
  851. }
  852. // dictionary operations
  853. static int
  854. invalidateindex(Par par, const ITab& itab)
  855. {
  856.   Con& con = par.con();
  857.   const Tab& tab = par.tab();
  858.   con.m_ndb->getDictionary()->invalidateIndex(itab.m_name, tab.m_name);
  859.   return 0;
  860. }
  861. static int
  862. invalidateindex(Par par)
  863. {
  864.   Con& con = par.con();
  865.   const Tab& tab = par.tab();
  866.   for (unsigned i = 0; i < tab.m_itabs; i++) {
  867.     if (! useindex(i))
  868.       continue;
  869.     const ITab& itab = tab.m_itab[i];
  870.     invalidateindex(par, itab);
  871.   }
  872.   return 0;
  873. }
  874. static int
  875. invalidatetable(Par par)
  876. {
  877.   Con& con = par.con();
  878.   const Tab& tab = par.tab();
  879.   invalidateindex(par);
  880.   con.m_ndb->getDictionary()->invalidateTable(tab.m_name);
  881.   return 0;
  882. }
  883. static int
  884. droptable(Par par)
  885. {
  886.   Con& con = par.con();
  887.   const Tab& tab = par.tab();
  888.   con.m_dic = con.m_ndb->getDictionary();
  889.   if (con.m_dic->getTable(tab.m_name) == 0) {
  890.     // how to check for error
  891.     LL4("no table " << tab.m_name);
  892.   } else {
  893.     LL3("drop table " << tab.m_name);
  894.     CHKCON(con.m_dic->dropTable(tab.m_name) == 0, con);
  895.   }
  896.   con.m_dic = 0;
  897.   return 0;
  898. }
  899. static int
  900. createtable(Par par)
  901. {
  902.   Con& con = par.con();
  903.   const Tab& tab = par.tab();
  904.   LL3("create table " << tab.m_name);
  905.   LL4(tab);
  906.   NdbDictionary::Table t(tab.m_name);
  907.   if (par.m_fragtype != NdbDictionary::Object::FragUndefined) {
  908.     t.setFragmentType(par.m_fragtype);
  909.   }
  910.   if (par.m_nologging) {
  911.     t.setLogging(false);
  912.   }
  913.   for (unsigned k = 0; k < tab.m_cols; k++) {
  914.     const Col& col = tab.m_col[k];
  915.     NdbDictionary::Column c(col.m_name);
  916.     c.setType(col.m_type);
  917.     c.setLength(col.m_length);
  918.     c.setPrimaryKey(col.m_pk);
  919.     c.setNullable(col.m_nullable);
  920.     if (c.getCharset()) { // test if char type
  921.       if (! col.m_pk)
  922.         c.setCharset(par.m_cs);
  923.     }
  924.     t.addColumn(c);
  925.   }
  926.   con.m_dic = con.m_ndb->getDictionary();
  927.   CHKCON(con.m_dic->createTable(t) == 0, con);
  928.   con.m_dic = 0;
  929.   return 0;
  930. }
  931. static int
  932. dropindex(Par par, const ITab& itab)
  933. {
  934.   Con& con = par.con();
  935.   const Tab& tab = par.tab();
  936.   con.m_dic = con.m_ndb->getDictionary();
  937.   if (con.m_dic->getIndex(itab.m_name, tab.m_name) == 0) {
  938.     // how to check for error
  939.     LL4("no index " << itab.m_name);
  940.   } else {
  941.     LL3("drop index " << itab.m_name);
  942.     CHKCON(con.m_dic->dropIndex(itab.m_name, tab.m_name) == 0, con);
  943.   }
  944.   con.m_dic = 0;
  945.   return 0;
  946. }
  947. static int
  948. dropindex(Par par)
  949. {
  950.   const Tab& tab = par.tab();
  951.   for (unsigned i = 0; i < tab.m_itabs; i++) {
  952.     if (! useindex(i))
  953.       continue;
  954.     const ITab& itab = tab.m_itab[i];
  955.     CHK(dropindex(par, itab) == 0);
  956.   }
  957.   return 0;
  958. }
  959. static int
  960. createindex(Par par, const ITab& itab)
  961. {
  962.   Con& con = par.con();
  963.   const Tab& tab = par.tab();
  964.   LL3("create index " << itab.m_name);
  965.   LL4(itab);
  966.   NdbDictionary::Index x(itab.m_name);
  967.   x.setTable(tab.m_name);
  968.   x.setType(NdbDictionary::Index::OrderedIndex);
  969.   x.setLogging(false);
  970.   for (unsigned k = 0; k < itab.m_icols; k++) {
  971.     const Col& col = itab.m_icol[k].m_col;
  972.     x.addColumnName(col.m_name);
  973.   }
  974.   con.m_dic = con.m_ndb->getDictionary();
  975.   CHKCON(con.m_dic->createIndex(x) == 0, con);
  976.   con.m_dic = 0;
  977.   return 0;
  978. }
  979. static int
  980. createindex(Par par)
  981. {
  982.   const Tab& tab = par.tab();
  983.   for (unsigned i = 0; i < tab.m_itabs; i++) {
  984.     if (! useindex(i))
  985.       continue;
  986.     const ITab& itab = tab.m_itab[i];
  987.     CHK(createindex(par, itab) == 0);
  988.   }
  989.   return 0;
  990. }
  991. // data sets
  992. static unsigned
  993. urandom(unsigned n)
  994. {
  995.   if (n == 0)
  996.     return 0;
  997.   unsigned i = random() % n;
  998.   return i;
  999. }
  1000. static int
  1001. irandom(unsigned n)
  1002. {
  1003.   if (n == 0)
  1004.     return 0;
  1005.   int i = random() % n;
  1006.   if (random() & 0x1)
  1007.     i = -i;
  1008.   return i;
  1009. }
  1010. static bool
  1011. randompct(unsigned pct)
  1012. {
  1013.   if (pct == 0)
  1014.     return false;
  1015.   if (pct >= 100)
  1016.     return true;
  1017.   return urandom(100) < pct;
  1018. }
  1019. // Val - typed column value
  1020. struct Val {
  1021.   const Col& m_col;
  1022.   union {
  1023.   Uint32 m_uint32;
  1024.   char* m_varchar;
  1025.   };
  1026.   Val(const Col& col);
  1027.   ~Val();
  1028.   void copy(const Val& val2);
  1029.   void copy(const void* addr);
  1030.   const void* dataaddr() const;
  1031.   bool m_null;
  1032.   int setval(Par par) const;
  1033.   void calc(Par par, unsigned i);
  1034.   int verify(const Val& val2) const;
  1035.   int cmp(const Val& val2) const;
  1036. private:
  1037.   Val& operator=(const Val& val2);
  1038. };
  1039. static NdbOut&
  1040. operator<<(NdbOut& out, const Val& val);
  1041. Val::Val(const Col& col) :
  1042.   m_col(col)
  1043. {
  1044.   switch (col.m_type) {
  1045.   case NdbDictionary::Column::Unsigned:
  1046.     break;
  1047.   case NdbDictionary::Column::Varchar:
  1048.     m_varchar = new char [2 + col.m_length];
  1049.     break;
  1050.   default:
  1051.     assert(false);
  1052.     break;
  1053.   }
  1054. }
  1055. Val::~Val()
  1056. {
  1057.   const Col& col = m_col;
  1058.   switch (col.m_type) {
  1059.   case NdbDictionary::Column::Unsigned:
  1060.     break;
  1061.   case NdbDictionary::Column::Varchar:
  1062.     delete [] m_varchar;
  1063.     break;
  1064.   default:
  1065.     assert(false);
  1066.     break;
  1067.   }
  1068. }
  1069. void
  1070. Val::copy(const Val& val2)
  1071. {
  1072.   const Col& col = m_col;
  1073.   const Col& col2 = val2.m_col;
  1074.   assert(col.m_type == col2.m_type && col.m_length == col2.m_length);
  1075.   if (val2.m_null) {
  1076.     m_null = true;
  1077.     return;
  1078.   }
  1079.   copy(val2.dataaddr());
  1080. }
  1081. void
  1082. Val::copy(const void* addr)
  1083. {
  1084.   const Col& col = m_col;
  1085.   switch (col.m_type) {
  1086.   case NdbDictionary::Column::Unsigned:
  1087.     m_uint32 = *(const Uint32*)addr;
  1088.     break;
  1089.   case NdbDictionary::Column::Varchar:
  1090.     memcpy(m_varchar, addr, 2 + col.m_length);
  1091.     break;
  1092.   default:
  1093.     assert(false);
  1094.     break;
  1095.   }
  1096.   m_null = false;
  1097. }
  1098. const void*
  1099. Val::dataaddr() const
  1100. {
  1101.   const Col& col = m_col;
  1102.   switch (col.m_type) {
  1103.   case NdbDictionary::Column::Unsigned:
  1104.     return &m_uint32;
  1105.   case NdbDictionary::Column::Varchar:
  1106.     return m_varchar;
  1107.   default:
  1108.     break;
  1109.   }
  1110.   assert(false);
  1111.   return 0;
  1112. }
  1113. int
  1114. Val::setval(Par par) const
  1115. {
  1116.   Con& con = par.con();
  1117.   const Col& col = m_col;
  1118.   const char* addr = (const char*)dataaddr();
  1119.   if (m_null)
  1120.     addr = 0;
  1121.   if (col.m_pk)
  1122.     CHK(con.equal(col.m_num, addr) == 0);
  1123.   else
  1124.     CHK(con.setValue(col.m_num, addr) == 0);
  1125.   LL5("setval [" << m_col << "] " << *this);
  1126.   return 0;
  1127. }
  1128. void
  1129. Val::calc(Par par, unsigned i)
  1130. {
  1131.   const Col& col = m_col;
  1132.   m_null = false;
  1133.   if (col.m_pk) {
  1134.     m_uint32 = i;
  1135.     return;
  1136.   }
  1137.   if (col.m_nullable && urandom(100) < par.m_pctnull) {
  1138.     m_null = true;
  1139.     return;
  1140.   }
  1141.   unsigned v = par.m_range + irandom((par.m_pctrange * par.m_range) / 100);
  1142.   switch (col.m_type) {
  1143.   case NdbDictionary::Column::Unsigned:
  1144.     m_uint32 = v;
  1145.     break;
  1146.   case NdbDictionary::Column::Varchar:
  1147.     {
  1148.       unsigned n = 0;
  1149.       while (n < col.m_length) {
  1150.         if (urandom(1 + col.m_length) == 0) {
  1151.           // nice distribution on lengths
  1152.           break;
  1153.         }
  1154.         m_varchar[2 + n++] = 'a' + urandom((par.m_pctrange * 10) / 100);
  1155.       }
  1156.       m_varchar[0] = (n >> 8);
  1157.       m_varchar[1] = (n & 0xff);
  1158.       while (n < col.m_length) {
  1159.         m_varchar[2 + n++] = 0;
  1160.       }
  1161.     }
  1162.     break;
  1163.   default:
  1164.     assert(false);
  1165.     break;
  1166.   }
  1167.   // verify format
  1168.   col.verify(dataaddr());
  1169. }
  1170. int
  1171. Val::verify(const Val& val2) const
  1172. {
  1173.   CHK(cmp(val2) == 0);
  1174.   return 0;
  1175. }
  1176. int
  1177. Val::cmp(const Val& val2) const
  1178. {
  1179.   const Col& col = m_col;
  1180.   const Col& col2 = val2.m_col;
  1181.   assert(col.m_type == col2.m_type && col.m_length == col2.m_length);
  1182.   if (m_null || val2.m_null) {
  1183.     if (! m_null)
  1184.       return +1;
  1185.     if (! val2.m_null)
  1186.       return -1;
  1187.     return 0;
  1188.   }
  1189.   // verify data formats
  1190.   col.verify(dataaddr());
  1191.   col.verify(val2.dataaddr());
  1192.   // compare
  1193.   switch (col.m_type) {
  1194.   case NdbDictionary::Column::Unsigned:
  1195.     if (m_uint32 < val2.m_uint32)
  1196.       return -1;
  1197.     if (m_uint32 > val2.m_uint32)
  1198.       return +1;
  1199.     return 0;
  1200.   case NdbDictionary::Column::Varchar:
  1201.     return memcmp(&m_varchar[2], &val2.m_varchar[2], col.m_length);
  1202.   default:
  1203.     break;
  1204.   }
  1205.   assert(false);
  1206.   return 0;
  1207. }
  1208. static NdbOut&
  1209. operator<<(NdbOut& out, const Val& val)
  1210. {
  1211.   const Col& col = val.m_col;
  1212.   if (val.m_null) {
  1213.     out << "NULL";
  1214.     return out;
  1215.   }
  1216.   switch (col.m_type) {
  1217.   case NdbDictionary::Column::Unsigned:
  1218.     out << val.m_uint32;
  1219.     break;
  1220.   case NdbDictionary::Column::Varchar:
  1221.     {
  1222.       char buf[8000];
  1223.       unsigned n = (val.m_varchar[0] << 8) | val.m_varchar[1];
  1224.       assert(n <= col.m_length);
  1225.       sprintf(buf, "'%.*s'[%d]", n, &val.m_varchar[2], n);
  1226.       out << buf;
  1227.     }
  1228.     break;
  1229.   default:
  1230.     out << "type" << col.m_type;
  1231.     assert(false);
  1232.     break;
  1233.   }
  1234.   return out;
  1235. }
  1236. // Row - table tuple
  1237. struct Row {
  1238.   const Tab& m_tab;
  1239.   Val** m_val;
  1240.   bool m_exist;
  1241.   enum Op { NoOp = 0, ReadOp, InsOp, UpdOp, DelOp };
  1242.   Op m_pending;
  1243.   Row(const Tab& tab);
  1244.   ~Row();
  1245.   void copy(const Row& row2);
  1246.   void calc(Par par, unsigned i);
  1247.   int verify(const Row& row2) const;
  1248.   int insrow(Par par);
  1249.   int updrow(Par par);
  1250.   int delrow(Par par);
  1251.   int selrow(Par par);
  1252.   int setrow(Par par);
  1253.   int cmp(const Row& row2) const;
  1254. private:
  1255.   Row& operator=(const Row& row2);
  1256. };
  1257. Row::Row(const Tab& tab) :
  1258.   m_tab(tab)
  1259. {
  1260.   m_val = new Val* [tab.m_cols];
  1261.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1262.     const Col& col = tab.m_col[k];
  1263.     m_val[k] = new Val(col);
  1264.   }
  1265.   m_exist = false;
  1266.   m_pending = NoOp;
  1267. }
  1268. Row::~Row()
  1269. {
  1270.   const Tab& tab = m_tab;
  1271.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1272.     delete m_val[k];
  1273.   }
  1274.   delete [] m_val;
  1275. }
  1276. void
  1277. Row::copy(const Row& row2)
  1278. {
  1279.   const Tab& tab = m_tab;
  1280.   assert(&tab == &row2.m_tab);
  1281.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1282.     Val& val = *m_val[k];
  1283.     const Val& val2 = *row2.m_val[k];
  1284.     val.copy(val2);
  1285.   }
  1286. }
  1287. void
  1288. Row::calc(Par par, unsigned i)
  1289. {
  1290.   const Tab& tab = m_tab;
  1291.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1292.     Val& val = *m_val[k];
  1293.     val.calc(par, i);
  1294.   }
  1295. }
  1296. int
  1297. Row::verify(const Row& row2) const
  1298. {
  1299.   const Tab& tab = m_tab;
  1300.   assert(&tab == &row2.m_tab && m_exist && row2.m_exist);
  1301.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1302.     const Val& val = *m_val[k];
  1303.     const Val& val2 = *row2.m_val[k];
  1304.     CHK(val.verify(val2) == 0);
  1305.   }
  1306.   return 0;
  1307. }
  1308. int
  1309. Row::insrow(Par par)
  1310. {
  1311.   Con& con = par.con();
  1312.   const Tab& tab = m_tab;
  1313.   assert(! m_exist);
  1314.   CHK(con.getNdbOperation(tab) == 0);
  1315.   CHKCON(con.m_op->insertTuple() == 0, con);
  1316.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1317.     const Val& val = *m_val[k];
  1318.     CHK(val.setval(par) == 0);
  1319.   }
  1320.   m_pending = InsOp;
  1321.   return 0;
  1322. }
  1323. int
  1324. Row::updrow(Par par)
  1325. {
  1326.   Con& con = par.con();
  1327.   const Tab& tab = m_tab;
  1328.   assert(m_exist);
  1329.   CHK(con.getNdbOperation(tab) == 0);
  1330.   CHKCON(con.m_op->updateTuple() == 0, con);
  1331.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1332.     const Val& val = *m_val[k];
  1333.     CHK(val.setval(par) == 0);
  1334.   }
  1335.   m_pending = UpdOp;
  1336.   return 0;
  1337. }
  1338. int
  1339. Row::delrow(Par par)
  1340. {
  1341.   Con& con = par.con();
  1342.   const Tab& tab = m_tab;
  1343.   assert(m_exist);
  1344.   CHK(con.getNdbOperation(m_tab) == 0);
  1345.   CHKCON(con.m_op->deleteTuple() == 0, con);
  1346.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1347.     const Val& val = *m_val[k];
  1348.     const Col& col = val.m_col;
  1349.     if (col.m_pk)
  1350.       CHK(val.setval(par) == 0);
  1351.   }
  1352.   m_pending = DelOp;
  1353.   return 0;
  1354. }
  1355. int
  1356. Row::selrow(Par par)
  1357. {
  1358.   Con& con = par.con();
  1359.   const Tab& tab = m_tab;
  1360.   CHK(con.getNdbOperation(m_tab) == 0);
  1361.   CHKCON(con.m_op->readTuple() == 0, con);
  1362.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1363.     const Val& val = *m_val[k];
  1364.     const Col& col = val.m_col;
  1365.     if (col.m_pk)
  1366.       CHK(val.setval(par) == 0);
  1367.   }
  1368.   return 0;
  1369. }
  1370. int
  1371. Row::setrow(Par par)
  1372. {
  1373.   Con& con = par.con();
  1374.   const Tab& tab = m_tab;
  1375.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1376.     const Val& val = *m_val[k];
  1377.     const Col& col = val.m_col;
  1378.     if (! col.m_pk)
  1379.       CHK(val.setval(par) == 0);
  1380.   }
  1381.   m_pending = UpdOp;
  1382.   return 0;
  1383. }
  1384. int
  1385. Row::cmp(const Row& row2) const
  1386. {
  1387.   const Tab& tab = m_tab;
  1388.   assert(&tab == &row2.m_tab);
  1389.   int c = 0;
  1390.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1391.     const Val& val = *m_val[k];
  1392.     const Val& val2 = *row2.m_val[k];
  1393.     if ((c = val.cmp(val2)) != 0)
  1394.       break;
  1395.   }
  1396.   return c;
  1397. }
  1398. static NdbOut&
  1399. operator<<(NdbOut& out, const Row& row)
  1400. {
  1401.   const Tab& tab = row.m_tab;
  1402.   for (unsigned i = 0; i < tab.m_cols; i++) {
  1403.     if (i > 0)
  1404.       out << " ";
  1405.     out << *row.m_val[i];
  1406.   }
  1407.   out << " [exist=" << row.m_exist;
  1408.   if (row.m_pending)
  1409.     out << " pending=" << row.m_pending;
  1410.   out << "]";
  1411.   return out;
  1412. }
  1413. // Set - set of table tuples
  1414. struct Set {
  1415.   const Tab& m_tab;
  1416.   unsigned m_rows;
  1417.   Row** m_row;
  1418.   Row** m_saverow;
  1419.   Row* m_keyrow;
  1420.   NdbRecAttr** m_rec;
  1421.   Set(const Tab& tab, unsigned rows);
  1422.   ~Set();
  1423.   void reset();
  1424.   unsigned count() const;
  1425.   // row methods
  1426.   bool exist(unsigned i) const;
  1427.   Row::Op pending(unsigned i) const;
  1428.   void notpending(unsigned i, ExecType et = Commit);
  1429.   void notpending(const Lst& lst, ExecType et = Commit);
  1430.   void calc(Par par, unsigned i);
  1431.   int insrow(Par par, unsigned i);
  1432.   int updrow(Par par, unsigned i);
  1433.   int delrow(Par par, unsigned i);
  1434.   int selrow(Par par, unsigned i);
  1435.   int setrow(Par par, unsigned i);
  1436.   int getval(Par par);
  1437.   int getkey(Par par, unsigned* i);
  1438.   int putval(unsigned i, bool force);
  1439.   // set methods
  1440.   int verify(const Set& set2) const;
  1441.   void savepoint();
  1442.   void commit();
  1443.   void rollback();
  1444.   // protect structure
  1445.   NdbMutex* m_mutex;
  1446.   void lock() {
  1447.     NdbMutex_Lock(m_mutex);
  1448.   }
  1449.   void unlock() {
  1450.     NdbMutex_Unlock(m_mutex);
  1451.   }
  1452. private:
  1453.   Set& operator=(const Set& set2);
  1454. };
  1455. Set::Set(const Tab& tab, unsigned rows) :
  1456.   m_tab(tab)
  1457. {
  1458.   m_rows = rows;
  1459.   m_row = new Row* [m_rows];
  1460.   for (unsigned i = 0; i < m_rows; i++) {
  1461.     // allocate on need to save space
  1462.     m_row[i] = 0;
  1463.   }
  1464.   m_saverow = 0;
  1465.   m_keyrow = new Row(tab);
  1466.   m_rec = new NdbRecAttr* [tab.m_cols];
  1467.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1468.     m_rec[k] = 0;
  1469.   }
  1470.   m_mutex = NdbMutex_Create();
  1471.   assert(m_mutex != 0);
  1472. }
  1473. Set::~Set()
  1474. {
  1475.   for (unsigned i = 0; i < m_rows; i++) {
  1476.     delete m_row[i];
  1477.     if (m_saverow != 0)
  1478.       delete m_saverow[i];
  1479.   }
  1480.   delete [] m_row;
  1481.   delete [] m_saverow;
  1482.   delete m_keyrow;
  1483.   delete [] m_rec;
  1484.   NdbMutex_Destroy(m_mutex);
  1485. }
  1486. void
  1487. Set::reset()
  1488. {
  1489.   for (unsigned i = 0; i < m_rows; i++) {
  1490.     if (m_row[i] != 0) {
  1491.       Row& row = *m_row[i];
  1492.       row.m_exist = false;
  1493.     }
  1494.   }
  1495. }
  1496. unsigned
  1497. Set::count() const
  1498. {
  1499.   unsigned count = 0;
  1500.   for (unsigned i = 0; i < m_rows; i++) {
  1501.     if (m_row[i] != 0) {
  1502.       Row& row = *m_row[i];
  1503.       if (row.m_exist)
  1504.         count++;
  1505.     }
  1506.   }
  1507.   return count;
  1508. }
  1509. bool
  1510. Set::exist(unsigned i) const
  1511. {
  1512.   assert(i < m_rows);
  1513.   if (m_row[i] == 0)    // not allocated => not exist
  1514.     return false;
  1515.   return m_row[i]->m_exist;
  1516. }
  1517. Row::Op
  1518. Set::pending(unsigned i) const
  1519. {
  1520.   assert(i < m_rows);
  1521.   if (m_row[i] == 0)    // not allocated => not pending
  1522.     return Row::NoOp;
  1523.   return m_row[i]->m_pending;
  1524. }
  1525. void
  1526. Set::calc(Par par, unsigned i)
  1527. {
  1528.   const Tab& tab = m_tab;
  1529.   if (m_row[i] == 0)
  1530.     m_row[i] = new Row(tab);
  1531.   Row& row = *m_row[i];
  1532.   // value generation parameters
  1533.   par.m_pctrange = 40;
  1534.   row.calc(par, i);
  1535. }
  1536. int
  1537. Set::insrow(Par par, unsigned i)
  1538. {
  1539.   assert(m_row[i] != 0);
  1540.   Row& row = *m_row[i];
  1541.   CHK(row.insrow(par) == 0);
  1542.   return 0;
  1543. }
  1544. int
  1545. Set::updrow(Par par, unsigned i)
  1546. {
  1547.   assert(m_row[i] != 0);
  1548.   Row& row = *m_row[i];
  1549.   CHK(row.updrow(par) == 0);
  1550.   return 0;
  1551. }
  1552. int
  1553. Set::delrow(Par par, unsigned i)
  1554. {
  1555.   assert(m_row[i] != 0);
  1556.   Row& row = *m_row[i];
  1557.   CHK(row.delrow(par) == 0);
  1558.   return 0;
  1559. }
  1560. int
  1561. Set::selrow(Par par, unsigned i)
  1562. {
  1563.   Con& con = par.con();
  1564.   m_keyrow->calc(par, i);
  1565.   CHK(m_keyrow->selrow(par) == 0);
  1566.   CHK(getval(par) == 0);
  1567.   return 0;
  1568. }
  1569. int
  1570. Set::setrow(Par par, unsigned i)
  1571. {
  1572.   Con& con = par.con();
  1573.   assert(m_row[i] != 0);
  1574.   CHK(m_row[i]->setrow(par) == 0);
  1575.   return 0;
  1576. }
  1577. int
  1578. Set::getval(Par par)
  1579. {
  1580.   Con& con = par.con();
  1581.   const Tab& tab = m_tab;
  1582.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1583.     CHK(con.getValue(k, m_rec[k]) == 0);
  1584.   }
  1585.   return 0;
  1586. }
  1587. int
  1588. Set::getkey(Par par, unsigned* i)
  1589. {
  1590.   assert(m_rec[0] != 0);
  1591.   const char* aRef0 = m_rec[0]->aRef();
  1592.   Uint32 key = *(const Uint32*)aRef0;
  1593.   CHK(key < m_rows);
  1594.   *i = key;
  1595.   return 0;
  1596. }
  1597. int
  1598. Set::putval(unsigned i, bool force)
  1599. {
  1600.   const Tab& tab = m_tab;
  1601.   if (m_row[i] == 0)
  1602.     m_row[i] = new Row(tab);
  1603.   Row& row = *m_row[i];
  1604.   CHK(! row.m_exist || force);
  1605.   for (unsigned k = 0; k < tab.m_cols; k++) {
  1606.     Val& val = *row.m_val[k];
  1607.     NdbRecAttr* rec = m_rec[k];
  1608.     assert(rec != 0);
  1609.     if (rec->isNULL()) {
  1610.       val.m_null = true;
  1611.       continue;
  1612.     }
  1613.     const char* aRef = m_rec[k]->aRef();
  1614.     val.copy(aRef);
  1615.     val.m_null = false;
  1616.   }
  1617.   if (! row.m_exist)
  1618.     row.m_exist = true;
  1619.   return 0;
  1620. }
  1621. void
  1622. Set::notpending(unsigned i, ExecType et)
  1623. {
  1624.   assert(m_row[i] != 0);
  1625.   Row& row = *m_row[i];
  1626.   if (et == Commit) {
  1627.     if (row.m_pending == Row::InsOp)
  1628.       row.m_exist = true;
  1629.     if (row.m_pending == Row::DelOp)
  1630.       row.m_exist = false;
  1631.   } else {
  1632.     if (row.m_pending == Row::InsOp)
  1633.       row.m_exist = false;
  1634.     if (row.m_pending == Row::DelOp)
  1635.       row.m_exist = true;
  1636.   }
  1637.   row.m_pending = Row::NoOp;
  1638. }
  1639. void
  1640. Set::notpending(const Lst& lst, ExecType et)
  1641. {
  1642.   for (unsigned j = 0; j < lst.m_cnt; j++) {
  1643.     unsigned i = lst.m_arr[j];
  1644.     notpending(i, et);
  1645.   }
  1646. }
  1647. int
  1648. Set::verify(const Set& set2) const
  1649. {
  1650.   const Tab& tab = m_tab;
  1651.   assert(&tab == &set2.m_tab && m_rows == set2.m_rows);
  1652.   for (unsigned i = 0; i < m_rows; i++) {
  1653.     CHK(exist(i) == set2.exist(i));
  1654.     if (! exist(i))
  1655.       continue;
  1656.     Row& row = *m_row[i];
  1657.     Row& row2 = *set2.m_row[i];
  1658.     CHK(row.verify(row2) == 0);
  1659.   }
  1660.   return 0;
  1661. }
  1662. void
  1663. Set::savepoint()
  1664. {
  1665.   const Tab& tab = m_tab;
  1666.   assert(m_saverow == 0);
  1667.   m_saverow = new Row* [m_rows];
  1668.   for (unsigned i = 0; i < m_rows; i++) {
  1669.     if (m_row[i] == 0)
  1670.       m_saverow[i] = 0;
  1671.     else {
  1672.       m_saverow[i] = new Row(tab);
  1673.       m_saverow[i]->copy(*m_row[i]);
  1674.     }
  1675.   }
  1676. }
  1677. void
  1678. Set::commit()
  1679. {
  1680.   delete [] m_saverow;
  1681.   m_saverow = 0;
  1682. }
  1683. void
  1684. Set::rollback()
  1685. {
  1686.   assert(m_saverow != 0);
  1687.   m_row = m_saverow;
  1688.   m_saverow = 0;
  1689. }
  1690. static NdbOut&
  1691. operator<<(NdbOut& out, const Set& set)
  1692. {
  1693.   for (unsigned i = 0; i < set.m_rows; i++) {
  1694.     const Row& row = *set.m_row[i];
  1695.     if (i > 0)
  1696.       out << endl;
  1697.     out << row;
  1698.   }
  1699.   return out;
  1700. }
  1701. // BVal - range scan bound
  1702. struct BVal : public Val {
  1703.   const ICol& m_icol;
  1704.   int m_type;
  1705.   BVal(const ICol& icol);
  1706.   int setbnd(Par par) const;
  1707. };
  1708. BVal::BVal(const ICol& icol) :
  1709.   Val(icol.m_col),
  1710.   m_icol(icol)
  1711. {
  1712. }
  1713. int
  1714. BVal::setbnd(Par par) const
  1715. {
  1716.   Con& con = par.con();
  1717.   assert(g_compare_null || ! m_null);
  1718.   const char* addr = ! m_null ? (const char*)dataaddr() : 0;
  1719.   const ICol& icol = m_icol;
  1720.   CHK(con.setBound(icol.m_num, m_type, addr) == 0);
  1721.   return 0;
  1722. }
  1723. static NdbOut&
  1724. operator<<(NdbOut& out, const BVal& bval)
  1725. {
  1726.   const ICol& icol = bval.m_icol;
  1727.   const Col& col = icol.m_col;
  1728.   const Val& val = bval;
  1729.   out << "type " << bval.m_type;
  1730.   out << " icol " << icol.m_num;
  1731.   out << " col " << col.m_name << "(" << col.m_num << ")";
  1732.   out << " value " << val;
  1733.   return out;
  1734. }
  1735. // BSet - set of bounds
  1736. struct BSet {
  1737.   const Tab& m_tab;
  1738.   const ITab& m_itab;
  1739.   unsigned m_alloc;
  1740.   unsigned m_bvals;
  1741.   BVal** m_bval;
  1742.   BSet(const Tab& tab, const ITab& itab, unsigned rows);
  1743.   ~BSet();
  1744.   void reset();
  1745.   void calc(Par par);
  1746.   void calcpk(Par par, unsigned i);
  1747.   int setbnd(Par par) const;
  1748.   void filter(const Set& set, Set& set2) const;
  1749. };
  1750. BSet::BSet(const Tab& tab, const ITab& itab, unsigned rows) :
  1751.   m_tab(tab),
  1752.   m_itab(itab),
  1753.   m_alloc(2 * itab.m_icols),
  1754.   m_bvals(0)
  1755. {
  1756.   m_bval = new BVal* [m_alloc];
  1757.   for (unsigned i = 0; i < m_alloc; i++) {
  1758.     m_bval[i] = 0;
  1759.   }
  1760. }
  1761. BSet::~BSet()
  1762. {
  1763.   delete [] m_bval;
  1764. }
  1765. void
  1766. BSet::reset()
  1767. {
  1768.   while (m_bvals > 0) {
  1769.     unsigned i = --m_bvals;
  1770.     delete m_bval[i];
  1771.     m_bval[i] = 0;
  1772.   }
  1773. }
  1774. void
  1775. BSet::calc(Par par)
  1776. {
  1777.   const ITab& itab = m_itab;
  1778.   reset();
  1779.   for (unsigned k = 0; k < itab.m_icols; k++) {
  1780.     const ICol& icol = itab.m_icol[k];
  1781.     const Col& col = icol.m_col;
  1782.     for (unsigned i = 0; i <= 1; i++) {
  1783.       if (urandom(10) == 0)
  1784.         return;
  1785.       assert(m_bvals < m_alloc);
  1786.       BVal& bval = *new BVal(icol);
  1787.       m_bval[m_bvals++] = &bval;
  1788.       bval.m_null = false;
  1789.       unsigned sel;
  1790.       do {
  1791.         // equality bound only on i==0
  1792.         sel = urandom(5 - i);
  1793.       } while (strchr(par.m_bound, '0' + sel) == 0);
  1794.       if (sel < 2)
  1795.         bval.m_type = 0 | (1 << i);
  1796.       else if (sel < 4)
  1797.         bval.m_type = 1 | (1 << i);
  1798.       else
  1799.         bval.m_type = 4;
  1800.       if (k + 1 < itab.m_icols)
  1801.         bval.m_type = 4;
  1802.       // value generation parammeters
  1803.       if (! g_compare_null)
  1804.         par.m_pctnull = 0;
  1805.       par.m_pctrange = 50;      // bit higher
  1806.       do {
  1807.         bval.calc(par, 0);
  1808.         if (i == 1) {
  1809.           assert(m_bvals >= 2);
  1810.           const BVal& bv1 = *m_bval[m_bvals - 2];
  1811.           const BVal& bv2 = *m_bval[m_bvals - 1];
  1812.           if (bv1.cmp(bv2) > 0 && urandom(100) != 0)
  1813.             continue;
  1814.         }
  1815.       } while (0);
  1816.       // equality bound only once
  1817.       if (bval.m_type == 4)
  1818.         break;
  1819.     }
  1820.   }
  1821. }
  1822. void
  1823. BSet::calcpk(Par par, unsigned i)
  1824. {
  1825.   const ITab& itab = m_itab;
  1826.   reset();
  1827.   for (unsigned k = 0; k < itab.m_icols; k++) {
  1828.     const ICol& icol = itab.m_icol[k];
  1829.     const Col& col = icol.m_col;
  1830.     assert(col.m_pk);
  1831.     assert(m_bvals < m_alloc);
  1832.     BVal& bval = *new BVal(icol);
  1833.     m_bval[m_bvals++] = &bval;
  1834.     bval.m_type = 4;
  1835.     bval.calc(par, i);
  1836.   }
  1837. }
  1838. int
  1839. BSet::setbnd(Par par) const
  1840. {
  1841.   if (m_bvals != 0) {
  1842.     unsigned p1 = urandom(m_bvals);
  1843.     unsigned p2 = 10009;        // prime
  1844.     // random order
  1845.     for (unsigned j = 0; j < m_bvals; j++) {
  1846.       unsigned k = p1 + p2 * j;
  1847.       const BVal& bval = *m_bval[k % m_bvals];
  1848.       CHK(bval.setbnd(par) == 0);
  1849.     }
  1850.     // duplicate
  1851.     if (urandom(5) == 0) {
  1852.       unsigned k = urandom(m_bvals);
  1853.       const BVal& bval = *m_bval[k];
  1854.       CHK(bval.setbnd(par) == 0);
  1855.     }
  1856.   }
  1857.   return 0;
  1858. }
  1859. void
  1860. BSet::filter(const Set& set, Set& set2) const
  1861. {
  1862.   const Tab& tab = m_tab;
  1863.   const ITab& itab = m_itab;
  1864.   assert(&tab == &set2.m_tab && set.m_rows == set2.m_rows);
  1865.   assert(set2.count() == 0);
  1866.   for (unsigned i = 0; i < set.m_rows; i++) {
  1867.     if (! set.exist(i))
  1868.       continue;
  1869.     const Row& row = *set.m_row[i];
  1870.     if (! g_store_null_key) {
  1871.       bool ok1 = false;
  1872.       for (unsigned k = 0; k < itab.m_icols; k++) {
  1873.         const ICol& icol = itab.m_icol[k];
  1874.         const Col& col = icol.m_col;
  1875.         const Val& val = *row.m_val[col.m_num];
  1876.         if (! val.m_null) {
  1877.           ok1 = true;
  1878.           break;
  1879.         }
  1880.       }
  1881.       if (! ok1)
  1882.         continue;
  1883.     }
  1884.     bool ok2 = true;
  1885.     for (unsigned j = 0; j < m_bvals; j++) {
  1886.       const BVal& bval = *m_bval[j];
  1887.       const ICol& icol = bval.m_icol;
  1888.       const Col& col = icol.m_col;
  1889.       const Val& val = *row.m_val[col.m_num];
  1890.       int ret = bval.cmp(val);
  1891.       if (bval.m_type == 0)
  1892.         ok2 = (ret <= 0);
  1893.       else if (bval.m_type == 1)
  1894.         ok2 = (ret < 0);
  1895.       else if (bval.m_type == 2)
  1896.         ok2 = (ret >= 0);
  1897.       else if (bval.m_type == 3)
  1898.         ok2 = (ret > 0);
  1899.       else if (bval.m_type == 4)
  1900.         ok2 = (ret == 0);
  1901.       else {
  1902.         assert(false);
  1903.       }
  1904.       if (! ok2)
  1905.         break;
  1906.     }
  1907.     if (! ok2)
  1908.       continue;
  1909.     if (set2.m_row[i] == 0)
  1910.       set2.m_row[i] = new Row(tab);
  1911.     Row& row2 = *set2.m_row[i];
  1912.     assert(! row2.m_exist);
  1913.     row2.copy(row);
  1914.     row2.m_exist = true;
  1915.   }
  1916. }
  1917. static NdbOut&
  1918. operator<<(NdbOut& out, const BSet& bset)
  1919. {
  1920.   out << "bounds=" << bset.m_bvals;
  1921.   for (unsigned j = 0; j < bset.m_bvals; j++) {
  1922.     out << endl;
  1923.     const BVal& bval = *bset.m_bval[j];
  1924.     out << "bound " << j << ": " << bval;
  1925.   }
  1926.   return out;
  1927. }
  1928. // pk operations
  1929. static int
  1930. pkinsert(Par par)
  1931. {
  1932.   Con& con = par.con();
  1933.   Set& set = par.set();
  1934.   LL3("pkinsert");
  1935.   CHK(con.startTransaction() == 0);
  1936.   Lst lst;
  1937.   for (unsigned j = 0; j < par.m_rows; j++) {
  1938.     unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
  1939.     unsigned i = thrrow(par, j2);
  1940.     set.lock();
  1941.     if (set.exist(i) || set.pending(i)) {
  1942.       set.unlock();
  1943.       continue;
  1944.     }
  1945.     set.calc(par, i);
  1946.     CHK(set.insrow(par, i) == 0);
  1947.     set.unlock();
  1948.     LL4("pkinsert " << i << ": " << *set.m_row[i]);
  1949.     lst.push(i);
  1950.     if (lst.cnt() == par.m_batch) {
  1951.       bool deadlock = par.m_deadlock;
  1952.       bool nospace = true;
  1953.       ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
  1954.       CHK(con.execute(et, deadlock, nospace) == 0);
  1955.       con.closeTransaction();
  1956.       if (deadlock) {
  1957.         LL1("pkinsert: stop on deadlock");
  1958.         return 0;
  1959.       }
  1960.       if (nospace) {
  1961.         LL1("pkinsert: cnt=" << j << " stop on nospace");
  1962.         return 0;
  1963.       }
  1964.       set.lock();
  1965.       set.notpending(lst, et);
  1966.       set.unlock();
  1967.       lst.reset();
  1968.       CHK(con.startTransaction() == 0);
  1969.     }
  1970.   }
  1971.   if (lst.cnt() != 0) {
  1972.     bool deadlock = par.m_deadlock;
  1973.     bool nospace = true;
  1974.     ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
  1975.     CHK(con.execute(et, deadlock, nospace) == 0);
  1976.     con.closeTransaction();
  1977.     if (deadlock) {
  1978.       LL1("pkinsert: stop on deadlock");
  1979.       return 0;
  1980.     }
  1981.     if (nospace) {
  1982.       LL1("pkinsert: end: stop on nospace");
  1983.       return 0;
  1984.     }
  1985.     set.lock();
  1986.     set.notpending(lst, et);
  1987.     set.unlock();
  1988.     return 0;
  1989.   }
  1990.   con.closeTransaction();
  1991.   return 0;
  1992. }
  1993. static int
  1994. pkupdate(Par par)
  1995. {
  1996.   Con& con = par.con();
  1997.   Set& set = par.set();
  1998.   LL3("pkupdate");
  1999.   CHK(con.startTransaction() == 0);
  2000.   Lst lst;
  2001.   bool deadlock = false;
  2002.   bool nospace = false;
  2003.   for (unsigned j = 0; j < par.m_rows; j++) {
  2004.     unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
  2005.     unsigned i = thrrow(par, j2);
  2006.     set.lock();
  2007.     if (! set.exist(i) || set.pending(i)) {
  2008.       set.unlock();
  2009.       continue;
  2010.     }
  2011.     set.calc(par, i);
  2012.     CHK(set.updrow(par, i) == 0);
  2013.     set.unlock();
  2014.     LL4("pkupdate " << i << ": " << *set.m_row[i]);
  2015.     lst.push(i);
  2016.     if (lst.cnt() == par.m_batch) {
  2017.       deadlock = par.m_deadlock;
  2018.       nospace = true;
  2019.       ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
  2020.       CHK(con.execute(et, deadlock, nospace) == 0);
  2021.       if (deadlock) {
  2022.         LL1("pkupdate: stop on deadlock");
  2023.         break;
  2024.       }
  2025.       if (nospace) {
  2026.         LL1("pkupdate: cnt=" << j << " stop on nospace");
  2027.         break;
  2028.       }
  2029.       con.closeTransaction();
  2030.       set.lock();
  2031.       set.notpending(lst, et);
  2032.       set.unlock();
  2033.       lst.reset();
  2034.       CHK(con.startTransaction() == 0);
  2035.     }
  2036.   }
  2037.   if (! deadlock && ! nospace && lst.cnt() != 0) {
  2038.     deadlock = par.m_deadlock;
  2039.     nospace = true;
  2040.     ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
  2041.     CHK(con.execute(et, deadlock, nospace) == 0);
  2042.     if (deadlock) {
  2043.       LL1("pkupdate: stop on deadlock");
  2044.     } else if (nospace) {
  2045.       LL1("pkupdate: end: stop on nospace");
  2046.     } else {
  2047.       set.lock();
  2048.       set.notpending(lst, et);
  2049.       set.unlock();
  2050.     }
  2051.   }
  2052.   con.closeTransaction();
  2053.   return 0;
  2054. }
  2055. static int
  2056. pkdelete(Par par)
  2057. {
  2058.   Con& con = par.con();
  2059.   Set& set = par.set();
  2060.   LL3("pkdelete");
  2061.   CHK(con.startTransaction() == 0);
  2062.   Lst lst;
  2063.   bool deadlock = false;
  2064.   bool nospace = false;
  2065.   for (unsigned j = 0; j < par.m_rows; j++) {
  2066.     unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
  2067.     unsigned i = thrrow(par, j2);
  2068.     set.lock();
  2069.     if (! set.exist(i) || set.pending(i)) {
  2070.       set.unlock();
  2071.       continue;
  2072.     }
  2073.     CHK(set.delrow(par, i) == 0);
  2074.     set.unlock();
  2075.     LL4("pkdelete " << i << ": " << *set.m_row[i]);
  2076.     lst.push(i);
  2077.     if (lst.cnt() == par.m_batch) {
  2078.       deadlock = par.m_deadlock;
  2079.       nospace = true;
  2080.       ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
  2081.       CHK(con.execute(et, deadlock, nospace) == 0);
  2082.       if (deadlock) {
  2083.         LL1("pkdelete: stop on deadlock");
  2084.         break;
  2085.       }
  2086.       con.closeTransaction();
  2087.       set.lock();
  2088.       set.notpending(lst, et);
  2089.       set.unlock();
  2090.       lst.reset();
  2091.       CHK(con.startTransaction() == 0);
  2092.     }
  2093.   }
  2094.   if (! deadlock && ! nospace && lst.cnt() != 0) {
  2095.     deadlock = par.m_deadlock;
  2096.     nospace = true;
  2097.     ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
  2098.     CHK(con.execute(et, deadlock, nospace) == 0);
  2099.     if (deadlock) {
  2100.       LL1("pkdelete: stop on deadlock");
  2101.     } else {
  2102.       set.lock();
  2103.       set.notpending(lst, et);
  2104.       set.unlock();
  2105.     }
  2106.   }
  2107.   con.closeTransaction();
  2108.   return 0;
  2109. }
  2110. static int
  2111. pkread(Par par)
  2112. {
  2113.   Con& con = par.con();
  2114.   const Tab& tab = par.tab();
  2115.   Set& set = par.set();
  2116.   LL3((par.m_verify ? "pkverify " : "pkread ") << tab.m_name);
  2117.   // expected
  2118.   const Set& set1 = set;
  2119.   Set set2(tab, set.m_rows);
  2120.   for (unsigned i = 0; i < set.m_rows; i++) {
  2121.     set.lock();
  2122.     if (! set.exist(i) || set.pending(i)) {
  2123.       set.unlock();
  2124.       continue;
  2125.     }
  2126.     set.unlock();
  2127.     CHK(con.startTransaction() == 0);
  2128.     CHK(set2.selrow(par, i) == 0);
  2129.     CHK(con.execute(Commit) == 0);
  2130.     unsigned i2 = (unsigned)-1;
  2131.     CHK(set2.getkey(par, &i2) == 0 && i == i2);
  2132.     CHK(set2.putval(i, false) == 0);
  2133.     LL4("row " << set2.count() << ": " << *set2.m_row[i]);
  2134.     con.closeTransaction();
  2135.   }
  2136.   if (par.m_verify)
  2137.     CHK(set1.verify(set2) == 0);
  2138.   return 0;
  2139. }
  2140. static int
  2141. pkreadfast(Par par, unsigned count)
  2142. {
  2143.   Con& con = par.con();
  2144.   const Tab& tab = par.tab();
  2145.   const Set& set = par.set();
  2146.   LL3("pkfast " << tab.m_name);
  2147.   Row keyrow(tab);
  2148.   // not batched on purpose
  2149.   for (unsigned j = 0; j < count; j++) {
  2150.     unsigned i = urandom(set.m_rows);
  2151.     assert(set.exist(i));
  2152.     CHK(con.startTransaction() == 0);
  2153.     // define key
  2154.     keyrow.calc(par, i);
  2155.     CHK(keyrow.selrow(par) == 0);
  2156.     NdbRecAttr* rec;
  2157.     // get 1st column
  2158.     CHK(con.getValue((Uint32)0, rec) == 0);
  2159.     CHK(con.execute(Commit) == 0);
  2160.     con.closeTransaction();
  2161.   }
  2162.   return 0;
  2163. }
  2164. // scan read
  2165. static int
  2166. scanreadtable(Par par)
  2167. {
  2168.   Con& con = par.con();
  2169.   const Tab& tab = par.tab();
  2170.   const Set& set = par.set();
  2171.   // expected
  2172.   const Set& set1 = set;
  2173.   LL3((par.m_verify ? "scanverify " : "scanread ") << tab.m_name);
  2174.   Set set2(tab, set.m_rows);
  2175.   CHK(con.startTransaction() == 0);
  2176.   CHK(con.getNdbScanOperation(tab) == 0);
  2177.   CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0);
  2178.   set2.getval(par);
  2179.   CHK(con.executeScan() == 0);
  2180.   while (1) {
  2181.     int ret;
  2182.     CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
  2183.     if (ret == 1)
  2184.       break;
  2185.     unsigned i = (unsigned)-1;
  2186.     CHK(set2.getkey(par, &i) == 0);
  2187.     CHK(set2.putval(i, false) == 0);
  2188.     LL4("row " << set2.count() << ": " << *set2.m_row[i]);
  2189.   }
  2190.   con.closeTransaction();
  2191.   if (par.m_verify)
  2192.     CHK(set1.verify(set2) == 0);
  2193.   return 0;
  2194. }
  2195. static int
  2196. scanreadtablefast(Par par, unsigned countcheck)
  2197. {
  2198.   Con& con = par.con();
  2199.   const Tab& tab = par.tab();
  2200.   const Set& set = par.set();
  2201.   LL3("scanfast " << tab.m_name);
  2202.   CHK(con.startTransaction() == 0);
  2203.   CHK(con.getNdbScanOperation(tab) == 0);
  2204.   CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0);
  2205.   // get 1st column
  2206.   NdbRecAttr* rec;
  2207.   CHK(con.getValue((Uint32)0, rec) == 0);
  2208.   CHK(con.executeScan() == 0);
  2209.   unsigned count = 0;
  2210.   while (1) {
  2211.     int ret;
  2212.     CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
  2213.     if (ret == 1)
  2214.       break;
  2215.     count++;
  2216.   }
  2217.   con.closeTransaction();
  2218.   CHK(count == countcheck);
  2219.   return 0;
  2220. }
  2221. static int
  2222. scanreadindex(Par par, const ITab& itab, const BSet& bset)
  2223. {
  2224.   Con& con = par.con();
  2225.   const Tab& tab = par.tab();
  2226.   const Set& set = par.set();
  2227.   // expected
  2228.   Set set1(tab, set.m_rows);
  2229.   bset.filter(set, set1);
  2230.   LL3((par.m_verify ? "scanverify " : "scanread ") << itab.m_name << " bounds=" << bset.m_bvals);
  2231.   LL4(bset);
  2232.   Set set2(tab, set.m_rows);
  2233.   CHK(con.startTransaction() == 0);
  2234.   CHK(con.getNdbScanOperation(itab, tab) == 0);
  2235.   CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0);
  2236.   CHK(bset.setbnd(par) == 0);
  2237.   set2.getval(par);
  2238.   CHK(con.executeScan() == 0);
  2239.   while (1) {
  2240.     int ret;
  2241.     CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
  2242.     if (ret == 1)
  2243.       break;
  2244.     unsigned i = (unsigned)-1;
  2245.     CHK(set2.getkey(par, &i) == 0);
  2246.     LL4("key " << i);
  2247.     CHK(set2.putval(i, par.m_dups) == 0);
  2248.     LL4("row " << set2.count() << ": " << *set2.m_row[i]);
  2249.   }
  2250.   con.closeTransaction();
  2251.   if (par.m_verify)
  2252.     CHK(set1.verify(set2) == 0);
  2253.   return 0;
  2254. }
  2255. static int
  2256. scanreadindexfast(Par par, const ITab& itab, const BSet& bset, unsigned countcheck)
  2257. {
  2258.   Con& con = par.con();
  2259.   const Tab& tab = par.tab();
  2260.   const Set& set = par.set();
  2261.   LL3("scanfast " << itab.m_name << " bounds=" << bset.m_bvals);
  2262.   LL4(bset);
  2263.   CHK(con.startTransaction() == 0);
  2264.   CHK(con.getNdbScanOperation(itab, tab) == 0);
  2265.   CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0);
  2266.   CHK(bset.setbnd(par) == 0);
  2267.   // get 1st column
  2268.   NdbRecAttr* rec;
  2269.   CHK(con.getValue((Uint32)0, rec) == 0);
  2270.   CHK(con.executeScan() == 0);
  2271.   unsigned count = 0;
  2272.   while (1) {
  2273.     int ret;
  2274.     CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
  2275.     if (ret == 1)
  2276.       break;
  2277.     count++;
  2278.   }
  2279.   con.closeTransaction();
  2280.   CHK(count == countcheck);
  2281.   return 0;
  2282. }
  2283. static int
  2284. scanreadindex(Par par, const ITab& itab)
  2285. {
  2286.   const Tab& tab = par.tab();
  2287.   for (unsigned i = 0; i < par.m_subsubloop; i++) {
  2288.     BSet bset(tab, itab, par.m_rows);
  2289.     bset.calc(par);
  2290.     CHK(scanreadindex(par, itab, bset) == 0);
  2291.   }
  2292.   return 0;
  2293. }
  2294. static int
  2295. scanreadindex(Par par)
  2296. {
  2297.   const Tab& tab = par.tab();
  2298.   for (unsigned i = 0; i < tab.m_itabs; i++) {
  2299.     if (! useindex(i))
  2300.       continue;
  2301.     const ITab& itab = tab.m_itab[i];
  2302.     CHK(scanreadindex(par, itab) == 0);
  2303.   }
  2304.   return 0;
  2305. }
  2306. static int
  2307. scanreadall(Par par)
  2308. {
  2309.   if (par.m_no < 11)
  2310.     CHK(scanreadtable(par) == 0);
  2311.   CHK(scanreadindex(par) == 0);
  2312.   return 0;
  2313. }
  2314. // timing scans
  2315. static int
  2316. timescantable(Par par)
  2317. {
  2318.   par.tmr().on();
  2319.   CHK(scanreadtablefast(par, par.m_totrows) == 0);
  2320.   par.tmr().off(par.set().m_rows);
  2321.   return 0;
  2322. }
  2323. static int
  2324. timescanpkindex(Par par)
  2325. {
  2326.   const Tab& tab = par.tab();
  2327.   const ITab& itab = tab.m_itab[0];     // 1st index is on PK
  2328.   BSet bset(tab, itab, par.m_rows);
  2329.   par.tmr().on();
  2330.   CHK(scanreadindexfast(par, itab, bset, par.m_totrows) == 0);
  2331.   par.tmr().off(par.set().m_rows);
  2332.   return 0;
  2333. }
  2334. static int
  2335. timepkreadtable(Par par)
  2336. {
  2337.   par.tmr().on();
  2338.   unsigned count = par.m_samples;
  2339.   if (count == 0)
  2340.     count = par.m_totrows;
  2341.   CHK(pkreadfast(par, count) == 0);
  2342.   par.tmr().off(count);
  2343.   return 0;
  2344. }
  2345. static int
  2346. timepkreadindex(Par par)
  2347. {
  2348.   const Tab& tab = par.tab();
  2349.   const ITab& itab = tab.m_itab[0];     // 1st index is on PK
  2350.   BSet bset(tab, itab, par.m_rows);
  2351.   unsigned count = par.m_samples;
  2352.   if (count == 0)
  2353.     count = par.m_totrows;
  2354.   par.tmr().on();
  2355.   for (unsigned j = 0; j < count; j++) {
  2356.     unsigned i = urandom(par.m_totrows);
  2357.     bset.calcpk(par, i);
  2358.     CHK(scanreadindexfast(par, itab, bset, 1) == 0);
  2359.   }
  2360.   par.tmr().off(count);
  2361.   return 0;
  2362. }
  2363. // scan update
  2364. static int
  2365. scanupdatetable(Par par)
  2366. {
  2367.   Con& con = par.con();
  2368.   const Tab& tab = par.tab();
  2369.   Set& set = par.set();
  2370.   LL3("scan update " << tab.m_name);
  2371.   Set set2(tab, set.m_rows);
  2372.   CHK(con.startTransaction() == 0);
  2373.   CHK(con.getNdbScanOperation(tab) == 0);
  2374.   CHK(con.openScanExclusive(par.m_scanbat, par.m_scanpar) == 0);
  2375.   set2.getval(par);
  2376.   CHK(con.executeScan() == 0);
  2377.   unsigned count = 0;
  2378.   // updating trans
  2379.   Con con2;
  2380.   con2.connect(con);
  2381.   CHK(con2.startTransaction() == 0);
  2382.   Lst lst;
  2383.   bool deadlock = false;
  2384.   while (1) {
  2385.     int ret;
  2386.     deadlock = par.m_deadlock;
  2387.     CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
  2388.     if (ret == 1)
  2389.       break;
  2390.     if (deadlock) {
  2391.       LL1("scanupdatetable: stop on deadlock");
  2392.       break;
  2393.     }
  2394.     if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) {
  2395.       con.closeScan();
  2396.       break;
  2397.     }
  2398.     do {
  2399.       unsigned i = (unsigned)-1;
  2400.       CHK(set2.getkey(par, &i) == 0);
  2401.       const Row& row = *set.m_row[i];
  2402.       set.lock();
  2403.       if (! set.exist(i) || set.pending(i)) {
  2404.         LL4("scan update " << tab.m_name << ": skip: " << row);
  2405.       } else {
  2406.         CHKTRY(set2.putval(i, false) == 0, set.unlock());
  2407.         CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
  2408.         Par par2 = par;
  2409.         par2.m_con = &con2;
  2410.         set.calc(par, i);
  2411.         CHKTRY(set.setrow(par2, i) == 0, set.unlock());
  2412.         LL4("scan update " << tab.m_name << ": " << row);
  2413.         lst.push(i);
  2414.       }
  2415.       set.unlock();
  2416.       if (lst.cnt() == par.m_batch) {
  2417.         CHK(con2.execute(Commit) == 0);
  2418.         con2.closeTransaction();
  2419.         set.lock();
  2420.         set.notpending(lst);
  2421.         set.unlock();
  2422.         count += lst.cnt();
  2423.         lst.reset();
  2424.         CHK(con2.startTransaction() == 0);
  2425.       }
  2426.       CHK((ret = con.nextScanResult(false)) == 0 || ret == 1 || ret == 2);
  2427.       if (ret == 2 && lst.cnt() != 0) {
  2428.         CHK(con2.execute(Commit) == 0);
  2429.         con2.closeTransaction();
  2430.         set.lock();
  2431.         set.notpending(lst);
  2432.         set.unlock();
  2433.         count += lst.cnt();
  2434.         lst.reset();
  2435.         CHK(con2.startTransaction() == 0);
  2436.       }
  2437.     } while (ret == 0);
  2438.     if (ret == 1)
  2439.       break;
  2440.   }
  2441.   con2.closeTransaction();
  2442.   LL3("scan update " << tab.m_name << " rows updated=" << count);
  2443.   con.closeTransaction();
  2444.   return 0;
  2445. }
  2446. static int
  2447. scanupdateindex(Par par, const ITab& itab, const BSet& bset)
  2448. {
  2449.   Con& con = par.con();
  2450.   const Tab& tab = par.tab();
  2451.   Set& set = par.set();
  2452.   LL3("scan update " << itab.m_name);
  2453.   Set set2(tab, set.m_rows);
  2454.   CHK(con.startTransaction() == 0);
  2455.   CHK(con.getNdbScanOperation(itab, tab) == 0);
  2456.   CHK(con.openScanExclusive(par.m_scanbat, par.m_scanpar) == 0);
  2457.   CHK(bset.setbnd(par) == 0);
  2458.   set2.getval(par);
  2459.   CHK(con.executeScan() == 0);
  2460.   unsigned count = 0;
  2461.   // updating trans
  2462.   Con con2;
  2463.   con2.connect(con);
  2464.   CHK(con2.startTransaction() == 0);
  2465.   Lst lst;
  2466.   bool deadlock = false;
  2467.   while (1) {
  2468.     int ret;
  2469.     deadlock = par.m_deadlock;
  2470.     CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
  2471.     if (ret == 1)
  2472.       break;
  2473.     if (deadlock) {
  2474.       LL1("scanupdateindex: stop on deadlock");
  2475.       break;
  2476.     }
  2477.     if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) {
  2478.       con.closeScan();
  2479.       break;
  2480.     }
  2481.     do {
  2482.       unsigned i = (unsigned)-1;
  2483.       CHK(set2.getkey(par, &i) == 0);
  2484.       const Row& row = *set.m_row[i];
  2485.       set.lock();
  2486.       if (! set.exist(i) || set.pending(i)) {
  2487.         LL4("scan update " << itab.m_name << ": skip: " << row);
  2488.       } else {
  2489.         CHKTRY(set2.putval(i, par.m_dups) == 0, set.unlock());
  2490.         CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
  2491.         Par par2 = par;
  2492.         par2.m_con = &con2;
  2493.         set.calc(par, i);
  2494.         CHKTRY(set.setrow(par2, i) == 0, set.unlock());
  2495.         LL4("scan update " << itab.m_name << ": " << row);
  2496.         lst.push(i);
  2497.       }
  2498.       set.unlock();
  2499.       if (lst.cnt() == par.m_batch) {
  2500.         CHK(con2.execute(Commit) == 0);
  2501.         con2.closeTransaction();
  2502.         set.lock();
  2503.         set.notpending(lst);
  2504.         set.unlock();
  2505.         count += lst.cnt();
  2506.         lst.reset();
  2507.         CHK(con2.startTransaction() == 0);
  2508.       }
  2509.       CHK((ret = con.nextScanResult(false)) == 0 || ret == 1 || ret == 2);
  2510.       if (ret == 2 && lst.cnt() != 0) {
  2511.         CHK(con2.execute(Commit) == 0);
  2512.         con2.closeTransaction();
  2513.         set.lock();
  2514.         set.notpending(lst);
  2515.         set.unlock();
  2516.         count += lst.cnt();
  2517.         lst.reset();
  2518.         CHK(con2.startTransaction() == 0);
  2519.       }
  2520.     } while (ret == 0);
  2521.   }
  2522.   con2.closeTransaction();
  2523.   LL3("scan update " << itab.m_name << " rows updated=" << count);
  2524.   con.closeTransaction();
  2525.   return 0;
  2526. }
  2527. static int
  2528. scanupdateindex(Par par, const ITab& itab)
  2529. {
  2530.   const Tab& tab = par.tab();
  2531.   for (unsigned i = 0; i < par.m_subsubloop; i++) {
  2532.     BSet bset(tab, itab, par.m_rows);
  2533.     bset.calc(par);
  2534.     CHK(scanupdateindex(par, itab, bset) == 0);
  2535.   }
  2536.   return 0;
  2537. }
  2538. static int
  2539. scanupdateindex(Par par)
  2540. {
  2541.   const Tab& tab = par.tab();
  2542.   for (unsigned i = 0; i < tab.m_itabs; i++) {
  2543.     if (! useindex(i))
  2544.       continue;
  2545.     const ITab& itab = tab.m_itab[i];
  2546.     CHK(scanupdateindex(par, itab) == 0);
  2547.   }
  2548.   return 0;
  2549. }
  2550. static int
  2551. scanupdateall(Par par)
  2552. {
  2553.   CHK(scanupdatetable(par) == 0);
  2554.   CHK(scanupdateindex(par) == 0);
  2555.   return 0;
  2556. }
  2557. // medium level routines
  2558. static int
  2559. readverify(Par par)
  2560. {
  2561.   if (par.m_noverify)
  2562.     return 0;
  2563.   par.m_verify = true;
  2564.   if (par.m_abortpct != 0) {
  2565.     LL2("skip verify in this version"); // implement in 5.0 version
  2566.     par.m_verify = false;
  2567.   }
  2568.   CHK(pkread(par) == 0);
  2569.   CHK(scanreadall(par) == 0);
  2570.   return 0;
  2571. }
  2572. static int
  2573. readverifyfull(Par par)
  2574. {
  2575.   if (par.m_noverify)
  2576.     return 0;
  2577.   par.m_verify = true;
  2578.   if (par.m_no == 0)
  2579.     CHK(scanreadtable(par) == 0);
  2580.   else {
  2581.     const Tab& tab = par.tab();
  2582.     unsigned i = par.m_no;
  2583.     if (i <= tab.m_itabs && useindex(i)) {
  2584.       const ITab& itab = tab.m_itab[i - 1];
  2585.       BSet bset(tab, itab, par.m_rows);
  2586.       CHK(scanreadindex(par, itab, bset) == 0);
  2587.     }
  2588.   }
  2589.   return 0;
  2590. }
  2591. static int
  2592. pkops(Par par)
  2593. {
  2594.   par.m_randomkey = true;
  2595.   for (unsigned i = 0; i < par.m_subsubloop; i++) {
  2596.     unsigned sel = urandom(10);
  2597.     if (par.m_slno % 2 == 0) {
  2598.       // favor insert
  2599.       if (sel < 8) {
  2600.         CHK(pkinsert(par) == 0);
  2601.       } else if (sel < 9) {
  2602.         CHK(pkupdate(par) == 0);
  2603.       } else {
  2604.         CHK(pkdelete(par) == 0);
  2605.       }
  2606.     } else {
  2607.       // favor delete
  2608.       if (sel < 1) {
  2609.         CHK(pkinsert(par) == 0);
  2610.       } else if (sel < 2) {
  2611.         CHK(pkupdate(par) == 0);
  2612.       } else {
  2613.         CHK(pkdelete(par) == 0);
  2614.       }
  2615.     }
  2616.   }
  2617.   return 0;
  2618. }
  2619. static int
  2620. pkupdatescanread(Par par)
  2621. {
  2622.   par.m_dups = true;
  2623.   unsigned sel = urandom(10);
  2624.   if (sel < 5) {
  2625.     CHK(pkupdate(par) == 0);
  2626.   } else if (sel < 6) {
  2627.     par.m_verify = false;
  2628.     CHK(scanreadtable(par) == 0);
  2629.   } else {
  2630.     par.m_verify = false;
  2631.     CHK(scanreadindex(par) == 0);
  2632.   }
  2633.   return 0;
  2634. }
  2635. static int
  2636. mixedoperations(Par par)
  2637. {
  2638.   par.m_dups = true;
  2639.   par.m_deadlock = true;
  2640.   par.m_scanstop = par.m_totrows;       // randomly close scans
  2641.   unsigned sel = urandom(10);
  2642.   if (sel < 2) {
  2643.     CHK(pkdelete(par) == 0);
  2644.   } else if (sel < 4) {
  2645.     CHK(pkupdate(par) == 0);
  2646.   } else if (sel < 6) {
  2647.     CHK(scanupdatetable(par) == 0);
  2648.   } else {
  2649.     CHK(scanupdateindex(par) == 0);
  2650.   }
  2651.   return 0;
  2652. }
  2653. static int
  2654. pkupdateindexbuild(Par par)
  2655. {
  2656.   if (par.m_no == 0) {
  2657.     CHK(createindex(par) == 0);
  2658.   } else {
  2659.     par.m_randomkey = true;
  2660.     CHK(pkupdate(par) == 0);
  2661.   }
  2662.   return 0;
  2663. }
  2664. // threads
  2665. typedef int (*TFunc)(Par par);
  2666. enum TMode { ST = 1, MT = 2 };
  2667. extern "C" { static void* runthread(void* arg); }
  2668. struct Thr {
  2669.   enum State { Wait, Start, Stop, Stopped, Exit };
  2670.   State m_state;
  2671.   Par m_par;
  2672.   Uint64 m_id;
  2673.   NdbThread* m_thread;
  2674.   NdbMutex* m_mutex;
  2675.   NdbCondition* m_cond;
  2676.   TFunc m_func;
  2677.   int m_ret;
  2678.   void* m_status;
  2679.   Thr(Par par, unsigned n);
  2680.   ~Thr();
  2681.   int run();
  2682.   void start();
  2683.   void stop();
  2684.   void stopped();
  2685.   void exit();
  2686.   //
  2687.   void lock() {
  2688.     NdbMutex_Lock(m_mutex);
  2689.   }
  2690.   void unlock() {
  2691.     NdbMutex_Unlock(m_mutex);
  2692.   }
  2693.   void wait() {
  2694.     NdbCondition_Wait(m_cond, m_mutex);
  2695.   }
  2696.   void signal() {
  2697.     NdbCondition_Signal(m_cond);
  2698.   }
  2699.   void join() {
  2700.     NdbThread_WaitFor(m_thread, &m_status);
  2701.     m_thread = 0;
  2702.   }
  2703. };
  2704. Thr::Thr(Par par, unsigned n) :
  2705.   m_state(Wait),
  2706.   m_par(par),
  2707.   m_id(0),
  2708.   m_thread(0),
  2709.   m_mutex(0),
  2710.   m_cond(0),
  2711.   m_func(0),
  2712.   m_ret(0),
  2713.   m_status(0)
  2714. {
  2715.   m_par.m_no = n;
  2716.   char buf[10];
  2717.   sprintf(buf, "thr%03u", par.m_no);
  2718.   const char* name = strcpy(new char[10], buf);
  2719.   // mutex
  2720.   m_mutex = NdbMutex_Create();
  2721.   m_cond = NdbCondition_Create();
  2722.   assert(m_mutex != 0 && m_cond != 0);
  2723.   // run
  2724.   const unsigned stacksize = 256 * 1024;
  2725.   const NDB_THREAD_PRIO prio = NDB_THREAD_PRIO_LOW;
  2726.   m_thread = NdbThread_Create(runthread, (void**)this, stacksize, name, prio);
  2727. }
  2728. Thr::~Thr()
  2729. {
  2730.   if (m_thread != 0) {
  2731.     NdbThread_Destroy(&m_thread);
  2732.     m_thread = 0;
  2733.   }
  2734.   if (m_cond != 0) {
  2735.     NdbCondition_Destroy(m_cond);
  2736.     m_cond = 0;
  2737.   }
  2738.   if (m_mutex != 0) {
  2739.     NdbMutex_Destroy(m_mutex);
  2740.     m_mutex = 0;
  2741.   }
  2742. }
  2743. static void*
  2744. runthread(void* arg)
  2745. {
  2746.   Thr& thr = *(Thr*)arg;
  2747.   thr.m_id = (Uint64)pthread_self();
  2748.   if (thr.run() < 0) {
  2749.     LL1("exit on error");
  2750.   } else {
  2751.     LL4("exit ok");
  2752.   }
  2753.   return 0;
  2754. }
  2755. int
  2756. Thr::run()
  2757. {
  2758.   LL4("run");
  2759.   Con con;
  2760.   CHK(con.connect() == 0);
  2761.   m_par.m_con = &con;
  2762.   LL4("connected");
  2763.   while (1) {
  2764.     lock();
  2765.     while (m_state != Start && m_state != Exit) {
  2766.       LL4("wait");
  2767.       wait();
  2768.     }
  2769.     if (m_state == Exit) {
  2770.       LL4("exit");
  2771.       unlock();
  2772.       break;
  2773.     }
  2774.     LL4("start");
  2775.     assert(m_state == Start);
  2776.     m_ret = (*m_func)(m_par);
  2777.     m_state = Stopped;
  2778.     LL4("stop");
  2779.     signal();
  2780.     unlock();
  2781.     CHK(m_ret == 0);
  2782.   }
  2783.   con.disconnect();
  2784.   return 0;
  2785. }
  2786. void
  2787. Thr::start()
  2788. {
  2789.   lock();
  2790.   m_state = Start;
  2791.   signal();
  2792.   unlock();
  2793. }
  2794. void
  2795. Thr::stop()
  2796. {
  2797.   lock();
  2798.   m_state = Stop;
  2799.   signal();
  2800.   unlock();
  2801. }
  2802. void
  2803. Thr::stopped()
  2804. {
  2805.   lock();
  2806.   while (m_state != Stopped)
  2807.     wait();
  2808.   m_state = Wait;
  2809.   unlock();
  2810. }
  2811. void
  2812. Thr::exit()
  2813. {
  2814.   lock();
  2815.   m_state = Exit;
  2816.   signal();
  2817.   unlock();
  2818. }
  2819. // test run
  2820. static Thr** g_thrlist = 0;
  2821. static unsigned
  2822. getthrno()
  2823. {
  2824.   if (g_thrlist != 0) {
  2825.     Uint64 id = (Uint64)pthread_self();
  2826.     for (unsigned n = 0; n < g_opt.m_threads; n++) {
  2827.       if (g_thrlist[n] != 0) {
  2828.         const Thr& thr = *g_thrlist[n];
  2829.         if (thr.m_id == id)
  2830.           return thr.m_par.m_no;
  2831.       }
  2832.     }
  2833.   }
  2834.   return (unsigned)-1;
  2835. }
  2836. static int
  2837. runstep(Par par, const char* fname, TFunc func, unsigned mode)
  2838. {
  2839.   LL2(fname);
  2840.   const int threads = (mode & ST ? 1 : par.m_threads);
  2841.   int n; 
  2842.   for (n = 0; n < threads; n++) {
  2843.     LL4("start " << n);
  2844.     Thr& thr = *g_thrlist[n];
  2845.     Par oldpar = thr.m_par;
  2846.     // update parameters
  2847.     thr.m_par = par;
  2848.     thr.m_par.m_no = oldpar.m_no;
  2849.     thr.m_par.m_con = oldpar.m_con;
  2850.     thr.m_func = func;
  2851.     thr.start();
  2852.   }
  2853.   unsigned errs = 0;
  2854.   for (n = threads - 1; n >= 0; n--) {
  2855.     LL4("stop " << n);
  2856.     Thr& thr = *g_thrlist[n];
  2857.     thr.stopped();
  2858.     if (thr.m_ret != 0)
  2859.       errs++;
  2860.   }
  2861.   CHK(errs == 0);
  2862.   return 0;
  2863. }
  2864. #define RUNSTEP(par, func, mode) CHK(runstep(par, #func, func, mode) == 0)
  2865. static int
  2866. tbuild(Par par)
  2867. {
  2868.   RUNSTEP(par, droptable, ST);
  2869.   RUNSTEP(par, createtable, ST);
  2870.   RUNSTEP(par, invalidatetable, MT);
  2871.   for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
  2872.     if (par.m_slno % 2 == 0) {
  2873.       RUNSTEP(par, createindex, ST);
  2874.       RUNSTEP(par, invalidateindex, MT);
  2875.       RUNSTEP(par, pkinsert, MT);
  2876.     } else {
  2877.       RUNSTEP(par, pkinsert, MT);
  2878.       RUNSTEP(par, createindex, ST);
  2879.       RUNSTEP(par, invalidateindex, MT);
  2880.     }
  2881.     RUNSTEP(par, pkupdate, MT);
  2882.     RUNSTEP(par, readverifyfull, MT);
  2883.     RUNSTEP(par, pkdelete, MT);
  2884.     RUNSTEP(par, readverifyfull, MT);
  2885.     RUNSTEP(par, dropindex, ST);
  2886.   }
  2887.   return 0;
  2888. }
  2889. static int
  2890. tpkops(Par par)
  2891. {
  2892.   RUNSTEP(par, droptable, ST);
  2893.   RUNSTEP(par, createtable, ST);
  2894.   RUNSTEP(par, invalidatetable, MT);
  2895.   RUNSTEP(par, createindex, ST);
  2896.   RUNSTEP(par, invalidateindex, MT);
  2897.   for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
  2898.     RUNSTEP(par, pkops, MT);
  2899.     LL2("rows=" << par.set().count());
  2900.     RUNSTEP(par, readverifyfull, MT);
  2901.   }
  2902.   return 0;
  2903. }
  2904. static int
  2905. tpkopsread(Par par)
  2906. {
  2907.   RUNSTEP(par, droptable, ST);
  2908.   RUNSTEP(par, createtable, ST);
  2909.   RUNSTEP(par, invalidatetable, MT);
  2910.   RUNSTEP(par, pkinsert, MT);
  2911.   RUNSTEP(par, createindex, ST);
  2912.   RUNSTEP(par, invalidateindex, MT);
  2913.   RUNSTEP(par, readverify, ST);
  2914.   for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
  2915.     RUNSTEP(par, pkupdatescanread, MT);
  2916.     RUNSTEP(par, readverify, ST);
  2917.   }
  2918.   RUNSTEP(par, pkdelete, MT);
  2919.   RUNSTEP(par, readverify, ST);
  2920.   return 0;
  2921. }
  2922. static int
  2923. tmixedops(Par par)
  2924. {
  2925.   RUNSTEP(par, droptable, ST);
  2926.   RUNSTEP(par, createtable, ST);
  2927.   RUNSTEP(par, invalidatetable, MT);
  2928.   RUNSTEP(par, pkinsert, MT);
  2929.   RUNSTEP(par, createindex, ST);
  2930.   RUNSTEP(par, invalidateindex, MT);
  2931.   RUNSTEP(par, readverify, ST);
  2932.   for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
  2933.     RUNSTEP(par, mixedoperations, MT);
  2934.     RUNSTEP(par, readverify, ST);
  2935.   }
  2936.   return 0;
  2937. }
  2938. static int
  2939. tbusybuild(Par par)
  2940. {
  2941.   RUNSTEP(par, droptable, ST);
  2942.   RUNSTEP(par, createtable, ST);
  2943.   RUNSTEP(par, invalidatetable, MT);
  2944.   RUNSTEP(par, pkinsert, MT);
  2945.   for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
  2946.     RUNSTEP(par, pkupdateindexbuild, MT);
  2947.     RUNSTEP(par, invalidateindex, MT);
  2948.     RUNSTEP(par, readverify, ST);
  2949.     RUNSTEP(par, dropindex, ST);
  2950.   }
  2951.   return 0;
  2952. }
  2953. static int
  2954. trollback(Par par)
  2955. {
  2956.   par.m_abortpct = 50;
  2957.   RUNSTEP(par, droptable, ST);
  2958.   RUNSTEP(par, createtable, ST);
  2959.   RUNSTEP(par, invalidatetable, MT);
  2960.   RUNSTEP(par, pkinsert, MT);
  2961.   RUNSTEP(par, createindex, ST);
  2962.   RUNSTEP(par, invalidateindex, MT);
  2963.   RUNSTEP(par, readverify, ST);
  2964.   for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
  2965.     RUNSTEP(par, mixedoperations, MT);
  2966.     RUNSTEP(par, readverify, ST);
  2967.   }
  2968.   return 0;
  2969. }
  2970. static int
  2971. ttimebuild(Par par)
  2972. {
  2973.   Tmr t1;
  2974.   RUNSTEP(par, droptable, ST);
  2975.   RUNSTEP(par, createtable, ST);
  2976.   RUNSTEP(par, invalidatetable, MT);
  2977.   for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
  2978.     RUNSTEP(par, pkinsert, MT);
  2979.     t1.on();
  2980.     RUNSTEP(par, createindex, ST);
  2981.     t1.off(par.m_totrows);
  2982.     RUNSTEP(par, invalidateindex, MT);
  2983.     RUNSTEP(par, dropindex, ST);
  2984.   }
  2985.   LL1("build index - " << t1.time());
  2986.   return 0;
  2987. }
  2988. static int
  2989. ttimemaint(Par par)
  2990. {
  2991.   Tmr t1, t2;
  2992.   RUNSTEP(par, droptable, ST);
  2993.   RUNSTEP(par, createtable, ST);
  2994.   RUNSTEP(par, invalidatetable, MT);
  2995.   for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
  2996.     RUNSTEP(par, pkinsert, MT);
  2997.     t1.on();
  2998.     RUNSTEP(par, pkupdate, MT);
  2999.     t1.off(par.m_totrows);
  3000.     RUNSTEP(par, createindex, ST);
  3001.     RUNSTEP(par, invalidateindex, MT);
  3002.     t2.on();
  3003.     RUNSTEP(par, pkupdate, MT);
  3004.     t2.off(par.m_totrows);
  3005.     RUNSTEP(par, dropindex, ST);
  3006.   }
  3007.   LL1("update - " << t1.time());
  3008.   LL1("update indexed - " << t2.time());
  3009.   LL1("overhead - " << t2.over(t1));
  3010.   return 0;
  3011. }
  3012. static int
  3013. ttimescan(Par par)
  3014. {
  3015.   Tmr t1, t2;
  3016.   RUNSTEP(par, droptable, ST);
  3017.   RUNSTEP(par, createtable, ST);
  3018.   RUNSTEP(par, invalidatetable, MT);
  3019.   for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
  3020.     RUNSTEP(par, pkinsert, MT);
  3021.     RUNSTEP(par, createindex, ST);
  3022.     par.m_tmr = &t1;
  3023.     RUNSTEP(par, timescantable, ST);
  3024.     par.m_tmr = &t2;
  3025.     RUNSTEP(par, timescanpkindex, ST);
  3026.     RUNSTEP(par, dropindex, ST);
  3027.   }
  3028.   LL1("full scan table - " << t1.time());
  3029.   LL1("full scan PK index - " << t2.time());
  3030.   LL1("overhead - " << t2.over(t1));
  3031.   return 0;
  3032. }
  3033. static int
  3034. ttimepkread(Par par)
  3035. {
  3036.   Tmr t1, t2;
  3037.   RUNSTEP(par, droptable, ST);
  3038.   RUNSTEP(par, createtable, ST);
  3039.   RUNSTEP(par, invalidatetable, MT);
  3040.   for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
  3041.     RUNSTEP(par, pkinsert, MT);
  3042.     RUNSTEP(par, createindex, ST);
  3043.     par.m_tmr = &t1;
  3044.     RUNSTEP(par, timepkreadtable, ST);
  3045.     par.m_tmr = &t2;
  3046.     RUNSTEP(par, timepkreadindex, ST);
  3047.     RUNSTEP(par, dropindex, ST);
  3048.   }
  3049.   LL1("pk read table - " << t1.time());
  3050.   LL1("pk read PK index - " << t2.time());
  3051.   LL1("overhead - " << t2.over(t1));
  3052.   return 0;
  3053. }
  3054. static int
  3055. tdrop(Par par)
  3056. {
  3057.   RUNSTEP(par, droptable, ST);
  3058.   return 0;
  3059. }
  3060. struct TCase {
  3061.   const char* m_name;
  3062.   TFunc m_func;
  3063.   const char* m_desc;
  3064.   TCase(const char* name, TFunc func, const char* desc) :
  3065.     m_name(name),
  3066.     m_func(func),
  3067.     m_desc(desc) {
  3068.   }
  3069. };
  3070. static const TCase
  3071. tcaselist[] = {
  3072.   TCase("a", tbuild, "index build"),
  3073.   // "b" in 5.0
  3074.   TCase("c", tpkops, "pk operations"),
  3075.   TCase("d", tpkopsread, "pk operations and scan reads"),
  3076.   TCase("e", tmixedops, "pk operations and scan operations"),
  3077.   TCase("f", tbusybuild, "pk operations and index build"),
  3078.   TCase("g", trollback, "operations with random rollbacks"),
  3079.   TCase("t", ttimebuild, "time index build"),
  3080.   TCase("u", ttimemaint, "time index maintenance"),
  3081.   TCase("v", ttimescan, "time full scan table vs index on pk"),
  3082.   TCase("w", ttimepkread, "time pk read table vs index on pk"),
  3083.   TCase("z", tdrop, "drop test tables")
  3084. };
  3085. static const unsigned
  3086. tcasecount = sizeof(tcaselist) / sizeof(tcaselist[0]);
  3087. static void
  3088. printcases()
  3089. {
  3090.   ndbout << "test cases:" << endl;
  3091.   for (unsigned i = 0; i < tcasecount; i++) {
  3092.     const TCase& tcase = tcaselist[i];
  3093.     ndbout << "  " << tcase.m_name << " - " << tcase.m_desc << endl;
  3094.   }
  3095. }
  3096. static void
  3097. printtables()
  3098. {
  3099.   ndbout << "tables and indexes (X1 is on table PK):" << endl;
  3100.   for (unsigned j = 0; j < tabcount; j++) {
  3101.     const Tab& tab = tablist[j];
  3102.     ndbout << "  " << tab.m_name;
  3103.     for (unsigned i = 0; i < tab.m_itabs; i++) {
  3104.       const ITab& itab = tab.m_itab[i];
  3105.       ndbout << " " << itab.m_name;
  3106.     }
  3107.     ndbout << endl;
  3108.   }
  3109. }
  3110. static int
  3111. runtest(Par par)
  3112. {
  3113.   LL1("start");
  3114.   if (par.m_seed != 0)
  3115.     srandom(par.m_seed);
  3116.   assert(par.m_csname != 0);
  3117.   CHARSET_INFO* cs;
  3118.   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);
  3119.   par.m_cs = cs;
  3120.   Con con;
  3121.   CHK(con.connect() == 0);
  3122.   par.m_con = &con;
  3123.   g_thrlist = new Thr* [par.m_threads];
  3124.   unsigned n;
  3125.   for (n = 0; n < par.m_threads; n++) {
  3126.     g_thrlist[n] = 0;
  3127.   }
  3128.   for (n = 0; n < par.m_threads; n++) {
  3129.     g_thrlist[n] = new Thr(par, n);
  3130.     Thr& thr = *g_thrlist[n];
  3131.     assert(thr.m_thread != 0);
  3132.   }
  3133.   for (par.m_lno = 0; par.m_loop == 0 || par.m_lno < par.m_loop; par.m_lno++) {
  3134.     LL1("loop " << par.m_lno);
  3135.     if (par.m_seed == 0)
  3136.       srandom(par.m_lno);
  3137.     for (unsigned i = 0; i < tcasecount; i++) {
  3138.       const TCase& tcase = tcaselist[i];
  3139.       if (par.m_case != 0 && strchr(par.m_case, tcase.m_name[0]) == 0)
  3140.         continue;
  3141.       LL1("case " << tcase.m_name << " - " << tcase.m_desc);
  3142.       for (unsigned j = 0; j < tabcount; j++) {
  3143.         if (! usetable(j))
  3144.           continue;
  3145.         const Tab& tab = tablist[j];
  3146.         par.m_tab = &tab;
  3147.         delete par.m_set;
  3148.         par.m_set = new Set(tab, par.m_totrows);
  3149.         LL1("table " << tab.m_name);
  3150.         CHK(tcase.m_func(par) == 0);
  3151.       }
  3152.     }
  3153.   }
  3154.   for (n = 0; n < par.m_threads; n++) {
  3155.     Thr& thr = *g_thrlist[n];
  3156.     thr.exit();
  3157.   }
  3158.   for (n = 0; n < par.m_threads; n++) {
  3159.     Thr& thr = *g_thrlist[n];
  3160.     thr.join();
  3161.     delete &thr;
  3162.   }
  3163.   delete [] g_thrlist;
  3164.   g_thrlist = 0;
  3165.   con.disconnect();
  3166.   LL1("done");
  3167.   return 0;
  3168. }
  3169. NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535)
  3170. {
  3171.   ndb_init();
  3172.   if (ndbout_mutex == NULL)
  3173.     ndbout_mutex= NdbMutex_Create();
  3174.   while (++argv, --argc > 0) {
  3175.     const char* arg = argv[0];
  3176.     if (*arg != '-') {
  3177.       ndbout << "testOIBasic: unknown argument " << arg;
  3178.       goto usage;
  3179.     }
  3180.     if (strcmp(arg, "-batch") == 0) {
  3181.       if (++argv, --argc > 0) {
  3182.         g_opt.m_batch = atoi(argv[0]);
  3183.         continue;
  3184.       }
  3185.     }
  3186.     if (strcmp(arg, "-bound") == 0) {
  3187.       if (++argv, --argc > 0) {
  3188.         const char* p = argv[0];
  3189.         if (strlen(p) != 0 && strlen(p) == strspn(p, "01234")) {
  3190.           g_opt.m_bound = strdup(p);
  3191.           continue;
  3192.         }
  3193.       }
  3194.     }
  3195.     if (strcmp(arg, "-case") == 0) {
  3196.       if (++argv, --argc > 0) {
  3197.         g_opt.m_case = strdup(argv[0]);
  3198.         continue;
  3199.       }
  3200.     }
  3201.     if (strcmp(arg, "-core") == 0) {
  3202.       g_opt.m_core = true;
  3203.       continue;
  3204.     }
  3205.     if (strcmp(arg, "-csname") == 0) {
  3206.       if (++argv, --argc > 0) {
  3207.         g_opt.m_csname = strdup(argv[0]);
  3208.         continue;
  3209.       }
  3210.     }
  3211.     if (strcmp(arg, "-die") == 0) {
  3212.       if (++argv, --argc > 0) {
  3213.         g_opt.m_die = atoi(argv[0]);
  3214.         continue;
  3215.       }
  3216.     }
  3217.     if (strcmp(arg, "-dups") == 0) {
  3218.       g_opt.m_dups = true;
  3219.       continue;
  3220.     }
  3221.     if (strcmp(arg, "-fragtype") == 0) {
  3222.       if (++argv, --argc > 0) {
  3223.         if (strcmp(argv[0], "single") == 0) {
  3224.           g_opt.m_fragtype = NdbDictionary::Object::FragSingle;
  3225.           continue;
  3226.         }
  3227.         if (strcmp(argv[0], "small") == 0) {
  3228.           g_opt.m_fragtype = NdbDictionary::Object::FragAllSmall;
  3229.           continue;
  3230.         }
  3231.         if (strcmp(argv[0], "medium") == 0) {
  3232.           g_opt.m_fragtype = NdbDictionary::Object::FragAllMedium;
  3233.           continue;
  3234.         }
  3235.         if (strcmp(argv[0], "large") == 0) {
  3236.           g_opt.m_fragtype = NdbDictionary::Object::FragAllLarge;
  3237.           continue;
  3238.         }
  3239.       }
  3240.     }
  3241.     if (strcmp(arg, "-index") == 0) {
  3242.       if (++argv, --argc > 0) {
  3243.         g_opt.m_index = strdup(argv[0]);
  3244.         continue;
  3245.       }
  3246.     }
  3247.     if (strcmp(arg, "-loop") == 0) {
  3248.       if (++argv, --argc > 0) {
  3249.         g_opt.m_loop = atoi(argv[0]);
  3250.         continue;
  3251.       }
  3252.     }
  3253.     if (strcmp(arg, "-nologging") == 0) {
  3254.       g_opt.m_nologging = true;
  3255.       continue;
  3256.     }
  3257.     if (strcmp(arg, "-noverify") == 0) {
  3258.       g_opt.m_noverify = true;
  3259.       continue;
  3260.     }
  3261.     if (strcmp(arg, "-pctnull") == 0) {
  3262.       if (++argv, --argc > 0) {
  3263.         g_opt.m_pctnull = atoi(argv[0]);
  3264.         continue;
  3265.       }
  3266.     }
  3267.     if (strcmp(arg, "-rows") == 0) {
  3268.       if (++argv, --argc > 0) {
  3269.         g_opt.m_rows = atoi(argv[0]);
  3270.         continue;
  3271.       }
  3272.     }
  3273.     if (strcmp(arg, "-samples") == 0) {
  3274.       if (++argv, --argc > 0) {
  3275.         g_opt.m_samples = atoi(argv[0]);
  3276.         continue;
  3277.       }
  3278.     }
  3279.     if (strcmp(arg, "-scanbat") == 0) {
  3280.       if (++argv, --argc > 0) {
  3281.         g_opt.m_scanbat = atoi(argv[0]);
  3282.         continue;
  3283.       }
  3284.     }
  3285.     if (strcmp(arg, "-scanpar") == 0) {
  3286.       if (++argv, --argc > 0) {
  3287.         g_opt.m_scanpar = atoi(argv[0]);
  3288.         continue;
  3289.       }
  3290.     }
  3291.     if (strcmp(arg, "-seed") == 0) {
  3292.       if (++argv, --argc > 0) {
  3293.         g_opt.m_seed = atoi(argv[0]);
  3294.         continue;
  3295.       }
  3296.     }
  3297.     if (strcmp(arg, "-subloop") == 0) {
  3298.       if (++argv, --argc > 0) {
  3299.         g_opt.m_subloop = atoi(argv[0]);
  3300.         continue;
  3301.       }
  3302.     }
  3303.     if (strcmp(arg, "-table") == 0) {
  3304.       if (++argv, --argc > 0) {
  3305.         g_opt.m_table = strdup(argv[0]);
  3306.         continue;
  3307.       }
  3308.     }
  3309.     if (strcmp(arg, "-threads") == 0) {
  3310.       if (++argv, --argc > 0) {
  3311.         g_opt.m_threads = atoi(argv[0]);
  3312.         continue;
  3313.       }
  3314.     }
  3315.     if (strcmp(arg, "-v") == 0) {
  3316.       if (++argv, --argc > 0) {
  3317.         g_opt.m_v = atoi(argv[0]);
  3318.         continue;
  3319.       }
  3320.     }
  3321.     if (strncmp(arg, "-v", 2) == 0 && isdigit(arg[2])) {
  3322.       g_opt.m_v = atoi(&arg[2]);
  3323.       continue;
  3324.     }
  3325.     if (strcmp(arg, "-h") == 0 || strcmp(arg, "-help") == 0) {
  3326.       printhelp();
  3327.       goto wrongargs;
  3328.     }
  3329.     ndbout << "testOIBasic: unknown option " << arg;
  3330.     goto usage;
  3331.   }
  3332.   {
  3333.     Par par(g_opt);
  3334.     g_ncc = new Ndb_cluster_connection();
  3335.     if (g_ncc->connect(30) != 0 || runtest(par) < 0)
  3336.       goto failed;
  3337.     delete g_ncc;
  3338.     g_ncc = 0;
  3339.   }
  3340.   // always exit with NDBT code
  3341. ok:
  3342.   return NDBT_ProgramExit(NDBT_OK);
  3343. failed:
  3344.   return NDBT_ProgramExit(NDBT_FAILED);
  3345. usage:
  3346.   ndbout << " (use -h for help)" << endl;
  3347. wrongargs:
  3348.   return NDBT_ProgramExit(NDBT_WRONGARGS);
  3349. }
  3350. // vim: set sw=2 et: