PageRenderTime 79ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src/router/mysql/storage/ndb/test/ndbapi/testScanFilter.cpp

https://gitlab.com/envieidoc/advancedtomato2
C++ | 860 lines | 550 code | 92 blank | 218 comment | 110 complexity | c42f773daeefd61d17459623036994b7 MD5 | raw file
  1. /* Copyright (C) 2007 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; version 2 of the License.
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License
  10. along with this program; if not, write to the Free Software
  11. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
  12. #include <NDBT.hpp>
  13. #include <NDBT_Test.hpp>
  14. #define ERR_EXIT(obj, msg) \
  15. do \
  16. { \
  17. fprintf(stderr, "%s: %s (%d) in %s:%d\n", \
  18. msg, obj->getNdbError().message, obj->getNdbError().code, __FILE__, __LINE__); \
  19. exit(-1); \
  20. } \
  21. while (0);
  22. #define PRINT_ERROR(code,msg) \
  23. do \
  24. { \
  25. fprintf(stderr, "Error in %s, line: %d, code: %d, msg: %s.\n", __FILE__, __LINE__, code, msg); \
  26. } \
  27. while (0);
  28. #define MYSQLERROR(mysql) { \
  29. PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
  30. exit(-1); }
  31. #define APIERROR(error) { \
  32. PRINT_ERROR(error.code,error.message); \
  33. exit(-1); }
  34. #define TEST_NAME "TestScanFilter"
  35. #define TABLE_NAME "TABLE_SCAN"
  36. const char *COL_NAME[] = {"id", "i", "j", "k", "l", "m", "n"};
  37. const char COL_LEN = 7;
  38. /*
  39. * Not to change TUPLE_NUM, because the column in TABLE_NAME is fixed,
  40. * there are six columns, 'i', 'j', 'k', 'l', 'm', 'n', and each on is equal to 1 or 1,
  41. * Since each tuple should be unique in this case, then TUPLE_NUM = 2 power 6 = 64
  42. */
  43. #ifdef _AIX
  44. /*
  45. IBM xlC_r breaks on the initialization with pow():
  46. "The expression must be an integral constant expression."
  47. */
  48. const int TUPLE_NUM = 64;
  49. #else
  50. const int TUPLE_NUM = (int)pow(2, COL_LEN-1);
  51. #endif
  52. /*
  53. * the recursive level of random scan filter, can
  54. * modify this parameter more or less, range from
  55. * 1 to 100, larger num consumes more scan time
  56. */
  57. const int RECURSIVE_LEVEL = 10;
  58. const int MAX_STR_LEN = (RECURSIVE_LEVEL * (COL_LEN+1) * 4);
  59. /*
  60. * Each time stands for one test, it will produce a random
  61. * filter string, and scan through ndb api and through
  62. * calculation with tuples' data, then compare the result,
  63. * if they are equal, this test passed, or failed.
  64. * Only all TEST_NUM times tests passed, we can believe
  65. * the suite of test cases are okay.
  66. * Change TEST_NUM to larger will need more time to test
  67. */
  68. const int TEST_NUM = 5000;
  69. /* Table definition*/
  70. static
  71. const
  72. NDBT_Attribute MYTAB1Attribs[] = {
  73. NDBT_Attribute("id", NdbDictionary::Column::Unsigned, 1, true),
  74. NDBT_Attribute("i", NdbDictionary::Column::Unsigned),
  75. NDBT_Attribute("j", NdbDictionary::Column::Unsigned),
  76. NDBT_Attribute("k", NdbDictionary::Column::Unsigned),
  77. NDBT_Attribute("l", NdbDictionary::Column::Unsigned),
  78. NDBT_Attribute("m", NdbDictionary::Column::Unsigned),
  79. NDBT_Attribute("n", NdbDictionary::Column::Unsigned),
  80. };
  81. static
  82. const
  83. NDBT_Table MYTAB1(TABLE_NAME, sizeof(MYTAB1Attribs)/sizeof(NDBT_Attribute), MYTAB1Attribs);
  84. int createTable(Ndb* pNdb, const NdbDictionary::Table* tab, bool _temp,
  85. bool existsOk, NDBT_CreateTableHook f)
  86. {
  87. int r = 0;
  88. do{
  89. NdbDictionary::Table tmpTab(* tab);
  90. tmpTab.setStoredTable(_temp ? 0 : 1);
  91. if(f != 0 && f(pNdb, tmpTab, 0, NULL))
  92. {
  93. ndbout << "Failed to create table" << endl;
  94. return NDBT_FAILED;
  95. }
  96. r = pNdb->getDictionary()->createTable(tmpTab);
  97. if(r == -1){
  98. if(!existsOk){
  99. ndbout << "Error: " << pNdb->getDictionary()->getNdbError() << endl;
  100. break;
  101. }
  102. if(pNdb->getDictionary()->getNdbError().code != 721){
  103. ndbout << "Error: " << pNdb->getDictionary()->getNdbError() << endl;
  104. break;
  105. }
  106. r = 0;
  107. }
  108. }while(false);
  109. return r;
  110. }
  111. /*
  112. * Function to produce the tuples' data
  113. */
  114. int runPopulate(NDBT_Context* ctx, NDBT_Step* step)
  115. {
  116. Ndb *myNdb = GETNDB(step);
  117. const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
  118. const NdbDictionary::Table *myTable= myDict->getTable(TABLE_NAME);
  119. if(myTable == NULL)
  120. APIERROR(myDict->getNdbError());
  121. NdbTransaction* myTrans = myNdb->startTransaction();
  122. if (myTrans == NULL)
  123. APIERROR(myNdb->getNdbError());
  124. for(int num = 0; num < TUPLE_NUM; num++)
  125. {
  126. NdbOperation* myNdbOperation = myTrans->getNdbOperation(myTable);
  127. if(myNdbOperation == NULL)
  128. {
  129. APIERROR(myTrans->getNdbError());
  130. }
  131. /* the tuples' data in TABLE_NAME
  132. +----+---+---+---+---+---+---+
  133. | id | i | j | k | l | m | n |
  134. +----+---+---+---+---+---+---+
  135. | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
  136. | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
  137. | 2 | 0 | 0 | 0 | 0 | 1 | 0 |
  138. | 3 | 0 | 0 | 0 | 0 | 1 | 1 |
  139. | 4 | 0 | 0 | 0 | 1 | 0 | 0 |
  140. | 5 | 0 | 0 | 0 | 1 | 0 | 1 |
  141. | 6 | 0 | 0 | 0 | 1 | 1 | 0 |
  142. | 7 | 0 | 0 | 0 | 1 | 1 | 1 |
  143. | 8 | 0 | 0 | 1 | 0 | 0 | 0 |
  144. | 9 | 0 | 0 | 1 | 0 | 0 | 1 |
  145. | 10 | 0 | 0 | 1 | 0 | 1 | 0 |
  146. | 11 | 0 | 0 | 1 | 0 | 1 | 1 |
  147. | 12 | 0 | 0 | 1 | 1 | 0 | 0 |
  148. | 13 | 0 | 0 | 1 | 1 | 0 | 1 |
  149. | 14 | 0 | 0 | 1 | 1 | 1 | 0 |
  150. | 15 | 0 | 0 | 1 | 1 | 1 | 1 |
  151. | 16 | 0 | 1 | 0 | 0 | 0 | 0 |
  152. | 17 | 0 | 1 | 0 | 0 | 0 | 1 |
  153. | 18 | 0 | 1 | 0 | 0 | 1 | 0 |
  154. | 19 | 0 | 1 | 0 | 0 | 1 | 1 |
  155. | 20 | 0 | 1 | 0 | 1 | 0 | 0 |
  156. | 21 | 0 | 1 | 0 | 1 | 0 | 1 |
  157. | 22 | 0 | 1 | 0 | 1 | 1 | 0 |
  158. | 23 | 0 | 1 | 0 | 1 | 1 | 1 |
  159. | 24 | 0 | 1 | 1 | 0 | 0 | 0 |
  160. | 25 | 0 | 1 | 1 | 0 | 0 | 1 |
  161. | 26 | 0 | 1 | 1 | 0 | 1 | 0 |
  162. | 27 | 0 | 1 | 1 | 0 | 1 | 1 |
  163. | 28 | 0 | 1 | 1 | 1 | 0 | 0 |
  164. | 29 | 0 | 1 | 1 | 1 | 0 | 1 |
  165. | 30 | 0 | 1 | 1 | 1 | 1 | 0 |
  166. | 31 | 0 | 1 | 1 | 1 | 1 | 1 |
  167. | 32 | 1 | 0 | 0 | 0 | 0 | 0 |
  168. | 33 | 1 | 0 | 0 | 0 | 0 | 1 |
  169. | 34 | 1 | 0 | 0 | 0 | 1 | 0 |
  170. | 35 | 1 | 0 | 0 | 0 | 1 | 1 |
  171. | 36 | 1 | 0 | 0 | 1 | 0 | 0 |
  172. | 37 | 1 | 0 | 0 | 1 | 0 | 1 |
  173. | 38 | 1 | 0 | 0 | 1 | 1 | 0 |
  174. | 39 | 1 | 0 | 0 | 1 | 1 | 1 |
  175. | 40 | 1 | 0 | 1 | 0 | 0 | 0 |
  176. | 41 | 1 | 0 | 1 | 0 | 0 | 1 |
  177. | 42 | 1 | 0 | 1 | 0 | 1 | 0 |
  178. | 43 | 1 | 0 | 1 | 0 | 1 | 1 |
  179. | 44 | 1 | 0 | 1 | 1 | 0 | 0 |
  180. | 45 | 1 | 0 | 1 | 1 | 0 | 1 |
  181. | 46 | 1 | 0 | 1 | 1 | 1 | 0 |
  182. | 47 | 1 | 0 | 1 | 1 | 1 | 1 |
  183. | 48 | 1 | 1 | 0 | 0 | 0 | 0 |
  184. | 49 | 1 | 1 | 0 | 0 | 0 | 1 |
  185. | 50 | 1 | 1 | 0 | 0 | 1 | 0 |
  186. | 51 | 1 | 1 | 0 | 0 | 1 | 1 |
  187. | 52 | 1 | 1 | 0 | 1 | 0 | 0 |
  188. | 53 | 1 | 1 | 0 | 1 | 0 | 1 |
  189. | 54 | 1 | 1 | 0 | 1 | 1 | 0 |
  190. | 55 | 1 | 1 | 0 | 1 | 1 | 1 |
  191. | 56 | 1 | 1 | 1 | 0 | 0 | 0 |
  192. | 57 | 1 | 1 | 1 | 0 | 0 | 1 |
  193. | 58 | 1 | 1 | 1 | 0 | 1 | 0 |
  194. | 59 | 1 | 1 | 1 | 0 | 1 | 1 |
  195. | 60 | 1 | 1 | 1 | 1 | 0 | 0 |
  196. | 61 | 1 | 1 | 1 | 1 | 0 | 1 |
  197. | 62 | 1 | 1 | 1 | 1 | 1 | 0 |
  198. | 63 | 1 | 1 | 1 | 1 | 1 | 1 |
  199. +----+---+---+---+---+---+---+
  200. */
  201. myNdbOperation->insertTuple();
  202. myNdbOperation->equal(COL_NAME[0], num);
  203. for(int col = 1; col < COL_LEN; col++)
  204. {
  205. myNdbOperation->setValue(COL_NAME[col], (num>>(COL_LEN-1-col))&1);
  206. }
  207. }
  208. int check = myTrans->execute(NdbTransaction::Commit);
  209. myTrans->close();
  210. if (check == -1)
  211. return NDBT_FAILED;
  212. else
  213. return NDBT_OK;
  214. }
  215. /*
  216. * a=AND, o=OR, A=NAND, O=NOR
  217. */
  218. char op_string[] = "aoAO";
  219. /*
  220. * the six columns' name of test table
  221. */
  222. char col_string[] = "ijklmn";
  223. const int op_len = strlen(op_string);
  224. const int col_len = strlen(col_string);
  225. /*
  226. * get a random op from "aoAO"
  227. */
  228. int get_rand_op_ch(char *ch)
  229. {
  230. static unsigned int num = 0;
  231. if(++num == 0)
  232. num = 1;
  233. srand(num*time(NULL));
  234. *ch = op_string[rand() % op_len];
  235. return 1;
  236. }
  237. /*
  238. * get a random order form of "ijklmn" trough exchanging letter
  239. */
  240. void change_col_order()
  241. {
  242. int pos1,pos2;
  243. char temp;
  244. for (int i = 0; i < 10; i++) //exchange for 10 times
  245. {
  246. srand(time(NULL)/(i+1));
  247. pos1 = rand() % col_len;
  248. srand((i+1)*time(NULL));
  249. pos2 = rand() % col_len;
  250. if (pos1 == pos2)
  251. continue;
  252. temp = col_string[pos1];
  253. col_string[pos1] = col_string[pos2];
  254. col_string[pos2] = temp;
  255. }
  256. }
  257. /*
  258. * get a random sub string of "ijklmn"
  259. */
  260. int get_rand_col_str(char *str)
  261. {
  262. int len;
  263. static unsigned int num = 0;
  264. if(++num == 0)
  265. num = 1;
  266. srand(num*time(NULL));
  267. len = rand() % col_len + 1;
  268. change_col_order();
  269. snprintf(str, len+1, "%s", col_string); //len+1, including '\0'
  270. return len;
  271. }
  272. /*
  273. * get a random string including operation and column
  274. * eg, Alnikx
  275. */
  276. int get_rand_op_str(char *str)
  277. {
  278. char temp[256];
  279. int len1, len2, len;
  280. len1 = get_rand_op_ch(temp);
  281. len2 = get_rand_col_str(temp+len1);
  282. len = len1 + len2;
  283. temp[len] = 'x';
  284. snprintf(str, len+1+1, "%s", temp); //len+1, including '\0'
  285. return len+1;
  286. }
  287. /*
  288. * replace a letter of source string with a new string
  289. * e.g., source string: 'Aijkx', replace i with new string 'olmx'
  290. * then source string is changed to 'Aolmxjkx'
  291. * source: its format should be produced from get_rand_op_str()
  292. * pos: range from 1 to strlen(source)-2
  293. */
  294. int replace_a_to_str(char *source, int pos, char *newstr)
  295. {
  296. char temp[MAX_STR_LEN];
  297. snprintf(temp, pos+1, "%s", source);
  298. snprintf(temp+pos, strlen(newstr)+1, "%s", newstr);
  299. snprintf(temp+pos+strlen(newstr), strlen(source)-pos, "%s", source+pos+1);
  300. snprintf(source, strlen(temp)+1, "%s", temp);
  301. return strlen(source);
  302. }
  303. /*
  304. * check whether the inputed char is an operation
  305. */
  306. bool check_op(char ch)
  307. {
  308. if( ch == 'a' || ch == 'A' || ch == 'o' || ch == 'O')
  309. return true;
  310. else
  311. return false;
  312. }
  313. /*
  314. * check whether the inputed char is end flag
  315. */
  316. bool check_end(char ch)
  317. {
  318. return (ch == 'x');
  319. }
  320. /*
  321. * check whether the inputed char is end flag
  322. */
  323. bool check_col(char ch)
  324. {
  325. if( ch == 'i' || ch == 'j' || ch == 'k'
  326. || ch == 'l' || ch == 'm' || ch == 'n' )
  327. return true;
  328. else
  329. return false;
  330. }
  331. /*
  332. * To ensure we can get a random string with RECURSIVE_LEVEL,
  333. * we need a position where can replace a letter with a new string.
  334. */
  335. int get_rand_replace_pos(char *str, int len)
  336. {
  337. int pos_op = 0;
  338. int pos_x = 0;
  339. int pos_col = 0;
  340. int span = 0;
  341. static int num = 0;
  342. char temp;
  343. for(int i = 0; i < len; i++)
  344. {
  345. temp = str[i];
  346. if(! check_end(temp))
  347. {
  348. if(check_op(temp))
  349. pos_op = i;
  350. }
  351. else
  352. {
  353. pos_x = i;
  354. break;
  355. }
  356. }
  357. if(++num == 0)
  358. num = 1;
  359. span = pos_x - pos_op - 1;
  360. if(span <= 1)
  361. {
  362. pos_col = pos_op + 1;
  363. }
  364. else
  365. {
  366. srand(num*time(NULL));
  367. pos_col = pos_op + rand() % span + 1;
  368. }
  369. return pos_col;
  370. }
  371. /*
  372. * Check whether the given random string is valid
  373. * and applicable for this test case
  374. */
  375. bool check_random_str(char *str)
  376. {
  377. char *p;
  378. int op_num = 0;
  379. int end_num = 0;
  380. for(p = str; *p; p++)
  381. {
  382. bool tmp1 = false, tmp2 = false;
  383. if(tmp1 = check_op(*p))
  384. op_num++;
  385. if(tmp2 = check_end(*p))
  386. end_num++;
  387. if(!(tmp1 || tmp2 || check_col(*p))) //there are illegal letters
  388. return false;
  389. }
  390. if(op_num != end_num) //begins are not equal to ends
  391. return false;
  392. return true;
  393. }
  394. /*
  395. * Get a random string with RECURSIVE_LEVEL
  396. */
  397. void get_rand_op_str_compound(char *str)
  398. {
  399. char small_str[256];
  400. int pos;
  401. int tmp;
  402. int level;
  403. static int num = 0;
  404. if(++num == 0)
  405. num = 1;
  406. srand(num*time(NULL));
  407. level = 1 + rand() % RECURSIVE_LEVEL;
  408. get_rand_op_str(str);
  409. for(int i = 0; i < level; i++)
  410. {
  411. get_rand_op_str(small_str);
  412. tmp = strlen(small_str);
  413. get_rand_op_str(small_str + tmp); //get two operations
  414. pos = get_rand_replace_pos(str, strlen(str));
  415. replace_a_to_str(str, pos, small_str);
  416. }
  417. //check the random string
  418. if(!check_random_str(str))
  419. {
  420. fprintf(stderr, "Error random string! \n");
  421. exit(-1);
  422. }
  423. }
  424. /*
  425. * get column id of i,j,k,l,m,n
  426. */
  427. int get_column_id(char ch)
  428. {
  429. return (ch - 'i' + 1); //from 1 to 6
  430. }
  431. /*
  432. * check whether column value of the NO. tuple is equal to 1
  433. * col_id: column id, range from 1 to 6
  434. * tuple_no: record NO., range from 0 to 63
  435. */
  436. bool check_col_equal_one(int tuple_no, int col_id)
  437. {
  438. int i = (int)pow((double)2, (double)(6 - col_id));
  439. int j = tuple_no / i;
  440. if(j % 2)
  441. return true;
  442. else
  443. return false;
  444. }
  445. /*
  446. * get a result after all elements in the array with AND
  447. * value: pointer to a bool array
  448. * len: length of the bool array
  449. */
  450. bool AND_op(bool *value, int len)
  451. {
  452. for(int i = 0; i < len; i++)
  453. {
  454. if(! value[i])
  455. return false;
  456. }
  457. return true;
  458. }
  459. /*
  460. * get a result after all elements in the array with OR
  461. * value: pointer to a bool array
  462. * len: length of the bool array
  463. */
  464. bool OR_op(bool *value, int len)
  465. {
  466. for(int i = 0; i < len; i++)
  467. {
  468. if(value[i])
  469. return true;
  470. }
  471. return false;
  472. }
  473. /*
  474. * get a result after all elements in the array with NAND
  475. * value: pointer to a bool array
  476. * len: length of the bool array
  477. */
  478. bool NAND_op(bool *value, int len)
  479. {
  480. return (! AND_op(value, len));
  481. }
  482. /*
  483. * get a result after all elements in the array with NOR
  484. * value: pointer to a bool array
  485. * len: length of the bool array
  486. */
  487. bool NOR_op(bool *value, int len)
  488. {
  489. return (! OR_op(value, len));
  490. }
  491. /*
  492. * AND/NAND/OR/NOR operation for a bool array
  493. */
  494. bool calculate_one_op(char op_type, bool *value, int len)
  495. {
  496. switch(op_type)
  497. {
  498. case 'a':
  499. return AND_op(value, len);
  500. break;
  501. case 'o':
  502. return OR_op(value, len);
  503. break;
  504. case 'A':
  505. return NAND_op(value, len);
  506. break;
  507. case 'O':
  508. return NOR_op(value, len);
  509. break;
  510. }
  511. return false; //make gcc happy
  512. }
  513. typedef struct _stack_element
  514. {
  515. char type;
  516. int num;
  517. }stack_element;
  518. /*
  519. * stack_op, store info for AND,OR,NAND,NOR
  520. * stack_col, store value of column(i,j,k,l,m,n) and temporary result for an operation
  521. */
  522. stack_element stack_op[RECURSIVE_LEVEL * COL_LEN];
  523. bool stack_col[RECURSIVE_LEVEL * COL_LEN * 2];
  524. /*
  525. * check whether the given tuple is chosen by judgement condition
  526. * tuple_no, the NO of tuple in TABLE_NAME, range from 0 to TUPLE_NUM
  527. * str: a random string of scan opearation and condition
  528. * len: length of str
  529. */
  530. bool check_one_tuple(int tuple_no, char *str, int len)
  531. {
  532. int pop_op = 0;
  533. int pop_col = 0;
  534. for(int i = 0; i < len; i++)
  535. {
  536. char letter = *(str + i);
  537. if(check_op(letter)) //push
  538. {
  539. stack_op[pop_op].type = letter;
  540. stack_op[pop_op].num = 0;
  541. pop_op++;
  542. }
  543. if(check_col(letter)) //push
  544. {
  545. stack_col[pop_col] = check_col_equal_one(tuple_no, get_column_id(letter));
  546. pop_col++;
  547. stack_op[pop_op-1].num += 1;
  548. }
  549. if(check_end(letter))
  550. {
  551. if(pop_op <= 1)
  552. {
  553. return calculate_one_op(stack_op[pop_op-1].type,
  554. stack_col,
  555. stack_op[pop_op-1].num);
  556. }
  557. else
  558. {
  559. bool tmp1 = calculate_one_op(stack_op[pop_op-1].type,
  560. stack_col + pop_col - stack_op[pop_op-1].num,
  561. stack_op[pop_op-1].num);
  562. pop_col -= stack_op[pop_op-1].num; //pop
  563. pop_op--;
  564. stack_col[pop_col] = tmp1; //push
  565. pop_col++;
  566. stack_op[pop_op-1].num += 1;
  567. }
  568. }
  569. }
  570. return false; //make gcc happy
  571. }
  572. /*
  573. * get lists of tuples which match the scan condiction through calculating
  574. * str: a random string of scan opearation and condition
  575. */
  576. void check_all_tuples(char *str, bool *res)
  577. {
  578. for (int i = 0; i < TUPLE_NUM; i++)
  579. {
  580. if(check_one_tuple(i, str, strlen(str)))
  581. res[i] = true;
  582. }
  583. }
  584. /*
  585. * convert a letter to group number what ndbapi need
  586. */
  587. NdbScanFilter::Group get_api_group(char op_name)
  588. {
  589. switch (op_name) {
  590. case 'a': return NdbScanFilter::AND;
  591. case 'o': return NdbScanFilter::OR;
  592. case 'A': return NdbScanFilter::NAND;
  593. case 'O': return NdbScanFilter::NOR;
  594. default:
  595. fprintf(stderr, "Invalid group name %c !\n", op_name);
  596. exit(3);
  597. }
  598. }
  599. /*
  600. * with ndbapi, call begin, eq/ne/lt/gt/le/ge..., end
  601. */
  602. NdbScanFilter * call_ndbapi(char *str, NdbTransaction *transaction,
  603. NdbScanOperation *scan, NdbDictionary::Column const *col[])
  604. {
  605. NdbScanFilter *scanfilter = new NdbScanFilter(scan);
  606. char *p;
  607. for (p = str; *p; p++)
  608. {
  609. if(check_op(*p))
  610. {
  611. if(scanfilter->begin(get_api_group(*p)))
  612. ERR_EXIT(transaction, "filter begin() failed");
  613. }
  614. if(check_col(*p))
  615. {
  616. if(scanfilter->eq(col[*p-'i'+1]->getColumnNo(), (Uint32)1))
  617. ERR_EXIT(transaction, "filter eq() failed");
  618. }
  619. if(check_end(*p))
  620. {
  621. if(scanfilter->end())
  622. ERR_EXIT(transaction, "filter end() failed");
  623. }
  624. }
  625. return scanfilter;
  626. }
  627. /*
  628. * get the tuples through ndbapi, and save the tuples NO.
  629. * str: a random string of scan opearation and condition
  630. */
  631. void ndbapi_tuples(Ndb *ndb, char *str, bool *res)
  632. {
  633. const NdbDictionary::Dictionary *dict = ndb->getDictionary();
  634. if (!dict)
  635. ERR_EXIT(ndb, "Can't get dict");
  636. const NdbDictionary::Table *table = dict->getTable(TABLE_NAME);
  637. if (!table)
  638. ERR_EXIT(dict, "Can't get table"TABLE_NAME);
  639. const NdbDictionary::Column *col[COL_LEN];
  640. for(int i = 0; i < COL_LEN; i++)
  641. {
  642. char tmp[128];
  643. col[i] = table->getColumn(COL_NAME[i]);
  644. if(!col[i])
  645. {
  646. snprintf(tmp, 128, "Can't get column %s", COL_NAME[i]);
  647. ERR_EXIT(dict, tmp);
  648. }
  649. }
  650. NdbTransaction *transaction;
  651. NdbScanOperation *scan;
  652. NdbScanFilter *filter;
  653. transaction = ndb->startTransaction();
  654. if (!transaction)
  655. ERR_EXIT(ndb, "Can't start transaction");
  656. scan = transaction->getNdbScanOperation(table);
  657. if (!scan)
  658. ERR_EXIT(transaction, "Can't get scan op");
  659. if (scan->readTuples(NdbOperation::LM_Exclusive))
  660. ERR_EXIT(scan, "Can't set up read");
  661. NdbRecAttr *rec[COL_LEN];
  662. for(int i = 0; i < COL_LEN; i++)
  663. {
  664. char tmp[128];
  665. rec[i] = scan->getValue(COL_NAME[i]);
  666. if(!rec[i])
  667. {
  668. snprintf(tmp, 128, "Can't get rec of %s", COL_NAME[i]);
  669. ERR_EXIT(scan, tmp);
  670. }
  671. }
  672. filter = call_ndbapi(str, transaction, scan, col);
  673. if (transaction->execute(NdbTransaction::NoCommit))
  674. ERR_EXIT(transaction, "Can't execute");
  675. int i,j,k,l,m,n;
  676. while (scan->nextResult(true) == 0)
  677. {
  678. do
  679. {
  680. i = rec[1]->u_32_value();
  681. j = rec[2]->u_32_value();
  682. k = rec[3]->u_32_value();
  683. l = rec[4]->u_32_value();
  684. m = rec[5]->u_32_value();
  685. n = rec[6]->u_32_value();
  686. res[32*i+16*j+8*k+4*l+2*m+n] = true;
  687. } while (scan->nextResult(false) == 0);
  688. }
  689. delete filter;
  690. transaction->close();
  691. }
  692. /*
  693. * compare the result between calculation and NDBAPI
  694. * str: a random string of scan opearation and condition
  695. * return: true stands for ndbapi ok, false stands for ndbapi failed
  696. */
  697. template class Vector<bool>;
  698. bool compare_cal_ndb(char *str, Ndb *ndb)
  699. {
  700. Vector<bool> res_cal;
  701. Vector<bool> res_ndb;
  702. for(int i = 0; i < TUPLE_NUM; i++)
  703. {
  704. res_cal.push_back(false);
  705. res_ndb.push_back(false);
  706. }
  707. check_all_tuples(str, res_cal.getBase());
  708. ndbapi_tuples(ndb, str, res_ndb.getBase());
  709. for(int i = 0; i < TUPLE_NUM; i++)
  710. {
  711. if(res_cal[i] != res_ndb[i])
  712. return false;
  713. }
  714. return true;
  715. }
  716. int runCreateTables(NDBT_Context* ctx, NDBT_Step* step)
  717. {
  718. Ndb *pNdb = GETNDB(step);
  719. pNdb->getDictionary()->dropTable(MYTAB1.getName());
  720. int ret = createTable(pNdb, &MYTAB1, false, true, 0);
  721. if(ret)
  722. return ret;
  723. return NDBT_OK;
  724. }
  725. int runDropTables(NDBT_Context* ctx, NDBT_Step* step)
  726. {
  727. int ret = GETNDB(step)->getDictionary()->dropTable(MYTAB1.getName());
  728. if(ret == -1)
  729. return NDBT_FAILED;
  730. return NDBT_OK;
  731. }
  732. int runScanRandomFilterTest(NDBT_Context* ctx, NDBT_Step* step)
  733. {
  734. char random_str[MAX_STR_LEN];
  735. Ndb *myNdb = GETNDB(step);
  736. bool res = true;
  737. for(int i = 0; i < TEST_NUM; i++)
  738. {
  739. get_rand_op_str_compound(random_str);
  740. if( !compare_cal_ndb(random_str, myNdb))
  741. return NDBT_FAILED;
  742. }
  743. return NDBT_OK;
  744. }
  745. NDBT_TESTSUITE(testScanFilter);
  746. TESTCASE(TEST_NAME,
  747. "Scan table TABLE_NAME for the records which accord with \
  748. conditions of logical scan operations: AND/OR/NAND/NOR")
  749. {
  750. INITIALIZER(runCreateTables);
  751. INITIALIZER(runPopulate);
  752. INITIALIZER(runScanRandomFilterTest);
  753. FINALIZER(runDropTables);
  754. }
  755. NDBT_TESTSUITE_END(testScanFilter);
  756. int main(int argc, const char** argv)
  757. {
  758. ndb_init();
  759. Ndb_cluster_connection con;
  760. if(con.connect(12, 5, 1))
  761. {
  762. return NDBT_ProgramExit(NDBT_FAILED);
  763. }
  764. return testScanFilter.executeOneCtx(con, &MYTAB1, TEST_NAME);
  765. }