MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
main.cpp
1 /*
2  Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 /*
19  * ndbapi_recattr_vs_record.cpp: Kitchen-sink example showing usage of
20  * NdbRecAttr based and NdbRecord interfaces to NDBAPI.
21  *
22  * A number of different aspects of the two APIs are exercised, with
23  * parallel implementations to show how the same tasks are accomplished
24  * in each. Some tasks cannot be accomplished via both APIs and so are
25  * missing from one or another.
26  *
27  * A simple schema is used, but the mechanisms generally extend to use
28  * with different types.
29  *
30  */
31 
32 #include <mysql.h>
33 #include <NdbApi.hpp>
34 // Used for cout
35 #include <stdio.h>
36 #include <iostream>
37 
38 // Do we use old-style (NdbRecAttr?) or new style (NdbRecord?)
39 enum ApiType {api_attr, api_record};
40 
41 static void run_application(MYSQL &, Ndb_cluster_connection &, ApiType);
42 
43 #define PRINT_ERROR(code,msg) \
44  std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
45  << ", code: " << code \
46  << ", msg: " << msg << "." << std::endl
47 #define MYSQLERROR(mysql) { \
48  PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
49  exit(-1); }
50 #define APIERROR(error) { \
51  PRINT_ERROR(error.code,error.message); \
52  exit(-1); }
53 
54 int main(int argc, char** argv)
55 {
56  if (argc != 4)
57  {
58  std::cout << "Arguments are <socket mysqld> <connect_string cluster> <attr|record>.\n";
59  exit(-1);
60  }
61  // ndb_init must be called first
62  ndb_init();
63 
64  // connect to mysql server and cluster and run application
65  {
66  char * mysqld_sock = argv[1];
67  const char *connectstring = argv[2];
68  ApiType accessType=api_attr;
69 
70  // Object representing the cluster
71  Ndb_cluster_connection cluster_connection(connectstring);
72 
73  // Connect to cluster management server (ndb_mgmd)
74  if (cluster_connection.connect(4 /* retries */,
75  5 /* delay between retries */,
76  1 /* verbose */))
77  {
78  std::cout << "Cluster management server was not ready within 30 secs.\n";
79  exit(-1);
80  }
81 
82  // Optionally connect and wait for the storage nodes (ndbd's)
83  if (cluster_connection.wait_until_ready(30,0) < 0)
84  {
85  std::cout << "Cluster was not ready within 30 secs.\n";
86  exit(-1);
87  }
88 
89  // connect to mysql server
90  MYSQL mysql;
91  if ( !mysql_init(&mysql) ) {
92  std::cout << "mysql_init failed\n";
93  exit(-1);
94  }
95  if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
96  0, mysqld_sock, 0) )
97  MYSQLERROR(mysql);
98 
99  if (0==strncmp("attr", argv[3], 4))
100  {
101  accessType=api_attr;
102  }
103  else if (0==strncmp("record", argv[3], 6))
104  {
105  accessType=api_record;
106  }
107  else
108  {
109  std::cout << "Bad access type argument : "<< argv[3] << "\n";
110  exit(-1);
111  }
112 
113  // run the application code
114  run_application(mysql, cluster_connection, accessType);
115  }
116 
117  ndb_end(0);
118 
119  return 0;
120 }
121 
122 static void init_ndbrecord_info(Ndb &);
123 static void create_table(MYSQL &);
124 static void do_insert(Ndb &, ApiType);
125 static void do_update(Ndb &, ApiType);
126 static void do_delete(Ndb &, ApiType);
127 static void do_read(Ndb &, ApiType);
128 static void do_mixed_read(Ndb &);
129 static void do_mixed_update(Ndb &);
130 static void do_scan(Ndb &, ApiType);
131 static void do_mixed_scan(Ndb &);
132 static void do_indexScan(Ndb &, ApiType);
133 static void do_mixed_indexScan(Ndb&);
134 static void do_read_and_delete(Ndb &);
135 static void do_scan_update(Ndb&, ApiType);
136 static void do_scan_delete(Ndb&, ApiType);
137 static void do_scan_lock_reread(Ndb&, ApiType);
138 static void do_all_extras_read(Ndb &myNdb);
139 static void do_secondary_indexScan(Ndb &myNdb, ApiType accessType);
140 static void do_secondary_indexScanEqual(Ndb &myNdb, ApiType accessType);
141 static void do_interpreted_update(Ndb &myNdb, ApiType accessType);
142 static void do_interpreted_scan(Ndb &myNdb, ApiType accessType);
143 static void do_read_using_default(Ndb &myNdb);
144 
145 /* This structure is used describe how we want data read using
146  * NDBRecord to be placed into memory. This can make it easier
147  * to work with data, but is not essential.
148  */
149 struct RowData
150 {
151  int attr1;
152  int attr2;
153  int attr3;
154 };
155 
156 
157 /* Handy struct for representing the data in the
158  * secondary index
159  */
160 struct IndexRow
161 {
162  unsigned int attr3;
163  unsigned int attr2;
164 };
165 
166 static void run_application(MYSQL &mysql,
167  Ndb_cluster_connection &cluster_connection,
168  ApiType accessType)
169 {
170  /********************************************
171  * Connect to database via mysql-c *
172  ********************************************/
173  mysql_query(&mysql, "CREATE DATABASE ndb_examples");
174  if (mysql_query(&mysql, "USE ndb_examples") != 0) MYSQLERROR(mysql);
175  create_table(mysql);
176 
177  /********************************************
178  * Connect to database via NdbApi *
179  ********************************************/
180  // Object representing the database
181  Ndb myNdb( &cluster_connection, "ndb_examples" );
182  if (myNdb.init()) APIERROR(myNdb.getNdbError());
183 
184  init_ndbrecord_info(myNdb);
185  /*
186  * Do different operations on database
187  */
188  do_insert(myNdb, accessType);
189  do_update(myNdb, accessType);
190  do_delete(myNdb, accessType);
191  do_read(myNdb, accessType);
192  do_mixed_read(myNdb);
193  do_mixed_update(myNdb);
194  do_read(myNdb, accessType);
195  do_scan(myNdb, accessType);
196  do_mixed_scan(myNdb);
197  do_indexScan(myNdb, accessType);
198  do_mixed_indexScan(myNdb);
199  do_read_and_delete(myNdb);
200  do_scan_update(myNdb, accessType);
201  do_scan_delete(myNdb, accessType);
202  do_scan_lock_reread(myNdb, accessType);
203  do_all_extras_read(myNdb);
204  do_secondary_indexScan(myNdb, accessType);
205  do_secondary_indexScanEqual(myNdb, accessType);
206  do_scan(myNdb, accessType);
207  do_interpreted_update(myNdb, accessType);
208  do_interpreted_scan(myNdb, accessType);
209  do_read_using_default(myNdb);
210  do_scan(myNdb, accessType);
211 }
212 
213 /*********************************************************
214  * Create a table named api_recattr_vs_record if it does not exist *
215  *********************************************************/
216 static void create_table(MYSQL &mysql)
217 {
218  if (mysql_query(&mysql,
219  "DROP TABLE IF EXISTS"
220  " api_recattr_vs_record"))
221  MYSQLERROR(mysql);
222 
223  if (mysql_query(&mysql,
224  "CREATE TABLE"
225  " api_recattr_vs_record"
226  " (ATTR1 INT UNSIGNED NOT NULL PRIMARY KEY,"
227  " ATTR2 INT UNSIGNED NOT NULL,"
228  " ATTR3 INT UNSIGNED NOT NULL)"
229  " ENGINE=NDB"))
230  MYSQLERROR(mysql);
231 
232  /* Add ordered secondary index on 2 attributes, in reverse order */
233  if (mysql_query(&mysql,
234  "CREATE INDEX"
235  " MYINDEXNAME"
236  " ON api_recattr_vs_record"
237  " (ATTR3, ATTR2)"))
238  MYSQLERROR(mysql);
239 }
240 
241 
242 /* Clunky statics for shared NdbRecord stuff */
243 static const NdbDictionary::Column *pattr1Col;
244 static const NdbDictionary::Column *pattr2Col;
245 static const NdbDictionary::Column *pattr3Col;
246 
247 static const NdbRecord *pkeyColumnRecord;
248 static const NdbRecord *pallColsRecord;
249 static const NdbRecord *pkeyIndexRecord;
250 static const NdbRecord *psecondaryIndexRecord;
251 
252 static int attr1ColNum;
253 static int attr2ColNum;
254 static int attr3ColNum;
255 
256 /**************************************************************
257  * Initialise NdbRecord structures for table and index access *
258  **************************************************************/
259 static void init_ndbrecord_info(Ndb &myNdb)
260 {
261  /* Here we create various NdbRecord structures for accessing
262  * data using the tables and indexes on api_recattr_vs_record
263  * We could use the default NdbRecord structures, but then
264  * we wouldn't have the nice ability to read and write rows
265  * to and from the RowData and IndexRow structs
266  */
267  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
268  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
269 
271 
272  if (myTable == NULL)
273  APIERROR(myDict->getNdbError());
274 
275  pattr1Col = myTable->getColumn("ATTR1");
276  if (pattr1Col == NULL) APIERROR(myDict->getNdbError());
277  pattr2Col = myTable->getColumn("ATTR2");
278  if (pattr2Col == NULL) APIERROR(myDict->getNdbError());
279  pattr3Col = myTable->getColumn("ATTR3");
280  if (pattr3Col == NULL) APIERROR(myDict->getNdbError());
281 
282  attr1ColNum = pattr1Col->getColumnNo();
283  attr2ColNum = pattr2Col->getColumnNo();
284  attr3ColNum = pattr3Col->getColumnNo();
285 
286  // ATTR 1
287  recordSpec[0].column = pattr1Col;
288  recordSpec[0].offset = offsetof(RowData, attr1);
289  recordSpec[0].nullbit_byte_offset = 0; // Not nullable
290  recordSpec[0].nullbit_bit_in_byte = 0;
291 
292  // ATTR 2
293  recordSpec[1].column = pattr2Col;
294  recordSpec[1].offset = offsetof(RowData, attr2);
295  recordSpec[1].nullbit_byte_offset = 0; // Not nullable
296  recordSpec[1].nullbit_bit_in_byte = 0;
297 
298  // ATTR 3
299  recordSpec[2].column = pattr3Col;
300  recordSpec[2].offset = offsetof(RowData, attr3);
301  recordSpec[2].nullbit_byte_offset = 0; // Not nullable
302  recordSpec[2].nullbit_bit_in_byte = 0;
303 
304  /* Create table record with just the primary key column */
305  pkeyColumnRecord =
306  myDict->createRecord(myTable, recordSpec, 1, sizeof(recordSpec[0]));
307 
308  if (pkeyColumnRecord == NULL) APIERROR(myDict->getNdbError());
309 
310  /* Create table record with all the columns */
311  pallColsRecord =
312  myDict->createRecord(myTable, recordSpec, 3, sizeof(recordSpec[0]));
313 
314  if (pallColsRecord == NULL) APIERROR(myDict->getNdbError());
315 
316  /* Create NdbRecord for primary index access */
317  const NdbDictionary::Index *myPIndex= myDict->getIndex("PRIMARY", "api_recattr_vs_record");
318 
319  if (myPIndex == NULL)
320  APIERROR(myDict->getNdbError());
321 
322  pkeyIndexRecord =
323  myDict->createRecord(myPIndex, recordSpec, 1, sizeof(recordSpec[0]));
324 
325  if (pkeyIndexRecord == NULL) APIERROR(myDict->getNdbError());
326 
327  /* Create Index NdbRecord for secondary index access
328  * Note that we use the columns from the table to define the index
329  * access record
330  */
331  const NdbDictionary::Index *mySIndex= myDict->getIndex("MYINDEXNAME", "api_recattr_vs_record");
332 
333  recordSpec[0].column= pattr3Col;
334  recordSpec[0].offset= offsetof(IndexRow, attr3);
335  recordSpec[0].nullbit_byte_offset=0;
336  recordSpec[0].nullbit_bit_in_byte=0;
337 
338  recordSpec[1].column= pattr2Col;
339  recordSpec[1].offset= offsetof(IndexRow, attr2);
340  recordSpec[1].nullbit_byte_offset=0;
341  recordSpec[1].nullbit_bit_in_byte=1;
342 
343  /* Create NdbRecord for accessing via secondary index */
344  psecondaryIndexRecord =
345  myDict->createRecord(mySIndex,
346  recordSpec,
347  2,
348  sizeof(recordSpec[0]));
349 
350 
351  if (psecondaryIndexRecord == NULL)
352  APIERROR(myDict->getNdbError());
353 
354 }
355 
356 
357 /**************************************************************************
358  * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
359  **************************************************************************/
360 static void do_insert(Ndb &myNdb, ApiType accessType)
361 {
362  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
363  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
364 
365  std::cout << "Running do_insert\n";
366 
367  if (myTable == NULL)
368  APIERROR(myDict->getNdbError());
369 
370  for (int i = 0; i < 5; i++) {
371  NdbTransaction *myTransaction= myNdb.startTransaction();
372  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
373 
374  switch (accessType)
375  {
376  case api_attr :
377  {
378  NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
379  if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
380 
381  myOperation->insertTuple();
382  myOperation->equal("ATTR1", i);
383  myOperation->setValue("ATTR2", i);
384  myOperation->setValue("ATTR3", i);
385 
386  myOperation= myTransaction->getNdbOperation(myTable);
387 
388  if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
389  myOperation->insertTuple();
390  myOperation->equal("ATTR1", i+5);
391  myOperation->setValue("ATTR2", i+5);
392  myOperation->setValue("ATTR3", i+5);
393  break;
394  }
395  case api_record :
396  {
397  RowData row;
398 
399  row.attr1= row.attr2= row.attr3= i;
400 
401  const NdbOperation *pop1=
402  myTransaction->insertTuple(pallColsRecord, (char *) &row);
403  if (pop1 == NULL) APIERROR(myTransaction->getNdbError());
404 
405  row.attr1= row.attr2= row.attr3= i+5;
406 
407  const NdbOperation *pop2=
408  myTransaction->insertTuple(pallColsRecord, (char *) &row);
409  if (pop2 == NULL) APIERROR(myTransaction->getNdbError());
410 
411  break;
412  }
413  default :
414  {
415  std::cout << "Bad branch : " << accessType << "\n";
416  exit(-1);
417  }
418  }
419 
420  if (myTransaction->execute( NdbTransaction::Commit ) == -1)
421  APIERROR(myTransaction->getNdbError());
422 
423  myNdb.closeTransaction(myTransaction);
424  }
425 
426  std::cout << "-------\n";
427 }
428 
429 /*****************************************************************
430  * Update the second attribute in half of the tuples (adding 10) *
431  *****************************************************************/
432 static void do_update(Ndb &myNdb, ApiType accessType)
433 {
434  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
435  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
436 
437  std::cout << "Running do_update\n";
438 
439  for (int i = 0; i < 10; i+=2) {
440  NdbTransaction *myTransaction= myNdb.startTransaction();
441  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
442 
443  switch (accessType)
444  {
445  case api_attr :
446  {
447  NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
448  if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
449 
450  myOperation->updateTuple();
451  myOperation->equal( "ATTR1", i );
452  myOperation->setValue( "ATTR2", i+10);
453  myOperation->setValue( "ATTR3", i+20);
454  break;
455  }
456  case api_record :
457  {
458  RowData row;
459  row.attr1=i;
460  row.attr2=i+10;
461  row.attr3=i+20;
462 
463  /* Since we're using an NdbRecord with all columns in it to
464  * specify the updated columns, we need to create a mask to
465  * indicate that we are only updating attr2 and attr3.
466  */
467  unsigned char attrMask=(1<<attr2ColNum) | (1<<attr3ColNum);
468 
469  const NdbOperation *pop =
470  myTransaction->updateTuple(pkeyColumnRecord, (char*) &row,
471  pallColsRecord, (char*) &row,
472  &attrMask);
473 
474  if (pop==NULL) APIERROR(myTransaction->getNdbError());
475  break;
476  }
477  default :
478  {
479  std::cout << "Bad branch : " << accessType << "\n";
480  exit(-1);
481  }
482  }
483 
484  if( myTransaction->execute( NdbTransaction::Commit ) == -1 )
485  APIERROR(myTransaction->getNdbError());
486 
487  myNdb.closeTransaction(myTransaction);
488  }
489 
490  std::cout << "-------\n";
491 };
492 
493 /*************************************************
494  * Delete one tuple (the one with primary key 3) *
495  *************************************************/
496 static void do_delete(Ndb &myNdb, ApiType accessType)
497 {
498  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
499  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
500 
501  std::cout << "Running do_delete\n";
502 
503  if (myTable == NULL)
504  APIERROR(myDict->getNdbError());
505 
506  NdbTransaction *myTransaction= myNdb.startTransaction();
507  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
508 
509  switch (accessType)
510  {
511  case api_attr :
512  {
513  NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
514  if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
515 
516  myOperation->deleteTuple();
517  myOperation->equal( "ATTR1", 3 );
518  break;
519  }
520  case api_record :
521  {
522  RowData keyInfo;
523  keyInfo.attr1=3;
524 
525  const NdbOperation *pop=
526  myTransaction->deleteTuple(pkeyColumnRecord,
527  (char*) &keyInfo,
528  pallColsRecord);
529 
530  if (pop==NULL) APIERROR(myTransaction->getNdbError());
531  break;
532  }
533  default :
534  {
535  std::cout << "Bad branch : " << accessType << "\n";
536  exit(-1);
537  }
538  }
539 
540 
541  if (myTransaction->execute(NdbTransaction::Commit) == -1)
542  APIERROR(myTransaction->getNdbError());
543 
544  myNdb.closeTransaction(myTransaction);
545 
546  std::cout << "-------\n";
547 }
548 
549 
550 /*****************************************************************
551  * Update the second attribute in half of the tuples (adding 10) *
552  *****************************************************************/
553 static void do_mixed_update(Ndb &myNdb)
554 {
555  /* This method performs an update using a mix of NdbRecord
556  * supplied attributes, and extra setvalues provided by
557  * the OperationOptions structure.
558  */
559  std::cout << "Running do_mixed_update (NdbRecord only)\n";
560 
561  for (int i = 0; i < 10; i+=2) {
562  NdbTransaction *myTransaction= myNdb.startTransaction();
563  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
564 
565  RowData row;
566  row.attr1=i;
567  row.attr2=i+30;
568 
569  /* Only attr2 is updated via NdbRecord */
570  unsigned char attrMask= (1<<attr2ColNum);
571 
572  NdbOperation::SetValueSpec setvalspecs[1];
573 
574  /* Value to set attr3 to */
575  Uint32 dataSource= i + 40;
576 
577  setvalspecs[0].column = pattr3Col;
578  setvalspecs[0].value = &dataSource;
579 
581  opts.optionsPresent= NdbOperation::OperationOptions::OO_SETVALUE;
582  opts.extraSetValues= &setvalspecs[0];
583  opts.numExtraSetValues= 1;
584 
585 
586  // Define mixed operation in one call to NDBAPI
587  const NdbOperation *pop =
588  myTransaction->updateTuple(pkeyColumnRecord, (char*) &row,
589  pallColsRecord, (char*) &row,
590  &attrMask,
591  &opts);
592 
593  if (pop==NULL) APIERROR(myTransaction->getNdbError());
594 
595  if( myTransaction->execute( NdbTransaction::Commit ) == -1 )
596  APIERROR(myTransaction->getNdbError());
597 
598  myNdb.closeTransaction(myTransaction);
599  }
600 
601  std::cout << "-------\n";
602 }
603 
604 
605 /*********************************************
606  * Read and print all tuples using PK access *
607  *********************************************/
608 static void do_read(Ndb &myNdb, ApiType accessType)
609 {
610  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
611  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
612 
613  std::cout << "Running do_read\n";
614 
615  if (myTable == NULL)
616  APIERROR(myDict->getNdbError());
617 
618  std::cout << "ATTR1 ATTR2 ATTR3" << std::endl;
619 
620  for (int i = 0; i < 10; i++) {
621  NdbTransaction *myTransaction= myNdb.startTransaction();
622  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
623 
624  RowData rowData;
625  NdbRecAttr *myRecAttr;
626  NdbRecAttr *myRecAttr2;
627 
628  switch (accessType)
629  {
630  case api_attr :
631  {
632  NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
633  if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
634 
635  myOperation->readTuple(NdbOperation::LM_Read);
636  myOperation->equal("ATTR1", i);
637 
638  myRecAttr= myOperation->getValue("ATTR2", NULL);
639  if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
640 
641  myRecAttr2=myOperation->getValue("ATTR3", NULL);
642  if (myRecAttr2 == NULL) APIERROR(myTransaction->getNdbError());
643 
644  break;
645  }
646  case api_record :
647  {
648  rowData.attr1=i;
649  const NdbOperation *pop=
650  myTransaction->readTuple(pkeyColumnRecord,
651  (char*) &rowData,
652  pallColsRecord, // Read PK+ATTR2+ATTR3
653  (char*) &rowData);
654  if (pop==NULL) APIERROR(myTransaction->getNdbError());
655 
656  break;
657  }
658  default :
659  {
660  std::cout << "Bad branch : " << accessType << "\n";
661  exit(-1);
662  }
663  }
664 
665  if(myTransaction->execute( NdbTransaction::Commit ) == -1)
666  APIERROR(myTransaction->getNdbError());
667 
668  if (myTransaction->getNdbError().classification == NdbError::NoDataFound)
669  if (i == 3)
670  std::cout << "Detected that deleted tuple doesn't exist!" << std::endl;
671  else
672  APIERROR(myTransaction->getNdbError());
673 
674  switch (accessType)
675  {
676  case api_attr :
677  {
678  if (i != 3) {
679  printf(" %2d %2d %2d\n",
680  i,
681  myRecAttr->u_32_value(),
682  myRecAttr2->u_32_value());
683  }
684  break;
685  }
686  case api_record :
687  {
688  if (i !=3) {
689  printf(" %2d %2d %2d\n",
690  i,
691  rowData.attr2,
692  rowData.attr3);
693  }
694  break;
695  }
696  default :
697  {
698  std::cout << "Bad branch : " << accessType << "\n";
699  exit(-1);
700  }
701  }
702 
703  myNdb.closeTransaction(myTransaction);
704  }
705 
706  std::cout << "-------\n";
707 }
708 
709 /*****************************
710  * Read and print all tuples *
711  *****************************/
712 static void do_mixed_read(Ndb &myNdb)
713 {
714  std::cout << "Running do_mixed_read (NdbRecord only)\n";
715 
716  std::cout << "ATTR1 ATTR2 ATTR3 COMMIT_COUNT" << std::endl;
717 
718  for (int i = 0; i < 10; i++) {
719  NdbTransaction *myTransaction= myNdb.startTransaction();
720  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
721 
722  RowData rowData;
723  NdbRecAttr *myRecAttr3, *myRecAttrCC;
724 
725  /* Start with NdbRecord read of ATTR2, and then add
726  * getValue NdbRecAttr read of ATTR3 and Commit count
727  */
728  NdbOperation::GetValueSpec extraCols[2];
729 
730  extraCols[0].column=pattr3Col;
731  extraCols[0].appStorage=NULL;
732  extraCols[0].recAttr=NULL;
733 
734  extraCols[1].column=NdbDictionary::Column::COMMIT_COUNT;
735  extraCols[1].appStorage=NULL;
736  extraCols[1].recAttr=NULL;
737 
739  opts.optionsPresent = NdbOperation::OperationOptions::OO_GETVALUE;
740 
741  opts.extraGetValues= &extraCols[0];
742  opts.numExtraGetValues= 2;
743 
744  /* We only read attr2 using the normal NdbRecord access */
745  unsigned char attrMask= (1<<attr2ColNum);
746 
747  // Set PK search criteria
748  rowData.attr1= i;
749 
750  const NdbOperation *pop=
751  myTransaction->readTuple(pkeyColumnRecord,
752  (char*) &rowData,
753  pallColsRecord, // Read all with mask
754  (char*) &rowData,
756  &attrMask, // result_mask
757  &opts);
758  if (pop==NULL) APIERROR(myTransaction->getNdbError());
759 
760  myRecAttr3= extraCols[0].recAttr;
761  myRecAttrCC= extraCols[1].recAttr;
762 
763  if (myRecAttr3 == NULL) APIERROR(myTransaction->getNdbError());
764  if (myRecAttrCC == NULL) APIERROR(myTransaction->getNdbError());
765 
766 
767  if(myTransaction->execute( NdbTransaction::Commit ) == -1)
768  APIERROR(myTransaction->getNdbError());
769 
770  if (myTransaction->getNdbError().classification == NdbError::NoDataFound)
771  if (i == 3)
772  std::cout << "Detected that deleted tuple doesn't exist!" << std::endl;
773  else
774  APIERROR(myTransaction->getNdbError());
775 
776 
777  if (i !=3) {
778  printf(" %2d %2d %2d %d\n",
779  rowData.attr1,
780  rowData.attr2,
781  myRecAttr3->u_32_value(),
782  myRecAttrCC->u_32_value()
783  );
784  }
785 
786  myNdb.closeTransaction(myTransaction);
787  }
788 
789  std::cout << "-------\n";
790 }
791 
792 /********************************************
793  * Read and print all tuples via table scan *
794  ********************************************/
795 static void do_scan(Ndb &myNdb, ApiType accessType)
796 {
797  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
798  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
799 
800  std::cout << "Running do_scan\n";
801 
802  if (myTable == NULL)
803  APIERROR(myDict->getNdbError());
804 
805  std::cout << "ATTR1 ATTR2 ATTR3" << std::endl;
806 
807  NdbTransaction *myTransaction=myNdb.startTransaction();
808  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
809 
810  NdbScanOperation *psop;
811  NdbRecAttr *recAttrAttr1;
812  NdbRecAttr *recAttrAttr2;
813  NdbRecAttr *recAttrAttr3;
814 
815  switch (accessType)
816  {
817  case api_attr :
818  {
819  psop=myTransaction->getNdbScanOperation(myTable);
820 
821  if (psop == NULL) APIERROR(myTransaction->getNdbError());
822 
823  if (psop->readTuples(NdbOperation::LM_Read) != 0) APIERROR (myTransaction->getNdbError());
824 
825  recAttrAttr1=psop->getValue("ATTR1");
826  recAttrAttr2=psop->getValue("ATTR2");
827  recAttrAttr3=psop->getValue("ATTR3");
828 
829  break;
830  }
831  case api_record :
832  {
833  /* Note that no row ptr is passed to the NdbRecord scan operation
834  * The scan will fetch a batch and give the user a series of pointers
835  * to rows in the batch in nextResult() below
836  */
837  psop=myTransaction->scanTable(pallColsRecord,
839 
840  if (psop == NULL) APIERROR(myTransaction->getNdbError());
841 
842  break;
843  }
844  default :
845  {
846  std::cout << "Bad branch : " << accessType << "\n";
847  exit(-1);
848  }
849  }
850 
851  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
852  APIERROR(myTransaction->getNdbError());
853 
854  switch (accessType)
855  {
856  case api_attr :
857  {
858  while (psop->nextResult(true) == 0)
859  {
860  printf(" %2d %2d %2d\n",
861  recAttrAttr1->u_32_value(),
862  recAttrAttr2->u_32_value(),
863  recAttrAttr3->u_32_value());
864  }
865 
866  psop->close();
867 
868  break;
869  }
870  case api_record :
871  {
872  RowData *prowData; // Ptr to point to our data
873 
874  int rc=0;
875 
876  /* Ask nextResult to update out ptr to point to the next
877  * row from the scan
878  */
879  while ((rc = psop->nextResult((const char**) &prowData,
880  true,
881  false)) == 0)
882  {
883  printf(" %2d %2d %2d\n",
884  prowData->attr1,
885  prowData->attr2,
886  prowData->attr3);
887  }
888 
889  if (rc != 1) APIERROR(myTransaction->getNdbError());
890 
891  psop->close(true);
892 
893  break;
894  }
895  default :
896  {
897  std::cout << "Bad branch : " << accessType << "\n";
898  exit(-1);
899  }
900  }
901 
902  if(myTransaction->execute( NdbTransaction::Commit ) !=0)
903  APIERROR(myTransaction->getNdbError());
904 
905  myNdb.closeTransaction(myTransaction);
906 
907  std::cout << "-------\n";
908 }
909 
910 /***********************************************************
911  * Read and print all tuples via table scan and mixed read *
912  ***********************************************************/
913 static void do_mixed_scan(Ndb &myNdb)
914 {
915  std::cout << "Running do_mixed_scan(NdbRecord only)\n";
916 
917  std::cout << "ATTR1 ATTR2 ATTR3" << std::endl;
918 
919  NdbTransaction *myTransaction=myNdb.startTransaction();
920  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
921 
922  NdbScanOperation *psop;
923  NdbRecAttr *recAttrAttr3;
924 
925  /* Set mask so that NdbRecord scan reads attr1 and attr2 only */
926  unsigned char attrMask=((1<<attr1ColNum) | (1<<attr2ColNum));
927 
928  /* Define extra get value to get attr3 */
929  NdbOperation::GetValueSpec extraGets[1];
930  extraGets[0].column = pattr3Col;
931  extraGets[0].appStorage= 0;
932  extraGets[0].recAttr= 0;
933 
935  options.optionsPresent= NdbScanOperation::ScanOptions::SO_GETVALUE;
936  options.extraGetValues= &extraGets[0];
937  options.numExtraGetValues= 1;
938 
939  psop=myTransaction->scanTable(pallColsRecord,
941  &attrMask,
942  &options,
944  if (psop == NULL) APIERROR(myTransaction->getNdbError());
945 
946  /* RecAttr for the extra get has been set by the operation definition */
947  recAttrAttr3 = extraGets[0].recAttr;
948 
949  if (recAttrAttr3 == NULL) APIERROR(myTransaction->getNdbError());
950 
951  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
952  APIERROR(myTransaction->getNdbError());
953 
954  RowData *prowData; // Ptr to point to our data
955 
956  int rc=0;
957 
958  while ((rc = psop->nextResult((const char**) &prowData,
959  true,
960  false)) == 0)
961  {
962  printf(" %2d %2d %2d\n",
963  prowData->attr1,
964  prowData->attr2,
965  recAttrAttr3->u_32_value());
966  }
967 
968  if (rc != 1) APIERROR(myTransaction->getNdbError());
969 
970  psop->close(true);
971 
972  if(myTransaction->execute( NdbTransaction::Commit ) !=0)
973  APIERROR(myTransaction->getNdbError());
974 
975  myNdb.closeTransaction(myTransaction);
976 
977  std::cout << "-------\n";
978 }
979 
980 
981 
982 /************************************************************
983  * Read and print all tuples via primary ordered index scan *
984  ************************************************************/
985 static void do_indexScan(Ndb &myNdb, ApiType accessType)
986 {
987  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
988  const NdbDictionary::Index *myPIndex= myDict->getIndex("PRIMARY", "api_recattr_vs_record");
989 
990  std::cout << "Running do_indexScan\n";
991 
992  if (myPIndex == NULL)
993  APIERROR(myDict->getNdbError());
994 
995  std::cout << "ATTR1 ATTR2 ATTR3" << std::endl;
996 
997  NdbTransaction *myTransaction=myNdb.startTransaction();
998  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
999 
1000  NdbIndexScanOperation *psop;
1001 
1002  /* RecAttrs for NdbRecAttr Api */
1003  NdbRecAttr *recAttrAttr1;
1004  NdbRecAttr *recAttrAttr2;
1005  NdbRecAttr *recAttrAttr3;
1006 
1007  switch (accessType)
1008  {
1009  case api_attr :
1010  {
1011  psop=myTransaction->getNdbIndexScanOperation(myPIndex);
1012 
1013  if (psop == NULL) APIERROR(myTransaction->getNdbError());
1014 
1015  /* Multi read range is not supported for the NdbRecAttr scan
1016  * API, so we just read one range.
1017  */
1018  Uint32 scanFlags=
1019  NdbScanOperation::SF_OrderBy |
1020  NdbScanOperation::SF_MultiRange |
1021  NdbScanOperation::SF_ReadRangeNo;
1022 
1023  if (psop->readTuples(NdbOperation::LM_Read,
1024  scanFlags,
1025  (Uint32) 0, // batch
1026  (Uint32) 0) != 0) // parallel
1027  APIERROR (myTransaction->getNdbError());
1028 
1029  /* Add a bound
1030  * Tuples where ATTR1 >=2 and < 4
1031  * 2,[3 deleted]
1032  */
1033  Uint32 low=2;
1034  Uint32 high=4;
1035 
1036  if (psop->setBound("ATTR1", NdbIndexScanOperation::BoundLE, (char*)&low))
1037  APIERROR(myTransaction->getNdbError());
1038  if (psop->setBound("ATTR1", NdbIndexScanOperation::BoundGT, (char*)&high))
1039  APIERROR(myTransaction->getNdbError());
1040 
1041  if (psop->end_of_bound(0))
1042  APIERROR(psop->getNdbError());
1043 
1044  /* Second bound
1045  * Tuples where ATTR1 > 5 and <=9
1046  * 6,7,8,9
1047  */
1048  low=5;
1049  high=9;
1050  if (psop->setBound("ATTR1", NdbIndexScanOperation::BoundLT, (char*)&low))
1051  APIERROR(myTransaction->getNdbError());
1052  if (psop->setBound("ATTR1", NdbIndexScanOperation::BoundGE, (char*)&high))
1053  APIERROR(myTransaction->getNdbError());
1054 
1055  if (psop->end_of_bound(1))
1056  APIERROR(psop->getNdbError());
1057 
1058  /* Read all columns */
1059  recAttrAttr1=psop->getValue("ATTR1");
1060  recAttrAttr2=psop->getValue("ATTR2");
1061  recAttrAttr3=psop->getValue("ATTR3");
1062 
1063  break;
1064  }
1065  case api_record :
1066  {
1067  /* NdbRecord supports scanning multiple ranges using a
1068  * single index scan operation
1069  */
1070  Uint32 scanFlags =
1071  NdbScanOperation::SF_OrderBy |
1072  NdbScanOperation::SF_MultiRange |
1073  NdbScanOperation::SF_ReadRangeNo;
1074 
1076  options.optionsPresent=NdbScanOperation::ScanOptions::SO_SCANFLAGS;
1077  options.scan_flags=scanFlags;
1078 
1079  psop=myTransaction->scanIndex(pkeyIndexRecord,
1080  pallColsRecord,
1082  NULL, // no mask - read all columns in result record
1083  NULL, // bound defined later
1084  &options,
1086 
1087  if (psop == NULL) APIERROR(myTransaction->getNdbError());
1088 
1089  /* Add a bound
1090  * Tuples where ATTR1 >=2 and < 4
1091  * 2,[3 deleted]
1092  */
1093  Uint32 low=2;
1094  Uint32 high=4;
1095 
1097  bound.low_key=(char*)&low;
1098  bound.low_key_count=1;
1099  bound.low_inclusive=true;
1100  bound.high_key=(char*)&high;
1101  bound.high_key_count=1;
1102  bound.high_inclusive=false;
1103  bound.range_no=0;
1104 
1105  if (psop->setBound(pkeyIndexRecord, bound))
1106  APIERROR(myTransaction->getNdbError());
1107 
1108  /* Second bound
1109  * Tuples where ATTR1 > 5 and <=9
1110  * 6,7,8,9
1111  */
1112  low=5;
1113  high=9;
1114 
1115  bound.low_key=(char*)&low;
1116  bound.low_key_count=1;
1117  bound.low_inclusive=false;
1118  bound.high_key=(char*)&high;
1119  bound.high_key_count=1;
1120  bound.high_inclusive=true;
1121  bound.range_no=1;
1122 
1123  if (psop->setBound(pkeyIndexRecord, bound))
1124  APIERROR(myTransaction->getNdbError());
1125 
1126  break;
1127  }
1128  default :
1129  {
1130  std::cout << "Bad branch : " << accessType << "\n";
1131  exit(-1);
1132  }
1133  }
1134 
1135  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
1136  APIERROR(myTransaction->getNdbError());
1137 
1138  if (myTransaction->getNdbError().code != 0)
1139  APIERROR(myTransaction->getNdbError());
1140 
1141  switch (accessType)
1142  {
1143  case api_attr :
1144  {
1145  while (psop->nextResult(true) == 0)
1146  {
1147  printf(" %2d %2d %2d Range no : %2d\n",
1148  recAttrAttr1->u_32_value(),
1149  recAttrAttr2->u_32_value(),
1150  recAttrAttr3->u_32_value(),
1151  psop->get_range_no());
1152  }
1153 
1154  psop->close();
1155 
1156  break;
1157  }
1158  case api_record :
1159  {
1160  RowData *prowData; // Ptr to point to our data
1161 
1162  int rc=0;
1163 
1164  while ((rc = psop->nextResult((const char**) &prowData,
1165  true,
1166  false)) == 0)
1167  {
1168  // printf(" PTR : %d\n", (int) prowData);
1169  printf(" %2d %2d %2d Range no : %2d\n",
1170  prowData->attr1,
1171  prowData->attr2,
1172  prowData->attr3,
1173  psop->get_range_no());
1174  }
1175 
1176  if (rc != 1) APIERROR(myTransaction->getNdbError());
1177 
1178  psop->close(true);
1179 
1180  break;
1181  }
1182  default :
1183  {
1184  std::cout << "Bad branch : " << accessType << "\n";
1185  exit(-1);
1186  }
1187  }
1188 
1189  if(myTransaction->execute( NdbTransaction::Commit ) !=0)
1190  APIERROR(myTransaction->getNdbError());
1191 
1192  myNdb.closeTransaction(myTransaction);
1193 
1194  std::cout << "-------\n";
1195 }
1196 
1197 
1198 
1199 /*************************************************************************
1200  * Read and print all tuples via index scan using mixed NdbRecord access *
1201  *************************************************************************/
1202 static void do_mixed_indexScan(Ndb &myNdb)
1203 {
1204  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
1205  const NdbDictionary::Index *myPIndex= myDict->getIndex("PRIMARY", "api_recattr_vs_record");
1206 
1207  std::cout << "Running do_mixed_indexScan\n";
1208 
1209  if (myPIndex == NULL)
1210  APIERROR(myDict->getNdbError());
1211 
1212  std::cout << "ATTR1 ATTR2 ATTR3" << std::endl;
1213 
1214  NdbTransaction *myTransaction=myNdb.startTransaction();
1215  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
1216 
1217  NdbIndexScanOperation *psop;
1218  NdbRecAttr *recAttrAttr3;
1219 
1220  Uint32 scanFlags =
1221  NdbScanOperation::SF_OrderBy |
1222  NdbScanOperation::SF_MultiRange |
1223  NdbScanOperation::SF_ReadRangeNo;
1224 
1225  /* We'll get Attr3 via ScanOptions */
1226  unsigned char attrMask=((1<<attr1ColNum) | (1<<attr2ColNum));
1227 
1228  NdbOperation::GetValueSpec extraGets[1];
1229  extraGets[0].column= pattr3Col;
1230  extraGets[0].appStorage= NULL;
1231  extraGets[0].recAttr= NULL;
1232 
1234  options.optionsPresent=
1235  NdbScanOperation::ScanOptions::SO_SCANFLAGS |
1236  NdbScanOperation::ScanOptions::SO_GETVALUE;
1237  options.scan_flags= scanFlags;
1238  options.extraGetValues= &extraGets[0];
1239  options.numExtraGetValues= 1;
1240 
1241  psop=myTransaction->scanIndex(pkeyIndexRecord,
1242  pallColsRecord,
1244  &attrMask, // mask
1245  NULL, // bound defined below
1246  &options,
1248 
1249  if (psop == NULL) APIERROR(myTransaction->getNdbError());
1250 
1251  /* Grab RecAttr now */
1252  recAttrAttr3= extraGets[0].recAttr;
1253 
1254  /* Add a bound
1255  * ATTR1 >= 2, < 4
1256  * 2,[3 deleted]
1257  */
1258  Uint32 low=2;
1259  Uint32 high=4;
1260 
1262  bound.low_key=(char*)&low;
1263  bound.low_key_count=1;
1264  bound.low_inclusive=true;
1265  bound.high_key=(char*)&high;
1266  bound.high_key_count=1;
1267  bound.high_inclusive=false;
1268  bound.range_no=0;
1269 
1270  if (psop->setBound(pkeyIndexRecord, bound))
1271  APIERROR(myTransaction->getNdbError());
1272 
1273  /* Second bound
1274  * ATTR1 > 5, <= 9
1275  * 6,7,8,9
1276  */
1277  low=5;
1278  high=9;
1279 
1280  bound.low_key=(char*)&low;
1281  bound.low_key_count=1;
1282  bound.low_inclusive=false;
1283  bound.high_key=(char*)&high;
1284  bound.high_key_count=1;
1285  bound.high_inclusive=true;
1286  bound.range_no=1;
1287 
1288  if (psop->setBound(pkeyIndexRecord, bound))
1289  APIERROR(myTransaction->getNdbError());
1290 
1291  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
1292  APIERROR(myTransaction->getNdbError());
1293 
1294 
1295  RowData *prowData; // Ptr to point to our data
1296 
1297  int rc=0;
1298 
1299  while ((rc = psop->nextResult((const char**) &prowData,
1300  true,
1301  false)) == 0)
1302  {
1303  printf(" %2d %2d %2d Range no : %2d\n",
1304  prowData->attr1,
1305  prowData->attr2,
1306  recAttrAttr3->u_32_value(),
1307  psop->get_range_no());
1308  }
1309 
1310  if (rc != 1) APIERROR(myTransaction->getNdbError());
1311 
1312  psop->close(true);
1313 
1314  if(myTransaction->execute( NdbTransaction::Commit ) !=0)
1315  APIERROR(myTransaction->getNdbError());
1316 
1317  myNdb.closeTransaction(myTransaction);
1318 
1319  std::cout << "-------\n";
1320 }
1321 
1322 
1323 /********************************************************
1324  * Read + Delete one tuple (the one with primary key 8) *
1325  ********************************************************/
1326 static void do_read_and_delete(Ndb &myNdb)
1327 {
1328  /* This procedure performs a single operation, single round
1329  * trip read and then delete of a tuple, specified by
1330  * primary key
1331  */
1332  std::cout << "Running do_read_and_delete (NdbRecord only)\n";
1333 
1334  NdbTransaction *myTransaction= myNdb.startTransaction();
1335  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
1336 
1337  RowData row;
1338  row.attr1=8;
1339  row.attr2=0; // Don't care
1340  row.attr3=0; // Don't care
1341 
1342  /* We'll also read some extra columns while we're
1343  * reading + deleting
1344  */
1346  NdbOperation::GetValueSpec extraGets[2];
1347  extraGets[0].column = pattr3Col;
1348  extraGets[0].appStorage = NULL;
1349  extraGets[0].recAttr = NULL;
1350  extraGets[1].column = NdbDictionary::Column::COMMIT_COUNT;
1351  extraGets[1].appStorage = NULL;
1352  extraGets[1].recAttr = NULL;
1353 
1354  options.optionsPresent= NdbOperation::OperationOptions::OO_GETVALUE;
1355  options.extraGetValues= &extraGets[0];
1356  options.numExtraGetValues= 2;
1357 
1358  unsigned char attrMask = (1<<attr2ColNum); // Only read Col2 into row
1359 
1360  const NdbOperation *pop=
1361  myTransaction->deleteTuple(pkeyColumnRecord, // Spec of key used
1362  (char*) &row, // Key information
1363  pallColsRecord, // Spec of columns to read
1364  (char*) &row, // Row to read values into
1365  &attrMask, // Columns to read as part of delete
1366  &options,
1368 
1369  if (pop==NULL) APIERROR(myTransaction->getNdbError());
1370 
1371  if (myTransaction->execute(NdbTransaction::Commit) == -1)
1372  APIERROR(myTransaction->getNdbError());
1373 
1374  std::cout << "ATTR1 ATTR2 ATTR3 COMMITS" << std::endl;
1375  printf(" %2d %2d %2d %2d\n",
1376  row.attr1,
1377  row.attr2,
1378  extraGets[0].recAttr->u_32_value(),
1379  extraGets[1].recAttr->u_32_value());
1380 
1381  myNdb.closeTransaction(myTransaction);
1382 
1383  std::cout << "-------\n";
1384 }
1385 
1386 /* Some handy consts for scan control */
1387 static const int GOT_ROW= 0;
1388 static const int NO_MORE_ROWS= 1;
1389 static const int NEED_TO_FETCH_ROWS= 2;
1390 
1391 /*********************************************
1392  * Read and update all tuples via table scan *
1393  *********************************************/
1394 static void do_scan_update(Ndb &myNdb, ApiType accessType)
1395 {
1396  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
1397  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
1398 
1399  if (myTable == NULL)
1400  APIERROR(myDict->getNdbError());
1401 
1402  std::cout << "Running do_scan_update\n";
1403 
1404  NdbTransaction *myTransaction=myNdb.startTransaction();
1405  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
1406 
1407  NdbScanOperation *psop;
1408  NdbRecAttr *recAttrAttr1;
1409  NdbRecAttr *recAttrAttr2;
1410  NdbRecAttr *recAttrAttr3;
1411 
1412  switch (accessType)
1413  {
1414  case api_attr :
1415  {
1416  psop=myTransaction->getNdbScanOperation(myTable);
1417 
1418  if (psop == NULL) APIERROR(myTransaction->getNdbError());
1419 
1420  /* When we want to operate on the tuples returned from a
1421  * scan, we need to request the the tuple's keyinfo is
1422  * returned, with SF_KeyInfo
1423  */
1424  if (psop->readTuples(NdbOperation::LM_Read,
1425  NdbScanOperation::SF_KeyInfo) != 0)
1426  APIERROR (myTransaction->getNdbError());
1427 
1428  recAttrAttr1=psop->getValue("ATTR1");
1429  recAttrAttr2=psop->getValue("ATTR2");
1430  recAttrAttr3=psop->getValue("ATTR3");
1431 
1432  break;
1433  }
1434  case api_record :
1435  {
1437  options.optionsPresent= NdbScanOperation::ScanOptions::SO_SCANFLAGS;
1438  options.scan_flags= NdbScanOperation::SF_KeyInfo;
1439 
1440  psop=myTransaction->scanTable(pallColsRecord,
1442  NULL, // mask - read all columns
1443  &options,
1445 
1446  if (psop == NULL) APIERROR(myTransaction->getNdbError());
1447 
1448  break;
1449  }
1450  default :
1451  {
1452  std::cout << "Bad branch : " << accessType << "\n";
1453  exit(-1);
1454  }
1455  }
1456 
1457  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
1458  APIERROR(myTransaction->getNdbError());
1459 
1460  switch (accessType)
1461  {
1462  case api_attr :
1463  {
1464 
1465 
1466  int result= NEED_TO_FETCH_ROWS;
1467  Uint32 processed= 0;
1468 
1469  while (result == NEED_TO_FETCH_ROWS)
1470  {
1471  bool fetch=true;
1472  while ((result = psop->nextResult(fetch)) == GOT_ROW)
1473  {
1474  fetch= false;
1475  Uint32 col2Value=recAttrAttr2->u_32_value();
1476 
1477  NdbOperation *op=psop->updateCurrentTuple();
1478  if (op==NULL)
1479  APIERROR(myTransaction->getNdbError());
1480  op->setValue("ATTR2", (10*col2Value));
1481 
1482  processed++;
1483  }
1484  if (result < 0)
1485  APIERROR(myTransaction->getNdbError());
1486 
1487  if (processed !=0)
1488  {
1489  // Need to execute
1490 
1491  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
1492  APIERROR(myTransaction->getNdbError());
1493  processed=0;
1494  }
1495  }
1496 
1497  psop->close();
1498 
1499  break;
1500  }
1501  case api_record :
1502  {
1503  RowData *prowData; // Ptr to point to our data
1504 
1505  int result= NEED_TO_FETCH_ROWS;
1506  Uint32 processed=0;
1507 
1508  while (result == NEED_TO_FETCH_ROWS)
1509  {
1510  bool fetch= true;
1511  while ((result = psop->nextResult((const char**) &prowData,
1512  fetch, false)) == GOT_ROW)
1513  {
1514  fetch= false;
1515 
1516  /* Copy row into a stack variable */
1517  RowData r= *prowData;
1518 
1519  /* Modify attr2 */
1520  r.attr2*= 10;
1521 
1522  /* Update it */
1523  const NdbOperation *op = psop->updateCurrentTuple(myTransaction,
1524  pallColsRecord,
1525  (char*) &r);
1526 
1527  if (op==NULL)
1528  APIERROR(myTransaction->getNdbError());
1529 
1530  processed ++;
1531  }
1532 
1533  if (result < 0)
1534  APIERROR(myTransaction->getNdbError());
1535 
1536 
1537  if (processed !=0)
1538  {
1539  /* To get here, there are no more cached scan results,
1540  * and some row updates that we've not sent yet.
1541  * Send them before we try to get another batch, or
1542  * finish.
1543  */
1544  if (myTransaction->execute( NdbTransaction::NoCommit ) != 0)
1545  APIERROR(myTransaction->getNdbError());
1546  processed=0;
1547  }
1548  }
1549 
1550  psop->close(true);
1551 
1552  break;
1553  }
1554  default :
1555  {
1556  std::cout << "Bad branch : " << accessType << "\n";
1557  exit(-1);
1558  }
1559  }
1560 
1561  if(myTransaction->execute( NdbTransaction::Commit ) !=0)
1562  APIERROR(myTransaction->getNdbError());
1563 
1564  myNdb.closeTransaction(myTransaction);
1565 
1566  std::cout << "-------\n";
1567 }
1568 
1569 /**************************************************
1570  * Read all and delete some tuples via table scan *
1571  **************************************************/
1572 static void do_scan_delete(Ndb &myNdb, ApiType accessType)
1573 {
1574  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
1575  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
1576 
1577  if (myTable == NULL)
1578  APIERROR(myDict->getNdbError());
1579 
1580  std::cout << "Running do_scan_delete\n";
1581 
1582  NdbTransaction *myTransaction=myNdb.startTransaction();
1583  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
1584 
1585  NdbScanOperation *psop;
1586  NdbRecAttr *recAttrAttr1;
1587 
1588  /* Scan, retrieving first column.
1589  * Delete particular records, based on first column
1590  * Read third column as part of delete
1591  */
1592  switch (accessType)
1593  {
1594  case api_attr :
1595  {
1596  psop=myTransaction->getNdbScanOperation(myTable);
1597 
1598  if (psop == NULL) APIERROR(myTransaction->getNdbError());
1599 
1600  /* Need KeyInfo when performing scanning delete */
1601  if (psop->readTuples(NdbOperation::LM_Read,
1602  NdbScanOperation::SF_KeyInfo) != 0)
1603  APIERROR (myTransaction->getNdbError());
1604 
1605  recAttrAttr1=psop->getValue("ATTR1");
1606 
1607  break;
1608  }
1609  case api_record :
1610  {
1611 
1612 
1614  options.optionsPresent=NdbScanOperation::ScanOptions::SO_SCANFLAGS;
1615  /* Need KeyInfo when performing scanning delete */
1616  options.scan_flags=NdbScanOperation::SF_KeyInfo;
1617 
1618  psop=myTransaction->scanTable(pkeyColumnRecord,
1620  NULL, // mask
1621  &options,
1623 
1624  if (psop == NULL) APIERROR(myTransaction->getNdbError());
1625 
1626  break;
1627  }
1628  default :
1629  {
1630  std::cout << "Bad branch : " << accessType << "\n";
1631  exit(-1);
1632  }
1633  }
1634 
1635  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
1636  APIERROR(myTransaction->getNdbError());
1637 
1638  switch (accessType)
1639  {
1640  case api_attr :
1641  {
1642  int result= NEED_TO_FETCH_ROWS;
1643  Uint32 processed=0;
1644 
1645  while (result == NEED_TO_FETCH_ROWS)
1646  {
1647  bool fetch=true;
1648  while ((result = psop->nextResult(fetch)) == GOT_ROW)
1649  {
1650  fetch= false;
1651  Uint32 col1Value=recAttrAttr1->u_32_value();
1652 
1653  if (col1Value == 2)
1654  {
1655  /* Note : We cannot do a delete pre-read via
1656  * the NdbRecAttr interface. We can only
1657  * delete here.
1658  */
1659  if (psop->deleteCurrentTuple())
1660  APIERROR(myTransaction->getNdbError());
1661  processed++;
1662  }
1663  }
1664  if (result < 0)
1665  APIERROR(myTransaction->getNdbError());
1666 
1667  if (processed !=0)
1668  {
1669  /* To get here, there are no more cached scan results,
1670  * and some row deletes that we've not sent yet.
1671  * Send them before we try to get another batch, or
1672  * finish.
1673  */
1674  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
1675  APIERROR(myTransaction->getNdbError());
1676  processed=0;
1677  }
1678  }
1679 
1680  psop->close();
1681 
1682  break;
1683  }
1684  case api_record :
1685  {
1686  RowData *prowData; // Ptr to point to our data
1687 
1688  int result= NEED_TO_FETCH_ROWS;
1689  Uint32 processed=0;
1690 
1691  while (result == NEED_TO_FETCH_ROWS)
1692  {
1693  bool fetch=true;
1694 
1695  const NdbOperation* theDeleteOp;
1696  RowData readRow;
1697  NdbRecAttr* attr3;
1698  NdbRecAttr* commitCount;
1699 
1700  while ((result = psop->nextResult((const char**) &prowData,
1701  fetch,
1702  false)) == GOT_ROW)
1703  {
1704  fetch = false;
1705 
1706  /* Copy latest row to a stack local */
1707  RowData r;
1708  r= *prowData;
1709 
1710  if (r.attr1 == 2)
1711  {
1712  /* We're going to perform a read+delete on this
1713  * row. We'll read attr1 and attr2 via NdbRecord
1714  * and Attr3 and the commit count via extra
1715  * get values.
1716  */
1718  NdbOperation::GetValueSpec extraGets[2];
1719  extraGets[0].column = pattr3Col;
1720  extraGets[0].appStorage = NULL;
1721  extraGets[0].recAttr = NULL;
1722  extraGets[1].column = NdbDictionary::Column::COMMIT_COUNT;
1723  extraGets[1].appStorage = NULL;
1724  extraGets[1].recAttr = NULL;
1725 
1726  options.optionsPresent= NdbOperation::OperationOptions::OO_GETVALUE;
1727  options.extraGetValues= &extraGets[0];
1728  options.numExtraGetValues= 2;
1729 
1730  // Read cols 1 + 2 via NdbRecord
1731  unsigned char attrMask = (1<<attr1ColNum) | (1<<attr2ColNum);
1732 
1733  theDeleteOp = psop->deleteCurrentTuple(myTransaction,
1734  pallColsRecord,
1735  (char*) &readRow,
1736  &attrMask,
1737  &options,
1739 
1740  if (theDeleteOp==NULL)
1741  APIERROR(myTransaction->getNdbError());
1742 
1743  /* Store extra Get RecAttrs */
1744  attr3= extraGets[0].recAttr;
1745  commitCount= extraGets[1].recAttr;
1746 
1747  processed ++;
1748  }
1749  }
1750 
1751  if (result < 0)
1752  APIERROR(myTransaction->getNdbError());
1753 
1754 
1755  if (processed !=0)
1756  {
1757  /* To get here, there are no more cached scan results,
1758  * and some row deletes that we've not sent yet.
1759  * Send them before we try to get another batch, or
1760  * finish.
1761  */
1762  if (myTransaction->execute( NdbTransaction::NoCommit ) != 0)
1763  APIERROR(myTransaction->getNdbError());
1764  processed=0;
1765 
1766  // Let's look at the data just read
1767  printf("Deleted data\n");
1768  printf("ATTR1 ATTR2 ATTR3 COMMITS\n");
1769  printf(" %2d %2d %2d %2d\n",
1770  readRow.attr1,
1771  readRow.attr2,
1772  attr3->u_32_value(),
1773  commitCount->u_32_value());
1774  }
1775  }
1776 
1777  psop->close(true);
1778 
1779  break;
1780  }
1781  default :
1782  {
1783  std::cout << "Bad branch : " << accessType << "\n";
1784  exit(-1);
1785  }
1786  }
1787 
1788  if(myTransaction->execute( NdbTransaction::Commit ) !=0)
1789  APIERROR(myTransaction->getNdbError());
1790 
1791  myNdb.closeTransaction(myTransaction);
1792 
1793  std::cout << "-------\n";
1794 }
1795 
1796 
1797 
1798 /***********************************************************
1799  * Read all tuples via scan, reread one with lock takeover *
1800  ***********************************************************/
1801 static void do_scan_lock_reread(Ndb &myNdb, ApiType accessType)
1802 {
1803  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
1804  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
1805 
1806  if (myTable == NULL)
1807  APIERROR(myDict->getNdbError());
1808 
1809  std::cout << "Running do_scan_lock_reread\n";
1810 
1811  NdbTransaction *myTransaction=myNdb.startTransaction();
1812  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
1813 
1814  NdbScanOperation *psop;
1815  NdbRecAttr *recAttrAttr1;
1816 
1817  switch (accessType)
1818  {
1819  case api_attr :
1820  {
1821  psop=myTransaction->getNdbScanOperation(myTable);
1822 
1823  if (psop == NULL) APIERROR(myTransaction->getNdbError());
1824 
1825  /* Need KeyInfo for lock takeover */
1826  if (psop->readTuples(NdbOperation::LM_Read,
1827  NdbScanOperation::SF_KeyInfo) != 0)
1828  APIERROR (myTransaction->getNdbError());
1829 
1830  recAttrAttr1=psop->getValue("ATTR1");
1831 
1832  break;
1833  }
1834  case api_record :
1835  {
1837  options.optionsPresent= NdbScanOperation::ScanOptions::SO_SCANFLAGS;
1838  /* Need KeyInfo for lock takeover */
1839  options.scan_flags= NdbScanOperation::SF_KeyInfo;
1840 
1841  psop=myTransaction->scanTable(pkeyColumnRecord,
1843  NULL, // mask
1844  &options,
1846 
1847  if (psop == NULL) APIERROR(myTransaction->getNdbError());
1848 
1849  break;
1850  }
1851  default :
1852  {
1853  std::cout << "Bad branch : " << accessType << "\n";
1854  exit(-1);
1855  }
1856  }
1857 
1858  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
1859  APIERROR(myTransaction->getNdbError());
1860 
1861  switch (accessType)
1862  {
1863  case api_attr :
1864  {
1865  int result= NEED_TO_FETCH_ROWS;
1866  Uint32 processed=0;
1867  NdbRecAttr *attr1, *attr2, *attr3, *commitCount;
1868 
1869  while (result == NEED_TO_FETCH_ROWS)
1870  {
1871  bool fetch=true;
1872  while ((result = psop->nextResult(fetch)) == GOT_ROW)
1873  {
1874  fetch= false;
1875  Uint32 col1Value=recAttrAttr1->u_32_value();
1876 
1877  if (col1Value == 9)
1878  {
1879  /* Let's read the rest of the info for it with
1880  * a separate operation
1881  */
1882  NdbOperation *op= psop->lockCurrentTuple();
1883 
1884  if (op==NULL)
1885  APIERROR(myTransaction->getNdbError());
1886  attr1=op->getValue("ATTR1");
1887  attr2=op->getValue("ATTR2");
1888  attr3=op->getValue("ATTR3");
1889  commitCount=op->getValue(NdbDictionary::Column::COMMIT_COUNT);
1890  processed++;
1891  }
1892  }
1893  if (result < 0)
1894  APIERROR(myTransaction->getNdbError());
1895 
1896  if (processed !=0)
1897  {
1898  // Need to execute
1899 
1900  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
1901  APIERROR(myTransaction->getNdbError());
1902  processed=0;
1903 
1904  // Let's look at the whole row...
1905  printf("Locked and re-read data:\n");
1906  printf("ATTR1 ATTR2 ATTR3 COMMITS\n");
1907  printf(" %2d %2d %2d %2d\n",
1908  attr1->u_32_value(),
1909  attr2->u_32_value(),
1910  attr3->u_32_value(),
1911  commitCount->u_32_value());
1912  }
1913  }
1914 
1915  psop->close();
1916 
1917  break;
1918  }
1919  case api_record :
1920  {
1921  RowData *prowData; // Ptr to point to our data
1922 
1923  int result= NEED_TO_FETCH_ROWS;
1924  Uint32 processed=0;
1925  RowData rereadData;
1926  NdbRecAttr *attr3, *commitCount;
1927 
1928  while (result == NEED_TO_FETCH_ROWS)
1929  {
1930  bool fetch=true;
1931  while ((result = psop->nextResult((const char**) &prowData,
1932  fetch,
1933  false)) == GOT_ROW)
1934  {
1935  fetch = false;
1936 
1937  /* Copy row to stack local */
1938  RowData r;
1939  r=*prowData;
1940 
1941  if (r.attr1 == 9)
1942  {
1943  /* Perform extra read of this row via lockCurrentTuple
1944  * Read all columns using NdbRecord for attr1 + attr2,
1945  * and extra get values for attr3 and the commit count
1946  */
1948  NdbOperation::GetValueSpec extraGets[2];
1949  extraGets[0].column = pattr3Col;
1950  extraGets[0].appStorage = NULL;
1951  extraGets[0].recAttr = NULL;
1952  extraGets[1].column = NdbDictionary::Column::COMMIT_COUNT;
1953  extraGets[1].appStorage = NULL;
1954  extraGets[1].recAttr = NULL;
1955 
1956  options.optionsPresent=NdbOperation::OperationOptions::OO_GETVALUE;
1957  options.extraGetValues=&extraGets[0];
1958  options.numExtraGetValues=2;
1959 
1960  // Read cols 1 + 2 via NdbRecord
1961  unsigned char attrMask = (1<<attr1ColNum) | (1<<attr2ColNum);
1962 
1963  const NdbOperation *lockOp = psop->lockCurrentTuple(myTransaction,
1964  pallColsRecord,
1965  (char *) &rereadData,
1966  &attrMask,
1967  &options,
1969  if (lockOp == NULL)
1970  APIERROR(myTransaction->getNdbError());
1971 
1972  attr3= extraGets[0].recAttr;
1973  commitCount= extraGets[1].recAttr;
1974 
1975  processed++;
1976  }
1977  }
1978 
1979  if (result < 0)
1980  APIERROR(myTransaction->getNdbError());
1981 
1982 
1983  if (processed !=0)
1984  {
1985  // Need to execute
1986 
1987  if (myTransaction->execute( NdbTransaction::NoCommit ) != 0)
1988  APIERROR(myTransaction->getNdbError());
1989  processed=0;
1990 
1991  // Let's look at the whole row...
1992  printf("Locked and re-read data:\n");
1993  printf("ATTR1 ATTR2 ATTR3 COMMITS\n");
1994  printf(" %2d %2d %2d %2d\n",
1995  rereadData.attr1,
1996  rereadData.attr2,
1997  attr3->u_32_value(),
1998  commitCount->u_32_value());
1999 
2000  }
2001  }
2002 
2003  psop->close(true);
2004 
2005  break;
2006  }
2007  default :
2008  {
2009  std::cout << "Bad branch : " << accessType << "\n";
2010  exit(-1);
2011  }
2012  }
2013 
2014  if(myTransaction->execute( NdbTransaction::Commit ) !=0)
2015  APIERROR(myTransaction->getNdbError());
2016 
2017  myNdb.closeTransaction(myTransaction);
2018 
2019  std::cout << "-------\n";
2020 }
2021 
2022 /***************************************************************
2023  * Read all tuples via primary key, using only extra getValues *
2024  ***************************************************************/
2025 static void do_all_extras_read(Ndb &myNdb)
2026 {
2027  std::cout << "Running do_all_extras_read(NdbRecord only)\n";
2028  std::cout << "ATTR1 ATTR2 ATTR3 COMMIT_COUNT" << std::endl;
2029 
2030  for (int i = 0; i < 10; i++) {
2031  NdbTransaction *myTransaction= myNdb.startTransaction();
2032  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
2033 
2034  RowData rowData;
2035  NdbRecAttr *myRecAttr1, *myRecAttr2, *myRecAttr3, *myRecAttrCC;
2036 
2037  /* We read nothing via NdbRecord, and everything via
2038  * 'extra' reads
2039  */
2040  NdbOperation::GetValueSpec extraCols[4];
2041 
2042  extraCols[0].column=pattr1Col;
2043  extraCols[0].appStorage=NULL;
2044  extraCols[0].recAttr=NULL;
2045 
2046  extraCols[1].column=pattr2Col;
2047  extraCols[1].appStorage=NULL;
2048  extraCols[1].recAttr=NULL;
2049 
2050  extraCols[2].column=pattr3Col;
2051  extraCols[2].appStorage=NULL;
2052  extraCols[2].recAttr=NULL;
2053 
2054  extraCols[3].column=NdbDictionary::Column::COMMIT_COUNT;
2055  extraCols[3].appStorage=NULL;
2056  extraCols[3].recAttr=NULL;
2057 
2059  opts.optionsPresent = NdbOperation::OperationOptions::OO_GETVALUE;
2060 
2061  opts.extraGetValues=&extraCols[0];
2062  opts.numExtraGetValues=4;
2063 
2064  unsigned char attrMask= 0; // No row results required.
2065 
2066  // Set PK search criteria
2067  rowData.attr1= i;
2068 
2069  const NdbOperation *pop=
2070  myTransaction->readTuple(pkeyColumnRecord,
2071  (char*) &rowData,
2072  pkeyColumnRecord,
2073  NULL, // null result row
2075  &attrMask,
2076  &opts);
2077  if (pop==NULL) APIERROR(myTransaction->getNdbError());
2078 
2079  myRecAttr1=extraCols[0].recAttr;
2080  myRecAttr2=extraCols[1].recAttr;
2081  myRecAttr3=extraCols[2].recAttr;
2082  myRecAttrCC=extraCols[3].recAttr;
2083 
2084  if (myRecAttr1 == NULL) APIERROR(myTransaction->getNdbError());
2085  if (myRecAttr2 == NULL) APIERROR(myTransaction->getNdbError());
2086  if (myRecAttr3 == NULL) APIERROR(myTransaction->getNdbError());
2087  if (myRecAttrCC == NULL) APIERROR(myTransaction->getNdbError());
2088 
2089  if(myTransaction->execute( NdbTransaction::Commit ) == -1)
2090  APIERROR(myTransaction->getNdbError());
2091 
2092  bool deleted= (myTransaction->getNdbError().classification ==
2094  if (deleted)
2095  printf("Detected that deleted tuple %d doesn't exist!\n", i);
2096  else
2097  {
2098  printf(" %2d %2d %2d %d\n",
2099  myRecAttr1->u_32_value(),
2100  myRecAttr2->u_32_value(),
2101  myRecAttr3->u_32_value(),
2102  myRecAttrCC->u_32_value()
2103  );
2104  }
2105 
2106  myNdb.closeTransaction(myTransaction);
2107  }
2108 
2109  std::cout << "-------\n";
2110 }
2111 
2112 
2113 /******************************************************************
2114  * Read and print some tuples via bounded scan of secondary index *
2115  ******************************************************************/
2116 static void do_secondary_indexScan(Ndb &myNdb, ApiType accessType)
2117 {
2118  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
2119  const NdbDictionary::Index *mySIndex= myDict->getIndex("MYINDEXNAME", "api_recattr_vs_record");
2120 
2121  std::cout << "Running do_secondary_indexScan\n";
2122  std::cout << "ATTR1 ATTR2 ATTR3" << std::endl;
2123 
2124  NdbTransaction *myTransaction=myNdb.startTransaction();
2125  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
2126 
2127  NdbIndexScanOperation *psop;
2128  NdbRecAttr *recAttrAttr1;
2129  NdbRecAttr *recAttrAttr2;
2130  NdbRecAttr *recAttrAttr3;
2131 
2132  Uint32 scanFlags =
2133  NdbScanOperation::SF_OrderBy |
2134  NdbScanOperation::SF_Descending |
2135  NdbScanOperation::SF_MultiRange |
2136  NdbScanOperation::SF_ReadRangeNo;
2137 
2138  switch (accessType)
2139  {
2140  case api_attr :
2141  {
2142  psop=myTransaction->getNdbIndexScanOperation(mySIndex);
2143 
2144  if (psop == NULL) APIERROR(myTransaction->getNdbError());
2145 
2146  if (psop->readTuples(NdbOperation::LM_Read,
2147  scanFlags,
2148  (Uint32) 0, // batch
2149  (Uint32) 0) != 0) // parallel
2150  APIERROR (myTransaction->getNdbError());
2151 
2152  /* Bounds :
2153  * > ATTR3=6
2154  * < ATTR3=42
2155  */
2156  Uint32 low=6;
2157  Uint32 high=42;
2158 
2159  if (psop->setBound("ATTR3", NdbIndexScanOperation::BoundLT, (char*)&low))
2160  APIERROR(psop->getNdbError());
2161  if (psop->setBound("ATTR3", NdbIndexScanOperation::BoundGT, (char*)&high))
2162  APIERROR(psop->getNdbError());
2163 
2164  recAttrAttr1=psop->getValue("ATTR1");
2165  recAttrAttr2=psop->getValue("ATTR2");
2166  recAttrAttr3=psop->getValue("ATTR3");
2167 
2168  break;
2169  }
2170  case api_record :
2171  {
2172 
2174  options.optionsPresent=NdbScanOperation::ScanOptions::SO_SCANFLAGS;
2175  options.scan_flags=scanFlags;
2176 
2177  psop=myTransaction->scanIndex(psecondaryIndexRecord,
2178  pallColsRecord,
2180  NULL, // mask
2181  NULL, // bound
2182  &options,
2184 
2185  if (psop == NULL) APIERROR(myTransaction->getNdbError());
2186 
2187  /* Bounds :
2188  * > ATTR3=6
2189  * < ATTR3=42
2190  */
2191  Uint32 low=6;
2192  Uint32 high=42;
2193 
2195  bound.low_key=(char*)&low;
2196  bound.low_key_count=1;
2197  bound.low_inclusive=false;
2198  bound.high_key=(char*)&high;
2199  bound.high_key_count=1;
2200  bound.high_inclusive=false;
2201  bound.range_no=0;
2202 
2203  if (psop->setBound(psecondaryIndexRecord, bound))
2204  APIERROR(myTransaction->getNdbError());
2205 
2206  break;
2207  }
2208  default :
2209  {
2210  std::cout << "Bad branch : " << accessType << "\n";
2211  exit(-1);
2212  }
2213  }
2214 
2215  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
2216  APIERROR(myTransaction->getNdbError());
2217 
2218  // Check rc anyway
2219  if (myTransaction->getNdbError().status != NdbError::Success)
2220  APIERROR(myTransaction->getNdbError());
2221 
2222  switch (accessType)
2223  {
2224  case api_attr :
2225  {
2226  while (psop->nextResult(true) == 0)
2227  {
2228  printf(" %2d %2d %2d Range no : %2d\n",
2229  recAttrAttr1->u_32_value(),
2230  recAttrAttr2->u_32_value(),
2231  recAttrAttr3->u_32_value(),
2232  psop->get_range_no());
2233  }
2234 
2235  psop->close();
2236 
2237  break;
2238  }
2239  case api_record :
2240  {
2241  RowData *prowData; // Ptr to point to our data
2242 
2243  int rc=0;
2244 
2245  while ((rc = psop->nextResult((const char**) &prowData,
2246  true,
2247  false)) == 0)
2248  {
2249  // printf(" PTR : %d\n", (int) prowData);
2250  printf(" %2d %2d %2d Range no : %2d\n",
2251  prowData->attr1,
2252  prowData->attr2,
2253  prowData->attr3,
2254  psop->get_range_no());
2255  }
2256 
2257  if (rc != 1) APIERROR(myTransaction->getNdbError());
2258 
2259  psop->close(true);
2260 
2261  break;
2262  }
2263  default :
2264  {
2265  std::cout << "Bad branch : " << accessType << "\n";
2266  exit(-1);
2267  }
2268  }
2269 
2270  if(myTransaction->execute( NdbTransaction::Commit ) !=0)
2271  APIERROR(myTransaction->getNdbError());
2272 
2273  myNdb.closeTransaction(myTransaction);
2274 
2275  std::cout << "-------\n";
2276 }
2277 
2278 
2279 /***********************************************************************
2280  * Index scan to read tuples from secondary index using equality bound *
2281  ***********************************************************************/
2282 static void do_secondary_indexScanEqual(Ndb &myNdb, ApiType accessType)
2283 {
2284  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
2285  const NdbDictionary::Index *mySIndex= myDict->getIndex("MYINDEXNAME", "api_recattr_vs_record");
2286 
2287  std::cout << "Running do_secondary_indexScanEqual\n";
2288  std::cout << "ATTR1 ATTR2 ATTR3" << std::endl;
2289 
2290  NdbTransaction *myTransaction=myNdb.startTransaction();
2291  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
2292 
2293  NdbIndexScanOperation *psop;
2294  NdbRecAttr *recAttrAttr1;
2295  NdbRecAttr *recAttrAttr2;
2296  NdbRecAttr *recAttrAttr3;
2297 
2298  Uint32 scanFlags = NdbScanOperation::SF_OrderBy;
2299 
2300  Uint32 attr3Eq= 44;
2301 
2302  switch (accessType)
2303  {
2304  case api_attr :
2305  {
2306  psop=myTransaction->getNdbIndexScanOperation(mySIndex);
2307 
2308  if (psop == NULL) APIERROR(myTransaction->getNdbError());
2309 
2310  if (psop->readTuples(NdbOperation::LM_Read,
2311  scanFlags,
2312  (Uint32) 0, // batch
2313  (Uint32) 0) != 0) // parallel
2314  APIERROR (myTransaction->getNdbError());
2315 
2316  if (psop->setBound("ATTR3", NdbIndexScanOperation::BoundEQ, (char*)&attr3Eq))
2317  APIERROR(myTransaction->getNdbError());
2318 
2319  recAttrAttr1=psop->getValue("ATTR1");
2320  recAttrAttr2=psop->getValue("ATTR2");
2321  recAttrAttr3=psop->getValue("ATTR3");
2322 
2323  break;
2324  }
2325  case api_record :
2326  {
2327 
2329  options.optionsPresent= NdbScanOperation::ScanOptions::SO_SCANFLAGS;
2330  options.scan_flags=scanFlags;
2331 
2332  psop=myTransaction->scanIndex(psecondaryIndexRecord,
2333  pallColsRecord, // Read all table rows back
2335  NULL, // mask
2336  NULL, // bound specified below
2337  &options,
2339 
2340  if (psop == NULL) APIERROR(myTransaction->getNdbError());
2341 
2342  /* Set equality bound via two inclusive bounds */
2344  bound.low_key= (char*)&attr3Eq;
2345  bound.low_key_count= 1;
2346  bound.low_inclusive= true;
2347  bound.high_key= (char*)&attr3Eq;
2348  bound.high_key_count= 1;
2349  bound.high_inclusive= true;
2350  bound.range_no= 0;
2351 
2352  if (psop->setBound(psecondaryIndexRecord, bound))
2353  APIERROR(myTransaction->getNdbError());
2354 
2355  break;
2356  }
2357  default :
2358  {
2359  std::cout << "Bad branch : " << accessType << "\n";
2360  exit(-1);
2361  }
2362  }
2363 
2364  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
2365  APIERROR(myTransaction->getNdbError());
2366 
2367  // Check rc anyway
2368  if (myTransaction->getNdbError().status != NdbError::Success)
2369  APIERROR(myTransaction->getNdbError());
2370 
2371  switch (accessType)
2372  {
2373  case api_attr :
2374  {
2375  int res;
2376 
2377  while ((res= psop->nextResult(true)) == GOT_ROW)
2378  {
2379  printf(" %2d %2d %2d\n",
2380  recAttrAttr1->u_32_value(),
2381  recAttrAttr2->u_32_value(),
2382  recAttrAttr3->u_32_value());
2383  }
2384 
2385  if (res != NO_MORE_ROWS)
2386  APIERROR(psop->getNdbError());
2387 
2388  psop->close();
2389 
2390  break;
2391  }
2392  case api_record :
2393  {
2394  RowData *prowData; // Ptr to point to our data
2395 
2396  int rc=0;
2397 
2398  while ((rc = psop->nextResult((const char**) &prowData,
2399  true, // fetch
2400  false)) // forceSend
2401  == GOT_ROW)
2402  {
2403  printf(" %2d %2d %2d\n",
2404  prowData->attr1,
2405  prowData->attr2,
2406  prowData->attr3);
2407  }
2408 
2409  if (rc != NO_MORE_ROWS)
2410  APIERROR(myTransaction->getNdbError());
2411 
2412  psop->close(true);
2413 
2414  break;
2415  }
2416  default :
2417  {
2418  std::cout << "Bad branch : " << accessType << "\n";
2419  exit(-1);
2420  }
2421  }
2422 
2423  if(myTransaction->execute( NdbTransaction::Commit ) !=0)
2424  APIERROR(myTransaction->getNdbError());
2425 
2426  myNdb.closeTransaction(myTransaction);
2427 
2428  std::cout << "-------\n";
2429 }
2430 
2431 
2432 /**********************
2433  * Interpreted update *
2434  **********************/
2435 static void do_interpreted_update(Ndb &myNdb, ApiType accessType)
2436 {
2437  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
2438  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
2439  const NdbDictionary::Index *myPIndex= myDict->getIndex("PRIMARY", "api_recattr_vs_record");
2440 
2441  std::cout << "Running do_interpreted_update\n";
2442 
2443  if (myTable == NULL)
2444  APIERROR(myDict->getNdbError());
2445  if (myPIndex == NULL)
2446  APIERROR(myDict->getNdbError());
2447 
2448  std::cout << "ATTR1 ATTR2 ATTR3" << std::endl;
2449 
2450  NdbTransaction *myTransaction=myNdb.startTransaction();
2451  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
2452 
2453  NdbRecAttr *recAttrAttr1;
2454  NdbRecAttr *recAttrAttr2;
2455  NdbRecAttr *recAttrAttr3;
2456  NdbRecAttr *recAttrAttr11;
2457  NdbRecAttr *recAttrAttr12;
2458  NdbRecAttr *recAttrAttr13;
2459  RowData rowData;
2460  RowData rowData2;
2461 
2462  /* Register aliases */
2463  const Uint32 R1=1, R2=2, R3=3, R4=4, R5=5, R6=6;
2464 
2465  switch (accessType)
2466  {
2467  case api_attr :
2468  {
2469  NdbOperation *pop;
2470  pop=myTransaction->getNdbOperation(myTable);
2471 
2472  if (pop == NULL) APIERROR(myTransaction->getNdbError());
2473 
2474  if (pop->interpretedUpdateTuple())
2475  APIERROR (pop->getNdbError());
2476 
2477  /* Interpreted update on row where ATTR1 == 4 */
2478  if (pop->equal("ATTR1", 4) != 0)
2479  APIERROR (pop->getNdbError());
2480 
2481  /* First, read the values of all attributes in the normal way */
2482  recAttrAttr1=pop->getValue("ATTR1");
2483  recAttrAttr2=pop->getValue("ATTR2");
2484  recAttrAttr3=pop->getValue("ATTR3");
2485 
2486  /* Now define interpreted program which will run after the
2487  * values have been read
2488  * This program is rather tortuous and doesn't achieve much other
2489  * than demonstrating control flow, register and some column
2490  * operations
2491  */
2492  // R5= 3
2493  if (pop->load_const_u32(R5, 3) != 0)
2494  APIERROR (pop->getNdbError());
2495 
2496  // R1= *ATTR1; R2= *ATTR2; R3= *ATTR3
2497  if (pop->read_attr("ATTR1", R1) != 0)
2498  APIERROR (pop->getNdbError());
2499  if (pop->read_attr("ATTR2", R2) != 0)
2500  APIERROR (pop->getNdbError());
2501  if (pop->read_attr("ATTR3", R3) != 0)
2502  APIERROR (pop->getNdbError());
2503 
2504  // R3= R3-R5
2505  if (pop->sub_reg(R3, R5, R3) != 0)
2506  APIERROR (pop->getNdbError());
2507 
2508  // R2= R1+R2
2509  if (pop->add_reg(R1, R2, R2) != 0)
2510  APIERROR (pop->getNdbError());
2511 
2512  // *ATTR2= R2
2513  if (pop->write_attr("ATTR2", R2) != 0)
2514  APIERROR (pop->getNdbError());
2515 
2516  // *ATTR3= R3
2517  if (pop->write_attr("ATTR3", R3) != 0)
2518  APIERROR (pop->getNdbError());
2519 
2520  // *ATTR3 = *ATTR3 - 30
2521  if (pop->subValue("ATTR3", (Uint32)30) != 0)
2522  APIERROR (pop->getNdbError());
2523 
2524  Uint32 comparisonValue= 10;
2525 
2526  // if *ATTR3 > comparisonValue, goto Label 0
2527  if (pop->branch_col_lt(pattr3Col->getColumnNo(),
2528  &comparisonValue,
2529  sizeof(Uint32),
2530  false,
2531  0) != 0)
2532  APIERROR (pop->getNdbError());
2533 
2534  // assert(false)
2535  // Fail the operation with error 627 if we get here.
2536  if (pop->interpret_exit_nok(627) != 0)
2537  APIERROR (pop->getNdbError());
2538 
2539  // Label 0
2540  if (pop->def_label(0) != 0)
2541  APIERROR (pop->getNdbError());
2542 
2543  Uint32 comparisonValue2= 344;
2544 
2545  // if *ATTR2 == comparisonValue, goto Label 1
2546  if (pop->branch_col_eq(pattr2Col->getColumnNo(),
2547  &comparisonValue2,
2548  sizeof(Uint32),
2549  false,
2550  1) != 0)
2551  APIERROR (pop->getNdbError());
2552 
2553  // assert(false)
2554  // Fail the operation with error 628 if we get here
2555  if (pop->interpret_exit_nok(628) != 0)
2556  APIERROR (pop->getNdbError());
2557 
2558  // Label 1
2559  if (pop->def_label(1) != 1)
2560  APIERROR (pop->getNdbError());
2561 
2562  // Optional infinite loop
2563  //if (pop->branch_label(0) != 0)
2564  // APIERROR (pop->getNdbError());
2565 
2566  // R1 = 10
2567  if (pop->load_const_u32(R1, 10) != 0)
2568  APIERROR (pop->getNdbError());
2569 
2570  // R3 = 2
2571  if (pop->load_const_u32(R3, 2) != 0)
2572  APIERROR (pop->getNdbError());
2573 
2574  // Now call subroutine 0
2575  if (pop->call_sub(0) != 0)
2576  APIERROR (pop->getNdbError());
2577 
2578  // *ATTR2= R2
2579  if (pop->write_attr("ATTR2", R2) != 0)
2580  APIERROR (pop->getNdbError());
2581 
2582  // Return ok, we'll move onto an update.
2583  if (pop->interpret_exit_ok() != 0)
2584  APIERROR (pop->getNdbError());
2585 
2586  /* Define a final read of the columns after the update */
2587  recAttrAttr11= pop->getValue("ATTR1");
2588  recAttrAttr12= pop->getValue("ATTR2");
2589  recAttrAttr13= pop->getValue("ATTR3");
2590 
2591  // Define any subroutines called by the 'main' program
2592  // Subroutine 0
2593  if (pop->def_subroutine(0) != 0)
2594  APIERROR (pop->getNdbError());
2595 
2596  // R4= 1
2597  if (pop->load_const_u32(R4, 1) != 0)
2598  APIERROR (pop->getNdbError());
2599 
2600  // Label 2
2601  if (pop->def_label(2) != 2)
2602  APIERROR (pop->getNdbError());
2603 
2604  // R3= R3-R4
2605  if (pop->sub_reg(R3, R4, R3) != 0)
2606  APIERROR (pop->getNdbError());
2607 
2608  // R2= R2 + R1
2609  if (pop->add_reg(R2, R1, R2) != 0)
2610  APIERROR (pop->getNdbError());
2611 
2612  // Optional infinite loop
2613  // if (pop->branch_label(2) != 0)
2614  // APIERROR (pop->getNdbError());
2615 
2616  // Loop, subtracting 1 from R4 until R4 < 1
2617  if (pop->branch_ge(R4, R3, 2) != 0)
2618  APIERROR (pop->getNdbError());
2619 
2620  // Jump to label 3
2621  if (pop->branch_label(3) != 0)
2622  APIERROR (pop->getNdbError());
2623 
2624  // assert(false)
2625  // Fail operation with error 629
2626  if (pop->interpret_exit_nok(629) != 0)
2627  APIERROR (pop->getNdbError());
2628 
2629  // Label 3
2630  if (pop->def_label(3) != 3)
2631  APIERROR (pop->getNdbError());
2632 
2633  // Nested subroutine call to sub 2
2634  if (pop->call_sub(2) != 0)
2635  APIERROR (pop->getNdbError());
2636 
2637  // Return from subroutine 0
2638  if (pop->ret_sub() !=0)
2639  APIERROR (pop->getNdbError());
2640 
2641  // Subroutine 1
2642  if (pop->def_subroutine(1) != 1)
2643  APIERROR (pop->getNdbError());
2644 
2645  // R6= R1+R2
2646  if (pop->add_reg(R1, R2, R6) != 0)
2647  APIERROR (pop->getNdbError());
2648 
2649  // Return from subrouine 1
2650  if (pop->ret_sub() !=0)
2651  APIERROR (pop->getNdbError());
2652 
2653  // Subroutine 2
2654  if (pop->def_subroutine(2) != 2)
2655  APIERROR (pop->getNdbError());
2656 
2657  // Call backwards to subroutine 1
2658  if (pop->call_sub(1) != 0)
2659  APIERROR (pop->getNdbError());
2660 
2661  // Return from subroutine 2
2662  if (pop->ret_sub() !=0)
2663  APIERROR (pop->getNdbError());
2664 
2665  break;
2666  }
2667  case api_record :
2668  {
2669  const NdbOperation *pop;
2670  rowData.attr1= 4;
2671  /* NdbRecord does not support an updateTuple pre-read or post-read, so
2672  * we use separate operations for these.
2673  * Note that this assumes that a operations are executed in
2674  * the order they are defined by NDBAPI, which is not guaranteed. To ensure
2675  * execution order, the application should perform a NoCommit execute between
2676  * operations.
2677  */
2678  const NdbOperation *op0= myTransaction->readTuple(pkeyColumnRecord,
2679  (char*) &rowData,
2680  pallColsRecord,
2681  (char*) &rowData);
2682  if (op0 == NULL)
2683  APIERROR (myTransaction->getNdbError());
2684 
2685  /* Allocate some space to define an Interpreted program */
2686  const Uint32 numWords= 64;
2687  Uint32 space[numWords];
2688 
2689  NdbInterpretedCode stackCode(myTable,
2690  &space[0],
2691  numWords);
2692 
2693  NdbInterpretedCode *code= &stackCode;
2694 
2695  /* Similar program as above, with tortuous control flow and little
2696  * purpose. Note that for NdbInterpretedCode, some instruction
2697  * arguments are in different orders
2698  */
2699 
2700  // R5= 3
2701  if (code->load_const_u32(R5, 3) != 0)
2702  APIERROR(code->getNdbError());
2703 
2704  // R1= *ATTR1; R2= *ATTR2; R3= *ATTR3
2705  if (code->read_attr(R1, pattr1Col) != 0)
2706  APIERROR (code->getNdbError());
2707  if (code->read_attr(R2, pattr2Col) != 0)
2708  APIERROR (code->getNdbError());
2709  if (code->read_attr(R3, pattr3Col) != 0)
2710  APIERROR (code->getNdbError());
2711 
2712  // R3= R3-R5
2713  if (code->sub_reg(R3, R3, R5) != 0)
2714  APIERROR (code->getNdbError());
2715 
2716  // R2= R1+R2
2717  if (code->add_reg(R2, R1, R2) != 0)
2718  APIERROR (code->getNdbError());
2719 
2720  // *ATTR2= R2
2721  if (code->write_attr(pattr2Col, R2) != 0)
2722  APIERROR (code->getNdbError());
2723 
2724  // *ATTR3= R3
2725  if (code->write_attr(pattr3Col, R3) != 0)
2726  APIERROR (code->getNdbError());
2727 
2728  // *ATTR3 = *ATTR3 - 30
2729  if (code->sub_val(pattr3Col->getColumnNo(), (Uint32)30) != 0)
2730  APIERROR (code->getNdbError());
2731 
2732  Uint32 comparisonValue= 10;
2733 
2734  // if comparisonValue < *ATTR3, goto Label 0
2735  if (code->branch_col_lt(&comparisonValue,
2736  sizeof(Uint32),
2737  pattr3Col->getColumnNo(),
2738  0) != 0)
2739  APIERROR (code->getNdbError());
2740 
2741  // assert(false)
2742  // Fail operation with error 627
2743  if (code->interpret_exit_nok(627) != 0)
2744  APIERROR (code->getNdbError());
2745 
2746  // Label 0
2747  if (code->def_label(0) != 0)
2748  APIERROR (code->getNdbError());
2749 
2750  Uint32 comparisonValue2= 344;
2751 
2752  // if *ATTR2 == comparisonValue, goto Label 1
2753  if (code->branch_col_eq(&comparisonValue2,
2754  sizeof(Uint32),
2755  pattr2Col->getColumnNo(),
2756  1) != 0)
2757  APIERROR (code->getNdbError());
2758 
2759  // assert(false)
2760  // Fail operation with error 628
2761  if (code->interpret_exit_nok(628) != 0)
2762  APIERROR (code->getNdbError());
2763 
2764  // Label 1
2765  if (code->def_label(1) != 0)
2766  APIERROR (code->getNdbError());
2767 
2768  // R1= 10
2769  if (code->load_const_u32(R1, 10) != 0)
2770  APIERROR (code->getNdbError());
2771 
2772  // R3= 2
2773  if (code->load_const_u32(R3, 2) != 0)
2774  APIERROR (code->getNdbError());
2775 
2776  // Call subroutine 0 to effect
2777  // R2 = R2 + (R1*R3)
2778  if (code->call_sub(0) != 0)
2779  APIERROR (code->getNdbError());
2780 
2781  // *ATTR2= R2
2782  if (code->write_attr(pattr2Col, R2) != 0)
2783  APIERROR (code->getNdbError());
2784 
2785  // Return ok
2786  if (code->interpret_exit_ok() != 0)
2787  APIERROR (code->getNdbError());
2788 
2789  // Subroutine 0
2790  if (code->def_sub(0) != 0)
2791  APIERROR (code->getNdbError());
2792 
2793  // R4= 1
2794  if (code->load_const_u32(R4, 1) != 0)
2795  APIERROR (code->getNdbError());
2796 
2797  // Label 2
2798  if (code->def_label(2) != 0)
2799  APIERROR (code->getNdbError());
2800 
2801  // R3= R3-R4
2802  if (code->sub_reg(R3, R3, R4) != 0)
2803  APIERROR (code->getNdbError());
2804 
2805  // R2= R2+R1
2806  if (code->add_reg(R2, R2, R1) != 0)
2807  APIERROR (code->getNdbError());
2808 
2809  // Loop, subtracting 1 from R4 until R4>1
2810  if (code->branch_ge(R3, R4, 2) != 0)
2811  APIERROR (code->getNdbError());
2812 
2813  // Jump to label 3
2814  if (code->branch_label(3) != 0)
2815  APIERROR (code->getNdbError());
2816 
2817  // Fail operation with error 629
2818  if (code->interpret_exit_nok(629) != 0)
2819  APIERROR (code->getNdbError());
2820 
2821  // Label 3
2822  if (code->def_label(3) != 0)
2823  APIERROR (code->getNdbError());
2824 
2825  // Call sub 2
2826  if (code->call_sub(2) != 0)
2827  APIERROR (code->getNdbError());
2828 
2829  // Return from sub 0
2830  if (code->ret_sub() != 0)
2831  APIERROR (code->getNdbError());
2832 
2833  // Subroutine 1
2834  if (code->def_sub(1) != 0)
2835  APIERROR (code->getNdbError());
2836 
2837  // R6= R1+R2
2838  if (code->add_reg(R6, R1, R2) != 0)
2839  APIERROR (code->getNdbError());
2840 
2841  // Return from subroutine 1
2842  if (code->ret_sub() !=0)
2843  APIERROR (code->getNdbError());
2844 
2845  // Subroutine 2
2846  if (code->def_sub(2) != 0)
2847  APIERROR (code->getNdbError());
2848 
2849  // Call backwards to subroutine 1
2850  if (code->call_sub(1) != 0)
2851  APIERROR (code->getNdbError());
2852 
2853  // Return from subroutine 2
2854  if (code->ret_sub() !=0)
2855  APIERROR (code->getNdbError());
2856 
2857  /* Finalise code object
2858  * This step is essential for NdbInterpretedCode objects
2859  * and must be done before they can be used.
2860  */
2861  if (code->finalise() !=0)
2862  APIERROR (code->getNdbError());
2863 
2864  /* Time to define the update operation to use the
2865  * InterpretedCode object. The same finalised object
2866  * could be used with multiple operations or even
2867  * multiple threads
2868  */
2870  oo.optionsPresent=
2871  NdbOperation::OperationOptions::OO_INTERPRETED;
2872  oo.interpretedCode= code;
2873 
2874  unsigned char mask= 0;
2875 
2876  pop= myTransaction->updateTuple(pkeyColumnRecord,
2877  (char*) &rowData,
2878  pallColsRecord,
2879  (char*) &rowData,
2880  (const unsigned char *) &mask, // mask - update nothing
2881  &oo,
2883  if (pop == NULL)
2884  APIERROR (myTransaction->getNdbError());
2885 
2886  // NoCommit execute so we can read the 'after' data.
2887  if (myTransaction->execute( NdbTransaction::NoCommit ) != 0)
2888  APIERROR(myTransaction->getNdbError());
2889 
2890  /* Second read op as we can't currently do a 'read after
2891  * 'interpreted code' read as part of NdbRecord.
2892  * We are assuming that the order of op definition == order
2893  * of execution on a single row, which is not guaranteed.
2894  */
2895  const NdbOperation *pop2=
2896  myTransaction->readTuple(pkeyColumnRecord,
2897  (char*) &rowData,
2898  pallColsRecord,
2899  (char*) &rowData2);
2900  if (pop2 == NULL)
2901  APIERROR (myTransaction->getNdbError());
2902 
2903  break;
2904  }
2905  default :
2906  {
2907  std::cout << "Bad branch : " << accessType << "\n";
2908  exit(-1);
2909  }
2910  }
2911 
2912  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
2913  APIERROR(myTransaction->getNdbError());
2914 
2915  // Check return code
2916  if (myTransaction->getNdbError().status != NdbError::Success)
2917  APIERROR(myTransaction->getNdbError());
2918 
2919  switch (accessType)
2920  {
2921  case api_attr :
2922  {
2923  printf(" %2d %2d %2d Before\n"
2924  " %2d %2d %2d After\n",
2925  recAttrAttr1->u_32_value(),
2926  recAttrAttr2->u_32_value(),
2927  recAttrAttr3->u_32_value(),
2928  recAttrAttr11->u_32_value(),
2929  recAttrAttr12->u_32_value(),
2930  recAttrAttr13->u_32_value());
2931  break;
2932  }
2933 
2934  case api_record :
2935  {
2936  printf(" %2d %2d %2d Before\n"
2937  " %2d %2d %2d After\n",
2938  rowData.attr1,
2939  rowData.attr2,
2940  rowData.attr3,
2941  rowData2.attr1,
2942  rowData2.attr2,
2943  rowData2.attr3);
2944  break;
2945  }
2946  default :
2947  {
2948  std::cout << "Bad branch : " << accessType << "\n";
2949  exit(-1);
2950  }
2951  }
2952 
2953  if(myTransaction->execute( NdbTransaction::Commit ) !=0)
2954  APIERROR(myTransaction->getNdbError());
2955 
2956  myNdb.closeTransaction(myTransaction);
2957 
2958  std::cout << "-------\n";
2959 }
2960 
2961 
2962 /******************************************************
2963  * Read and print selected rows with interpreted code *
2964  ******************************************************/
2965 static void do_interpreted_scan(Ndb &myNdb, ApiType accessType)
2966 {
2967  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
2968  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
2969 
2970  std::cout << "Running do_interpreted_scan\n";
2971 
2972  if (myTable == NULL)
2973  APIERROR(myDict->getNdbError());
2974 
2975  std::cout << "ATTR1 ATTR2 ATTR3" << std::endl;
2976 
2977  NdbTransaction *myTransaction=myNdb.startTransaction();
2978  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
2979 
2980  NdbScanOperation *psop;
2981  NdbRecAttr *recAttrAttr1;
2982  NdbRecAttr *recAttrAttr2;
2983  NdbRecAttr *recAttrAttr3;
2984 
2985  /* Create some space on the stack for the program */
2986  const Uint32 numWords= 64;
2987  Uint32 space[numWords];
2988 
2989  NdbInterpretedCode stackCode(myTable,
2990  &space[0],
2991  numWords);
2992 
2993  NdbInterpretedCode *code= &stackCode;
2994 
2995  /* RecAttr and NdbRecord scans both use NdbInterpretedCode
2996  * Let's define a small scan filter of sorts
2997  */
2998  Uint32 comparisonValue= 10;
2999 
3000  // Return rows where 10 > ATTR3 (ATTR3 <10)
3001  if (code->branch_col_gt(&comparisonValue,
3002  sizeof(Uint32),
3003  pattr3Col->getColumnNo(),
3004  0) != 0)
3005  APIERROR (myTransaction->getNdbError());
3006 
3007  /* If we get here then we don't return this row */
3008  if (code->interpret_exit_nok() != 0)
3009  APIERROR (myTransaction->getNdbError());
3010 
3011  /* Label 0 */
3012  if (code->def_label(0) != 0)
3013  APIERROR (myTransaction->getNdbError());
3014 
3015  /* Return this row */
3016  if (code->interpret_exit_ok() != 0)
3017  APIERROR (myTransaction->getNdbError());
3018 
3019  /* Finalise the Interpreted Program */
3020  if (code->finalise() != 0)
3021  APIERROR (myTransaction->getNdbError());
3022 
3023  switch (accessType)
3024  {
3025  case api_attr :
3026  {
3027  psop=myTransaction->getNdbScanOperation(myTable);
3028 
3029  if (psop == NULL) APIERROR(myTransaction->getNdbError());
3030 
3031  if (psop->readTuples(NdbOperation::LM_Read) != 0) APIERROR (myTransaction->getNdbError());
3032 
3033  if (psop->setInterpretedCode(code) != 0)
3034  APIERROR (myTransaction->getNdbError());
3035 
3036  recAttrAttr1=psop->getValue("ATTR1");
3037  recAttrAttr2=psop->getValue("ATTR2");
3038  recAttrAttr3=psop->getValue("ATTR3");
3039 
3040  break;
3041  }
3042  case api_record :
3043  {
3045 
3046  so.optionsPresent = NdbScanOperation::ScanOptions::SO_INTERPRETED;
3047  so.interpretedCode= code;
3048 
3049  psop=myTransaction->scanTable(pallColsRecord,
3051  NULL, // mask
3052  &so,
3054 
3055  if (psop == NULL) APIERROR(myTransaction->getNdbError());
3056 
3057  break;
3058  }
3059  default :
3060  {
3061  std::cout << "Bad branch : " << accessType << "\n";
3062  exit(-1);
3063  }
3064  }
3065 
3066  if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
3067  APIERROR(myTransaction->getNdbError());
3068 
3069  switch (accessType)
3070  {
3071  case api_attr :
3072  {
3073  while (psop->nextResult(true) == 0)
3074  {
3075  printf(" %2d %2d %2d\n",
3076  recAttrAttr1->u_32_value(),
3077  recAttrAttr2->u_32_value(),
3078  recAttrAttr3->u_32_value());
3079  }
3080 
3081  psop->close();
3082 
3083  break;
3084  }
3085  case api_record :
3086  {
3087  RowData *prowData; // Ptr to point to our data
3088 
3089  int rc=0;
3090 
3091  while ((rc = psop->nextResult((const char**) &prowData,
3092  true,
3093  false)) == GOT_ROW)
3094  {
3095  printf(" %2d %2d %2d\n",
3096  prowData->attr1,
3097  prowData->attr2,
3098  prowData->attr3);
3099  }
3100 
3101  if (rc != NO_MORE_ROWS) APIERROR(myTransaction->getNdbError());
3102 
3103  psop->close(true);
3104 
3105  break;
3106  }
3107  default :
3108  {
3109  std::cout << "Bad branch : " << accessType << "\n";
3110  exit(-1);
3111  }
3112  }
3113 
3114  if(myTransaction->execute( NdbTransaction::Commit ) !=0)
3115  APIERROR(myTransaction->getNdbError());
3116 
3117  myNdb.closeTransaction(myTransaction);
3118 
3119  std::cout << "-------\n";
3120 }
3121 
3122 /******************************************************
3123  * Read some data using the default NdbRecord objects *
3124  ******************************************************/
3125 static void do_read_using_default(Ndb &myNdb)
3126 {
3127  NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
3128  const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
3129  const NdbRecord* tableRec= myTable->getDefaultRecord();
3130 
3131  if (myTable == NULL)
3132  APIERROR(myDict->getNdbError());
3133 
3134  std::cout << "Running do_read_using_default_record (NdbRecord only)\n";
3135  std::cout << "ATTR1 ATTR2 ATTR3" << std::endl;
3136 
3137  /* Allocate some space for the rows to be read into */
3138  char* buffer= (char*)malloc(NdbDictionary::getRecordRowLength(tableRec));
3139 
3140  if (buffer== NULL)
3141  {
3142  printf("Allocation failed\n");
3143  exit(-1);
3144  }
3145 
3146  for (int i = 0; i < 10; i++) {
3147  NdbTransaction *myTransaction= myNdb.startTransaction();
3148  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
3149 
3150  char* attr1= NdbDictionary::getValuePtr(tableRec,
3151  buffer,
3152  attr1ColNum);
3153  *((unsigned int*)attr1)= i;
3154 
3155  const NdbOperation *pop=
3156  myTransaction->readTuple(tableRec,
3157  buffer,
3158  tableRec, // Read everything
3159  buffer);
3160  if (pop==NULL) APIERROR(myTransaction->getNdbError());
3161 
3162  if(myTransaction->execute( NdbTransaction::Commit ) == -1)
3163  APIERROR(myTransaction->getNdbError());
3164 
3165  NdbError err= myTransaction->getNdbError();
3166  if (err.code != 0)
3167  {
3169  std::cout << "Detected that tuple " << i << " doesn't exist!" << std::endl;
3170  else
3171  APIERROR(myTransaction->getNdbError());
3172  }
3173  else
3174  {
3175  printf(" %2d %2d %2d\n",
3176  i,
3177  *((unsigned int*) NdbDictionary::getValuePtr(tableRec,
3178  buffer,
3179  attr2ColNum)),
3180  *((unsigned int*) NdbDictionary::getValuePtr(tableRec,
3181  buffer,
3182  attr3ColNum)));
3183  }
3184 
3185  myNdb.closeTransaction(myTransaction);
3186  }
3187 
3188  free(buffer);
3189 
3190  std::cout << "-------\n";
3191 }