MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdbOperationDefine.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 "API.hpp"
19 #include "NdbOut.hpp"
20 #include <NdbBlob.hpp>
21 
22 #include <Interpreter.hpp>
23 #include <NdbInterpretedCode.hpp>
24 #include <AttributeHeader.hpp>
25 #include <signaldata/TcKeyReq.hpp>
26 
27 /*****************************************************************************
28  * int insertTuple();
29  *****************************************************************************/
30 int
32 {
33  NdbTransaction* tNdbCon = theNdbCon;
34  int tErrorLine = theErrorLine;
35  if (theStatus == Init) {
36  theStatus = OperationDefined;
37  theOperationType = InsertRequest;
38  tNdbCon->theSimpleState = 0;
39  theErrorLine = tErrorLine++;
40  theLockMode = LM_Exclusive;
41  m_abortOption = AbortOnError;
42  return 0;
43  } else {
44  setErrorCode(4200);
45  return -1;
46  }//if
47 }//NdbOperation::insertTuple()
48 /******************************************************************************
49  * int updateTuple();
50  *****************************************************************************/
51 int
53 {
54  NdbTransaction* tNdbCon = theNdbCon;
55  int tErrorLine = theErrorLine;
56  if (theStatus == Init) {
57  theStatus = OperationDefined;
58  tNdbCon->theSimpleState = 0;
59  theOperationType = UpdateRequest;
60  theErrorLine = tErrorLine++;
61  theLockMode = LM_Exclusive;
62  m_abortOption = AbortOnError;
63  return 0;
64  } else {
65  setErrorCode(4200);
66  return -1;
67  }//if
68 }//NdbOperation::updateTuple()
69 /*****************************************************************************
70  * int writeTuple();
71  *****************************************************************************/
72 int
74 {
75  NdbTransaction* tNdbCon = theNdbCon;
76  int tErrorLine = theErrorLine;
77  if (theStatus == Init) {
78  theStatus = OperationDefined;
79  tNdbCon->theSimpleState = 0;
80  theOperationType = WriteRequest;
81  theErrorLine = tErrorLine++;
82  theLockMode = LM_Exclusive;
83  m_abortOption = AbortOnError;
84  return 0;
85  } else {
86  setErrorCode(4200);
87  return -1;
88  }//if
89 }//NdbOperation::writeTuple()
90 /*****************************************************************************
91  * int deleteTuple();
92  *****************************************************************************/
93 int
95 {
96  NdbTransaction* tNdbCon = theNdbCon;
97  int tErrorLine = theErrorLine;
98  if (theStatus == Init) {
99  theStatus = OperationDefined;
100  tNdbCon->theSimpleState = 0;
101  theOperationType = DeleteRequest;
102  theErrorLine = tErrorLine++;
103  theLockMode = LM_Exclusive;
104  m_abortOption = AbortOnError;
105  return 0;
106  } else {
107  setErrorCode(4200);
108  return -1;
109  }//if
110 }//NdbOperation::deleteTuple()
111 
112 /******************************************************************************
113  * int readTuple();
114  *****************************************************************************/
115 int
117 {
118  switch(lm) {
119  case LM_Read:
120  return readTuple();
121  break;
122  case LM_Exclusive:
123  return readTupleExclusive();
124  break;
125  case LM_CommittedRead:
126  return committedRead();
127  break;
128  case LM_SimpleRead:
129  return simpleRead();
130  default:
131  return -1;
132  };
133 }
134 /******************************************************************************
135  * int readTuple();
136  *****************************************************************************/
137 int
139 {
140  NdbTransaction* tNdbCon = theNdbCon;
141  int tErrorLine = theErrorLine;
142  if (theStatus == Init) {
143  theStatus = OperationDefined;
144  tNdbCon->theSimpleState = 0;
145  theOperationType = ReadRequest;
146  theErrorLine = tErrorLine++;
147  theLockMode = LM_Read;
148  m_abortOption = AO_IgnoreError;
149  return 0;
150  } else {
151  setErrorCode(4200);
152  return -1;
153  }//if
154 }//NdbOperation::readTuple()
155 
156 /******************************************************************************
157  * int readTupleExclusive();
158  *****************************************************************************/
159 int
161 {
162  NdbTransaction* tNdbCon = theNdbCon;
163  int tErrorLine = theErrorLine;
164  if (theStatus == Init) {
165  theStatus = OperationDefined;
166  tNdbCon->theSimpleState = 0;
167  theOperationType = ReadExclusive;
168  theErrorLine = tErrorLine++;
169  theLockMode = LM_Exclusive;
170  m_abortOption = AO_IgnoreError;
171  return 0;
172  } else {
173  setErrorCode(4200);
174  return -1;
175  }//if
176 }//NdbOperation::readTupleExclusive()
177 
178 /*****************************************************************************
179  * int simpleRead();
180  *****************************************************************************/
181 int
183 {
184  NdbTransaction* tNdbCon = theNdbCon;
185  int tErrorLine = theErrorLine;
186  if (theStatus == Init) {
187  theStatus = OperationDefined;
188  theOperationType = ReadRequest;
189  theSimpleIndicator = 1;
190  theDirtyIndicator = 0;
191  theErrorLine = tErrorLine++;
192  theLockMode = LM_SimpleRead;
193  m_abortOption = AO_IgnoreError;
194  tNdbCon->theSimpleState = 0;
195  return 0;
196  } else {
197  setErrorCode(4200);
198  return -1;
199  }//if
200 }//NdbOperation::simpleRead()
201 
202 /*****************************************************************************
203  * int dirtyRead();
204  *****************************************************************************/
205 int
207 {
208  return committedRead();
209 }//NdbOperation::dirtyRead()
210 
211 /*****************************************************************************
212  * int committedRead();
213  *****************************************************************************/
214 int
216 {
217  int tErrorLine = theErrorLine;
218  if (theStatus == Init) {
219  theStatus = OperationDefined;
220  theOperationType = ReadRequest;
221  theSimpleIndicator = 1;
222  theDirtyIndicator = 1;
223  theErrorLine = tErrorLine++;
224  theLockMode = LM_CommittedRead;
225  m_abortOption = AO_IgnoreError;
226  return 0;
227  } else {
228  setErrorCode(4200);
229  return -1;
230  }//if
231 }//NdbOperation::committedRead()
232 
233 /*****************************************************************************
234  * int dirtyUpdate();
235  ****************************************************************************/
236 int
238 {
239  NdbTransaction* tNdbCon = theNdbCon;
240  int tErrorLine = theErrorLine;
241  if (theStatus == Init) {
242  theStatus = OperationDefined;
243  theOperationType = UpdateRequest;
244  tNdbCon->theSimpleState = 0;
245  theSimpleIndicator = 1;
246  theDirtyIndicator = 1;
247  theErrorLine = tErrorLine++;
248  theLockMode = LM_CommittedRead;
249  m_abortOption = AbortOnError;
250  return 0;
251  } else {
252  setErrorCode(4200);
253  return -1;
254  }//if
255 }//NdbOperation::dirtyUpdate()
256 
257 /******************************************************************************
258  * int dirtyWrite();
259  *****************************************************************************/
260 int
262 {
263  NdbTransaction* tNdbCon = theNdbCon;
264  int tErrorLine = theErrorLine;
265  if (theStatus == Init) {
266  theStatus = OperationDefined;
267  theOperationType = WriteRequest;
268  tNdbCon->theSimpleState = 0;
269  theSimpleIndicator = 1;
270  theDirtyIndicator = 1;
271  theErrorLine = tErrorLine++;
272  theLockMode = LM_CommittedRead;
273  m_abortOption = AbortOnError;
274  return 0;
275  } else {
276  setErrorCode(4200);
277  return -1;
278  }//if
279 }//NdbOperation::dirtyWrite()
280 
281 /******************************************************************************
282  * int interpretedUpdateTuple();
283  ****************************************************************************/
284 int
286 {
287  NdbTransaction* tNdbCon = theNdbCon;
288  int tErrorLine = theErrorLine;
289  if (theStatus == Init) {
290  theStatus = OperationDefined;
291  tNdbCon->theSimpleState = 0;
292  theOperationType = UpdateRequest;
293  theAI_LenInCurrAI = 25;
294  theLockMode = LM_Exclusive;
295  theErrorLine = tErrorLine++;
296  m_abortOption = AbortOnError;
297  initInterpreter();
298  return 0;
299  } else {
300  setErrorCode(4200);
301  return -1;
302  }//if
303 }//NdbOperation::interpretedUpdateTuple()
304 
305 /*****************************************************************************
306  * int interpretedDeleteTuple();
307  *****************************************************************************/
308 int
310 {
311  NdbTransaction* tNdbCon = theNdbCon;
312  int tErrorLine = theErrorLine;
313  if (theStatus == Init) {
314  theStatus = OperationDefined;
315  tNdbCon->theSimpleState = 0;
316  theOperationType = DeleteRequest;
317 
318  theErrorLine = tErrorLine++;
319  theAI_LenInCurrAI = 25;
320  theLockMode = LM_Exclusive;
321  m_abortOption = AbortOnError;
322  initInterpreter();
323  return 0;
324  } else {
325  setErrorCode(4200);
326  return -1;
327  }//if
328 }//NdbOperation::interpretedDeleteTuple()
329 
330 void
331 NdbOperation::setReadLockMode(LockMode lockMode)
332 {
333  /* We only support changing lock mode for read operations at this time. */
334  assert(theOperationType == ReadRequest || theOperationType == ReadExclusive);
335  switch (lockMode) {
336  case LM_CommittedRead: /* TODO, check theNdbCon->theSimpleState */
337  theOperationType= ReadRequest;
338  theSimpleIndicator= 1;
339  theDirtyIndicator= 1;
340  break;
341  case LM_SimpleRead: /* TODO, check theNdbCon->theSimpleState */
342  theOperationType= ReadRequest;
343  theSimpleIndicator= 1;
344  theDirtyIndicator= 0;
345  break;
346  case LM_Read:
347  theNdbCon->theSimpleState= 0;
348  theOperationType= ReadRequest;
349  theSimpleIndicator= 0;
350  theDirtyIndicator= 0;
351  break;
352  case LM_Exclusive:
353  theNdbCon->theSimpleState= 0;
354  theOperationType= ReadExclusive;
355  theSimpleIndicator= 0;
356  theDirtyIndicator= 0;
357  break;
358  default:
359  /* Not supported / invalid. */
360  assert(false);
361  }
362  theLockMode= lockMode;
363 }
364 
365 
366 /******************************************************************************
367  * int getValue(AttrInfo* tAttrInfo, char* aRef )
368  *
369  * Return Value Return 0 : GetValue was successful.
370  * Return -1: In all other case.
371  * Parameters: tAttrInfo : Attribute object of the retrieved attribute
372  * value.
373  * Remark: Define an attribute to retrieve in query.
374  *****************************************************************************/
375 NdbRecAttr*
376 NdbOperation::getValue_impl(const NdbColumnImpl* tAttrInfo, char* aValue)
377 {
378  NdbRecAttr* tRecAttr;
379  if ((tAttrInfo != NULL) &&
380  (theStatus != Init)){
381  if (tAttrInfo->m_storageType == NDB_STORAGETYPE_DISK)
382  {
383  m_flags &= ~Uint8(OF_NO_DISK);
384  }
385  if (theStatus != GetValue) {
386  if (theStatus == UseNdbRecord)
387  /* This path for extra GetValues for NdbRecord */
388  return getValue_NdbRecord(tAttrInfo, aValue);
389  if (theInterpretIndicator == 1) {
390  if (theStatus == FinalGetValue) {
391  ; // Simply continue with getValue
392  } else if (theStatus == ExecInterpretedValue) {
393  if (insertATTRINFO(Interpreter::EXIT_OK) == -1)
394  return NULL;
395  theInterpretedSize = theTotalCurrAI_Len -
396  (theInitialReadSize + 5);
397  } else if (theStatus == SetValueInterpreted) {
398  theFinalUpdateSize = theTotalCurrAI_Len -
399  (theInitialReadSize + theInterpretedSize + 5);
400  } else {
401  setErrorCodeAbort(4230);
402  return NULL;
403  }//if
404  /* Final read, after running interpreted instructions. */
405  theStatus = FinalGetValue;
406  } else {
407  setErrorCodeAbort(4230);
408  return NULL;
409  }//if
410  }//if
411  AttributeHeader ah(tAttrInfo->m_attrId, 0);
412  if (insertATTRINFO(ah.m_value) != -1) {
413  // Insert Attribute Id into ATTRINFO part.
414 
415  /************************************************************************
416  * Get a Receive Attribute object and link it into the operation object.
417  ***********************************************************************/
418  if((tRecAttr = theReceiver.getValue(tAttrInfo, aValue)) != 0){
419  theErrorLine++;
420  return tRecAttr;
421  } else {
422  setErrorCodeAbort(4000);
423  return NULL;
424  }
425  } else {
426  return NULL;
427  }//if insertATTRINFO failure
428  } else {
429  if (tAttrInfo == NULL) {
430  setErrorCodeAbort(4004);
431  return NULL;
432  }//if
433  }//if
434  setErrorCodeAbort(4200);
435  return NULL;
436 }
437 
438 NdbRecAttr*
439 NdbOperation::getValue_NdbRecord(const NdbColumnImpl* tAttrInfo, char* aValue)
440 {
441  NdbRecAttr* tRecAttr;
442 
443  if (tAttrInfo->m_storageType == NDB_STORAGETYPE_DISK)
444  {
445  m_flags &= ~Uint8(OF_NO_DISK);
446  }
447 
448  /*
449  For getValue with NdbRecord operations, we just allocate the NdbRecAttr,
450  the signal data will be constructed later.
451  */
452  if((tRecAttr = theReceiver.getValue(tAttrInfo, aValue)) != 0) {
453  theErrorLine++;
454  return tRecAttr;
455  } else {
456  setErrorCodeAbort(4000);
457  return NULL;
458  }
459 }
460 
461 /*****************************************************************************
462  * int setValue(AttrInfo* tAttrInfo, char* aValue, Uint32 len)
463  *
464  * Return Value: Return 0 : SetValue was succesful.
465  * Return -1: In all other case.
466  * Parameters: tAttrInfo : Attribute object where the attribute
467  * info exists.
468  * aValue : Reference to the variable with the new value.
469  * len : Length of the value
470  * Remark: Define a attribute to set in a query.
471 ******************************************************************************/
472 int
473 NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
474  const char* aValuePassed)
475 {
476  DBUG_ENTER("NdbOperation::setValue");
477  DBUG_PRINT("enter", ("col: %s op:%d val: 0x%lx",
478  tAttrInfo ? tAttrInfo->m_name.c_str() : "NULL",
479  theOperationType, (long) aValuePassed));
480 
481  int tReturnCode;
482  Uint32 tAttrId;
483  Uint32 tData;
484  Uint32 tempData[ NDB_MAX_TUPLE_SIZE_IN_WORDS ];
485  OperationType tOpType = theOperationType;
486  OperationStatus tStatus = theStatus;
487 
488 
489  if ((tOpType == UpdateRequest) ||
490  (tOpType == WriteRequest)) {
491  if (theInterpretIndicator == 0) {
492  if (tStatus == SetValue) {
493  ;
494  } else {
495  setErrorCodeAbort(4234);
496  DBUG_RETURN(-1);
497  }//if
498  } else {
499  if (tStatus == GetValue) {
500  theInitialReadSize = theTotalCurrAI_Len - 5;
501  } else if (tStatus == ExecInterpretedValue) {
502  //--------------------------------------------------------------------
503  // We insert an exit from interpretation since we are now starting
504  // to set values in the tuple by setValue.
505  //--------------------------------------------------------------------
506  if (insertATTRINFO(Interpreter::EXIT_OK) == -1){
507  DBUG_RETURN(-1);
508  }
509  theInterpretedSize = theTotalCurrAI_Len -
510  (theInitialReadSize + 5);
511  } else if (tStatus == SetValueInterpreted) {
512  ; // Simply continue adding new setValue
513  } else {
514  //--------------------------------------------------------------------
515  // setValue used in the wrong context. Application coding error.
516  //-------------------------------------------------------------------
517  setErrorCodeAbort(4234); //Wrong error code
518  DBUG_RETURN(-1);
519  }//if
520  theStatus = SetValueInterpreted;
521  }//if
522  } else if (tOpType == InsertRequest) {
523  if ((theStatus != SetValue) && (theStatus != OperationDefined)) {
524  setErrorCodeAbort(4234);
525  DBUG_RETURN(-1);
526  }//if
527  } else if (tOpType == ReadRequest || tOpType == ReadExclusive) {
528  setErrorCodeAbort(4504);
529  DBUG_RETURN(-1);
530  } else if (tOpType == DeleteRequest) {
531  setErrorCodeAbort(4504);
532  DBUG_RETURN(-1);
533  } else if (tOpType == OpenScanRequest || tOpType == OpenRangeScanRequest) {
534  setErrorCodeAbort(4228);
535  DBUG_RETURN(-1);
536  } else {
537  //---------------------------------------------------------------------
538  // setValue with undefined operation type.
539  // Probably application coding error.
540  //---------------------------------------------------------------------
541  setErrorCodeAbort(4108);
542  DBUG_RETURN(-1);
543  }//if
544  if (tAttrInfo == NULL) {
545  setErrorCodeAbort(4004);
546  DBUG_RETURN(-1);
547  }//if
548  if (tAttrInfo->m_pk) {
549  if (theOperationType == InsertRequest) {
550  DBUG_RETURN(equal_impl(tAttrInfo, aValuePassed));
551  } else {
552  setErrorCodeAbort(4202);
553  DBUG_RETURN(-1);
554  }//if
555  }//if
556 
557  // Insert Attribute Id into ATTRINFO part.
558  tAttrId = tAttrInfo->m_attrId;
559  if (tAttrInfo->m_storageType == NDB_STORAGETYPE_DISK)
560  {
561  m_flags &= ~Uint8(OF_NO_DISK);
562  }
563  const char *aValue = aValuePassed;
564  if (aValue == NULL) {
565  if (tAttrInfo->m_nullable) {
566  AttributeHeader ah(tAttrId, 0);
567  ah.setNULL();
568  insertATTRINFO(ah.m_value);
569  // Insert Attribute Id with the value
570  // NULL into ATTRINFO part.
571  DBUG_RETURN(0);
572  } else {
573  /***********************************************************************
574  * Setting a NULL value on a NOT NULL attribute is not allowed.
575  **********************************************************************/
576  setErrorCodeAbort(4203);
577  DBUG_RETURN(-1);
578  }//if
579  }//if
580 
581  Uint32 len;
582  if (! tAttrInfo->get_var_length(aValue, len)) {
583  setErrorCodeAbort(4209);
584  DBUG_RETURN(-1);
585  }
586 
587  const Uint32 sizeInBytes = len;
588  const Uint32 bitsInLastWord = 8 * (sizeInBytes & 3) ;
589 
590  const int attributeSize = sizeInBytes;
591  const int slack = sizeInBytes & 3;
592 
593  if (((UintPtr)aValue & 3) != 0 || (slack != 0)){
594  memcpy(&tempData[0], aValue, attributeSize);
595  aValue = (char*)&tempData[0];
596  if(slack != 0) {
597  char * tmp = (char*)&tempData[0];
598  memset(&tmp[attributeSize], 0, (4 - slack));
599  }//if
600  }//if
601 
602  // Excluding bits in last word
603  const Uint32 sizeInWords = sizeInBytes / 4;
604  AttributeHeader ah(tAttrId, sizeInBytes);
605  insertATTRINFO( ah.m_value );
606 
607  /***********************************************************************
608  * Check if the pointer of the value passed is aligned on a 4 byte boundary.
609  * If so only assign the pointer to the internal variable aValue.
610  * If it is not aligned then we start by copying the value to tempData and
611  * use this as aValue instead.
612  *************************************************************************/
613 
614  tReturnCode = insertATTRINFOloop((Uint32*)aValue, sizeInWords);
615  if (tReturnCode == -1) {
616  DBUG_RETURN(tReturnCode);
617  }//if
618  if (bitsInLastWord != 0) {
619  tData = *(Uint32*)(aValue + sizeInWords*4);
620  tData = convertEndian(tData);
621  tData = tData & ((1 << bitsInLastWord) - 1);
622  tData = convertEndian(tData);
623  tReturnCode = insertATTRINFO(tData);
624  if (tReturnCode == -1) {
625  DBUG_RETURN(tReturnCode);
626  }//if
627  }//if
628  theErrorLine++;
629  DBUG_RETURN(0);
630 }//NdbOperation::setValue()
631 
632 
633 int
634 NdbOperation::setAnyValue(Uint32 any_value)
635 {
636  OperationType tOpType = theOperationType;
637 
638  if (theStatus == UseNdbRecord)
639  {
640  /* Method not allowed for NdbRecord, use OperationOptions or
641  ScanOptions structure instead */
642  setErrorCodeAbort(4515);
643  return -1;
644  }
645 
646  const NdbColumnImpl* impl =
647  &NdbColumnImpl::getImpl(* NdbDictionary::Column::ANY_VALUE);
648 
649  switch(tOpType){
650  case DeleteRequest:{
651  Uint32 ah;
652  AttributeHeader::init(&ah, AttributeHeader::ANY_VALUE, 4);
653  if (insertATTRINFO(ah) != -1 && insertATTRINFO(any_value) != -1 )
654  {
655  return 0;
656  }
657  }
658  default:
659  return setValue(impl, (const char *)&any_value);
660  }
661 
662  setErrorCodeAbort(4000);
663  return -1;
664 }
665 
666 int
667 NdbOperation::setOptimize(Uint32 options)
668 {
669  return setValue(&NdbColumnImpl::getImpl(*NdbDictionary::Column::OPTIMIZE),
670  (const char*)&options);
671 }
672 
673 /* Non-const variant of getBlobHandle - can return existing blob
674  * handles, or create new ones for non-NdbRecord operations
675  */
676 NdbBlob*
678 {
679  NdbBlob* tBlob = theBlobList;
680  NdbBlob* tLastBlob = NULL;
681  while (tBlob != NULL) {
682  if (tBlob->theColumn == tAttrInfo)
683  return tBlob;
684  tLastBlob = tBlob;
685  tBlob = tBlob->theNext;
686  }
687 
688  /*
689  * For NdbRecord PK, unique index and scan operations, we only fetch existing
690  * blob handles here, creation must be done by requesting the blob in the
691  * NdbRecord and mask when creating the operation.
692  * For NdbRecAttr PK, IK and scan operations, we allow Blob handles
693  * to be created here. Note that NdbRecAttr PK and unique index ops are handled
694  * differently to NdbRecAttr scan operations.
695  */
696  if (m_attribute_record)
697  {
698  setErrorCodeAbort(4288);
699  return NULL;
700  }
701 
702  /* Check key fully defined for key operations */
703  switch (theStatus)
704  {
705  case TupleKeyDefined:
706  case GetValue:
707  case SetValue:
708  case FinalGetValue:
709  case ExecInterpretedValue:
710  case SetValueInterpreted:
711  /* All ok states to create a Blob Handle in */
712  break;
713  default:
714  {
715  /* Unexpected state to be obtaining Blob handle */
716  /* Invalid usage of blob attribute */
717  setErrorCodeAbort(4264);
718  return NULL;
719  }
720  }
721 
722  tBlob = theNdb->getNdbBlob();
723  if (tBlob == NULL)
724  return NULL;
725  if (tBlob->atPrepare(aCon, this, tAttrInfo) == -1) {
726  theNdb->releaseNdbBlob(tBlob);
727  return NULL;
728  }
729  if (tLastBlob == NULL)
730  theBlobList = tBlob;
731  else
732  tLastBlob->theNext = tBlob;
733  tBlob->theNext = NULL;
734  theNdbCon->theBlobFlag = true;
735  return tBlob;
736 }
737 
738 /* const variant of getBlobHandle - only returns existing blob handles */
739 NdbBlob*
740 NdbOperation::getBlobHandle(NdbTransaction* aCon, const NdbColumnImpl* tAttrInfo) const
741 {
742  NdbBlob* tBlob = theBlobList;
743  while (tBlob != NULL) {
744  if (tBlob->theColumn == tAttrInfo)
745  return tBlob;
746  tBlob = tBlob->theNext;
747  }
748 
749  /*
750  Const method - cannot create a new BLOB handle, NdbRecord
751  or NdbRecAttr
752  */
753  setErrorCodeAbort(4288);
754  return NULL;
755 }
756 
757 /*
758  This is used to set up a blob handle for an NdbRecord operation.
759 
760  It allocates the NdbBlob object, initialises it, and links it into the
761  operation.
762 
763  There are two cases for how to set up the primary key info:
764  1. Normal primary key or hash index key operations. The keyinfo argument
765  is passed as NULL, and the key value is read from the NdbRecord and
766  row passed from the application.
767  2. Take-over scan operation. The keyinfo argument points to a buffer
768  containing KEYINFO20 data.
769 
770  For a scan operation, there is no key info to set up at prepare time.
771 */
772 NdbBlob *
773 NdbOperation::linkInBlobHandle(NdbTransaction *aCon,
774  const NdbColumnImpl *column,
775  NdbBlob * & lastPtr)
776 {
777  int res;
778 
779  NdbBlob *bh= theNdb->getNdbBlob();
780  if (bh == NULL)
781  return NULL;
782 
783  if (theOperationType == OpenScanRequest ||
784  theOperationType == OpenRangeScanRequest)
785  {
786  res= bh->atPrepareNdbRecordScan(aCon, this, column);
787  }
788  else if (m_key_record == NULL)
789  {
790  /* This means that we have a scan take-over operation, and we should
791  obtain the key from KEYINFO20 data.
792  */
793  res= bh->atPrepareNdbRecordTakeover(aCon, this, column,
794  m_key_row, m_keyinfo_length*4);
795  }
796  else
797  {
798  res= bh->atPrepareNdbRecord(aCon, this, column, m_key_record, m_key_row);
799  }
800  if (res == -1)
801  {
802  theNdb->releaseNdbBlob(bh);
803  return NULL;
804  }
805  if (lastPtr)
806  lastPtr->theNext= bh;
807  else
808  theBlobList= bh;
809  lastPtr= bh;
810  bh->theNext= NULL;
811  theNdbCon->theBlobFlag= true;
812 
813  return bh;
814 }
815 
816 /*
817  * Setup blob handles for an NdbRecord operation.
818  *
819  * Create blob handles for all requested blob columns.
820  *
821  * For read request, store the pointers to blob handles in the row.
822  */
823 int
824 NdbOperation::getBlobHandlesNdbRecord(NdbTransaction* aCon,
825  const Uint32 * m_read_mask)
826 {
827  NdbBlob *lastBlob= NULL;
828 
829  for (Uint32 i= 0; i<m_attribute_record->noOfColumns; i++)
830  {
831  const NdbRecord::Attr *col= &m_attribute_record->columns[i];
832  if (!(col->flags & NdbRecord::IsBlob))
833  continue;
834 
835  Uint32 attrId= col->attrId;
836  if (!BitmaskImpl::get((NDB_MAX_ATTRIBUTES_IN_TABLE+31)>>5,
837  m_read_mask, attrId))
838  continue;
839 
840  const NdbColumnImpl *tableColumn= m_currentTable->getColumn(attrId);
841  assert(tableColumn != NULL);
842 
843  NdbBlob *bh= linkInBlobHandle(aCon, tableColumn, lastBlob);
844  if (bh == NULL)
845  return -1;
846 
847  if (theOperationType == ReadRequest || theOperationType == ReadExclusive)
848  {
849  /*
850  * For read request, it is safe to cast away const-ness for the
851  * m_attribute_row.
852  */
853  memcpy((char *)&m_attribute_row[col->offset], &bh, sizeof(bh));
854  }
855  }
856 
857  return 0;
858 }
859 
860 /*
861  For a delete, we need to create blob handles for all table blob columns,
862  so that we can be sure to delete all blob parts for the row.
863  If checkReadset is true, we also check that the caller is not asking to
864  read any blobs as part of the delete.
865 */
866 int
867 NdbOperation::getBlobHandlesNdbRecordDelete(NdbTransaction* aCon,
868  bool checkReadSet,
869  const Uint32 * m_read_mask)
870 {
871  NdbBlob *lastBlob= NULL;
872 
873  assert(theOperationType == DeleteRequest);
874 
875  for (Uint32 i= 0; i < m_currentTable->m_columns.size(); i++)
876  {
877  const NdbColumnImpl* c= m_currentTable->m_columns[i];
878  assert(c != 0);
879  if (!c->getBlobType())
880  continue;
881 
882  if (checkReadSet &&
883  (BitmaskImpl::get((NDB_MAX_ATTRIBUTES_IN_TABLE+31)>>5,
884  m_read_mask, c->m_attrId)))
885  {
886  /* Blobs are not allowed in NdbRecord delete result record */
887  setErrorCodeAbort(4511);
888  return -1;
889  }
890 
891  NdbBlob *bh= linkInBlobHandle(aCon, c, lastBlob);
892  if (bh == NULL)
893  return -1;
894  }
895 
896  return 0;
897 }
898 
899 NdbRecAttr*
900 NdbOperation::getVarValue(const NdbColumnImpl* tAttrInfo,
901  char* aBareValue, Uint16* aLenLoc)
902 {
903  NdbRecAttr* ra = getValue(tAttrInfo, aBareValue);
904  if (ra != NULL) {
905  assert(aLenLoc != NULL);
906  ra->m_getVarValue = aLenLoc;
907  }
908  return ra;
909 }
910 
911 int
912 NdbOperation::setVarValue(const NdbColumnImpl* tAttrInfo,
913  const char* aBareValue, const Uint16& aLen)
914 {
915  DBUG_ENTER("NdbOperation::setVarValue");
916  DBUG_PRINT("info", ("aLen=%u", (Uint32)aLen));
917 
918  // wl3717_todo not optimal..
919  const Uint32 MaxTupleSizeInLongWords= (NDB_MAX_TUPLE_SIZE + 7)/ 8;
920  Uint64 buf[ MaxTupleSizeInLongWords ];
921  assert( aLen < (NDB_MAX_TUPLE_SIZE - 2) );
922  unsigned char* p = (unsigned char*)buf;
923  p[0] = (aLen & 0xff);
924  p[1] = (aLen >> 8);
925  memcpy(&p[2], aBareValue, aLen);
926  if (setValue(tAttrInfo, (char*)buf) == -1)
927  DBUG_RETURN(-1);
928  DBUG_RETURN(0);
929 }
930 
931 /****************************************************************************
932  * int insertATTRINFO( Uint32 aData );
933  *
934  * Return Value: Return 0 : insertATTRINFO was succesful.
935  * Return -1: In all other case.
936  * Parameters: aData: the data to insert into ATTRINFO.
937  * Remark: Puts the the data into either TCKEYREQ signal or
938  * ATTRINFO signal.
939  *****************************************************************************/
940 int
941 NdbOperation::insertATTRINFO( Uint32 aData )
942 {
943  NdbApiSignal* tSignal;
944  register Uint32 tAI_LenInCurrAI = theAI_LenInCurrAI;
945  register Uint32* tAttrPtr = theATTRINFOptr;
946  register Uint32 tTotCurrAILen = theTotalCurrAI_Len;
947 
948  if (tAI_LenInCurrAI >= 25) {
949  Ndb* tNdb = theNdb;
950  NdbApiSignal* tFirstAttrinfo = theFirstATTRINFO;
951  tAI_LenInCurrAI = 3;
952  tSignal = tNdb->getSignal();
953  if (tSignal != NULL) {
954  tSignal->setSignal(m_attrInfoGSN, refToBlock(theNdbCon->m_tcRef));
955  tAttrPtr = &tSignal->getDataPtrSend()[3];
956  if (tFirstAttrinfo == NULL) {
957  tSignal->next(NULL);
958  theFirstATTRINFO = tSignal;
959  theCurrentATTRINFO = tSignal;
960  } else {
961  NdbApiSignal* tCurrentAttrinfoBeforeUpdate = theCurrentATTRINFO;
962  tSignal->next(NULL);
963  theCurrentATTRINFO = tSignal;
964  tCurrentAttrinfoBeforeUpdate->next(tSignal);
965  }//if
966  } else {
967  goto insertATTRINFO_error1;
968  }//if
969  }//if
970  *tAttrPtr = aData;
971  tAttrPtr++;
972  tTotCurrAILen++;
973  tAI_LenInCurrAI++;
974  theTotalCurrAI_Len = tTotCurrAILen;
975  theAI_LenInCurrAI = tAI_LenInCurrAI;
976  theATTRINFOptr = tAttrPtr;
977  return 0;
978 
979 insertATTRINFO_error1:
980  setErrorCodeAbort(4000);
981  return -1;
982 
983 }//NdbOperation::insertATTRINFO()
984 
985 /*****************************************************************************
986  * int insertATTRINFOloop(Uint32* aDataPtr, Uint32 aLength );
987  *
988  * Return Value: Return 0 : insertATTRINFO was succesful.
989  * Return -1: In all other case.
990  * Parameters: aDataPtr: Pointer to the data to insert into ATTRINFO.
991  * aLength: Length of data to be copied
992  * Remark: Puts the the data into either TCKEYREQ signal or
993  * ATTRINFO signal.
994  *****************************************************************************/
995 int
996 NdbOperation::insertATTRINFOloop(register const Uint32* aDataPtr,
997  register Uint32 aLength)
998 {
999  NdbApiSignal* tSignal;
1000  register Uint32 tAI_LenInCurrAI = theAI_LenInCurrAI;
1001  register Uint32 tTotCurrAILen = theTotalCurrAI_Len;
1002  register Uint32* tAttrPtr = theATTRINFOptr;
1003  Ndb* tNdb = theNdb;
1004 
1005  while (aLength > 0) {
1006  if (tAI_LenInCurrAI >= 25) {
1007  NdbApiSignal* tFirstAttrinfo = theFirstATTRINFO;
1008  tAI_LenInCurrAI = 3;
1009  tSignal = tNdb->getSignal();
1010  if (tSignal != NULL) {
1011  tSignal->setSignal(m_attrInfoGSN, refToBlock(theNdbCon->m_tcRef));
1012  tAttrPtr = &tSignal->getDataPtrSend()[3];
1013  if (tFirstAttrinfo == NULL) {
1014  tSignal->next(NULL);
1015  theFirstATTRINFO = tSignal;
1016  theCurrentATTRINFO = tSignal;
1017  } else {
1018  NdbApiSignal* tCurrentAttrinfoBeforeUpdate = theCurrentATTRINFO;
1019  tSignal->next(NULL);
1020  theCurrentATTRINFO = tSignal;
1021  tCurrentAttrinfoBeforeUpdate->next(tSignal);
1022  }//if
1023  } else {
1024  goto insertATTRINFO_error1;
1025  }//if
1026  }//if
1027  {
1028  register Uint32 tData = *aDataPtr;
1029  aDataPtr++;
1030  aLength--;
1031  tAI_LenInCurrAI++;
1032  *tAttrPtr = tData;
1033  tAttrPtr++;
1034  tTotCurrAILen++;
1035  }
1036  }//while
1037  theATTRINFOptr = tAttrPtr;
1038  theTotalCurrAI_Len = tTotCurrAILen;
1039  theAI_LenInCurrAI = tAI_LenInCurrAI;
1040  return 0;
1041 
1042 insertATTRINFO_error1:
1043  setErrorCodeAbort(4000);
1044  return -1;
1045 
1046 }//NdbOperation::insertATTRINFOloop()
1047 
1050 {
1051  return (AbortOption)m_abortOption;
1052 }
1053 
1054 int
1055 NdbOperation::setAbortOption(AbortOption ao)
1056 {
1057  if (theStatus == UseNdbRecord)
1058  {
1059  /* Method not allowed for NdbRecord, use OperationOptions or
1060  ScanOptions structure instead */
1061  setErrorCodeAbort(4515);
1062  return -1;
1063  }
1064 
1065  switch(ao)
1066  {
1067  case AO_IgnoreError:
1068  case AbortOnError:
1069  m_abortOption= ao;
1070  return 0;
1071  default:
1072  return -1;
1073  }
1074 }
1075 
1076 
1077 int
1078 NdbOperation::prepareGetLockHandleNdbRecord()
1079 {
1080  /* This method is used to perform the correct actions
1081  * when the OO_LOCKHANDLE flag is set on an NdbRecord
1082  * operation.
1083  */
1084  assert(theLockHandle == NULL);
1085  theLockHandle = theNdbCon->getLockHandle();
1086  if (!theLockHandle)
1087  {
1088  return 4000; /* Memory allocation issue */
1089  }
1090 
1091  assert(! theLockHandle->isLockRefValid());
1092 
1093  assert(m_attribute_record);
1094  theLockHandle->m_table = m_attribute_record->table;
1095  assert(theLockHandle->m_table);
1096 
1097  NdbRecAttr* ra =
1098  getValue_NdbRecord(&NdbColumnImpl::getImpl(*NdbDictionary::Column::LOCK_REF),
1099  (char*) &theLockHandle->m_lockRef);
1100 
1101  if (!ra)
1102  {
1103  /* Assume error code set */
1104  assert(theError.code);
1105  return theError.code;
1106  }
1107 
1108  theLockHandle->m_state = NdbLockHandle::PREPARED;
1109 
1110  return 0;
1111 }
1112 
1113 /*
1114  * handleOperationOptions
1115  * static member for setting operation options
1116  * Called when defining operations, from NdbTransaction and
1117  * NdbScanOperation
1118  */
1119 int
1120 NdbOperation::handleOperationOptions (const OperationType type,
1121  const OperationOptions *opts,
1122  const Uint32 sizeOfOptions,
1123  NdbOperation *op)
1124 {
1125  /* Check options size for versioning... */
1126  if (unlikely((sizeOfOptions != 0) &&
1127  (sizeOfOptions != sizeof(OperationOptions))))
1128  {
1129  // Handle different sized OperationOptions
1130  // Probably smaller is old version, larger is new version.
1131 
1132  // No other versions currently supported
1133  // Invalid or unsupported OperationOptions structure
1134  return 4297;
1135  }
1136 
1137  bool isScanTakeoverOp = (op->m_key_record == NULL);
1138 
1139  if (opts->optionsPresent & OperationOptions::OO_ABORTOPTION)
1140  {
1141  /* User defined operation abortoption : Allowed for
1142  * any operation
1143  */
1144  switch (opts->abortOption)
1145  {
1146  case AO_IgnoreError:
1147  case AbortOnError:
1148  {
1149  op->m_abortOption=opts->abortOption;
1150  break;
1151  }
1152  default:
1153  // Non-specific abortoption
1154  // Invalid AbortOption
1155  return 4296;
1156  }
1157  }
1158 
1159  if ((opts->optionsPresent & OperationOptions::OO_GETVALUE) &&
1160  (opts->numExtraGetValues > 0))
1161  {
1162  if (opts->extraGetValues == NULL)
1163  {
1164  // Incorrect combination of OperationOptions optionsPresent,
1165  // extraGet/SetValues ptr and numExtraGet/SetValues
1166  return 4512;
1167  }
1168 
1169  // Only certain operation types allow extra GetValues
1170  // Update could be made to support it in future
1171  if (type == ReadRequest ||
1172  type == ReadExclusive ||
1173  type == DeleteRequest)
1174  {
1175  // Could be readTuple(), or lockCurrentTuple().
1176  // We perform old-school NdbRecAttr reads on
1177  // these values.
1178  for (unsigned int i=0; i < opts->numExtraGetValues; i++)
1179  {
1180  GetValueSpec *pvalSpec
1181  = &(opts->extraGetValues[i]);
1182 
1183  pvalSpec->recAttr=NULL;
1184 
1185  if (pvalSpec->column == NULL)
1186  {
1187  // Column is NULL in Get/SetValueSpec structure
1188  return 4295;
1189  }
1190 
1191  NdbRecAttr *pra=
1192  op->getValue_NdbRecord(&NdbColumnImpl::getImpl(*pvalSpec->column),
1193  (char *) pvalSpec->appStorage);
1194 
1195  if (pra == NULL)
1196  {
1197  return -1;
1198  }
1199 
1200  pvalSpec->recAttr = pra;
1201  }
1202  }
1203  else
1204  {
1205  // Bad operation type for GetValue
1206  switch (type)
1207  {
1208  case WriteRequest :
1209  case UpdateRequest :
1210  {
1211  return 4502;
1212  // GetValue not allowed in Update operation
1213  }
1214  case InsertRequest :
1215  {
1216  return 4503;
1217  // GetValue not allowed in Insert operation
1218  }
1219  default :
1220  return 4118;
1221  // Parameter error in API call
1222  }
1223  }
1224  }
1225 
1226  if ((opts->optionsPresent & OperationOptions::OO_SETVALUE) &&
1227  (opts->numExtraSetValues > 0))
1228  {
1229  if (opts->extraSetValues == NULL)
1230  {
1231  // Incorrect combination of OperationOptions optionsPresent,
1232  // extraGet/SetValues ptr and numExtraGet/SetValues
1233  return 4512;
1234  }
1235 
1236  if ((type == InsertRequest) ||
1237  (type == UpdateRequest) ||
1238  (type == WriteRequest))
1239  {
1240  /* Could be insert/update/writeTuple() or
1241  * updateCurrentTuple()
1242  */
1243  // Validate SetValuesSpec
1244  for (Uint32 i=0; i< opts->numExtraSetValues; i++)
1245  {
1246  const NdbDictionary::Column *pcol=opts->extraSetValues[i].column;
1247  const void *pvalue=opts->extraSetValues[i].value;
1248 
1249  if (pcol == NULL)
1250  {
1251  // Column is NULL in Get/SetValueSpec structure
1252  return 4295;
1253  }
1254 
1255  if (type == UpdateRequest && pcol->getPrimaryKey())
1256  {
1257  // It is not possible to update a primary key column.
1258  // It can be set like this for insert and write (but it
1259  // still needs to be included in the key NdbRecord and row).
1260  return 4202;
1261  }
1262 
1263  if (pvalue == NULL)
1264  {
1265  if (!pcol->getNullable())
1266  {
1267  // Trying to set a NOT NULL attribute to NULL
1268  return 4203;
1269  }
1270  }
1271 
1272  NdbDictionary::Column::Type colType=pcol->getType();
1273 
1274  if ((colType == NdbDictionary::Column::Blob) ||
1275  (colType == NdbDictionary::Column::Text))
1276  {
1277  // Invalid usage of blob attribute
1278  return 4264;
1279  }
1280  }
1281 
1282  // Store details of extra set values for later
1283  op->m_extraSetValues = opts->extraSetValues;
1284  op->m_numExtraSetValues = opts->numExtraSetValues;
1285  }
1286  else
1287  {
1288  // Set value and Read/Delete etc is incompatible
1289  return 4204;
1290  }
1291  }
1292 
1293  if (opts->optionsPresent & OperationOptions::OO_PARTITION_ID)
1294  {
1295  /* Should not have any blobs defined at this stage */
1296  assert(op->theBlobList == NULL);
1297 
1298  /* Not allowed for scan takeover ops */
1299  if (unlikely(isScanTakeoverOp))
1300  {
1301  return 4510;
1302  /* User-specified partition id not allowed for scan
1303  * takeover operation
1304  */
1305  }
1306  /* Only allowed for pk ops on user defined partitioned tables
1307  * or when defining an unlock operation
1308  */
1309  if (unlikely( ! (((op->m_attribute_record->flags &
1310  NdbRecord::RecHasUserDefinedPartitioning) &&
1311  (op->m_key_record->table->m_index == NULL)) ||
1312  (type == UnlockRequest))))
1313  {
1314  /* Explicit partitioning info not allowed for table and operation*/
1315  return 4546;
1316  }
1317  op->theDistributionKey=opts->partitionId;
1318  op->theDistrKeyIndicator_= 1;
1319  }
1320 
1321  if (opts->optionsPresent & OperationOptions::OO_INTERPRETED)
1322  {
1323  /* Check the operation type is valid */
1324  if (! ((type == ReadRequest) ||
1325  (type == ReadExclusive) ||
1326  (type == UpdateRequest) ||
1327  (type == DeleteRequest)))
1328  /* NdbInterpretedCode not supported for operation type */
1329  return 4539;
1330 
1331  /* Check the program's for the same table as the
1332  * operation, within a major version number
1333  * Perhaps NdbInterpretedCode should not contain the table
1334  */
1335  const NdbDictionary::Table* codeTable= opts->interpretedCode->getTable();
1336  if (codeTable != NULL)
1337  {
1338  NdbTableImpl* impl= &NdbTableImpl::getImpl(*codeTable);
1339 
1340  if ((impl->m_id != (int) op->m_attribute_record->tableId) ||
1341  (table_version_major(impl->m_version) !=
1342  table_version_major(op->m_attribute_record->tableVersion)))
1343  return 4524; // NdbInterpretedCode is for different table`
1344  }
1345 
1346  /* Check the program's finalised */
1347  if ((opts->interpretedCode->m_flags &
1348  NdbInterpretedCode::Finalised) == 0)
1349  return 4519; // NdbInterpretedCode::finalise() not called.
1350 
1351  op->m_interpreted_code = opts->interpretedCode;
1352  }
1353 
1354  if (opts->optionsPresent & OperationOptions::OO_ANYVALUE)
1355  {
1356  /* Any operation can have an ANYVALUE set */
1357  op->m_any_value = opts->anyValue;
1358  op->m_flags |= OF_USE_ANY_VALUE;
1359  }
1360 
1361  if (opts->optionsPresent & OperationOptions::OO_CUSTOMDATA)
1362  {
1363  /* Set the operation's customData ptr */
1364  op->m_customData = opts->customData;
1365  }
1366 
1367  if (opts->optionsPresent & OperationOptions::OO_LOCKHANDLE)
1368  {
1369  if (unlikely(op->theNdb->getMinDbNodeVersion() <
1370  NDBD_UNLOCK_OP_SUPPORTED))
1371  {
1372  /* Function not implemented yet */
1373  return 4003;
1374  }
1375 
1376  /* Check that this is a pk read with a lock
1377  * No need to worry about Blob lock upgrade issues as
1378  * Blobs have not been handled at this stage
1379  */
1380  if (((type != ReadRequest) &&
1381  (type != ReadExclusive)) ||
1382  (op->m_key_record &&
1383  (op->m_key_record->flags & NdbRecord::RecIsIndex)) ||
1384  ((op->theLockMode != LM_Read) &&
1385  (op->theLockMode != LM_Exclusive)))
1386  {
1387  return 4549; /* getLockHandle only supported for primary key read with a lock */
1388  }
1389 
1390  int prepareRc = op->prepareGetLockHandleNdbRecord();
1391  if (prepareRc != 0)
1392  {
1393  return prepareRc;
1394  }
1395  }
1396 
1397  if (opts->optionsPresent & OperationOptions::OO_QUEUABLE)
1398  {
1399  op->m_flags |= OF_QUEUEABLE;
1400  }
1401 
1402  if (opts->optionsPresent & OperationOptions::OO_NOT_QUEUABLE)
1403  {
1404  op->m_flags &= ~Uint8(OF_QUEUEABLE);
1405  }
1406 
1407  if (opts->optionsPresent & OperationOptions::OO_DEFERRED_CONSTAINTS)
1408  {
1409  op->m_flags |= OF_DEFERRED_CONSTRAINTS;
1410  }
1411 
1412  return 0;
1413 }