MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HugoOperations.cpp
1 /*
2  Copyright (c) 2003, 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 #include <HugoOperations.hpp>
19 
20 #undef ERR
21 #define ERR(error) \
22 { \
23  const NdbError &_error= (error); \
24  if (!m_quiet) ERR_OUT(g_err, _error); \
25 }
26 
27 int HugoOperations::startTransaction(Ndb* pNdb,
29  const char *keyData, Uint32 keyLen){
30 
31  if (pTrans != NULL){
32  ndbout << "HugoOperations::startTransaction, pTrans != NULL" << endl;
33  return NDBT_FAILED;
34  }
35  pTrans = pNdb->startTransaction(table, keyData, keyLen);
36  if (pTrans == NULL) {
37  const NdbError err = pNdb->getNdbError();
38  ERR(err);
39  setNdbError(err);
40  return NDBT_FAILED;
41  }
42  return NDBT_OK;
43 }
44 
45 int HugoOperations::setTransaction(NdbTransaction* new_trans, bool not_null_ok){
46 
47  if (pTrans != NULL && !not_null_ok){
48  ndbout << "HugoOperations::startTransaction, pTrans != NULL" << endl;
49  return NDBT_FAILED;
50  }
51  pTrans = new_trans;
52  if (pTrans == NULL) {
53  return NDBT_FAILED;
54  }
55  return NDBT_OK;
56 }
57 
58 void
59 HugoOperations::setTransactionId(Uint64 id){
60  if (pTrans != NULL){
61  pTrans->setTransactionId(id);
62  }
63 }
64 
65 int HugoOperations::closeTransaction(Ndb* pNdb){
66 
67  UtilTransactions::closeTransaction(pNdb);
68 
69  m_result_sets.clear();
70  m_executed_result_sets.clear();
71 
72  return NDBT_OK;
73 }
74 
75 NdbConnection* HugoOperations::getTransaction(){
76  return pTrans;
77 }
78 
79 int HugoOperations::pkReadRecord(Ndb* pNdb,
80  int recordNo,
81  int numRecords,
83  NdbOperation::LockMode *lmused){
84  int a;
85  allocRows(numRecords);
86  indexScans.clear();
87  int check;
88 
89  NdbOperation* pOp = 0;
90  pIndexScanOp = 0;
91 
92  for(int r=0; r < numRecords; r++){
93 
94  if(pOp == 0)
95  {
96  pOp = getOperation(pTrans, NdbOperation::ReadRequest);
97  }
98  if (pOp == NULL) {
99  ERR(pTrans->getNdbError());
100  setNdbError(pTrans->getNdbError());
101  return NDBT_FAILED;
102  }
103 
104 rand_lock_mode:
105  switch(lm){
110  if (lmused)
111  * lmused = lm;
112  if(idx && idx->getType() == NdbDictionary::Index::OrderedIndex)
113  {
114  if (pIndexScanOp == 0)
115  {
116  pIndexScanOp = ((NdbIndexScanOperation*)pOp);
117  bool mrrScan= (numRecords > 1);
118  Uint32 flags= mrrScan? NdbScanOperation::SF_MultiRange : 0;
119  check = pIndexScanOp->readTuples(lm, flags);
120  /* Record NdbIndexScanOperation ptr for later... */
121  indexScans.push_back(pIndexScanOp);
122  }
123  }
124  else
125  check = pOp->readTuple(lm);
126  break;
127  default:
128  lm = (NdbOperation::LockMode)((rand() >> 16) & 3);
129  goto rand_lock_mode;
130  }
131 
132  if( check == -1 ) {
133  ERR(pTrans->getNdbError());
134  setNdbError(pTrans->getNdbError());
135  return NDBT_FAILED;
136  }
137 
138  // Define primary keys
139  if (equalForRow(pOp, r+recordNo) != 0)
140  return NDBT_FAILED;
141 
142  Uint32 partId;
143  /* Do we need to set the partitionId for this operation? */
144  if (getPartIdForRow(pOp, r+recordNo, partId))
145  {
146  g_info << "Setting operation partition Id" << endl;
147  pOp->setPartitionId(partId);
148  }
149 
150  if(pIndexScanOp)
151  pIndexScanOp->end_of_bound(r);
152 
153  if(r == 0 || pIndexScanOp == 0)
154  {
155  // Define attributes to read
156  for(a = 0; a<tab.getNoOfColumns(); a++){
157  if((rows[r]->attributeStore(a) =
158  pOp->getValue(tab.getColumn(a)->getName())) == 0) {
159  ERR(pTrans->getNdbError());
160  setNdbError(pTrans->getNdbError());
161  return NDBT_FAILED;
162  }
163  }
164  }
165  /* Note pIndexScanOp will point to the 'last' index scan op
166  * we used. The full list is in the indexScans vector
167  */
168  pOp = pIndexScanOp;
169  }
170  return NDBT_OK;
171 }
172 
173 int HugoOperations::pkReadRandRecord(Ndb* pNdb,
174  int records,
175  int numRecords,
177  NdbOperation::LockMode *lmused){
178  int a;
179  allocRows(numRecords);
180  indexScans.clear();
181  int check;
182 
183  NdbOperation* pOp = 0;
184  pIndexScanOp = 0;
185 
186  for(int r=0; r < numRecords; r++){
187 
188  if(pOp == 0)
189  {
190  pOp = getOperation(pTrans, NdbOperation::ReadRequest);
191  }
192  if (pOp == NULL) {
193  ERR(pTrans->getNdbError());
194  setNdbError(pTrans->getNdbError());
195  return NDBT_FAILED;
196  }
197 
198 rand_lock_mode:
199  switch(lm){
204  if (lmused)
205  * lmused = lm;
206  if(idx && idx->getType() == NdbDictionary::Index::OrderedIndex &&
207  pIndexScanOp == 0)
208  {
209  pIndexScanOp = ((NdbIndexScanOperation*)pOp);
210  check = pIndexScanOp->readTuples(lm);
211  /* Record NdbIndexScanOperation ptr for later... */
212  indexScans.push_back(pIndexScanOp);
213  }
214  else
215  check = pOp->readTuple(lm);
216  break;
217  default:
218  lm = (NdbOperation::LockMode)((rand() >> 16) & 3);
219  goto rand_lock_mode;
220  }
221 
222  if( check == -1 ) {
223  ERR(pTrans->getNdbError());
224  setNdbError(pTrans->getNdbError());
225  return NDBT_FAILED;
226  }
227 
228  int rowid= rand() % records;
229 
230  // Define primary keys
231  if (equalForRow(pOp, rowid) != 0)
232  return NDBT_FAILED;
233 
234  Uint32 partId;
235  /* Do we need to set the partitionId for this operation? */
236  if (getPartIdForRow(pOp, rowid, partId))
237  {
238  g_info << "Setting operation partition Id" << endl;
239  pOp->setPartitionId(partId);
240  }
241 
242  if(pIndexScanOp)
243  pIndexScanOp->end_of_bound(r);
244 
245  if(r == 0 || pIndexScanOp == 0)
246  {
247  // Define attributes to read
248  for(a = 0; a<tab.getNoOfColumns(); a++){
249  if((rows[r]->attributeStore(a) =
250  pOp->getValue(tab.getColumn(a)->getName())) == 0) {
251  ERR(pTrans->getNdbError());
252  setNdbError(pTrans->getNdbError());
253  return NDBT_FAILED;
254  }
255  }
256  }
257  /* Note pIndexScanOp will point to the 'last' index scan op
258  * we used. The full list is in the indexScans vector
259  */
260  pOp = pIndexScanOp;
261  }
262  return NDBT_OK;
263 }
264 
265 int HugoOperations::pkReadRecordLockHandle(Ndb* pNdb,
266  Vector<const NdbLockHandle*>& lockHandles,
267  int recordNo,
268  int numRecords,
270  NdbOperation::LockMode *lmused){
271  if (idx)
272  {
273  g_err << "ERROR : Cannot call pkReadRecordLockHandle on an index"
274  << endl;
275  return NDBT_FAILED;
276  }
277 
278  /* If something other than LM_Read or LM_Exclusive is
279  * passed in then we'll choose, and PkReadRecord
280  * will update lm_used
281  */
282  while (lm != NdbOperation::LM_Read &&
284  {
285  lm = (NdbOperation::LockMode)((rand() >> 16) & 1);
286  }
287 
288  const NdbOperation* prevOp = pTrans->getLastDefinedOperation();
289 
290  int readRc = pkReadRecord(pNdb,
291  recordNo,
292  numRecords,
293  lm,
294  lmused);
295 
296  if (readRc == NDBT_OK)
297  {
298  /* Now traverse operations added, requesting
299  * LockHandles
300  */
301  const NdbOperation* definedOp = (prevOp)? prevOp->next() :
302  pTrans->getFirstDefinedOperation();
303 
304  while (definedOp)
305  {
306  /* Look away now */
307  const NdbLockHandle* lh =
308  (const_cast<NdbOperation*>(definedOp))->getLockHandle();
309 
310  if (lh == NULL)
311  {
312  ERR(definedOp->getNdbError());
313  setNdbError(definedOp->getNdbError());
314  return NDBT_FAILED;
315  }
316 
317  lockHandles.push_back(lh);
318  definedOp = definedOp->next();
319  }
320  }
321 
322  return readRc;
323 }
324 
325 int HugoOperations::pkUnlockRecord(Ndb* pNdb,
326  Vector<const NdbLockHandle*>& lockHandles,
327  int offset,
328  int numRecords,
330 {
331  if (numRecords == ~(0))
332  {
333  numRecords = lockHandles.size() - offset;
334  }
335 
336  if (lockHandles.size() < (unsigned)(offset + numRecords))
337  {
338  g_err << "ERROR : LockHandles size is "
339  << lockHandles.size()
340  << " offset ("
341  << offset
342  << ") and/or numRecords ("
343  << numRecords
344  << ") too large." << endl;
345  return NDBT_FAILED;
346  }
347 
348  for (int i = 0; i < numRecords; i++)
349  {
350  const NdbLockHandle* lh = lockHandles[offset + i];
351  if (lh != NULL)
352  {
353  const NdbOperation* unlockOp = pTrans->unlock(lh, ao);
354 
355  if (unlockOp == NULL)
356  {
357  ERR(pTrans->getNdbError());
358  setNdbError(pTrans->getNdbError());
359  return NDBT_FAILED;
360  }
361  }
362  else
363  {
364  g_err << "ERROR : LockHandle number "
365  << i+offset << " is NULL. "
366  << " offset is " << offset << endl;
367  return NDBT_FAILED;
368  }
369  }
370 
371  return NDBT_OK;
372 }
373 
374 int HugoOperations::pkUpdateRecord(Ndb* pNdb,
375  int recordNo,
376  int numRecords,
377  int updatesValue){
378  allocRows(numRecords);
379  int check;
380  for(int r=0; r < numRecords; r++){
381  NdbOperation* pOp = getOperation(pTrans, NdbOperation::UpdateRequest);
382  if (pOp == NULL) {
383  ERR(pTrans->getNdbError());
384  setNdbError(pTrans->getNdbError());
385  return NDBT_FAILED;
386  }
387 
388  check = pOp->updateTuple();
389  if( check == -1 ) {
390  ERR(pTrans->getNdbError());
391  setNdbError(pTrans->getNdbError());
392  return NDBT_FAILED;
393  }
394 
395  if(setValues(pOp, r+recordNo, updatesValue) != NDBT_OK)
396  {
397  return NDBT_FAILED;
398  }
399 
400  Uint32 partId;
401  if(getPartIdForRow(pOp, r+recordNo, partId))
402  pOp->setPartitionId(partId);
403 
404  pOp->setAnyValue(getAnyValueForRowUpd(r+recordNo, updatesValue));
405 
406  }
407  return NDBT_OK;
408 }
409 
410 int
411 HugoOperations::setValues(NdbOperation* pOp, int rowId, int updateId)
412 {
413  // Define primary keys
414  int a;
415  if (equalForRow(pOp, rowId) != 0)
416  return NDBT_FAILED;
417 
418  for(a = 0; a<tab.getNoOfColumns(); a++){
419  if (tab.getColumn(a)->getPrimaryKey() == false){
420  if(setValueForAttr(pOp, a, rowId, updateId ) != 0){
421  ERR(pTrans->getNdbError());
422  setNdbError(pTrans->getNdbError());
423  return NDBT_FAILED;
424  }
425  }
426  }
427 
428  return NDBT_OK;
429 }
430 
431 int HugoOperations::pkInsertRecord(Ndb* pNdb,
432  int recordNo,
433  int numRecords,
434  int updatesValue){
435 
436  int check;
437  for(int r=0; r < numRecords; r++){
438  NdbOperation* pOp = getOperation(pTrans, NdbOperation::InsertRequest);
439  if (pOp == NULL) {
440  ERR(pTrans->getNdbError());
441  setNdbError(pTrans->getNdbError());
442  return NDBT_FAILED;
443  }
444 
445  check = pOp->insertTuple();
446  if( check == -1 ) {
447  ERR(pTrans->getNdbError());
448  setNdbError(pTrans->getNdbError());
449  return NDBT_FAILED;
450  }
451 
452  if(setValues(pOp, r+recordNo, updatesValue) != NDBT_OK)
453  {
454  m_error.code = pTrans->getNdbError().code;
455  return NDBT_FAILED;
456  }
457 
458  Uint32 partId;
459  if(getPartIdForRow(pOp, r+recordNo, partId))
460  pOp->setPartitionId(partId);
461 
462  }
463  return NDBT_OK;
464 }
465 
466 int HugoOperations::pkWriteRecord(Ndb* pNdb,
467  int recordNo,
468  int numRecords,
469  int updatesValue){
470  int a, check;
471  for(int r=0; r < numRecords; r++){
472  NdbOperation* pOp = pTrans->getNdbOperation(tab.getName());
473  if (pOp == NULL) {
474  ERR(pTrans->getNdbError());
475  setNdbError(pTrans->getNdbError());
476  return NDBT_FAILED;
477  }
478 
479  check = pOp->writeTuple();
480  if( check == -1 ) {
481  ERR(pTrans->getNdbError());
482  setNdbError(pTrans->getNdbError());
483  return NDBT_FAILED;
484  }
485 
486  // Define primary keys
487  if (equalForRow(pOp, r+recordNo) != 0)
488  return NDBT_FAILED;
489 
490  Uint32 partId;
491  if(getPartIdForRow(pOp, r+recordNo, partId))
492  pOp->setPartitionId(partId);
493 
494 
495  // Define attributes to update
496  for(a = 0; a<tab.getNoOfColumns(); a++){
497  if (tab.getColumn(a)->getPrimaryKey() == false){
498  if(setValueForAttr(pOp, a, recordNo+r, updatesValue ) != 0){
499  ERR(pTrans->getNdbError());
500  setNdbError(pTrans->getNdbError());
501  return NDBT_FAILED;
502  }
503  }
504  }
505  }
506  return NDBT_OK;
507 }
508 
509 int HugoOperations::pkWritePartialRecord(Ndb* pNdb,
510  int recordNo,
511  int numRecords){
512 
513  int check;
514  for(int r=0; r < numRecords; r++){
515  NdbOperation* pOp = pTrans->getNdbOperation(tab.getName());
516  if (pOp == NULL) {
517  ERR(pTrans->getNdbError());
518  setNdbError(pTrans->getNdbError());
519  return NDBT_FAILED;
520  }
521 
522  check = pOp->writeTuple();
523  if( check == -1 ) {
524  ERR(pTrans->getNdbError());
525  setNdbError(pTrans->getNdbError());
526  return NDBT_FAILED;
527  }
528 
529  // Define primary keys
530  if (equalForRow(pOp, r+recordNo) != 0)
531  return NDBT_FAILED;
532 
533  Uint32 partId;
534  if(getPartIdForRow(pOp, r+recordNo, partId))
535  pOp->setPartitionId(partId);
536 
537  }
538  return NDBT_OK;
539 }
540 
541 int HugoOperations::pkDeleteRecord(Ndb* pNdb,
542  int recordNo,
543  int numRecords){
544 
545  int check;
546  for(int r=0; r < numRecords; r++){
547  NdbOperation* pOp = getOperation(pTrans, NdbOperation::DeleteRequest);
548  if (pOp == NULL) {
549  ERR(pTrans->getNdbError());
550  setNdbError(pTrans->getNdbError());
551  return NDBT_FAILED;
552  }
553 
554  check = pOp->deleteTuple();
555  if( check == -1 ) {
556  ERR(pTrans->getNdbError());
557  setNdbError(pTrans->getNdbError());
558  return NDBT_FAILED;
559  }
560 
561  // Define primary keys
562  if (equalForRow(pOp, r+recordNo) != 0)
563  return NDBT_FAILED;
564 
565  Uint32 partId;
566  if(getPartIdForRow(pOp, r+recordNo, partId))
567  pOp->setPartitionId(partId);
568  }
569  return NDBT_OK;
570 }
571 
572 int HugoOperations::pkRefreshRecord(Ndb* pNdb,
573  int recordNo,
574  int numRecords,
575  int anyValueInfo){
576 
577  char buffer[NDB_MAX_TUPLE_SIZE];
578  const NdbDictionary::Table * pTab =
579  pNdb->getDictionary()->getTable(tab.getName());
580 
581  if (pTab == 0)
582  {
583  return NDBT_FAILED;
584  }
585 
586  const NdbRecord * record = pTab->getDefaultRecord();
588  opts.optionsPresent = NdbOperation::OperationOptions::OO_ANYVALUE;
589  for(int r=0; r < numRecords; r++)
590  {
591  bzero(buffer, sizeof(buffer));
592  if (calc.equalForRow((Uint8*)buffer, record, r + recordNo))
593  {
594  return NDBT_FAILED;
595  }
596 
597  opts.anyValue = anyValueInfo?
598  (anyValueInfo << 16) | (r+recordNo) :
599  0;
600 
601  const NdbOperation* pOp = pTrans->refreshTuple(record, buffer,
602  &opts, sizeof(opts));
603  if (pOp == NULL)
604  {
605  ERR(pTrans->getNdbError());
606  setNdbError(pTrans->getNdbError());
607  return NDBT_FAILED;
608  }
609  }
610  return NDBT_OK;
611 }
612 
613 int HugoOperations::execute_Commit(Ndb* pNdb,
614  AbortOption eao){
615 
616  int check = 0;
617  check = pTrans->execute(Commit, eao);
618 
619  const NdbError err = pTrans->getNdbError();
620  if( check == -1 || err.code) {
621  ERR(err);
622  setNdbError(err);
623  NdbOperation* pOp = pTrans->getNdbErrorOperation();
624  if (pOp != NULL){
625  const NdbError err2 = pOp->getNdbError();
626  ERR(err2);
627  setNdbError(err2);
628  }
629  if (err.code == 0)
630  return NDBT_FAILED;
631  return err.code;
632  }
633 
634  for(unsigned int i = 0; i<m_result_sets.size(); i++){
635  m_executed_result_sets.push_back(m_result_sets[i]);
636 
637  int rows = m_result_sets[i].records;
638  NdbScanOperation* rs = m_result_sets[i].m_result_set;
639  int res = rs->nextResult();
640  switch(res){
641  case 1:
642  return 626;
643  case -1:
644  const NdbError err = pTrans->getNdbError();
645  ERR(err);
646  setNdbError(err);
647  return (err.code > 0 ? err.code : NDBT_FAILED);
648  }
649 
650  // A row found
651 
652  switch(rows){
653  case 0:
654  return 4000;
655  default:
656  m_result_sets[i].records--;
657  break;
658  }
659  }
660 
661  m_result_sets.clear();
662 
663  return NDBT_OK;
664 }
665 
666 int HugoOperations::execute_NoCommit(Ndb* pNdb, AbortOption eao){
667 
668  int check;
669  check = pTrans->execute(NoCommit, eao);
670 
671  const NdbError err = pTrans->getNdbError();
672  if( check == -1 || err.code) {
673  ERR(err);
674  setNdbError(err);
675  const NdbOperation* pOp = pTrans->getNdbErrorOperation();
676  while (pOp != NULL)
677  {
678  const NdbError err2 = pOp->getNdbError();
679  if (err2.code)
680  {
681  ERR(err2);
682  setNdbError(err2);
683  }
684  pOp = pTrans->getNextCompletedOperation(pOp);
685  }
686  if (err.code == 0)
687  return NDBT_FAILED;
688  return err.code;
689  }
690 
691  for(unsigned int i = 0; i<m_result_sets.size(); i++){
692  m_executed_result_sets.push_back(m_result_sets[i]);
693 
694  int rows = m_result_sets[i].records;
695  NdbScanOperation* rs = m_result_sets[i].m_result_set;
696  int res = rs->nextResult();
697  switch(res){
698  case 1:
699  return 626;
700  case -1:
701  const NdbError err = pTrans->getNdbError();
702  ERR(err);
703  setNdbError(err);
704  return (err.code > 0 ? err.code : NDBT_FAILED);
705  }
706 
707  // A row found
708 
709  switch(rows){
710  case 0:
711  return 4000;
712  default:
713  case 1:
714  break;
715  }
716  }
717 
718  m_result_sets.clear();
719 
720  return NDBT_OK;
721 }
722 
723 int HugoOperations::execute_Rollback(Ndb* pNdb){
724  int check;
725  check = pTrans->execute(Rollback);
726  if( check == -1 ) {
727  const NdbError err = pTrans->getNdbError();
728  ERR(err);
729  setNdbError(err);
730  return NDBT_FAILED;
731  }
732  return NDBT_OK;
733 }
734 
735 void
736 HugoOperations_async_callback(int res, NdbTransaction* pCon, void* ho)
737 {
738  ((HugoOperations*)ho)->callback(res, pCon);
739 }
740 
741 void
742 HugoOperations::callback(int res, NdbTransaction* pCon)
743 {
744  assert(pCon == pTrans);
745  m_async_reply= 1;
746  if(res)
747  {
748  m_async_return = pCon->getNdbError().code;
749  }
750  else
751  {
752  m_async_return = 0;
753  }
754 }
755 
756 int
757 HugoOperations::execute_async(Ndb* pNdb, NdbTransaction::ExecType et,
759 
760  m_async_reply= 0;
761  pTrans->executeAsynchPrepare(et,
762  HugoOperations_async_callback,
763  this,
764  eao);
765 
766  pNdb->sendPreparedTransactions();
767 
768  return NDBT_OK;
769 }
770 
771 int
772 HugoOperations::execute_async_prepare(Ndb* pNdb, NdbTransaction::ExecType et,
774 
775  m_async_reply= 0;
776  pTrans->executeAsynchPrepare(et,
777  HugoOperations_async_callback,
778  this,
779  eao);
780 
781  return NDBT_OK;
782 }
783 
784 int
785 HugoOperations::wait_async(Ndb* pNdb, int timeout)
786 {
787  volatile int * wait = &m_async_reply;
788  while (!* wait)
789  {
790  pNdb->sendPollNdb(1000);
791 
792  if(* wait)
793  {
794  if(m_async_return)
795  ndbout << "ERROR: " << pNdb->getNdbError(m_async_return) << endl;
796  return m_async_return;
797  }
798  }
799  ndbout_c("wait returned nothing...");
800  return -1;
801 }
802 
803 HugoOperations::HugoOperations(const NdbDictionary::Table& _tab,
804  const NdbDictionary::Index* idx):
805  UtilTransactions(_tab, idx),
806  pIndexScanOp(NULL),
807  calc(_tab),
808  m_quiet(false),
809  avCallback(NULL)
810 {
811 }
812 
813 HugoOperations::~HugoOperations(){
814  deallocRows();
815  if (pTrans != NULL)
816  {
817  pTrans->close();
818  pTrans = NULL;
819  }
820 }
821 
822 int
823 HugoOperations::equalForRow(NdbOperation* pOp, int row)
824 {
825  for(int a = 0; a<tab.getNoOfColumns(); a++)
826  {
827  if (tab.getColumn(a)->getPrimaryKey() == true)
828  {
829  if(equalForAttr(pOp, a, row) != 0)
830  {
831  ERR(pOp->getNdbError());
832  setNdbError(pOp->getNdbError());
833  return NDBT_FAILED;
834  }
835  }
836  }
837  return NDBT_OK;
838 }
839 
840 bool HugoOperations::getPartIdForRow(const NdbOperation* pOp,
841  int rowid,
842  Uint32& partId)
843 {
844  if (tab.getFragmentType() == NdbDictionary::Object::UserDefined)
845  {
846  /* Primary keys and Ordered indexes are partitioned according
847  * to the row number
848  * PartitionId must be set for PK access. Ordered indexes
849  * can scan all partitions.
850  */
852  {
853  /* Need to set the partitionId for this op
854  * For Hugo, we use 'HASH' partitioning, which is probably
855  * better called 'MODULO' partitioning with
856  * FragId == rowNum % NumPartitions
857  * This gives a good balance with the normal Hugo data, but different
858  * row to partition assignments than normal key partitioning.
859  */
860  const Uint32 numFrags= tab.getFragmentCount();
861  partId= rowid % numFrags;
862  g_info << "Returning partition Id of " << partId << endl;
863  return true;
864  }
865  }
866  partId= ~0;
867  return false;
868 }
869 
870 int HugoOperations::equalForAttr(NdbOperation* pOp,
871  int attrId,
872  int rowId){
873  const NdbDictionary::Column* attr = tab.getColumn(attrId);
874  if (attr->getPrimaryKey() == false){
875  g_info << "Can't call equalForAttr on non PK attribute" << endl;
876  return NDBT_FAILED;
877  }
878 
879  int len = attr->getSizeInBytes();
880  char buf[NDB_MAX_TUPLE_SIZE];
881  memset(buf, 0, sizeof(buf));
882  Uint32 real_len;
883  const char * value = calc.calcValue(rowId, attrId, 0, buf, len, &real_len);
884  return pOp->equal( attr->getName(), value, real_len);
885 }
886 
887 int HugoOperations::setValueForAttr(NdbOperation* pOp,
888  int attrId,
889  int rowId,
890  int updateId){
891  const NdbDictionary::Column* attr = tab.getColumn(attrId);
892 
893  if (! (attr->getType() == NdbDictionary::Column::Blob))
894  {
895  int len = attr->getSizeInBytes();
896  char buf[NDB_MAX_TUPLE_SIZE];
897  memset(buf, 0, sizeof(buf));
898  Uint32 real_len;
899  const char * value = calc.calcValue(rowId, attrId,
900  updateId, buf, len, &real_len);
901  return pOp->setValue( attr->getName(), value, real_len);
902  }
903  else
904  {
905  char buf[32000];
906  int len = (int)sizeof(buf);
907  Uint32 real_len;
908  const char * value = calc.calcValue(rowId, attrId,
909  updateId, buf, len, &real_len);
910  NdbBlob * b = pOp->getBlobHandle(attrId);
911  if (b == 0)
912  return -1;
913 
914  if (real_len == 0)
915  return b->setNull();
916  else
917  return b->setValue(value, real_len);
918  }
919 }
920 
921 int
922 HugoOperations::verifyUpdatesValue(int updatesValue, int _numRows){
923  _numRows = (_numRows == 0 ? rows.size() : _numRows);
924 
925  int result = NDBT_OK;
926 
927  for(int i = 0; i<_numRows; i++){
928  if(calc.verifyRowValues(rows[i]) != NDBT_OK){
929  g_err << "Inconsistent row"
930  << endl << "\t" << rows[i]->c_str().c_str() << endl;
931  result = NDBT_FAILED;
932  continue;
933  }
934 
935  if(calc.getUpdatesValue(rows[i]) != updatesValue){
936  result = NDBT_FAILED;
937  g_err << "Invalid updates value for row " << i << endl
938  << " updatesValue: " << updatesValue << endl
939  << " calc.getUpdatesValue: " << calc.getUpdatesValue(rows[i]) << endl
940  << rows[i]->c_str().c_str() << endl;
941  continue;
942  }
943  }
944 
945  if(_numRows == 0){
946  g_err << "No rows -> Invalid updates value" << endl;
947  return NDBT_FAILED;
948  }
949 
950  return result;
951 }
952 
953 void HugoOperations::allocRows(int _numRows){
954  if(_numRows <= 0){
955  g_info << "Illegal value for num rows : " << _numRows << endl;
956  abort();
957  }
958 
959  for(int b=rows.size(); b<_numRows; b++){
960  rows.push_back(new NDBT_ResultRow(tab));
961  }
962 }
963 
964 void HugoOperations::deallocRows(){
965  while(rows.size() > 0){
966  delete rows.back();
967  rows.erase(rows.size() - 1);
968  }
969 }
970 
971 int HugoOperations::saveCopyOfRecord(int numRecords ){
972 
973  if (numRecords > (int)rows.size())
974  return NDBT_FAILED;
975 
976  for (int i = 0; i < numRecords; i++){
977  savedRecords.push_back(rows[i]->c_str());
978  }
979  return NDBT_OK;
980 }
981 
982 BaseString HugoOperations::getRecordStr(int recordNum){
983  if (recordNum > (int)rows.size())
984  return NULL;
985  return rows[recordNum]->c_str();
986 }
987 
988 int HugoOperations::getRecordGci(int recordNum){
989  return pTrans->getGCI();
990 }
991 
992 
993 int HugoOperations::compareRecordToCopy(int numRecords ){
994  if (numRecords > (int)rows.size())
995  return NDBT_FAILED;
996  if ((unsigned)numRecords > savedRecords.size())
997  return NDBT_FAILED;
998 
999  int result = NDBT_OK;
1000  for (int i = 0; i < numRecords; i++){
1001  BaseString str = rows[i]->c_str();
1002  ndbout << "row["<<i<<"]: " << str << endl;
1003  ndbout << "sav["<<i<<"]: " << savedRecords[i] << endl;
1004  if (savedRecords[i] == str){
1005  ;
1006  } else {
1007  result = NDBT_FAILED;
1008  }
1009  }
1010  return result;
1011 }
1012 
1013 void
1014 HugoOperations::refresh() {
1015  NdbTransaction * t = getTransaction();
1016  if(t)
1017  t->refresh();
1018 }
1019 
1020 int HugoOperations::indexReadRecords(Ndb*, const char * idxName, int recordNo,
1021  bool exclusive,
1022  int numRecords){
1023 
1024  int a;
1025  allocRows(numRecords);
1026  int check;
1027  for(int r=0; r < numRecords; r++){
1028  NdbOperation* pOp = pTrans->getNdbIndexOperation(idxName, tab.getName());
1029  if (pOp == NULL) {
1030  ERR(pTrans->getNdbError());
1031  setNdbError(pTrans->getNdbError());
1032  return NDBT_FAILED;
1033  }
1034 
1035  if (exclusive == true)
1036  check = pOp->readTupleExclusive();
1037  else
1038  check = pOp->readTuple();
1039  if( check == -1 ) {
1040  ERR(pTrans->getNdbError());
1041  setNdbError(pTrans->getNdbError());
1042  return NDBT_FAILED;
1043  }
1044 
1045  // Define primary keys
1046  if (equalForRow(pOp, r+recordNo) != 0)
1047  return NDBT_FAILED;
1048 
1049  // Define attributes to read
1050  for(a = 0; a<tab.getNoOfColumns(); a++){
1051  if((rows[r]->attributeStore(a) =
1052  pOp->getValue(tab.getColumn(a)->getName())) == 0) {
1053  ERR(pTrans->getNdbError());
1054  setNdbError(pTrans->getNdbError());
1055  return NDBT_FAILED;
1056  }
1057  }
1058  }
1059  return NDBT_OK;
1060 }
1061 
1062 int
1063 HugoOperations::indexUpdateRecord(Ndb*,
1064  const char * idxName,
1065  int recordNo,
1066  int numRecords,
1067  int updatesValue){
1068  int a;
1069  allocRows(numRecords);
1070  int check;
1071  for(int r=0; r < numRecords; r++){
1072  NdbOperation* pOp = pTrans->getNdbIndexOperation(idxName, tab.getName());
1073  if (pOp == NULL) {
1074  ERR(pTrans->getNdbError());
1075  setNdbError(pTrans->getNdbError());
1076  return NDBT_FAILED;
1077  }
1078 
1079  check = pOp->updateTuple();
1080  if( check == -1 ) {
1081  ERR(pTrans->getNdbError());
1082  setNdbError(pTrans->getNdbError());
1083  return NDBT_FAILED;
1084  }
1085 
1086  // Define primary keys
1087  if (equalForRow(pOp, r+recordNo) != 0)
1088  return NDBT_FAILED;
1089 
1090  // Define attributes to update
1091  for(a = 0; a<tab.getNoOfColumns(); a++){
1092  if (tab.getColumn(a)->getPrimaryKey() == false){
1093  if(setValueForAttr(pOp, a, recordNo+r, updatesValue ) != 0){
1094  ERR(pTrans->getNdbError());
1095  setNdbError(pTrans->getNdbError());
1096  return NDBT_FAILED;
1097  }
1098  }
1099  }
1100  }
1101  return NDBT_OK;
1102 }
1103 
1104 int
1105 HugoOperations::scanReadRecords(Ndb* pNdb, NdbScanOperation::LockMode lm,
1106  int records){
1107 
1108  allocRows(records);
1109  NdbScanOperation * pOp = pTrans->getNdbScanOperation(tab.getName());
1110 
1111  if(!pOp)
1112  return -1;
1113 
1114  if(pOp->readTuples(lm, 0, 1)){
1115  return -1;
1116  }
1117 
1118  for(int a = 0; a<tab.getNoOfColumns(); a++){
1119  if((rows[0]->attributeStore(a) =
1120  pOp->getValue(tab.getColumn(a)->getName())) == 0) {
1121  ERR(pTrans->getNdbError());
1122  setNdbError(pTrans->getNdbError());
1123  return NDBT_FAILED;
1124  }
1125  }
1126 
1127  RsPair p = {pOp, records};
1128  m_result_sets.push_back(p);
1129 
1130  return 0;
1131 }
1132 
1133 int
1134 HugoOperations::releaseLockHandles(Ndb* pNdb,
1135  Vector<const NdbLockHandle*>& lockHandles,
1136  int offset,
1137  int numRecords)
1138 {
1139  int totalSize = lockHandles.size();
1140  if (numRecords == ~(0))
1141  {
1142  numRecords = totalSize - offset;
1143  }
1144 
1145  if (totalSize < (offset + numRecords))
1146  {
1147  g_err << "ERROR : LockHandles size is "
1148  << lockHandles.size()
1149  << " offset ("
1150  << offset
1151  << ") and/or numRecords ("
1152  << numRecords
1153  << ") too large." << endl;
1154  return NDBT_FAILED;
1155  }
1156 
1157  for (int i = 0; i < numRecords; i++)
1158  {
1159  const NdbLockHandle* lh = lockHandles[offset + i];
1160  if (lh != NULL)
1161  {
1162  if (pTrans->releaseLockHandle(lh) != 0)
1163  {
1164  ERR(pTrans->getNdbError());
1165  setNdbError(pTrans->getNdbError());
1166  return NDBT_FAILED;
1167  }
1168  const NdbLockHandle* nullPtr = NULL;
1169  (void)nullPtr; // ??
1170  //lockHandles.set(nullPtr, offset + i, nullPtr);
1171  }
1172  else
1173  {
1174  g_err << "ERROR : LockHandle number "
1175  << i+offset << " is NULL. "
1176  << " offset is " << offset << endl;
1177  return NDBT_FAILED;
1178  }
1179  }
1180 
1181  return NDBT_OK;
1182 
1183 }
1184 
1185 static void
1186 update(const NdbError & _err)
1187 {
1188  NdbError & error = (NdbError &) _err;
1189  ndberror_struct ndberror = (ndberror_struct)error;
1190  ndberror_update(&ndberror);
1191  error = NdbError(ndberror);
1192 }
1193 
1194 const NdbError &
1195 HugoOperations::getNdbError() const
1196 {
1197  update(m_error);
1198  return m_error;
1199 }
1200 
1201 void
1202 HugoOperations::setNdbError(const NdbError& error)
1203 {
1204  m_error.code = error.code ? error.code : 1;
1205 }
1206 
1207 void
1208 HugoOperations::setAnyValueCallback(AnyValueCallback avc)
1209 {
1210  avCallback = avc;
1211 }
1212 
1213 Uint32
1214 HugoOperations::getAnyValueForRowUpd(int row, int update)
1215 {
1216  if (avCallback == NULL)
1217  return 0;
1218 
1219  return (avCallback)(pTrans->getNdb(), pTrans,
1220  row, update);
1221 }
1222 
1223 template class Vector<HugoOperations::RsPair>;
1224 template class Vector<const NdbLockHandle*>;