1 /*
2    Copyright (c) 2005, 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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 /*
26  *  ndbapi_simple.cpp: Using synchronous transactions in NDB API
27  *
28  *  Correct output from this program is:
29  *
30  *  ATTR1 ATTR2
31  *    0    10
32  *    1     1
33  *    2    12
34  *  Detected that deleted tuple doesn't exist!
35  *    4    14
36  *    5     5
37  *    6    16
38  *    7     7
39  *    8    18
40  *    9     9
41  *
42  */
43 
44 #include <mysql.h>
45 #include <mysqld_error.h>
46 #include <NdbApi.hpp>
47 // Used for cout
48 #include <stdio.h>
49 #include <iostream>
50 
51 static void run_application(MYSQL &, Ndb_cluster_connection &);
52 
53 #define PRINT_ERROR(code,msg) \
54   std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
55             << ", code: " << code \
56             << ", msg: " << msg << "." << std::endl
57 #define MYSQLERROR(mysql) { \
58   PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
59   exit(-1); }
60 #define APIERROR(error) { \
61   PRINT_ERROR(error.code,error.message); \
62   exit(-1); }
63 
main(int argc,char ** argv)64 int main(int argc, char** argv)
65 {
66   if (argc != 3)
67   {
68     std::cout << "Arguments are <socket mysqld> <connect_string cluster>.\n";
69     exit(-1);
70   }
71   // ndb_init must be called first
72   ndb_init();
73 
74   // connect to mysql server and cluster and run application
75   {
76     char * mysqld_sock  = argv[1];
77     const char *connectstring = argv[2];
78     // Object representing the cluster
79     Ndb_cluster_connection cluster_connection(connectstring);
80 
81     // Connect to cluster management server (ndb_mgmd)
82     if (cluster_connection.connect(4 /* retries               */,
83 				   5 /* delay between retries */,
84 				   1 /* verbose               */))
85     {
86       std::cout << "Cluster management server was not ready within 30 secs.\n";
87       exit(-1);
88     }
89 
90     // Optionally connect and wait for the storage nodes (ndbd's)
91     if (cluster_connection.wait_until_ready(30,0) < 0)
92     {
93       std::cout << "Cluster was not ready within 30 secs.\n";
94       exit(-1);
95     }
96 
97     // connect to mysql server
98     MYSQL mysql;
99     if ( !mysql_init(&mysql) ) {
100       std::cout << "mysql_init failed\n";
101       exit(-1);
102     }
103     if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
104 			     0, mysqld_sock, 0) )
105       MYSQLERROR(mysql);
106 
107     // run the application code
108     run_application(mysql, cluster_connection);
109   }
110 
111   ndb_end(0);
112 
113   return 0;
114 }
115 
116 static void create_table(MYSQL &);
117 static void do_insert(Ndb &);
118 static void do_update(Ndb &);
119 static void do_delete(Ndb &);
120 static void do_read(Ndb &);
121 
run_application(MYSQL & mysql,Ndb_cluster_connection & cluster_connection)122 static void run_application(MYSQL &mysql,
123 			    Ndb_cluster_connection &cluster_connection)
124 {
125   /********************************************
126    * Connect to database via mysql-c          *ndb_examples
127    ********************************************/
128   mysql_query(&mysql, "CREATE DATABASE ndb_examples");
129   if (mysql_query(&mysql, "USE ndb_examples") != 0) MYSQLERROR(mysql);
130   create_table(mysql);
131 
132   /********************************************
133    * Connect to database via NdbApi           *
134    ********************************************/
135   // Object representing the database
136   Ndb myNdb( &cluster_connection, "ndb_examples" );
137   if (myNdb.init()) APIERROR(myNdb.getNdbError());
138 
139   /*
140    * Do different operations on database
141    */
142   do_insert(myNdb);
143   do_update(myNdb);
144   do_delete(myNdb);
145   do_read(myNdb);
146 }
147 
148 /*********************************************************
149  * Create a table named api_simple if it does not exist *
150  *********************************************************/
create_table(MYSQL & mysql)151 static void create_table(MYSQL &mysql)
152 {
153   while (mysql_query(&mysql,
154 		  "CREATE TABLE"
155 		  "  api_simple"
156 		  "    (ATTR1 INT UNSIGNED NOT NULL PRIMARY KEY,"
157 		  "     ATTR2 INT UNSIGNED NOT NULL)"
158 		  "  ENGINE=NDB"))
159   {
160     if (mysql_errno(&mysql) == ER_TABLE_EXISTS_ERROR)
161     {
162       std::cout << "MySQL Cluster already has example table: api_simple. "
163       << "Dropping it..." << std::endl;
164       mysql_query(&mysql, "DROP TABLE api_simple");
165     }
166     else MYSQLERROR(mysql);
167   }
168 }
169 
170 /**************************************************************************
171  * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
172  **************************************************************************/
do_insert(Ndb & myNdb)173 static void do_insert(Ndb &myNdb)
174 {
175   const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
176   const NdbDictionary::Table *myTable= myDict->getTable("api_simple");
177 
178   if (myTable == NULL)
179     APIERROR(myDict->getNdbError());
180 
181   for (int i = 0; i < 5; i++) {
182     NdbTransaction *myTransaction= myNdb.startTransaction();
183     if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
184 
185     NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
186     if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
187 
188     myOperation->insertTuple();
189     myOperation->equal("ATTR1", i);
190     myOperation->setValue("ATTR2", i);
191 
192     myOperation= myTransaction->getNdbOperation(myTable);
193     if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
194 
195     myOperation->insertTuple();
196     myOperation->equal("ATTR1", i+5);
197     myOperation->setValue("ATTR2", i+5);
198 
199     if (myTransaction->execute( NdbTransaction::Commit ) == -1)
200       APIERROR(myTransaction->getNdbError());
201 
202     myNdb.closeTransaction(myTransaction);
203   }
204 }
205 
206 /*****************************************************************
207  * Update the second attribute in half of the tuples (adding 10) *
208  *****************************************************************/
do_update(Ndb & myNdb)209 static void do_update(Ndb &myNdb)
210 {
211   const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
212   const NdbDictionary::Table *myTable= myDict->getTable("api_simple");
213 
214   if (myTable == NULL)
215     APIERROR(myDict->getNdbError());
216 
217   for (int i = 0; i < 10; i+=2) {
218     NdbTransaction *myTransaction= myNdb.startTransaction();
219     if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
220 
221     NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
222     if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
223 
224     myOperation->updateTuple();
225     myOperation->equal( "ATTR1", i );
226     myOperation->setValue( "ATTR2", i+10);
227 
228     if( myTransaction->execute( NdbTransaction::Commit ) == -1 )
229       APIERROR(myTransaction->getNdbError());
230 
231     myNdb.closeTransaction(myTransaction);
232   }
233 }
234 
235 /*************************************************
236  * Delete one tuple (the one with primary key 3) *
237  *************************************************/
do_delete(Ndb & myNdb)238 static void do_delete(Ndb &myNdb)
239 {
240   const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
241   const NdbDictionary::Table *myTable= myDict->getTable("api_simple");
242 
243   if (myTable == NULL)
244     APIERROR(myDict->getNdbError());
245 
246   NdbTransaction *myTransaction= myNdb.startTransaction();
247   if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
248 
249   NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
250   if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
251 
252   myOperation->deleteTuple();
253   myOperation->equal( "ATTR1", 3 );
254 
255   if (myTransaction->execute(NdbTransaction::Commit) == -1)
256     APIERROR(myTransaction->getNdbError());
257 
258   myNdb.closeTransaction(myTransaction);
259 }
260 
261 /*****************************
262  * Read and print all tuples *
263  *****************************/
do_read(Ndb & myNdb)264 static void do_read(Ndb &myNdb)
265 {
266   const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
267   const NdbDictionary::Table *myTable= myDict->getTable("api_simple");
268 
269   if (myTable == NULL)
270     APIERROR(myDict->getNdbError());
271 
272   std::cout << "ATTR1 ATTR2" << std::endl;
273 
274   for (int i = 0; i < 10; i++) {
275     NdbTransaction *myTransaction= myNdb.startTransaction();
276     if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
277 
278     NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
279     if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
280 
281     myOperation->readTuple(NdbOperation::LM_Read);
282     myOperation->equal("ATTR1", i);
283 
284     NdbRecAttr *myRecAttr= myOperation->getValue("ATTR2", NULL);
285     if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
286 
287     if(myTransaction->execute( NdbTransaction::Commit ) == -1)
288       APIERROR(myTransaction->getNdbError());
289 
290     if (myTransaction->getNdbError().classification == NdbError::NoDataFound)
291       if (i == 3)
292         std::cout << "Detected that deleted tuple doesn't exist!" << std::endl;
293       else
294 	APIERROR(myTransaction->getNdbError());
295 
296     if (i != 3) {
297       printf(" %2d    %2d\n", i, myRecAttr->u_32_value());
298     }
299     myNdb.closeTransaction(myTransaction);
300   }
301 }
302