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