1 
2 /*
3    Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License, version 2.0,
7    as published by the Free Software Foundation.
8 
9    This program is also distributed with certain software (including
10    but not limited to OpenSSL) that is licensed under separate terms,
11    as designated in a particular file or component or in included license
12    documentation.  The authors of MySQL hereby grant you an additional
13    permission to link the program and your derivative works with the
14    separately licensed software that they have included with MySQL.
15 
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License, version 2.0, for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
24 */
25 
26 
27 /*
28  * ndbapi_scan.cpp:
29  * Illustrates how to use the scan api in the NDBAPI.
30  * The example shows how to do scan, scan for update and scan for delete
31  * using NdbScanFilter and NdbScanOperation
32  *
33  * Classes and methods used in this example:
34  *
35  *  Ndb_cluster_connection
36  *       connect()
37  *       wait_until_ready()
38  *
39  *  Ndb
40  *       init()
41  *       getDictionary()
42  *       startTransaction()
43  *       closeTransaction()
44  *
45  *  NdbTransaction
46  *       getNdbScanOperation()
47  *       execute()
48  *
49  *  NdbScanOperation
50  *       getValue()
51  *       readTuples()
52  *       nextResult()
53  *       deleteCurrentTuple()
54  *       updateCurrentTuple()
55  *
56  *  const NdbDictionary::Dictionary
57  *       getTable()
58  *
59  *  const NdbDictionary::Table
60  *       getColumn()
61  *
62  *  const NdbDictionary::Column
63  *       getLength()
64  *
65  *  NdbOperation
66  *       insertTuple()
67  *       equal()
68  *       setValue()
69  *
70  *  NdbScanFilter
71  *       begin()
72  *	 eq()
73  *	 end()
74  *
75  */
76 
77 
78 #include <mysql.h>
79 #include <mysqld_error.h>
80 #include <NdbApi.hpp>
81 // Used for cout
82 #include <iostream>
83 #include <stdio.h>
84 #include <string.h>
85 #include <stdlib.h>
86 
87 /**
88  * Helper sleep function
89  */
90 static void
milliSleep(int milliseconds)91 milliSleep(int milliseconds){
92   struct timeval sleeptime;
93   sleeptime.tv_sec = milliseconds / 1000;
94   sleeptime.tv_usec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000;
95   select(0, 0, 0, 0, &sleeptime);
96 }
97 
98 
99 /**
100  * Helper debugging macros
101  */
102 #define PRINT_ERROR(code,msg) \
103   std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
104             << ", code: " << code \
105             << ", msg: " << msg << "." << std::endl
106 #define MYSQLERROR(mysql) { \
107   PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
108   exit(-1); }
109 #define APIERROR(error) { \
110   PRINT_ERROR(error.code,error.message); \
111   exit(-1); }
112 
113 struct Car
114 {
115   /**
116    * Note memset, so that entire char-fields are cleared
117    *   as all 20 bytes are significant (as type is char)
118    */
CarCar119   Car() { memset(this, 0, sizeof(* this)); }
120 
121   unsigned int reg_no;
122   char brand[20];
123   char color[20];
124 };
125 
126 /**
127  * Function to drop table
128  */
drop_table(MYSQL & mysql)129 void drop_table(MYSQL &mysql)
130 {
131   if (mysql_query(&mysql, "DROP TABLE IF EXISTS api_scan"))
132     MYSQLERROR(mysql);
133 }
134 
135 
136 /**
137  * Function to create table
138  */
create_table(MYSQL & mysql)139 void create_table(MYSQL &mysql)
140 {
141   while (mysql_query(&mysql,
142 		  "CREATE TABLE"
143 		  "  api_scan"
144 		  "    (REG_NO INT UNSIGNED NOT NULL,"
145 		  "     BRAND CHAR(20) NOT NULL,"
146 		  "     COLOR CHAR(20) NOT NULL,"
147 		  "     PRIMARY KEY USING HASH (REG_NO))"
148 		  "  ENGINE=NDB"))
149   {
150     if (mysql_errno(&mysql) != ER_TABLE_EXISTS_ERROR)
151       MYSQLERROR(mysql);
152     std::cout << "MySQL Cluster already has example table: api_scan. "
153 	      << "Dropping it..." << std::endl;
154     drop_table(mysql);
155   }
156 }
157 
populate(Ndb * myNdb)158 int populate(Ndb * myNdb)
159 {
160   int i;
161   Car cars[15];
162 
163   const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
164   const NdbDictionary::Table *myTable= myDict->getTable("api_scan");
165 
166   if (myTable == NULL)
167     APIERROR(myDict->getNdbError());
168 
169   /**
170    * Five blue mercedes
171    */
172   for (i = 0; i < 5; i++)
173   {
174     cars[i].reg_no = i;
175     sprintf(cars[i].brand, "Mercedes");
176     sprintf(cars[i].color, "Blue");
177   }
178 
179   /**
180    * Five black bmw
181    */
182   for (i = 5; i < 10; i++)
183   {
184     cars[i].reg_no = i;
185     sprintf(cars[i].brand, "BMW");
186     sprintf(cars[i].color, "Black");
187   }
188 
189   /**
190    * Five pink toyotas
191    */
192   for (i = 10; i < 15; i++)
193   {
194     cars[i].reg_no = i;
195     sprintf(cars[i].brand, "Toyota");
196     sprintf(cars[i].color, "Pink");
197   }
198 
199   NdbTransaction* myTrans = myNdb->startTransaction();
200   if (myTrans == NULL)
201     APIERROR(myNdb->getNdbError());
202 
203   for (i = 0; i < 15; i++)
204   {
205     NdbOperation* myNdbOperation = myTrans->getNdbOperation(myTable);
206     if (myNdbOperation == NULL)
207       APIERROR(myTrans->getNdbError());
208     myNdbOperation->insertTuple();
209     myNdbOperation->equal("REG_NO", cars[i].reg_no);
210     myNdbOperation->setValue("BRAND", cars[i].brand);
211     myNdbOperation->setValue("COLOR", cars[i].color);
212   }
213 
214   int check = myTrans->execute(NdbTransaction::Commit);
215 
216   myTrans->close();
217 
218   return check != -1;
219 }
220 
scan_delete(Ndb * myNdb,int column,const char * color)221 int scan_delete(Ndb* myNdb,
222 		int column,
223 		const char * color)
224 
225 {
226 
227   // Scan all records exclusive and delete
228   // them one by one
229   int                  retryAttempt = 0;
230   const int            retryMax = 10;
231   int deletedRows = 0;
232   int check;
233   NdbError              err;
234   NdbTransaction	*myTrans;
235   NdbScanOperation	*myScanOp;
236 
237   const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
238   const NdbDictionary::Table *myTable= myDict->getTable("api_scan");
239 
240   if (myTable == NULL)
241     APIERROR(myDict->getNdbError());
242 
243   /**
244    * Loop as long as :
245    *  retryMax not reached
246    *  failed operations due to TEMPORARY erros
247    *
248    * Exit loop;
249    *  retyrMax reached
250    *  Permanent error (return -1)
251    */
252   while (true)
253   {
254     if (retryAttempt >= retryMax)
255     {
256       std::cout << "ERROR: has retried this operation " << retryAttempt
257 		<< " times, failing!" << std::endl;
258       return -1;
259     }
260 
261     myTrans = myNdb->startTransaction();
262     if (myTrans == NULL)
263     {
264       const NdbError err = myNdb->getNdbError();
265 
266       if (err.status == NdbError::TemporaryError)
267       {
268 	milliSleep(50);
269 	retryAttempt++;
270 	continue;
271       }
272       std::cout <<  err.message << std::endl;
273       return -1;
274     }
275 
276    /**
277     * Get a scan operation.
278     */
279     myScanOp = myTrans->getNdbScanOperation(myTable);
280     if (myScanOp == NULL)
281     {
282       std::cout << myTrans->getNdbError().message << std::endl;
283       myNdb->closeTransaction(myTrans);
284       return -1;
285     }
286 
287     /**
288      * Define a result set for the scan.
289      */
290     if(myScanOp->readTuples(NdbOperation::LM_Exclusive) != 0)
291     {
292       std::cout << myTrans->getNdbError().message << std::endl;
293       myNdb->closeTransaction(myTrans);
294       return -1;
295     }
296 
297     /**
298      * Use NdbScanFilter to define a search critera
299      */
300     NdbScanFilter filter(myScanOp) ;
301     if(filter.begin(NdbScanFilter::AND) < 0  ||
302        filter.cmp(NdbScanFilter::COND_EQ, column, color, 20) < 0 ||
303        filter.end() < 0)
304     {
305       std::cout <<  myTrans->getNdbError().message << std::endl;
306       myNdb->closeTransaction(myTrans);
307       return -1;
308     }
309 
310     /**
311      * Start scan    (NoCommit since we are only reading at this stage);
312      */
313     if(myTrans->execute(NdbTransaction::NoCommit) != 0){
314       err = myTrans->getNdbError();
315       if(err.status == NdbError::TemporaryError){
316 	std::cout << myTrans->getNdbError().message << std::endl;
317 	myNdb->closeTransaction(myTrans);
318 	milliSleep(50);
319 	continue;
320       }
321       std::cout << err.code << std::endl;
322       std::cout << myTrans->getNdbError().code << std::endl;
323       myNdb->closeTransaction(myTrans);
324       return -1;
325     }
326 
327 
328    /**
329     * start of loop: nextResult(true) means that "parallelism" number of
330     * rows are fetched from NDB and cached in NDBAPI
331     */
332     while((check = myScanOp->nextResult(true)) == 0){
333       do
334       {
335 	if (myScanOp->deleteCurrentTuple() != 0)
336 	{
337 	  std::cout << myTrans->getNdbError().message << std::endl;
338 	  myNdb->closeTransaction(myTrans);
339 	  return -1;
340 	}
341 	deletedRows++;
342 
343 	/**
344 	 * nextResult(false) means that the records
345 	 * cached in the NDBAPI are modified before
346 	 * fetching more rows from NDB.
347 	 */
348       } while((check = myScanOp->nextResult(false)) == 0);
349 
350       /**
351        * NoCommit when all cached tuple have been marked for deletion
352        */
353       if(check != -1)
354       {
355 	check = myTrans->execute(NdbTransaction::NoCommit);
356       }
357 
358       /**
359        * Check for errors
360        */
361       err = myTrans->getNdbError();
362       if(check == -1)
363       {
364 	if(err.status == NdbError::TemporaryError)
365 	{
366 	  std::cout << myTrans->getNdbError().message << std::endl;
367 	  myNdb->closeTransaction(myTrans);
368 	  milliSleep(50);
369 	  continue;
370 	}
371       }
372       /**
373        * End of loop
374        */
375     }
376     /**
377      * Commit all prepared operations
378      */
379     if(myTrans->execute(NdbTransaction::Commit) == -1)
380     {
381       if(err.status == NdbError::TemporaryError){
382 	std::cout << myTrans->getNdbError().message << std::endl;
383 	myNdb->closeTransaction(myTrans);
384 	milliSleep(50);
385 	continue;
386       }
387     }
388 
389     std::cout << myTrans->getNdbError().message << std::endl;
390     myNdb->closeTransaction(myTrans);
391     return 0;
392   }
393 
394   if(myTrans!=0)
395   {
396     std::cout << myTrans->getNdbError().message << std::endl;
397     myNdb->closeTransaction(myTrans);
398   }
399   return -1;
400 }
401 
402 
scan_update(Ndb * myNdb,int update_column,const char * before_color,const char * after_color)403 int scan_update(Ndb* myNdb,
404 		int update_column,
405 		const char * before_color,
406 		const char * after_color)
407 
408 {
409 
410   // Scan all records exclusive and update
411   // them one by one
412   int                  retryAttempt = 0;
413   const int            retryMax = 10;
414   int updatedRows = 0;
415   int check;
416   NdbError              err;
417   NdbTransaction	*myTrans;
418   NdbScanOperation	*myScanOp;
419 
420   const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
421   const NdbDictionary::Table *myTable= myDict->getTable("api_scan");
422 
423   if (myTable == NULL)
424     APIERROR(myDict->getNdbError());
425 
426   /**
427    * Loop as long as :
428    *  retryMax not reached
429    *  failed operations due to TEMPORARY erros
430    *
431    * Exit loop;
432    *  retryMax reached
433    *  Permanent error (return -1)
434    */
435   while (true)
436   {
437 
438     if (retryAttempt >= retryMax)
439     {
440       std::cout << "ERROR: has retried this operation " << retryAttempt
441 		<< " times, failing!" << std::endl;
442       return -1;
443     }
444 
445     myTrans = myNdb->startTransaction();
446     if (myTrans == NULL)
447     {
448       const NdbError err = myNdb->getNdbError();
449 
450       if (err.status == NdbError::TemporaryError)
451       {
452 	milliSleep(50);
453 	retryAttempt++;
454 	continue;
455       }
456       std::cout <<  err.message << std::endl;
457       return -1;
458     }
459 
460    /**
461     * Get a scan operation.
462     */
463     myScanOp = myTrans->getNdbScanOperation(myTable);
464     if (myScanOp == NULL)
465     {
466       std::cout << myTrans->getNdbError().message << std::endl;
467       myNdb->closeTransaction(myTrans);
468       return -1;
469     }
470 
471     /**
472      * Define a result set for the scan.
473      */
474     if( myScanOp->readTuples(NdbOperation::LM_Exclusive) )
475     {
476       std::cout << myTrans->getNdbError().message << std::endl;
477       myNdb->closeTransaction(myTrans);
478       return -1;
479     }
480 
481     /**
482      * Use NdbScanFilter to define a search critera
483      */
484     NdbScanFilter filter(myScanOp) ;
485     if(filter.begin(NdbScanFilter::AND) < 0  ||
486        filter.cmp(NdbScanFilter::COND_EQ, update_column, before_color, 20) <0||
487        filter.end() <0)
488     {
489       std::cout <<  myTrans->getNdbError().message << std::endl;
490       myNdb->closeTransaction(myTrans);
491       return -1;
492     }
493 
494     /**
495      * Start scan    (NoCommit since we are only reading at this stage);
496      */
497     if(myTrans->execute(NdbTransaction::NoCommit) != 0)
498     {
499       err = myTrans->getNdbError();
500       if(err.status == NdbError::TemporaryError){
501 	std::cout << myTrans->getNdbError().message << std::endl;
502 	myNdb->closeTransaction(myTrans);
503 	milliSleep(50);
504 	continue;
505       }
506       std::cout << myTrans->getNdbError().code << std::endl;
507       myNdb->closeTransaction(myTrans);
508       return -1;
509     }
510 
511     /**
512      * start of loop: nextResult(true) means that "parallelism" number of
513      * rows are fetched from NDB and cached in NDBAPI
514      */
515     while((check = myScanOp->nextResult(true)) == 0){
516       do {
517 	/**
518 	 * Get update operation
519 	 */
520 	NdbOperation * myUpdateOp = myScanOp->updateCurrentTuple();
521 	if (myUpdateOp == 0)
522 	{
523 	  std::cout << myTrans->getNdbError().message << std::endl;
524 	  myNdb->closeTransaction(myTrans);
525 	  return -1;
526 	}
527 	updatedRows++;
528 
529 	/**
530 	 * do the update
531 	 */
532 	myUpdateOp->setValue(update_column, after_color);
533 	/**
534 	 * nextResult(false) means that the records
535 	 * cached in the NDBAPI are modified before
536 	 * fetching more rows from NDB.
537 	 */
538       } while((check = myScanOp->nextResult(false)) == 0);
539 
540       /**
541        * NoCommit when all cached tuple have been updated
542        */
543       if(check != -1)
544       {
545 	check = myTrans->execute(NdbTransaction::NoCommit);
546       }
547 
548       /**
549        * Check for errors
550        */
551       err = myTrans->getNdbError();
552       if(check == -1)
553       {
554 	if(err.status == NdbError::TemporaryError){
555 	  std::cout << myTrans->getNdbError().message << std::endl;
556 	  myNdb->closeTransaction(myTrans);
557 	  milliSleep(50);
558 	  continue;
559 	}
560       }
561       /**
562        * End of loop
563        */
564     }
565 
566     /**
567      * Commit all prepared operations
568      */
569     if(myTrans->execute(NdbTransaction::Commit) == -1)
570     {
571       if(err.status == NdbError::TemporaryError){
572 	std::cout << myTrans->getNdbError().message << std::endl;
573 	myNdb->closeTransaction(myTrans);
574 	milliSleep(50);
575 	continue;
576       }
577     }
578 
579     std::cout << myTrans->getNdbError().message << std::endl;
580     myNdb->closeTransaction(myTrans);
581     return 0;
582   }
583 
584 
585   if(myTrans!=0)
586   {
587     std::cout << myTrans->getNdbError().message << std::endl;
588     myNdb->closeTransaction(myTrans);
589   }
590   return -1;
591 }
592 
593 
594 
scan_print(Ndb * myNdb)595 int scan_print(Ndb * myNdb)
596 {
597 // Scan all records exclusive and update
598   // them one by one
599   int                  retryAttempt = 0;
600   const int            retryMax = 10;
601   int fetchedRows = 0;
602   int check;
603   NdbError              err;
604   NdbTransaction	*myTrans;
605   NdbScanOperation	*myScanOp;
606   /* Result of reading attribute value, three columns:
607      REG_NO, BRAND, and COLOR
608    */
609   NdbRecAttr *    	myRecAttr[3];
610 
611   const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
612   const NdbDictionary::Table *myTable= myDict->getTable("api_scan");
613 
614   if (myTable == NULL)
615     APIERROR(myDict->getNdbError());
616 
617   /**
618    * Loop as long as :
619    *  retryMax not reached
620    *  failed operations due to TEMPORARY erros
621    *
622    * Exit loop;
623    *  retyrMax reached
624    *  Permanent error (return -1)
625    */
626   while (true)
627   {
628 
629     if (retryAttempt >= retryMax)
630     {
631       std::cout << "ERROR: has retried this operation " << retryAttempt
632 		<< " times, failing!" << std::endl;
633       return -1;
634     }
635 
636     myTrans = myNdb->startTransaction();
637     if (myTrans == NULL)
638     {
639       const NdbError err = myNdb->getNdbError();
640 
641       if (err.status == NdbError::TemporaryError)
642       {
643 	milliSleep(50);
644 	retryAttempt++;
645 	continue;
646       }
647      std::cout << err.message << std::endl;
648       return -1;
649     }
650     /*
651      * Define a scan operation.
652      * NDBAPI.
653      */
654     myScanOp = myTrans->getNdbScanOperation(myTable);
655     if (myScanOp == NULL)
656     {
657       std::cout << myTrans->getNdbError().message << std::endl;
658       myNdb->closeTransaction(myTrans);
659       return -1;
660     }
661 
662     /**
663      * Read without locks, without being placed in lock queue
664      */
665     if( myScanOp->readTuples(NdbOperation::LM_CommittedRead) == -1)
666     {
667       std::cout << myTrans->getNdbError().message << std::endl;
668       myNdb->closeTransaction(myTrans);
669       return -1;
670     }
671 
672     /**
673      * Define storage for fetched attributes.
674      * E.g., the resulting attributes of executing
675      * myOp->getValue("REG_NO") is placed in myRecAttr[0].
676      * No data exists in myRecAttr until transaction has commited!
677      */
678     myRecAttr[0] = myScanOp->getValue("REG_NO");
679     myRecAttr[1] = myScanOp->getValue("BRAND");
680     myRecAttr[2] = myScanOp->getValue("COLOR");
681     if(myRecAttr[0] ==NULL || myRecAttr[1] == NULL || myRecAttr[2]==NULL)
682     {
683 	std::cout << myTrans->getNdbError().message << std::endl;
684 	myNdb->closeTransaction(myTrans);
685 	return -1;
686     }
687     /**
688      * Start scan   (NoCommit since we are only reading at this stage);
689      */
690     if(myTrans->execute(NdbTransaction::NoCommit) != 0){
691       err = myTrans->getNdbError();
692       if(err.status == NdbError::TemporaryError){
693 	std::cout << myTrans->getNdbError().message << std::endl;
694 	myNdb->closeTransaction(myTrans);
695 	milliSleep(50);
696 	continue;
697       }
698       std::cout << err.code << std::endl;
699       std::cout << myTrans->getNdbError().code << std::endl;
700       myNdb->closeTransaction(myTrans);
701       return -1;
702     }
703 
704     /**
705      * start of loop: nextResult(true) means that "parallelism" number of
706      * rows are fetched from NDB and cached in NDBAPI
707      */
708     while((check = myScanOp->nextResult(true)) == 0){
709       do {
710 
711 	fetchedRows++;
712 	/**
713 	 * print  REG_NO unsigned int
714 	 */
715 	std::cout << myRecAttr[0]->u_32_value() << "\t";
716 
717 	/**
718 	 * print  BRAND character string
719 	 */
720 	std::cout << myRecAttr[1]->aRef() << "\t";
721 
722 	/**
723 	 * print  COLOR character string
724 	 */
725 	std::cout << myRecAttr[2]->aRef() << std::endl;
726 
727 	/**
728 	 * nextResult(false) means that the records
729 	 * cached in the NDBAPI are modified before
730 	 * fetching more rows from NDB.
731 	 */
732       } while((check = myScanOp->nextResult(false)) == 0);
733 
734     }
735     myNdb->closeTransaction(myTrans);
736     return 1;
737   }
738   return -1;
739 
740 }
741 
742 
main(int argc,char ** argv)743 int main(int argc, char** argv)
744 {
745   if (argc != 3)
746   {
747     std::cout << "Arguments are <socket mysqld> <connect_string cluster>.\n";
748     exit(-1);
749   }
750   char * mysqld_sock  = argv[1];
751   const char *connectstring = argv[2];
752   ndb_init();
753   MYSQL mysql;
754 
755   /**************************************************************
756    * Connect to mysql server and create table                   *
757    **************************************************************/
758   {
759     if ( !mysql_init(&mysql) ) {
760       std::cout << "mysql_init failed\n";
761       exit(-1);
762     }
763     if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
764 			     0, mysqld_sock, 0) )
765       MYSQLERROR(mysql);
766 
767     mysql_query(&mysql, "CREATE DATABASE ndb_examples");
768     if (mysql_query(&mysql, "USE ndb_examples") != 0) MYSQLERROR(mysql);
769 
770     create_table(mysql);
771   }
772 
773   /**************************************************************
774    * Connect to ndb cluster                                     *
775    **************************************************************/
776 
777   Ndb_cluster_connection cluster_connection(connectstring);
778   if (cluster_connection.connect(4, 5, 1))
779   {
780     std::cout << "Unable to connect to cluster within 30 secs." << std::endl;
781     exit(-1);
782   }
783   // Optionally connect and wait for the storage nodes (ndbd's)
784   if (cluster_connection.wait_until_ready(30,0) < 0)
785   {
786     std::cout << "Cluster was not ready within 30 secs.\n";
787     exit(-1);
788   }
789 
790   Ndb myNdb(&cluster_connection,"ndb_examples");
791   if (myNdb.init(1024) == -1) {      // Set max 1024  parallel transactions
792     APIERROR(myNdb.getNdbError());
793     exit(-1);
794   }
795 
796   /*******************************************
797    * Check table definition                  *
798    *******************************************/
799   int column_color;
800   {
801     const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
802     const NdbDictionary::Table *t= myDict->getTable("api_scan");
803     if(t == NULL)
804     {
805       std::cout << "Dictionary::getTable() failed.";
806       exit(-1);
807     }
808     Car car;
809     if (t->getColumn("COLOR")->getLength() != sizeof(car.color) ||
810 	t->getColumn("BRAND")->getLength() != sizeof(car.brand))
811     {
812       std::cout << "Wrong table definition" << std::endl;
813       exit(-1);
814     }
815     column_color= t->getColumn("COLOR")->getColumnNo();
816   }
817 
818   if(populate(&myNdb) > 0)
819     std::cout << "populate: Success!" << std::endl;
820 
821   if(scan_print(&myNdb) > 0)
822     std::cout << "scan_print: Success!" << std::endl  << std::endl;
823 
824   std::cout << "Going to delete all pink cars!" << std::endl;
825 
826   {
827     /**
828      * Note! color needs to be of exact the same size as column defined
829      */
830     Car tmp;
831     sprintf(tmp.color, "Pink");
832     if(scan_delete(&myNdb, column_color, tmp.color) > 0)
833       std::cout << "scan_delete: Success!" << std::endl  << std::endl;
834   }
835 
836   if(scan_print(&myNdb) > 0)
837     std::cout << "scan_print: Success!" << std::endl  << std::endl;
838 
839   {
840     /**
841      * Note! color1 & 2 need to be of exact the same size as column defined
842      */
843     Car tmp1, tmp2;
844     sprintf(tmp1.color, "Blue");
845     sprintf(tmp2.color, "Black");
846     std::cout << "Going to update all " << tmp1.color
847 	      << " cars to " << tmp2.color << " cars!" << std::endl;
848     if(scan_update(&myNdb, column_color, tmp1.color, tmp2.color) > 0)
849       std::cout << "scan_update: Success!" << std::endl  << std::endl;
850   }
851   if(scan_print(&myNdb) > 0)
852     std::cout << "scan_print: Success!" << std::endl  << std::endl;
853 
854   /**
855    * Drop table
856    */
857   drop_table(mysql);
858 
859   return 0;
860 }
861