MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ndbapi_blob.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 /*
20  ndbapi_blob.cpp:
21 
22  Illustrates the manipulation of BLOB (actually TEXT in this example).
23 
24  Shows insert, read, and update, using both inline value buffer and
25  read/write methods.
26  */
27 
28 
29 #include <mysql.h>
30 #include <mysqld_error.h>
31 #include <NdbApi.hpp>
32 /* Used for cout. */
33 #include <iostream>
34 #include <stdio.h>
35 #include <ctype.h>
36 
37 
41 #define PRINT_ERROR(code,msg) \
42  std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
43  << ", code: " << code \
44  << ", msg: " << msg << "." << std::endl
45 #define MYSQLERROR(mysql) { \
46  PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
47  exit(-1); }
48 #define APIERROR(error) { \
49  PRINT_ERROR(error.code,error.message); \
50  exit(-1); }
51 
52 /* Quote taken from Project Gutenberg. */
53 const char *text_quote=
54 "Just at this moment, somehow or other, they began to run.\n"
55 "\n"
56 " Alice never could quite make out, in thinking it over\n"
57 "afterwards, how it was that they began: all she remembers is,\n"
58 "that they were running hand in hand, and the Queen went so fast\n"
59 "that it was all she could do to keep up with her: and still the\n"
60 "Queen kept crying 'Faster! Faster!' but Alice felt she COULD NOT\n"
61 "go faster, though she had not breath left to say so.\n"
62 "\n"
63 " The most curious part of the thing was, that the trees and the\n"
64 "other things round them never changed their places at all:\n"
65 "however fast they went, they never seemed to pass anything. 'I\n"
66 "wonder if all the things move along with us?' thought poor\n"
67 "puzzled Alice. And the Queen seemed to guess her thoughts, for\n"
68 "she cried, 'Faster! Don't try to talk!'\n"
69 "\n"
70 " Not that Alice had any idea of doing THAT. She felt as if she\n"
71 "would never be able to talk again, she was getting so much out of\n"
72 "breath: and still the Queen cried 'Faster! Faster!' and dragged\n"
73 "her along. 'Are we nearly there?' Alice managed to pant out at\n"
74 "last.\n"
75 "\n"
76 " 'Nearly there!' the Queen repeated. 'Why, we passed it ten\n"
77 "minutes ago! Faster!' And they ran on for a time in silence,\n"
78 "with the wind whistling in Alice's ears, and almost blowing her\n"
79 "hair off her head, she fancied.\n"
80 "\n"
81 " 'Now! Now!' cried the Queen. 'Faster! Faster!' And they\n"
82 "went so fast that at last they seemed to skim through the air,\n"
83 "hardly touching the ground with their feet, till suddenly, just\n"
84 "as Alice was getting quite exhausted, they stopped, and she found\n"
85 "herself sitting on the ground, breathless and giddy.\n"
86 "\n"
87 " The Queen propped her up against a tree, and said kindly, 'You\n"
88 "may rest a little now.'\n"
89 "\n"
90 " Alice looked round her in great surprise. 'Why, I do believe\n"
91 "we've been under this tree the whole time! Everything's just as\n"
92 "it was!'\n"
93 "\n"
94 " 'Of course it is,' said the Queen, 'what would you have it?'\n"
95 "\n"
96 " 'Well, in OUR country,' said Alice, still panting a little,\n"
97 "'you'd generally get to somewhere else--if you ran very fast\n"
98 "for a long time, as we've been doing.'\n"
99 "\n"
100 " 'A slow sort of country!' said the Queen. 'Now, HERE, you see,\n"
101 "it takes all the running YOU can do, to keep in the same place.\n"
102 "If you want to get somewhere else, you must run at least twice as\n"
103 "fast as that!'\n"
104 "\n"
105 " 'I'd rather not try, please!' said Alice. 'I'm quite content\n"
106 "to stay here--only I AM so hot and thirsty!'\n"
107 "\n"
108 " -- Lewis Carroll, 'Through the Looking-Glass'.";
109 
110 /*
111  Function to drop table.
112 */
113 void drop_table(MYSQL &mysql)
114 {
115  if (mysql_query(&mysql, "DROP TABLE api_blob"))
116  MYSQLERROR(mysql);
117 }
118 
119 
120 /*
121  Functions to create table.
122 */
123 int try_create_table(MYSQL &mysql)
124 {
125  return mysql_query(&mysql,
126  "CREATE TABLE"
127  " api_blob"
128  " (my_id INT UNSIGNED NOT NULL,"
129  " my_text TEXT NOT NULL,"
130  " PRIMARY KEY USING HASH (my_id))"
131  " ENGINE=NDB");
132 }
133 
134 void create_table(MYSQL &mysql)
135 {
136  if (try_create_table(mysql))
137  {
138  if (mysql_errno(&mysql) != ER_TABLE_EXISTS_ERROR)
139  MYSQLERROR(mysql);
140  std::cout << "MySQL Cluster already has example table: api_blob. "
141  << "Dropping it..." << std::endl;
142  /******************
143  * Recreate table *
144  ******************/
145  drop_table(mysql);
146  if (try_create_table(mysql))
147  MYSQLERROR(mysql);
148  }
149 }
150 
151 int populate(Ndb *myNdb)
152 {
153  const NdbDictionary::Dictionary *myDict= myNdb->getDictionary();
154  const NdbDictionary::Table *myTable= myDict->getTable("api_blob");
155  if (myTable == NULL)
156  APIERROR(myDict->getNdbError());
157 
158  NdbTransaction *myTrans= myNdb->startTransaction();
159  if (myTrans == NULL)
160  APIERROR(myNdb->getNdbError());
161 
162  NdbOperation *myNdbOperation= myTrans->getNdbOperation(myTable);
163  if (myNdbOperation == NULL)
164  APIERROR(myTrans->getNdbError());
165  myNdbOperation->insertTuple();
166  myNdbOperation->equal("my_id", 1);
167  NdbBlob *myBlobHandle= myNdbOperation->getBlobHandle("my_text");
168  if (myBlobHandle == NULL)
169  APIERROR(myNdbOperation->getNdbError());
170  myBlobHandle->setValue(text_quote, strlen(text_quote));
171 
172  int check= myTrans->execute(NdbTransaction::Commit);
173  myTrans->close();
174  return check != -1;
175 }
176 
177 
178 int update_key(Ndb *myNdb)
179 {
180  /*
181  Uppercase all characters in TEXT field, using primary key operation.
182  Use piece-wise read/write to avoid loading entire data into memory
183  at once.
184  */
185  const NdbDictionary::Dictionary *myDict= myNdb->getDictionary();
186  const NdbDictionary::Table *myTable= myDict->getTable("api_blob");
187  if (myTable == NULL)
188  APIERROR(myDict->getNdbError());
189 
190  NdbTransaction *myTrans= myNdb->startTransaction();
191  if (myTrans == NULL)
192  APIERROR(myNdb->getNdbError());
193 
194  NdbOperation *myNdbOperation= myTrans->getNdbOperation(myTable);
195  if (myNdbOperation == NULL)
196  APIERROR(myTrans->getNdbError());
197  myNdbOperation->updateTuple();
198  myNdbOperation->equal("my_id", 1);
199  NdbBlob *myBlobHandle= myNdbOperation->getBlobHandle("my_text");
200  if (myBlobHandle == NULL)
201  APIERROR(myNdbOperation->getNdbError());
202 
203  /* Execute NoCommit to make the blob handle active. */
204  if (-1 == myTrans->execute(NdbTransaction::NoCommit))
205  APIERROR(myTrans->getNdbError());
206 
207  Uint64 length= 0;
208  if (-1 == myBlobHandle->getLength(length))
209  APIERROR(myBlobHandle->getNdbError());
210 
211  /*
212  A real application should use a much larger chunk size for
213  efficiency, preferably much larger than the part size, which
214  defaults to 2000. 64000 might be a good value.
215  */
216 #define CHUNK_SIZE 100
217  int chunk;
218  char buffer[CHUNK_SIZE];
219  for (chunk= (length-1)/CHUNK_SIZE; chunk >=0; chunk--)
220  {
221  Uint64 pos= chunk*CHUNK_SIZE;
222  Uint32 chunk_length= CHUNK_SIZE;
223  if (pos + chunk_length > length)
224  chunk_length= length - pos;
225 
226  /* Read from the end back, to illustrate seeking. */
227  if (-1 == myBlobHandle->setPos(pos))
228  APIERROR(myBlobHandle->getNdbError());
229  if (-1 == myBlobHandle->readData(buffer, chunk_length))
230  APIERROR(myBlobHandle->getNdbError());
231  int res= myTrans->execute(NdbTransaction::NoCommit);
232  if (-1 == res)
233  APIERROR(myTrans->getNdbError());
234 
235  /* Uppercase everything. */
236  for (Uint64 j= 0; j < chunk_length; j++)
237  buffer[j]= toupper(buffer[j]);
238 
239  if (-1 == myBlobHandle->setPos(pos))
240  APIERROR(myBlobHandle->getNdbError());
241  if (-1 == myBlobHandle->writeData(buffer, chunk_length))
242  APIERROR(myBlobHandle->getNdbError());
243  /* Commit on the final update. */
244  if (-1 == myTrans->execute(chunk ?
247  APIERROR(myTrans->getNdbError());
248  }
249 
250  myNdb->closeTransaction(myTrans);
251 
252  return 1;
253 }
254 
255 
256 int update_scan(Ndb *myNdb)
257 {
258  /*
259  Lowercase all characters in TEXT field, using a scan with
260  updateCurrentTuple().
261  */
262  char buffer[10000];
263 
264  const NdbDictionary::Dictionary *myDict= myNdb->getDictionary();
265  const NdbDictionary::Table *myTable= myDict->getTable("api_blob");
266  if (myTable == NULL)
267  APIERROR(myDict->getNdbError());
268 
269  NdbTransaction *myTrans= myNdb->startTransaction();
270  if (myTrans == NULL)
271  APIERROR(myNdb->getNdbError());
272 
273  NdbScanOperation *myScanOp= myTrans->getNdbScanOperation(myTable);
274  if (myScanOp == NULL)
275  APIERROR(myTrans->getNdbError());
276  myScanOp->readTuples(NdbOperation::LM_Exclusive);
277  NdbBlob *myBlobHandle= myScanOp->getBlobHandle("my_text");
278  if (myBlobHandle == NULL)
279  APIERROR(myScanOp->getNdbError());
280  if (myBlobHandle->getValue(buffer, sizeof(buffer)))
281  APIERROR(myBlobHandle->getNdbError());
282 
283  /* Start the scan. */
284  if (-1 == myTrans->execute(NdbTransaction::NoCommit))
285  APIERROR(myTrans->getNdbError());
286 
287  int res;
288  for (;;)
289  {
290  res= myScanOp->nextResult(true);
291  if (res==1)
292  break; // Scan done.
293  else if (res)
294  APIERROR(myScanOp->getNdbError());
295 
296  Uint64 length= 0;
297  if (myBlobHandle->getLength(length) == -1)
298  APIERROR(myBlobHandle->getNdbError());
299 
300  /* Lowercase everything. */
301  for (Uint64 j= 0; j < length; j++)
302  buffer[j]= tolower(buffer[j]);
303 
304  NdbOperation *myUpdateOp= myScanOp->updateCurrentTuple();
305  if (myUpdateOp == NULL)
306  APIERROR(myTrans->getNdbError());
307  NdbBlob *myBlobHandle2= myUpdateOp->getBlobHandle("my_text");
308  if (myBlobHandle2 == NULL)
309  APIERROR(myUpdateOp->getNdbError());
310  if (myBlobHandle2->setValue(buffer, length))
311  APIERROR(myBlobHandle2->getNdbError());
312 
313  if (-1 == myTrans->execute(NdbTransaction::NoCommit))
314  APIERROR(myTrans->getNdbError());
315  }
316 
317  if (-1 == myTrans->execute(NdbTransaction::Commit))
318  APIERROR(myTrans->getNdbError());
319 
320  myNdb->closeTransaction(myTrans);
321 
322  return 1;
323 }
324 
325 
327  char buffer[10000];
328  Uint32 readLength;
329 };
330 
331 int myFetchHook(NdbBlob* myBlobHandle, void* arg)
332 {
333  ActiveHookData *ahd= (ActiveHookData *)arg;
334 
335  ahd->readLength= sizeof(ahd->buffer) - 1;
336  return myBlobHandle->readData(ahd->buffer, ahd->readLength);
337 }
338 
339 int fetch_key(Ndb *myNdb)
340 {
341  /*
342  Fetch and show the blob field, using setActiveHook().
343  */
344  const NdbDictionary::Dictionary *myDict= myNdb->getDictionary();
345  const NdbDictionary::Table *myTable= myDict->getTable("api_blob");
346  if (myTable == NULL)
347  APIERROR(myDict->getNdbError());
348 
349  NdbTransaction *myTrans= myNdb->startTransaction();
350  if (myTrans == NULL)
351  APIERROR(myNdb->getNdbError());
352 
353  NdbOperation *myNdbOperation= myTrans->getNdbOperation(myTable);
354  if (myNdbOperation == NULL)
355  APIERROR(myTrans->getNdbError());
356  myNdbOperation->readTuple();
357  myNdbOperation->equal("my_id", 1);
358  NdbBlob *myBlobHandle= myNdbOperation->getBlobHandle("my_text");
359  if (myBlobHandle == NULL)
360  APIERROR(myNdbOperation->getNdbError());
361  struct ActiveHookData ahd;
362  if (myBlobHandle->setActiveHook(myFetchHook, &ahd) == -1)
363  APIERROR(myBlobHandle->getNdbError());
364 
365  /*
366  Execute Commit, but calling our callback set up in setActiveHook()
367  before actually committing.
368  */
369  if (-1 == myTrans->execute(NdbTransaction::Commit))
370  APIERROR(myTrans->getNdbError());
371  myNdb->closeTransaction(myTrans);
372 
373  /* Our fetch callback will have been called during the execute(). */
374 
375  ahd.buffer[ahd.readLength]= '\0';
376  std::cout << "Fetched data:" << std::endl << ahd.buffer << std::endl;
377 
378  return 1;
379 }
380 
381 
382 int update2_key(Ndb *myNdb)
383 {
384  char buffer[10000];
385 
386  /* Simple setValue() update. */
387  const NdbDictionary::Dictionary *myDict= myNdb->getDictionary();
388  const NdbDictionary::Table *myTable= myDict->getTable("api_blob");
389  if (myTable == NULL)
390  APIERROR(myDict->getNdbError());
391 
392  NdbTransaction *myTrans= myNdb->startTransaction();
393  if (myTrans == NULL)
394  APIERROR(myNdb->getNdbError());
395 
396  NdbOperation *myNdbOperation= myTrans->getNdbOperation(myTable);
397  if (myNdbOperation == NULL)
398  APIERROR(myTrans->getNdbError());
399  myNdbOperation->updateTuple();
400  myNdbOperation->equal("my_id", 1);
401  NdbBlob *myBlobHandle= myNdbOperation->getBlobHandle("my_text");
402  if (myBlobHandle == NULL)
403  APIERROR(myNdbOperation->getNdbError());
404  memset(buffer, ' ', sizeof(buffer));
405  if (myBlobHandle->setValue(buffer, sizeof(buffer)) == -1)
406  APIERROR(myBlobHandle->getNdbError());
407 
408  if (-1 == myTrans->execute(NdbTransaction::Commit))
409  APIERROR(myTrans->getNdbError());
410  myNdb->closeTransaction(myTrans);
411 
412  return 1;
413 }
414 
415 
416 int delete_key(Ndb *myNdb)
417 {
418  /* Deletion of blob row. */
419  const NdbDictionary::Dictionary *myDict= myNdb->getDictionary();
420  const NdbDictionary::Table *myTable= myDict->getTable("api_blob");
421  if (myTable == NULL)
422  APIERROR(myDict->getNdbError());
423 
424  NdbTransaction *myTrans= myNdb->startTransaction();
425  if (myTrans == NULL)
426  APIERROR(myNdb->getNdbError());
427 
428  NdbOperation *myNdbOperation= myTrans->getNdbOperation(myTable);
429  if (myNdbOperation == NULL)
430  APIERROR(myTrans->getNdbError());
431  myNdbOperation->deleteTuple();
432  myNdbOperation->equal("my_id", 1);
433 
434  if (-1 == myTrans->execute(NdbTransaction::Commit))
435  APIERROR(myTrans->getNdbError());
436  myNdb->closeTransaction(myTrans);
437 
438  return 1;
439 }
440 
441 
442 int main(int argc, char**argv)
443 {
444  if (argc != 3)
445  {
446  std::cout << "Arguments are <socket mysqld> <connect_string cluster>.\n";
447  exit(-1);
448  }
449  char *mysqld_sock = argv[1];
450  const char *connectstring = argv[2];
451  ndb_init();
452  MYSQL mysql;
453 
454  /* Connect to mysql server and create table. */
455  {
456  if ( !mysql_init(&mysql) ) {
457  std::cout << "mysql_init failed.\n";
458  exit(-1);
459  }
460  if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
461  0, mysqld_sock, 0) )
462  MYSQLERROR(mysql);
463 
464  mysql_query(&mysql, "CREATE DATABASE ndb_examples");
465  if (mysql_query(&mysql, "USE ndb_examples") != 0)
466  MYSQLERROR(mysql);
467 
468  create_table(mysql);
469  }
470 
471  /* Connect to ndb cluster. */
472 
473  Ndb_cluster_connection cluster_connection(connectstring);
474  if (cluster_connection.connect(4, 5, 1))
475  {
476  std::cout << "Unable to connect to cluster within 30 secs." << std::endl;
477  exit(-1);
478  }
479  /* Optionally connect and wait for the storage nodes (ndbd's). */
480  if (cluster_connection.wait_until_ready(30,0) < 0)
481  {
482  std::cout << "Cluster was not ready within 30 secs.\n";
483  exit(-1);
484  }
485 
486  Ndb myNdb(&cluster_connection,"ndb_examples");
487  if (myNdb.init(1024) == -1) { // Set max 1024 parallel transactions
488  APIERROR(myNdb.getNdbError());
489  exit(-1);
490  }
491 
492  if(populate(&myNdb) > 0)
493  std::cout << "populate: Success!" << std::endl;
494 
495  if(update_key(&myNdb) > 0)
496  std::cout << "update_key: Success!" << std::endl;
497 
498  if(update_scan(&myNdb) > 0)
499  std::cout << "update_scan: Success!" << std::endl;
500 
501  if(fetch_key(&myNdb) > 0)
502  std::cout << "fetch_key: Success!" << std::endl;
503 
504  if(update2_key(&myNdb) > 0)
505  std::cout << "update2_key: Success!" << std::endl;
506 
507  if(delete_key(&myNdb) > 0)
508  std::cout << "delete_key: Success!" << std::endl;
509 
510  return 0;
511 }