1 /* Copyright (c) 2003-2008 MySQL AB
2    Use is subject to license terms
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 Street, Fifth Floor, Boston, MA  02110-1301, USA */
16 
17 #include <ndb_global.h>
18 #include <NdbOperation.hpp>
19 #include "NdbApiSignal.hpp"
20 #include <NdbTransaction.hpp>
21 #include <Ndb.hpp>
22 #include <NdbRecAttr.hpp>
23 #include "NdbUtil.hpp"
24 #include "NdbOut.hpp"
25 #include "NdbImpl.hpp"
26 #include <NdbIndexScanOperation.hpp>
27 #include <NdbBlob.hpp>
28 
29 #include <Interpreter.hpp>
30 
31 #include <AttributeHeader.hpp>
32 #include <signaldata/TcKeyReq.hpp>
33 
34 /*****************************************************************************
35  * int insertTuple();
36  *****************************************************************************/
37 int
insertTuple()38 NdbOperation::insertTuple()
39 {
40   NdbTransaction* tNdbCon = theNdbCon;
41   int tErrorLine = theErrorLine;
42   if (theStatus == Init) {
43     theStatus = OperationDefined;
44     theOperationType = InsertRequest;
45     tNdbCon->theSimpleState = 0;
46     theErrorLine = tErrorLine++;
47     theLockMode = LM_Exclusive;
48     m_abortOption = AbortOnError;
49     return 0;
50   } else {
51     setErrorCode(4200);
52     return -1;
53   }//if
54 }//NdbOperation::insertTuple()
55 /******************************************************************************
56  * int updateTuple();
57  *****************************************************************************/
58 int
updateTuple()59 NdbOperation::updateTuple()
60 {
61   NdbTransaction* tNdbCon = theNdbCon;
62   int tErrorLine = theErrorLine;
63   if (theStatus == Init) {
64     theStatus = OperationDefined;
65     tNdbCon->theSimpleState = 0;
66     theOperationType = UpdateRequest;
67     theErrorLine = tErrorLine++;
68     theLockMode = LM_Exclusive;
69     m_abortOption = AbortOnError;
70     return 0;
71   } else {
72     setErrorCode(4200);
73     return -1;
74   }//if
75 }//NdbOperation::updateTuple()
76 /*****************************************************************************
77  * int writeTuple();
78  *****************************************************************************/
79 int
writeTuple()80 NdbOperation::writeTuple()
81 {
82   NdbTransaction* tNdbCon = theNdbCon;
83   int tErrorLine = theErrorLine;
84   if (theStatus == Init) {
85     theStatus = OperationDefined;
86     tNdbCon->theSimpleState = 0;
87     theOperationType = WriteRequest;
88     theErrorLine = tErrorLine++;
89     theLockMode = LM_Exclusive;
90     m_abortOption = AbortOnError;
91     return 0;
92   } else {
93     setErrorCode(4200);
94     return -1;
95   }//if
96 }//NdbOperation::writeTuple()
97 /*****************************************************************************
98  * int deleteTuple();
99  *****************************************************************************/
100 int
deleteTuple()101 NdbOperation::deleteTuple()
102 {
103   NdbTransaction* tNdbCon = theNdbCon;
104   int tErrorLine = theErrorLine;
105   if (theStatus == Init) {
106     theStatus = OperationDefined;
107     tNdbCon->theSimpleState = 0;
108     theOperationType = DeleteRequest;
109     theErrorLine = tErrorLine++;
110     theLockMode = LM_Exclusive;
111     m_abortOption = AbortOnError;
112     return 0;
113   } else {
114     setErrorCode(4200);
115     return -1;
116   }//if
117 }//NdbOperation::deleteTuple()
118 
119 /******************************************************************************
120  * int readTuple();
121  *****************************************************************************/
122 int
readTuple(NdbOperation::LockMode lm)123 NdbOperation::readTuple(NdbOperation::LockMode lm)
124 {
125   switch(lm) {
126   case LM_Read:
127     return readTuple();
128     break;
129   case LM_Exclusive:
130     return readTupleExclusive();
131     break;
132   case LM_CommittedRead:
133     return committedRead();
134     break;
135   case LM_SimpleRead:
136     return simpleRead();
137   default:
138     return -1;
139   };
140 }
141 /******************************************************************************
142  * int readTuple();
143  *****************************************************************************/
144 int
readTuple()145 NdbOperation::readTuple()
146 {
147   NdbTransaction* tNdbCon = theNdbCon;
148   int tErrorLine = theErrorLine;
149   if (theStatus == Init) {
150     theStatus = OperationDefined;
151     tNdbCon->theSimpleState = 0;
152     theOperationType = ReadRequest;
153     theErrorLine = tErrorLine++;
154     theLockMode = LM_Read;
155     m_abortOption = AO_IgnoreError;
156     return 0;
157   } else {
158     setErrorCode(4200);
159     return -1;
160   }//if
161 }//NdbOperation::readTuple()
162 
163 /******************************************************************************
164  * int readTupleExclusive();
165  *****************************************************************************/
166 int
readTupleExclusive()167 NdbOperation::readTupleExclusive()
168 {
169   NdbTransaction* tNdbCon = theNdbCon;
170   int tErrorLine = theErrorLine;
171   if (theStatus == Init) {
172     theStatus = OperationDefined;
173     tNdbCon->theSimpleState = 0;
174     theOperationType = ReadExclusive;
175     theErrorLine = tErrorLine++;
176     theLockMode = LM_Exclusive;
177     m_abortOption = AO_IgnoreError;
178     return 0;
179   } else {
180     setErrorCode(4200);
181     return -1;
182   }//if
183 }//NdbOperation::readTupleExclusive()
184 
185 /*****************************************************************************
186  * int simpleRead();
187  *****************************************************************************/
188 int
simpleRead()189 NdbOperation::simpleRead()
190 {
191   NdbTransaction* tNdbCon = theNdbCon;
192   int tErrorLine = theErrorLine;
193   if (theStatus == Init) {
194     theStatus = OperationDefined;
195     theOperationType = ReadRequest;
196     theSimpleIndicator = 1;
197     theDirtyIndicator = 0;
198     theErrorLine = tErrorLine++;
199     theLockMode = LM_SimpleRead;
200     m_abortOption = AO_IgnoreError;
201     tNdbCon->theSimpleState = 0;
202     return 0;
203   } else {
204     setErrorCode(4200);
205     return -1;
206   }//if
207 }//NdbOperation::simpleRead()
208 
209 /*****************************************************************************
210  * int dirtyRead();
211  *****************************************************************************/
212 int
dirtyRead()213 NdbOperation::dirtyRead()
214 {
215   return committedRead();
216 }//NdbOperation::dirtyRead()
217 
218 /*****************************************************************************
219  * int committedRead();
220  *****************************************************************************/
221 int
committedRead()222 NdbOperation::committedRead()
223 {
224   int tErrorLine = theErrorLine;
225   if (theStatus == Init) {
226     theStatus = OperationDefined;
227     theOperationType = ReadRequest;
228     theSimpleIndicator = 1;
229     theDirtyIndicator = 1;
230     theErrorLine = tErrorLine++;
231     theLockMode = LM_CommittedRead;
232     m_abortOption = AO_IgnoreError;
233     return 0;
234   } else {
235     setErrorCode(4200);
236     return -1;
237   }//if
238 }//NdbOperation::committedRead()
239 
240 /*****************************************************************************
241  * int dirtyUpdate();
242  ****************************************************************************/
243 int
dirtyUpdate()244 NdbOperation::dirtyUpdate()
245 {
246   NdbTransaction* tNdbCon = theNdbCon;
247   int tErrorLine = theErrorLine;
248   if (theStatus == Init) {
249     theStatus = OperationDefined;
250     theOperationType = UpdateRequest;
251     tNdbCon->theSimpleState = 0;
252     theSimpleIndicator = 1;
253     theDirtyIndicator = 1;
254     theErrorLine = tErrorLine++;
255     theLockMode = LM_CommittedRead;
256     m_abortOption = AbortOnError;
257     return 0;
258   } else {
259     setErrorCode(4200);
260     return -1;
261   }//if
262 }//NdbOperation::dirtyUpdate()
263 
264 /******************************************************************************
265  * int dirtyWrite();
266  *****************************************************************************/
267 int
dirtyWrite()268 NdbOperation::dirtyWrite()
269 {
270   NdbTransaction* tNdbCon = theNdbCon;
271   int tErrorLine = theErrorLine;
272   if (theStatus == Init) {
273     theStatus = OperationDefined;
274     theOperationType = WriteRequest;
275     tNdbCon->theSimpleState = 0;
276     theSimpleIndicator = 1;
277     theDirtyIndicator = 1;
278     theErrorLine = tErrorLine++;
279     theLockMode = LM_CommittedRead;
280     m_abortOption = AbortOnError;
281     return 0;
282   } else {
283     setErrorCode(4200);
284     return -1;
285   }//if
286 }//NdbOperation::dirtyWrite()
287 
288 /******************************************************************************
289  * int interpretedUpdateTuple();
290  ****************************************************************************/
291 int
interpretedUpdateTuple()292 NdbOperation::interpretedUpdateTuple()
293 {
294   NdbTransaction* tNdbCon = theNdbCon;
295   int tErrorLine = theErrorLine;
296   if (theStatus == Init) {
297     theStatus = OperationDefined;
298     tNdbCon->theSimpleState = 0;
299     theOperationType = UpdateRequest;
300     theAI_LenInCurrAI = 25;
301     theLockMode = LM_Exclusive;
302     theErrorLine = tErrorLine++;
303     m_abortOption = AbortOnError;
304     initInterpreter();
305     return 0;
306   } else {
307     setErrorCode(4200);
308     return -1;
309   }//if
310 }//NdbOperation::interpretedUpdateTuple()
311 
312 /*****************************************************************************
313  * int interpretedDeleteTuple();
314  *****************************************************************************/
315 int
interpretedDeleteTuple()316 NdbOperation::interpretedDeleteTuple()
317 {
318   NdbTransaction* tNdbCon = theNdbCon;
319   int tErrorLine = theErrorLine;
320   if (theStatus == Init) {
321     theStatus = OperationDefined;
322     tNdbCon->theSimpleState = 0;
323     theOperationType = DeleteRequest;
324 
325     theErrorLine = tErrorLine++;
326     theAI_LenInCurrAI = 25;
327     theLockMode = LM_Exclusive;
328     m_abortOption = AbortOnError;
329     initInterpreter();
330     return 0;
331   } else {
332     setErrorCode(4200);
333     return -1;
334   }//if
335 }//NdbOperation::interpretedDeleteTuple()
336 
337 void
setReadLockMode(LockMode lockMode)338 NdbOperation::setReadLockMode(LockMode lockMode)
339 {
340   /* We only support changing lock mode for read operations at this time. */
341   assert(theOperationType == ReadRequest || theOperationType == ReadExclusive);
342   switch (lockMode) {
343   case LM_CommittedRead: /* TODO, check theNdbCon->theSimpleState */
344     theOperationType= ReadRequest;
345     theSimpleIndicator= 1;
346     theDirtyIndicator= 1;
347     break;
348   case LM_SimpleRead: /* TODO, check theNdbCon->theSimpleState */
349     theOperationType= ReadRequest;
350     theSimpleIndicator= 1;
351     theDirtyIndicator= 0;
352     break;
353   case LM_Read:
354     theNdbCon->theSimpleState= 0;
355     theOperationType= ReadRequest;
356     theSimpleIndicator= 0;
357     theDirtyIndicator= 0;
358     break;
359   case LM_Exclusive:
360     theNdbCon->theSimpleState= 0;
361     theOperationType= ReadExclusive;
362     theSimpleIndicator= 0;
363     theDirtyIndicator= 0;
364     break;
365   default:
366     /* Not supported / invalid. */
367     assert(false);
368   }
369   theLockMode= lockMode;
370 }
371 
372 
373 /******************************************************************************
374  * int getValue(AttrInfo* tAttrInfo, char* aRef )
375  *
376  * Return Value   Return 0 : GetValue was successful.
377  *                Return -1: In all other case.
378  * Parameters:    tAttrInfo : Attribute object of the retrieved attribute
379  *                            value.
380  * Remark:        Define an attribute to retrieve in query.
381  *****************************************************************************/
382 NdbRecAttr*
getValue_impl(const NdbColumnImpl * tAttrInfo,char * aValue)383 NdbOperation::getValue_impl(const NdbColumnImpl* tAttrInfo, char* aValue)
384 {
385   NdbRecAttr* tRecAttr;
386   if ((tAttrInfo != NULL) &&
387       (theStatus != Init)){
388     m_no_disk_flag &= (tAttrInfo->m_storageType == NDB_STORAGETYPE_DISK ? 0:1);
389     if (theStatus != GetValue) {
390       if (theInterpretIndicator == 1) {
391 	if (theStatus == FinalGetValue) {
392 	  ; // Simply continue with getValue
393 	} else if (theStatus == ExecInterpretedValue) {
394 	  if (insertATTRINFO(Interpreter::EXIT_OK) == -1)
395 	    return NULL;
396 	  theInterpretedSize = theTotalCurrAI_Len -
397 	    (theInitialReadSize + 5);
398 	} else if (theStatus == SetValueInterpreted) {
399 	  theFinalUpdateSize = theTotalCurrAI_Len -
400 	    (theInitialReadSize + theInterpretedSize + 5);
401 	} else {
402 	  setErrorCodeAbort(4230);
403 	  return NULL;
404 	}//if
405 	// MASV - How would execution come here?
406 	theStatus = FinalGetValue;
407       } else {
408 	setErrorCodeAbort(4230);
409 	return NULL;
410       }//if
411     }//if
412     AttributeHeader ah(tAttrInfo->m_attrId, 0);
413     if (insertATTRINFO(ah.m_value) != -1) {
414       // Insert Attribute Id into ATTRINFO part.
415 
416       /************************************************************************
417        * Get a Receive Attribute object and link it into the operation object.
418        ***********************************************************************/
419       if((tRecAttr = theReceiver.getValue(tAttrInfo, aValue)) != 0){
420 	theErrorLine++;
421 	return tRecAttr;
422       } else {
423 	setErrorCodeAbort(4000);
424 	return NULL;
425       }
426     } else {
427       return NULL;
428     }//if insertATTRINFO failure
429   } else {
430     if (tAttrInfo == NULL) {
431       setErrorCodeAbort(4004);
432       return NULL;
433     }//if
434   }//if
435   setErrorCodeAbort(4200);
436   return NULL;
437 }
438 
439 /*****************************************************************************
440  * int setValue(AttrInfo* tAttrInfo, char* aValue, Uint32 len)
441  *
442  * Return Value:  Return 0 : SetValue was succesful.
443  *                Return -1: In all other case.
444  * Parameters:    tAttrInfo : Attribute object where the attribute
445  *                            info exists.
446  *                aValue : Reference to the variable with the new value.
447  *		  len    : Length of the value
448  * Remark:        Define a attribute to set in a query.
449 ******************************************************************************/
450 int
setValue(const NdbColumnImpl * tAttrInfo,const char * aValuePassed)451 NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
452 			const char* aValuePassed)
453 {
454   DBUG_ENTER("NdbOperation::setValue");
455   DBUG_PRINT("enter", ("col: %s  op:%d  val: 0x%lx",
456                        tAttrInfo->m_name.c_str(), theOperationType,
457                        (long) aValuePassed));
458 
459   int tReturnCode;
460   Uint32 tAttrId;
461   Uint32 tData;
462   Uint32 tempData[2000];
463   OperationType tOpType = theOperationType;
464   OperationStatus tStatus = theStatus;
465 
466 
467   if ((tOpType == UpdateRequest) ||
468       (tOpType == WriteRequest)) {
469     if (theInterpretIndicator == 0) {
470       if (tStatus == SetValue) {
471         ;
472       } else {
473         setErrorCodeAbort(4234);
474         DBUG_RETURN(-1);
475       }//if
476     } else {
477       if (tStatus == GetValue) {
478         theInitialReadSize = theTotalCurrAI_Len - 5;
479       } else if	(tStatus == ExecInterpretedValue) {
480 	//--------------------------------------------------------------------
481 	// We insert an exit from interpretation since we are now starting
482 	// to set values in the tuple by setValue.
483 	//--------------------------------------------------------------------
484         if (insertATTRINFO(Interpreter::EXIT_OK) == -1){
485           DBUG_RETURN(-1);
486 	}
487         theInterpretedSize = theTotalCurrAI_Len -
488           (theInitialReadSize + 5);
489       } else if (tStatus == SetValueInterpreted) {
490         ; // Simply continue adding new setValue
491       } else {
492 	//--------------------------------------------------------------------
493 	// setValue used in the wrong context. Application coding error.
494 	//-------------------------------------------------------------------
495         setErrorCodeAbort(4234); //Wrong error code
496         DBUG_RETURN(-1);
497       }//if
498       theStatus = SetValueInterpreted;
499     }//if
500   } else if (tOpType == InsertRequest) {
501     if ((theStatus != SetValue) && (theStatus != OperationDefined)) {
502       setErrorCodeAbort(4234);
503       DBUG_RETURN(-1);
504     }//if
505   } else if (tOpType == ReadRequest || tOpType == ReadExclusive) {
506     setErrorCodeAbort(4504);
507     DBUG_RETURN(-1);
508   } else if (tOpType == DeleteRequest) {
509     setErrorCodeAbort(4504);
510     DBUG_RETURN(-1);
511   } else if (tOpType == OpenScanRequest || tOpType == OpenRangeScanRequest) {
512     setErrorCodeAbort(4228);
513     DBUG_RETURN(-1);
514   } else {
515     //---------------------------------------------------------------------
516     // setValue with undefined operation type.
517     // Probably application coding error.
518     //---------------------------------------------------------------------
519     setErrorCodeAbort(4108);
520     DBUG_RETURN(-1);
521   }//if
522   if (tAttrInfo == NULL) {
523     setErrorCodeAbort(4004);
524     DBUG_RETURN(-1);
525   }//if
526   if (tAttrInfo->m_pk) {
527     if (theOperationType == InsertRequest) {
528       DBUG_RETURN(equal_impl(tAttrInfo, aValuePassed));
529     } else {
530       setErrorCodeAbort(4202);
531       DBUG_RETURN(-1);
532     }//if
533   }//if
534 
535   // Insert Attribute Id into ATTRINFO part.
536   tAttrId = tAttrInfo->m_attrId;
537   m_no_disk_flag &= (tAttrInfo->m_storageType == NDB_STORAGETYPE_DISK ? 0:1);
538   const char *aValue = aValuePassed;
539   if (aValue == NULL) {
540     if (tAttrInfo->m_nullable) {
541       AttributeHeader ah(tAttrId, 0);
542       ah.setNULL();
543       insertATTRINFO(ah.m_value);
544       // Insert Attribute Id with the value
545       // NULL into ATTRINFO part.
546       DBUG_RETURN(0);
547     } else {
548       /***********************************************************************
549        * Setting a NULL value on a NOT NULL attribute is not allowed.
550        **********************************************************************/
551       setErrorCodeAbort(4203);
552       DBUG_RETURN(-1);
553     }//if
554   }//if
555 
556   Uint32 len;
557   if (! tAttrInfo->get_var_length(aValue, len)) {
558     setErrorCodeAbort(4209);
559     DBUG_RETURN(-1);
560   }
561 
562   const Uint32 sizeInBytes = len;
563   const Uint32 bitsInLastWord = 8 * (sizeInBytes & 3) ;
564 
565   const int attributeSize = sizeInBytes;
566   const int slack = sizeInBytes & 3;
567 
568   if (((UintPtr)aValue & 3) != 0 || (slack != 0)){
569     memcpy(&tempData[0], aValue, attributeSize);
570     aValue = (char*)&tempData[0];
571     if(slack != 0) {
572       char * tmp = (char*)&tempData[0];
573       memset(&tmp[attributeSize], 0, (4 - slack));
574     }//if
575   }//if
576 
577   // Excluding bits in last word
578   const Uint32 sizeInWords = sizeInBytes / 4;
579   AttributeHeader ah(tAttrId, sizeInBytes);
580   insertATTRINFO( ah.m_value );
581 
582   /***********************************************************************
583    * Check if the pointer of the value passed is aligned on a 4 byte boundary.
584    * If so only assign the pointer to the internal variable aValue.
585    * If it is not aligned then we start by copying the value to tempData and
586    * use this as aValue instead.
587    *************************************************************************/
588 
589   tReturnCode = insertATTRINFOloop((Uint32*)aValue, sizeInWords);
590   if (tReturnCode == -1) {
591     DBUG_RETURN(tReturnCode);
592   }//if
593   if (bitsInLastWord != 0) {
594     tData = *(Uint32*)(aValue + sizeInWords*4);
595     tData = convertEndian(tData);
596     tData = tData & ((1 << bitsInLastWord) - 1);
597     tData = convertEndian(tData);
598     tReturnCode = insertATTRINFO(tData);
599     if (tReturnCode == -1) {
600       DBUG_RETURN(tReturnCode);
601     }//if
602   }//if
603   theErrorLine++;
604   DBUG_RETURN(0);
605 }//NdbOperation::setValue()
606 
607 
608 int
setAnyValue(Uint32 any_value)609 NdbOperation::setAnyValue(Uint32 any_value)
610 {
611   const NdbColumnImpl* impl =
612     &NdbColumnImpl::getImpl(* NdbDictionary::Column::ANY_VALUE);
613   OperationType tOpType = theOperationType;
614 
615   switch(tOpType){
616   case DeleteRequest:{
617     Uint32 ah;
618     AttributeHeader::init(&ah, AttributeHeader::ANY_VALUE, 4);
619     if (insertATTRINFO(ah) != -1 && insertATTRINFO(any_value) != -1 )
620     {
621       return 0;
622     }
623   }
624   default:
625     return setValue(impl, (const char *)&any_value);
626   }
627 
628   setErrorCodeAbort(4000);
629   return -1;
630 }
631 
632 
633 NdbBlob*
getBlobHandle(NdbTransaction * aCon,const NdbColumnImpl * tAttrInfo)634 NdbOperation::getBlobHandle(NdbTransaction* aCon, const NdbColumnImpl* tAttrInfo)
635 {
636   NdbBlob* tBlob = theBlobList;
637   NdbBlob* tLastBlob = NULL;
638   while (tBlob != NULL) {
639     if (tBlob->theColumn == tAttrInfo)
640       return tBlob;
641     tLastBlob = tBlob;
642     tBlob = tBlob->theNext;
643   }
644   tBlob = theNdb->getNdbBlob();
645   if (tBlob == NULL)
646     return NULL;
647   if (tBlob->atPrepare(aCon, this, tAttrInfo) == -1) {
648     theNdb->releaseNdbBlob(tBlob);
649     return NULL;
650   }
651   if (tLastBlob == NULL)
652     theBlobList = tBlob;
653   else
654     tLastBlob->theNext = tBlob;
655   tBlob->theNext = NULL;
656   theNdbCon->theBlobFlag = true;
657   return tBlob;
658 }
659 
660 /****************************************************************************
661  * int insertATTRINFO( Uint32 aData );
662  *
663  * Return Value:   Return 0 : insertATTRINFO was succesful.
664  *                 Return -1: In all other case.
665  * Parameters:     aData: the data to insert into ATTRINFO.
666  * Remark:         Puts the the data into either TCKEYREQ signal or
667  *                 ATTRINFO signal.
668  *****************************************************************************/
669 int
insertATTRINFO(Uint32 aData)670 NdbOperation::insertATTRINFO( Uint32 aData )
671 {
672   NdbApiSignal* tSignal;
673   register Uint32 tAI_LenInCurrAI = theAI_LenInCurrAI;
674   register Uint32* tAttrPtr = theATTRINFOptr;
675   register Uint32 tTotCurrAILen = theTotalCurrAI_Len;
676 
677   if (tAI_LenInCurrAI >= 25) {
678     Ndb* tNdb = theNdb;
679     NdbApiSignal* tFirstAttrinfo = theFirstATTRINFO;
680     tAI_LenInCurrAI = 3;
681     tSignal = tNdb->getSignal();
682     if (tSignal != NULL) {
683       tSignal->setSignal(m_attrInfoGSN);
684       tAttrPtr = &tSignal->getDataPtrSend()[3];
685       if (tFirstAttrinfo == NULL) {
686         tSignal->next(NULL);
687         theFirstATTRINFO = tSignal;
688         theCurrentATTRINFO = tSignal;
689       } else {
690         NdbApiSignal* tCurrentAttrinfoBeforeUpdate = theCurrentATTRINFO;
691         tSignal->next(NULL);
692         theCurrentATTRINFO = tSignal;
693         tCurrentAttrinfoBeforeUpdate->next(tSignal);
694       }//if
695     } else {
696       goto insertATTRINFO_error1;
697     }//if
698   }//if
699   *tAttrPtr = aData;
700   tAttrPtr++;
701   tTotCurrAILen++;
702   tAI_LenInCurrAI++;
703   theTotalCurrAI_Len = tTotCurrAILen;
704   theAI_LenInCurrAI = tAI_LenInCurrAI;
705   theATTRINFOptr = tAttrPtr;
706   return 0;
707 
708 insertATTRINFO_error1:
709   setErrorCodeAbort(4000);
710   return -1;
711 
712 }//NdbOperation::insertATTRINFO()
713 
714 /*****************************************************************************
715  * int insertATTRINFOloop(Uint32* aDataPtr, Uint32 aLength );
716  *
717  * Return Value:  Return 0 : insertATTRINFO was succesful.
718  *                Return -1: In all other case.
719  * Parameters:    aDataPtr: Pointer to the data to insert into ATTRINFO.
720  *                aLength: Length of data to be copied
721  * Remark:        Puts the the data into either TCKEYREQ signal or
722  *                ATTRINFO signal.
723  *****************************************************************************/
724 int
insertATTRINFOloop(register const Uint32 * aDataPtr,register Uint32 aLength)725 NdbOperation::insertATTRINFOloop(register const Uint32* aDataPtr,
726 				 register Uint32 aLength)
727 {
728   NdbApiSignal* tSignal;
729   register Uint32 tAI_LenInCurrAI = theAI_LenInCurrAI;
730   register Uint32 tTotCurrAILen = theTotalCurrAI_Len;
731   register Uint32* tAttrPtr = theATTRINFOptr;
732   Ndb* tNdb = theNdb;
733 
734   while (aLength > 0) {
735     if (tAI_LenInCurrAI >= 25) {
736       NdbApiSignal* tFirstAttrinfo = theFirstATTRINFO;
737       tAI_LenInCurrAI = 3;
738       tSignal = tNdb->getSignal();
739       if (tSignal != NULL) {
740         tSignal->setSignal(m_attrInfoGSN);
741         tAttrPtr = &tSignal->getDataPtrSend()[3];
742         if (tFirstAttrinfo == NULL) {
743           tSignal->next(NULL);
744           theFirstATTRINFO = tSignal;
745           theCurrentATTRINFO = tSignal;
746         } else {
747           NdbApiSignal* tCurrentAttrinfoBeforeUpdate = theCurrentATTRINFO;
748           tSignal->next(NULL);
749           theCurrentATTRINFO = tSignal;
750           tCurrentAttrinfoBeforeUpdate->next(tSignal);
751         }//if
752       } else {
753         goto insertATTRINFO_error1;
754       }//if
755     }//if
756     {
757       register Uint32 tData = *aDataPtr;
758       aDataPtr++;
759       aLength--;
760       tAI_LenInCurrAI++;
761       *tAttrPtr = tData;
762       tAttrPtr++;
763       tTotCurrAILen++;
764     }
765   }//while
766   theATTRINFOptr = tAttrPtr;
767   theTotalCurrAI_Len = tTotCurrAILen;
768   theAI_LenInCurrAI = tAI_LenInCurrAI;
769   return 0;
770 
771 insertATTRINFO_error1:
772   setErrorCodeAbort(4000);
773   return -1;
774 
775 }//NdbOperation::insertATTRINFOloop()
776 
777 NdbOperation::AbortOption
getAbortOption() const778 NdbOperation::getAbortOption() const
779 {
780   return (AbortOption)m_abortOption;
781 }
782 
783 int
setAbortOption(AbortOption ao)784 NdbOperation::setAbortOption(AbortOption ao)
785 {
786   switch(ao)
787   {
788     case AO_IgnoreError:
789     case AbortOnError:
790       m_abortOption= ao;
791       return 0;
792     default:
793       return -1;
794   }
795 }
796