1 /*
2    Copyright (C) 2007 MySQL AB, 2010 Sun Microsystems, Inc.
3     All rights reserved. Use is subject to license terms.
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  *  ndbapi_simple.cpp: Using synchronous transactions in NDB API
28  *
29  *  Correct output from this program is:
30  *
31  *  ATTR1 ATTR2
32  *    0    10
33  *    1     1
34  *    2    12
35  *  Detected that deleted tuple doesn't exist!
36  *    4    14
37  *    5     5
38  *    6    16
39  *    7     7
40  *    8    18
41  *    9     9
42  *
43  */
44 
45 #include <mysql.h>
46 #include <NdbApi.hpp>
47 // Used for cout
48 #include <stdio.h>
49 #include <NdbOut.hpp>
50 
51 static void run_application(MYSQL &, Ndb_cluster_connection &);
52 
53 #define PRINT_ERROR(code,msg) \
54   ndbout << "Error in " << __FILE__ << ", line: " << __LINE__ \
55             << ", code: " << code \
56             << ", msg: " << msg << "." << 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()64 int main()
65 {
66   // ndb_init must be called first
67   ndb_init();
68 
69   // connect to mysql server and cluster and run application
70   {
71     // Object representing the cluster
72     Ndb_cluster_connection cluster_connection;
73 
74     // Connect to cluster management server (ndb_mgmd)
75     if (cluster_connection.connect(4 /* retries               */,
76 				   5 /* delay between retries */,
77 				   1 /* verbose               */))
78     {
79       ndbout << "Cluster management server was not ready within 30 secs.\n";
80       exit(-1);
81     }
82 
83     // Optionally connect and wait for the storage nodes (ndbd's)
84     if (cluster_connection.wait_until_ready(30,0) < 0)
85     {
86       ndbout << "Cluster was not ready within 30 secs.\n";
87       exit(-1);
88     }
89 
90     // connect to mysql server
91     MYSQL mysql;
92     if ( !mysql_init(&mysql) ) {
93       ndbout << "mysql_init failed\n";
94       exit(-1);
95     }
96     if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
97 			     3306, "/tmp/mysql.sock", 0) )
98       MYSQLERROR(mysql);
99 
100     // run the application code
101     run_application(mysql, cluster_connection);
102   }
103 
104   ndb_end(0);
105 
106   ndbout << "\nTo drop created table use:\n"
107 	    << "echo \"drop table MYTABLENAME\" | mysql TEST_DB_1 -u root\n";
108 
109   return 0;
110 }
111 
112 static void create_table(MYSQL &);
113 static void do_insert(Ndb &);
114 static void do_update(Ndb &);
115 static void do_delete(Ndb &);
116 static void do_read(Ndb &);
117 
run_application(MYSQL & mysql,Ndb_cluster_connection & cluster_connection)118 static void run_application(MYSQL &mysql,
119 			    Ndb_cluster_connection &cluster_connection)
120 {
121   /********************************************
122    * Connect to database via mysql-c          *
123    ********************************************/
124   mysql_query(&mysql, "CREATE DATABASE TEST_DB_1");
125   if (mysql_query(&mysql, "USE TEST_DB_1") != 0) MYSQLERROR(mysql);
126   create_table(mysql);
127 
128   /********************************************
129    * Connect to database via NdbApi           *
130    ********************************************/
131   // Object representing the database
132   Ndb myNdb( &cluster_connection, "TEST_DB_1" );
133   if (myNdb.init()) APIERROR(myNdb.getNdbError());
134 
135   /*
136    * Do different operations on database
137    */
138   do_insert(myNdb);
139   do_update(myNdb);
140   do_delete(myNdb);
141   do_read(myNdb);
142 }
143 
144 /*********************************************************
145  * Create a table named MYTABLENAME if it does not exist *
146  *********************************************************/
create_table(MYSQL & mysql)147 static void create_table(MYSQL &mysql)
148 {
149   if (mysql_query(&mysql,
150 		  "CREATE TABLE"
151 		  "  MYTABLENAME"
152 		  "    (ATTR1 INT UNSIGNED NOT NULL PRIMARY KEY,"
153 		  "     ATTR2 INT UNSIGNED NOT NULL)"
154 		  "  ENGINE=NDB"))
155     MYSQLERROR(mysql);
156 }
157 
158 /**************************************************************************
159  * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
160  **************************************************************************/
do_insert(Ndb & myNdb)161 static void do_insert(Ndb &myNdb)
162 {
163   const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
164   const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
165 
166   if (myTable == NULL)
167     APIERROR(myDict->getNdbError());
168 
169   for (int i = 0; i < 5; i++) {
170     NdbTransaction *myTransaction= myNdb.startTransaction();
171     if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
172 
173     NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
174     if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
175 
176     myOperation->insertTuple();
177     myOperation->equal("ATTR1", i);
178     myOperation->setValue("ATTR2", i);
179 
180     myOperation= myTransaction->getNdbOperation(myTable);
181     if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
182 
183     myOperation->insertTuple();
184     myOperation->equal("ATTR1", i+5);
185     myOperation->setValue("ATTR2", i+5);
186 
187     if (myTransaction->execute( NdbTransaction::Commit, NdbTransaction::AbortOnError, 1) == -1)
188       APIERROR(myTransaction->getNdbError());
189 
190     myNdb.closeTransaction(myTransaction);
191   }
192 }
193 
194 /*****************************************************************
195  * Update the second attribute in half of the tuples (adding 10) *
196  *****************************************************************/
do_update(Ndb & myNdb)197 static void do_update(Ndb &myNdb)
198 {
199   const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
200   const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
201 
202   if (myTable == NULL)
203     APIERROR(myDict->getNdbError());
204 
205   for (int i = 0; i < 10; i+=2) {
206     NdbTransaction *myTransaction= myNdb.startTransaction();
207     if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
208 
209     NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
210     if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
211 
212     myOperation->updateTuple();
213     myOperation->equal( "ATTR1", i );
214     myOperation->setValue( "ATTR2", i+10);
215 
216     if( myTransaction->execute( NdbTransaction::Commit ) == -1 )
217       APIERROR(myTransaction->getNdbError());
218 
219     myNdb.closeTransaction(myTransaction);
220   }
221 }
222 
223 /*************************************************
224  * Delete one tuple (the one with primary key 3) *
225  *************************************************/
do_delete(Ndb & myNdb)226 static void do_delete(Ndb &myNdb)
227 {
228   const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
229   const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
230 
231   if (myTable == NULL)
232     APIERROR(myDict->getNdbError());
233 
234   NdbTransaction *myTransaction= myNdb.startTransaction();
235   if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
236 
237   NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
238   if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
239 
240   myOperation->deleteTuple();
241   myOperation->equal( "ATTR1", 3 );
242 
243   if (myTransaction->execute(NdbTransaction::Commit) == -1)
244     APIERROR(myTransaction->getNdbError());
245 
246   myNdb.closeTransaction(myTransaction);
247 }
248 
249 /*****************************
250  * Read and print all tuples *
251  *****************************/
do_read(Ndb & myNdb)252 static void do_read(Ndb &myNdb)
253 {
254   const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
255   const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
256 
257   if (myTable == NULL)
258     APIERROR(myDict->getNdbError());
259 
260   ndbout << "ATTR1 ATTR2" << endl;
261 
262   for (int i = 0; i < 10; i++) {
263     NdbTransaction *myTransaction= myNdb.startTransaction();
264     if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
265 
266     NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
267     if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
268 
269     myOperation->readTuple(NdbOperation::LM_Read);
270     myOperation->equal("ATTR1", i);
271 
272     NdbRecAttr *myRecAttr= myOperation->getValue("ATTR2", NULL);
273     if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
274 
275     if(myTransaction->execute( NdbTransaction::Commit ) == -1)
276     {
277       if (i == 3) {
278 	ndbout << "Detected that deleted tuple doesn't exist!" << endl;
279       } else {
280 	APIERROR(myTransaction->getNdbError());
281       }
282     }
283 
284     if (i != 3) {
285       printf(" %2d    %2d\n", i, myRecAttr->u_32_value());
286     }
287     myNdb.closeTransaction(myTransaction);
288   }
289 }
290