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