MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
main.cpp
1 /*
2  Copyright (c) 2007, 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 as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 //
19 // ndbapi_simple_index_ndbrecord.cpp: Using secondary unique hash indexes
20 // in NDB API, utilising the NdbRecord interface.
21 //
22 // Correct output from this program is (from a two-node cluster):
23 //
24 // ATTR1 ATTR2
25 // 0 0 (frag=0)
26 // 1 1 (frag=1)
27 // 2 2 (frag=1)
28 // 3 3 (frag=0)
29 // 4 4 (frag=1)
30 // 5 5 (frag=1)
31 // 6 6 (frag=0)
32 // 7 7 (frag=0)
33 // 8 8 (frag=1)
34 // 9 9 (frag=0)
35 // ATTR1 ATTR2
36 // 0 10
37 // 1 1
38 // 2 12
39 // Detected that deleted tuple doesn't exist!
40 // 4 14
41 // 5 5
42 // 6 16
43 // 7 7
44 // 8 18
45 // 9 9
46 
47 #include <mysql.h>
48 #include <NdbApi.hpp>
49 
50 // Used for cout
51 #include <stdio.h>
52 #include <iostream>
53 
54 #define PRINT_ERROR(code,msg) \
55  std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
56  << ", code: " << code \
57  << ", msg: " << msg << "." << std::endl
58 #define MYSQLERROR(mysql) { \
59  PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
60  exit(1); }
61 #define APIERROR(error) { \
62  PRINT_ERROR(error.code,error.message); \
63  exit(1); }
64 
65 /* C struct representing layout of data from table
66  * api_s_i_ndbrecord in memory
67  * This can make it easier to work with rows in the application,
68  * but is not necessary - NdbRecord can map columns to any
69  * pattern of offsets.
70  * In this program, the same row offsets are used for columns
71  * specified as part of a key, and as part of an attribute or
72  * result. This makes the example simpler, but is not
73  * essential.
74  */
75 struct MyTableRow
76 {
77  unsigned int attr1;
78  unsigned int attr2;
79 };
80 
81 int main(int argc, char** argv)
82 {
83  if (argc != 3)
84  {
85  std::cout << "Arguments are <socket mysqld> <connect_string cluster>.\n";
86  exit(1);
87  }
88  char * mysqld_sock = argv[1];
89  const char *connectstring = argv[2];
90  ndb_init();
91  MYSQL mysql;
92 
93  /**************************************************************
94  * Connect to mysql server and create table *
95  **************************************************************/
96  {
97  if ( !mysql_init(&mysql) ) {
98  std::cout << "mysql_init failed\n";
99  exit(1);
100  }
101  if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
102  0, mysqld_sock, 0) )
103  MYSQLERROR(mysql);
104 
105  mysql_query(&mysql, "CREATE DATABASE ndb_examples");
106  if (mysql_query(&mysql, "USE ndb_examples") != 0)
107  MYSQLERROR(mysql);
108 
109  mysql_query(&mysql, "DROP TABLE api_s_i_ndbrecord");
110  if (mysql_query(&mysql,
111  "CREATE TABLE"
112  " api_s_i_ndbrecord"
113  " (ATTR1 INT UNSIGNED,"
114  " ATTR2 INT UNSIGNED NOT NULL,"
115  " PRIMARY KEY USING HASH (ATTR1),"
116  " UNIQUE MYINDEXNAME USING HASH (ATTR2))"
117  " ENGINE=NDB"))
118  MYSQLERROR(mysql);
119  }
120 
121  /**************************************************************
122  * Connect to ndb cluster *
123  **************************************************************/
124 
125  Ndb_cluster_connection *cluster_connection=
126  new Ndb_cluster_connection(connectstring); // Object representing the cluster
127 
128  if (cluster_connection->connect(5,3,1))
129  {
130  std::cout << "Connect to cluster management server failed.\n";
131  exit(1);
132  }
133 
134  if (cluster_connection->wait_until_ready(30,30))
135  {
136  std::cout << "Cluster was not ready within 30 secs.\n";
137  exit(1);
138  }
139 
140  Ndb* myNdb = new Ndb( cluster_connection,
141  "ndb_examples" ); // Object representing the database
142  if (myNdb->init() == -1) {
143  APIERROR(myNdb->getNdbError());
144  exit(1);
145  }
146 
147  NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
148  const NdbDictionary::Table *myTable= myDict->getTable("api_s_i_ndbrecord");
149  if (myTable == NULL)
150  APIERROR(myDict->getNdbError());
151  const NdbDictionary::Index *myIndex= myDict->getIndex("MYINDEXNAME$unique","api_s_i_ndbrecord");
152  if (myIndex == NULL)
153  APIERROR(myDict->getNdbError());
154 
155  /* Create NdbRecord descriptors. */
156  const NdbDictionary::Column *col1= myTable->getColumn("ATTR1");
157  if (col1 == NULL)
158  APIERROR(myDict->getNdbError());
159  const NdbDictionary::Column *col2= myTable->getColumn("ATTR2");
160  if (col2 == NULL)
161  APIERROR(myDict->getNdbError());
162 
163  /* NdbRecord for primary key lookup. */
165  spec[0].column= col1;
166  spec[0].offset= offsetof(MyTableRow, attr1);
167  // So that it goes nicely into the struct
168  spec[0].nullbit_byte_offset= 0;
169  spec[0].nullbit_bit_in_byte= 0;
170  const NdbRecord *pk_record=
171  myDict->createRecord(myTable, spec, 1, sizeof(spec[0]));
172  if (pk_record == NULL)
173  APIERROR(myDict->getNdbError());
174 
175  /* NdbRecord for all table attributes (insert/read). */
176  spec[0].column= col1;
177  spec[0].offset= offsetof(MyTableRow, attr1);
178  spec[0].nullbit_byte_offset= 0;
179  spec[0].nullbit_bit_in_byte= 0;
180  spec[1].column= col2;
181  spec[1].offset= offsetof(MyTableRow, attr2);
182  spec[1].nullbit_byte_offset= 0;
183  spec[1].nullbit_bit_in_byte= 0;
184  const NdbRecord *attr_record=
185  myDict->createRecord(myTable, spec, 2, sizeof(spec[0]));
186  if (attr_record == NULL)
187  APIERROR(myDict->getNdbError());
188 
189  /* NdbRecord for unique key lookup. */
190  spec[0].column= col2;
191  spec[0].offset= offsetof(MyTableRow, attr2);
192  spec[0].nullbit_byte_offset= 0;
193  spec[0].nullbit_bit_in_byte= 0;
194  const NdbRecord *key_record=
195  myDict->createRecord(myIndex, spec, 1, sizeof(spec[0]));
196  if (key_record == NULL)
197  APIERROR(myDict->getNdbError());
198 
199  MyTableRow row;
200 
201  /**************************************************************************
202  * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
203  **************************************************************************/
204  for (int i = 0; i < 5; i++) {
205  NdbTransaction *myTransaction= myNdb->startTransaction();
206  if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
207 
208  /*
209  We initialise the row data and pass to each insertTuple operation
210  The data is copied in the call to insertTuple and so the original
211  row object can be reused for the two operations.
212  */
213  row.attr1= row.attr2= i;
214 
215  const NdbOperation *myOperation=
216  myTransaction->insertTuple(attr_record, (const char*)&row);
217  if (myOperation == NULL)
218  APIERROR(myTransaction->getNdbError());
219 
220  row.attr1= row.attr2= i+5;
221  myOperation=
222  myTransaction->insertTuple(attr_record, (const char*)&row);
223  if (myOperation == NULL)
224  APIERROR(myTransaction->getNdbError());
225 
226  if (myTransaction->execute( NdbTransaction::Commit ) == -1)
227  APIERROR(myTransaction->getNdbError());
228 
229  myNdb->closeTransaction(myTransaction);
230  }
231 
232  /*****************************************
233  * Read and print all tuples using index *
234  *****************************************/
235  std::cout << "ATTR1 ATTR2" << std::endl;
236 
237  for (int i = 0; i < 10; i++) {
238  NdbTransaction *myTransaction= myNdb->startTransaction();
239  if (myTransaction == NULL)
240  APIERROR(myNdb->getNdbError());
241 
242  /* The optional OperationOptions parameter to NdbRecord methods
243  * can be used to specify extra reads of columns which are not in
244  * the NdbRecord specification, which need to be stored somewhere
245  * other than specified in the NdbRecord specification, or
246  * which cannot be specified as part of an NdbRecord (pseudo
247  * columns)
248  */
249  Uint32 frag;
250  NdbOperation::GetValueSpec getSpec[1];
251  getSpec[0].column=NdbDictionary::Column::FRAGMENT;
252  getSpec[0].appStorage=&frag;
253 
255  options.optionsPresent = NdbOperation::OperationOptions::OO_GETVALUE;
256  options.extraGetValues = &getSpec[0];
257  options.numExtraGetValues = 1;
258 
259  /* We're going to read using the secondary unique hash index
260  * Set the value of its column
261  */
262  row.attr2= i;
263 
264  MyTableRow resultRow;
265 
266  unsigned char mask[1]= { 0x01 }; // Only read ATTR1 into resultRow
267  const NdbOperation *myOperation=
268  myTransaction->readTuple(key_record, (const char*) &row,
269  attr_record, (char*) &resultRow,
270  NdbOperation::LM_Read, mask,
271  &options,
273  if (myOperation == NULL)
274  APIERROR(myTransaction->getNdbError());
275 
276  if (myTransaction->execute( NdbTransaction::Commit,
278  {
279  printf(" %2d %2d (frag=%u)\n", resultRow.attr1, i, frag);
280  }
281 
282  myNdb->closeTransaction(myTransaction);
283  }
284 
285  /*****************************************************************
286  * Update the second attribute in half of the tuples (adding 10) *
287  *****************************************************************/
288  for (int i = 0; i < 10; i+=2) {
289  NdbTransaction *myTransaction= myNdb->startTransaction();
290  if (myTransaction == NULL)
291  APIERROR(myNdb->getNdbError());
292 
293  /* Specify key column to lookup in secondary index */
294  row.attr2= i;
295 
296  /* Specify new column value to set */
297  MyTableRow newRowData;
298  newRowData.attr2= i+10;
299  unsigned char mask[1]= { 0x02 }; // Only update ATTR2
300 
301  const NdbOperation *myOperation=
302  myTransaction->updateTuple(key_record, (const char*)&row,
303  attr_record,(char*) &newRowData, mask);
304  if (myOperation == NULL)
305  APIERROR(myTransaction->getNdbError());
306 
307  if ( myTransaction->execute( NdbTransaction::Commit ) == -1 )
308  APIERROR(myTransaction->getNdbError());
309 
310  myNdb->closeTransaction(myTransaction);
311  }
312 
313  /*************************************************
314  * Delete one tuple (the one with unique key 3) *
315  *************************************************/
316  {
317  NdbTransaction *myTransaction= myNdb->startTransaction();
318  if (myTransaction == NULL)
319  APIERROR(myNdb->getNdbError());
320 
321  row.attr2= 3;
322  const NdbOperation *myOperation=
323  myTransaction->deleteTuple(key_record, (const char*) &row,
324  attr_record);
325  if (myOperation == NULL)
326  APIERROR(myTransaction->getNdbError());
327 
328  if (myTransaction->execute(NdbTransaction::Commit) == -1)
329  APIERROR(myTransaction->getNdbError());
330 
331  myNdb->closeTransaction(myTransaction);
332  }
333 
334  /*****************************
335  * Read and print all tuples *
336  *****************************/
337  {
338  std::cout << "ATTR1 ATTR2" << std::endl;
339 
340  for (int i = 0; i < 10; i++) {
341  NdbTransaction *myTransaction= myNdb->startTransaction();
342  if (myTransaction == NULL)
343  APIERROR(myNdb->getNdbError());
344 
345  row.attr1= i;
346 
347  /* Read using pk. Note the same row space is used as
348  * key and result storage space
349  */
350  const NdbOperation *myOperation=
351  myTransaction->readTuple(pk_record, (const char*) &row,
352  attr_record, (char*) &row);
353  if (myOperation == NULL)
354  APIERROR(myTransaction->getNdbError());
355 
356  if (myTransaction->execute( NdbTransaction::Commit,
358  if (i == 3) {
359  std::cout << "Detected that deleted tuple doesn't exist!\n";
360  } else {
361  APIERROR(myTransaction->getNdbError());
362  }
363 
364  if (i != 3)
365  printf(" %2d %2d\n", row.attr1, row.attr2);
366 
367  myNdb->closeTransaction(myTransaction);
368  }
369  }
370 
371  delete myNdb;
372  delete cluster_connection;
373 
374  ndb_end(0);
375  return 0;
376 }