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