1
/* Copyright (C) 2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#include <ndb_global.h>
17
#include <NdbOperation.hpp>
18
#include "NdbApiSignal.hpp"
19
#include <NdbTransaction.hpp>
21
#include <NdbRecAttr.hpp>
22
#include "NdbUtil.hpp"
24
#include "NdbImpl.hpp"
25
#include <NdbIndexScanOperation.hpp>
26
#include <NdbBlob.hpp>
28
#include <Interpreter.hpp>
30
#include <AttributeHeader.hpp>
31
#include <signaldata/TcKeyReq.hpp>
33
/*****************************************************************************
35
*****************************************************************************/
37
NdbOperation::insertTuple()
39
NdbTransaction* tNdbCon = theNdbCon;
40
int tErrorLine = theErrorLine;
41
if (theStatus == Init) {
42
theStatus = OperationDefined;
43
theOperationType = InsertRequest;
44
tNdbCon->theSimpleState = 0;
45
theErrorLine = tErrorLine++;
46
theLockMode = LM_Exclusive;
47
m_abortOption = AbortOnError;
53
}//NdbOperation::insertTuple()
54
/******************************************************************************
56
*****************************************************************************/
58
NdbOperation::updateTuple()
60
NdbTransaction* tNdbCon = theNdbCon;
61
int tErrorLine = theErrorLine;
62
if (theStatus == Init) {
63
theStatus = OperationDefined;
64
tNdbCon->theSimpleState = 0;
65
theOperationType = UpdateRequest;
66
theErrorLine = tErrorLine++;
67
theLockMode = LM_Exclusive;
68
m_abortOption = AbortOnError;
74
}//NdbOperation::updateTuple()
75
/*****************************************************************************
77
*****************************************************************************/
79
NdbOperation::writeTuple()
81
NdbTransaction* tNdbCon = theNdbCon;
82
int tErrorLine = theErrorLine;
83
if (theStatus == Init) {
84
theStatus = OperationDefined;
85
tNdbCon->theSimpleState = 0;
86
theOperationType = WriteRequest;
87
theErrorLine = tErrorLine++;
88
theLockMode = LM_Exclusive;
89
m_abortOption = AbortOnError;
95
}//NdbOperation::writeTuple()
96
/*****************************************************************************
98
*****************************************************************************/
100
NdbOperation::deleteTuple()
102
NdbTransaction* tNdbCon = theNdbCon;
103
int tErrorLine = theErrorLine;
104
if (theStatus == Init) {
105
theStatus = OperationDefined;
106
tNdbCon->theSimpleState = 0;
107
theOperationType = DeleteRequest;
108
theErrorLine = tErrorLine++;
109
theLockMode = LM_Exclusive;
110
m_abortOption = AbortOnError;
116
}//NdbOperation::deleteTuple()
118
/******************************************************************************
120
*****************************************************************************/
122
NdbOperation::readTuple(NdbOperation::LockMode lm)
129
return readTupleExclusive();
131
case LM_CommittedRead:
132
return committedRead();
140
/******************************************************************************
142
*****************************************************************************/
144
NdbOperation::readTuple()
146
NdbTransaction* tNdbCon = theNdbCon;
147
int tErrorLine = theErrorLine;
148
if (theStatus == Init) {
149
theStatus = OperationDefined;
150
tNdbCon->theSimpleState = 0;
151
theOperationType = ReadRequest;
152
theErrorLine = tErrorLine++;
153
theLockMode = LM_Read;
154
m_abortOption = AO_IgnoreError;
160
}//NdbOperation::readTuple()
162
/******************************************************************************
163
* int readTupleExclusive();
164
*****************************************************************************/
166
NdbOperation::readTupleExclusive()
168
NdbTransaction* tNdbCon = theNdbCon;
169
int tErrorLine = theErrorLine;
170
if (theStatus == Init) {
171
theStatus = OperationDefined;
172
tNdbCon->theSimpleState = 0;
173
theOperationType = ReadExclusive;
174
theErrorLine = tErrorLine++;
175
theLockMode = LM_Exclusive;
176
m_abortOption = AO_IgnoreError;
182
}//NdbOperation::readTupleExclusive()
184
/*****************************************************************************
186
*****************************************************************************/
188
NdbOperation::simpleRead()
190
NdbTransaction* tNdbCon = theNdbCon;
191
int tErrorLine = theErrorLine;
192
if (theStatus == Init) {
193
theStatus = OperationDefined;
194
theOperationType = ReadRequest;
195
theSimpleIndicator = 1;
196
theDirtyIndicator = 0;
197
theErrorLine = tErrorLine++;
198
theLockMode = LM_SimpleRead;
199
m_abortOption = AO_IgnoreError;
200
tNdbCon->theSimpleState = 0;
206
}//NdbOperation::simpleRead()
208
/*****************************************************************************
210
*****************************************************************************/
212
NdbOperation::dirtyRead()
214
return committedRead();
215
}//NdbOperation::dirtyRead()
217
/*****************************************************************************
218
* int committedRead();
219
*****************************************************************************/
221
NdbOperation::committedRead()
223
int tErrorLine = theErrorLine;
224
if (theStatus == Init) {
225
theStatus = OperationDefined;
226
theOperationType = ReadRequest;
227
theSimpleIndicator = 1;
228
theDirtyIndicator = 1;
229
theErrorLine = tErrorLine++;
230
theLockMode = LM_CommittedRead;
231
m_abortOption = AO_IgnoreError;
237
}//NdbOperation::committedRead()
239
/*****************************************************************************
241
****************************************************************************/
243
NdbOperation::dirtyUpdate()
245
NdbTransaction* tNdbCon = theNdbCon;
246
int tErrorLine = theErrorLine;
247
if (theStatus == Init) {
248
theStatus = OperationDefined;
249
theOperationType = UpdateRequest;
250
tNdbCon->theSimpleState = 0;
251
theSimpleIndicator = 1;
252
theDirtyIndicator = 1;
253
theErrorLine = tErrorLine++;
254
theLockMode = LM_CommittedRead;
255
m_abortOption = AbortOnError;
261
}//NdbOperation::dirtyUpdate()
263
/******************************************************************************
265
*****************************************************************************/
267
NdbOperation::dirtyWrite()
269
NdbTransaction* tNdbCon = theNdbCon;
270
int tErrorLine = theErrorLine;
271
if (theStatus == Init) {
272
theStatus = OperationDefined;
273
theOperationType = WriteRequest;
274
tNdbCon->theSimpleState = 0;
275
theSimpleIndicator = 1;
276
theDirtyIndicator = 1;
277
theErrorLine = tErrorLine++;
278
theLockMode = LM_CommittedRead;
279
m_abortOption = AbortOnError;
285
}//NdbOperation::dirtyWrite()
287
/******************************************************************************
288
* int interpretedUpdateTuple();
289
****************************************************************************/
291
NdbOperation::interpretedUpdateTuple()
293
NdbTransaction* tNdbCon = theNdbCon;
294
int tErrorLine = theErrorLine;
295
if (theStatus == Init) {
296
theStatus = OperationDefined;
297
tNdbCon->theSimpleState = 0;
298
theOperationType = UpdateRequest;
299
theAI_LenInCurrAI = 25;
300
theLockMode = LM_Exclusive;
301
theErrorLine = tErrorLine++;
302
m_abortOption = AbortOnError;
309
}//NdbOperation::interpretedUpdateTuple()
311
/*****************************************************************************
312
* int interpretedDeleteTuple();
313
*****************************************************************************/
315
NdbOperation::interpretedDeleteTuple()
317
NdbTransaction* tNdbCon = theNdbCon;
318
int tErrorLine = theErrorLine;
319
if (theStatus == Init) {
320
theStatus = OperationDefined;
321
tNdbCon->theSimpleState = 0;
322
theOperationType = DeleteRequest;
324
theErrorLine = tErrorLine++;
325
theAI_LenInCurrAI = 25;
326
theLockMode = LM_Exclusive;
327
m_abortOption = AbortOnError;
334
}//NdbOperation::interpretedDeleteTuple()
337
NdbOperation::setReadLockMode(LockMode lockMode)
339
/* We only support changing lock mode for read operations at this time. */
340
assert(theOperationType == ReadRequest || theOperationType == ReadExclusive);
342
case LM_CommittedRead: /* TODO, check theNdbCon->theSimpleState */
343
theOperationType= ReadRequest;
344
theSimpleIndicator= 1;
345
theDirtyIndicator= 1;
347
case LM_SimpleRead: /* TODO, check theNdbCon->theSimpleState */
348
theOperationType= ReadRequest;
349
theSimpleIndicator= 1;
350
theDirtyIndicator= 0;
353
theNdbCon->theSimpleState= 0;
354
theOperationType= ReadRequest;
355
theSimpleIndicator= 0;
356
theDirtyIndicator= 0;
359
theNdbCon->theSimpleState= 0;
360
theOperationType= ReadExclusive;
361
theSimpleIndicator= 0;
362
theDirtyIndicator= 0;
365
/* Not supported / invalid. */
368
theLockMode= lockMode;
372
/******************************************************************************
373
* int getValue(AttrInfo* tAttrInfo, char* aRef )
375
* Return Value Return 0 : GetValue was successful.
376
* Return -1: In all other case.
377
* Parameters: tAttrInfo : Attribute object of the retrieved attribute
379
* Remark: Define an attribute to retrieve in query.
380
*****************************************************************************/
382
NdbOperation::getValue_impl(const NdbColumnImpl* tAttrInfo, char* aValue)
384
NdbRecAttr* tRecAttr;
385
if ((tAttrInfo != NULL) &&
386
(theStatus != Init)){
387
m_no_disk_flag &= (tAttrInfo->m_storageType == NDB_STORAGETYPE_DISK ? 0:1);
388
if (theStatus != GetValue) {
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)
395
theInterpretedSize = theTotalCurrAI_Len -
396
(theInitialReadSize + 5);
397
} else if (theStatus == SetValueInterpreted) {
398
theFinalUpdateSize = theTotalCurrAI_Len -
399
(theInitialReadSize + theInterpretedSize + 5);
401
setErrorCodeAbort(4230);
404
// MASV - How would execution come here?
405
theStatus = FinalGetValue;
407
setErrorCodeAbort(4230);
411
AttributeHeader ah(tAttrInfo->m_attrId, 0);
412
if (insertATTRINFO(ah.m_value) != -1) {
413
// Insert Attribute Id into ATTRINFO part.
415
/************************************************************************
416
* Get a Receive Attribute object and link it into the operation object.
417
***********************************************************************/
418
if((tRecAttr = theReceiver.getValue(tAttrInfo, aValue)) != 0){
422
setErrorCodeAbort(4000);
427
}//if insertATTRINFO failure
429
if (tAttrInfo == NULL) {
430
setErrorCodeAbort(4004);
434
setErrorCodeAbort(4200);
438
/*****************************************************************************
439
* int setValue(AttrInfo* tAttrInfo, char* aValue, Uint32 len)
441
* Return Value: Return 0 : SetValue was succesful.
442
* Return -1: In all other case.
443
* Parameters: tAttrInfo : Attribute object where the attribute
445
* aValue : Reference to the variable with the new value.
446
* len : Length of the value
447
* Remark: Define a attribute to set in a query.
448
******************************************************************************/
450
NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
451
const char* aValuePassed)
453
DBUG_ENTER("NdbOperation::setValue");
454
DBUG_PRINT("enter", ("col: %s op:%d val: 0x%lx",
455
tAttrInfo->m_name.c_str(), theOperationType,
456
(long) aValuePassed));
461
Uint32 tempData[2000];
462
OperationType tOpType = theOperationType;
463
OperationStatus tStatus = theStatus;
466
if ((tOpType == UpdateRequest) ||
467
(tOpType == WriteRequest)) {
468
if (theInterpretIndicator == 0) {
469
if (tStatus == SetValue) {
472
setErrorCodeAbort(4234);
476
if (tStatus == GetValue) {
477
theInitialReadSize = theTotalCurrAI_Len - 5;
478
} else if (tStatus == ExecInterpretedValue) {
479
//--------------------------------------------------------------------
480
// We insert an exit from interpretation since we are now starting
481
// to set values in the tuple by setValue.
482
//--------------------------------------------------------------------
483
if (insertATTRINFO(Interpreter::EXIT_OK) == -1){
486
theInterpretedSize = theTotalCurrAI_Len -
487
(theInitialReadSize + 5);
488
} else if (tStatus == SetValueInterpreted) {
489
; // Simply continue adding new setValue
491
//--------------------------------------------------------------------
492
// setValue used in the wrong context. Application coding error.
493
//-------------------------------------------------------------------
494
setErrorCodeAbort(4234); //Wrong error code
497
theStatus = SetValueInterpreted;
499
} else if (tOpType == InsertRequest) {
500
if ((theStatus != SetValue) && (theStatus != OperationDefined)) {
501
setErrorCodeAbort(4234);
504
} else if (tOpType == ReadRequest || tOpType == ReadExclusive) {
505
setErrorCodeAbort(4504);
507
} else if (tOpType == DeleteRequest) {
508
setErrorCodeAbort(4504);
510
} else if (tOpType == OpenScanRequest || tOpType == OpenRangeScanRequest) {
511
setErrorCodeAbort(4228);
514
//---------------------------------------------------------------------
515
// setValue with undefined operation type.
516
// Probably application coding error.
517
//---------------------------------------------------------------------
518
setErrorCodeAbort(4108);
521
if (tAttrInfo == NULL) {
522
setErrorCodeAbort(4004);
525
if (tAttrInfo->m_pk) {
526
if (theOperationType == InsertRequest) {
527
DBUG_RETURN(equal_impl(tAttrInfo, aValuePassed));
529
setErrorCodeAbort(4202);
534
// Insert Attribute Id into ATTRINFO part.
535
tAttrId = tAttrInfo->m_attrId;
536
m_no_disk_flag &= (tAttrInfo->m_storageType == NDB_STORAGETYPE_DISK ? 0:1);
537
const char *aValue = aValuePassed;
538
if (aValue == NULL) {
539
if (tAttrInfo->m_nullable) {
540
AttributeHeader ah(tAttrId, 0);
542
insertATTRINFO(ah.m_value);
543
// Insert Attribute Id with the value
544
// NULL into ATTRINFO part.
547
/***********************************************************************
548
* Setting a NULL value on a NOT NULL attribute is not allowed.
549
**********************************************************************/
550
setErrorCodeAbort(4203);
556
if (! tAttrInfo->get_var_length(aValue, len)) {
557
setErrorCodeAbort(4209);
561
const Uint32 sizeInBytes = len;
562
const Uint32 bitsInLastWord = 8 * (sizeInBytes & 3) ;
564
const int attributeSize = sizeInBytes;
565
const int slack = sizeInBytes & 3;
567
if (((UintPtr)aValue & 3) != 0 || (slack != 0)){
568
memcpy(&tempData[0], aValue, attributeSize);
569
aValue = (char*)&tempData[0];
571
char * tmp = (char*)&tempData[0];
572
memset(&tmp[attributeSize], 0, (4 - slack));
576
// Excluding bits in last word
577
const Uint32 sizeInWords = sizeInBytes / 4;
578
AttributeHeader ah(tAttrId, sizeInBytes);
579
insertATTRINFO( ah.m_value );
581
/***********************************************************************
582
* Check if the pointer of the value passed is aligned on a 4 byte boundary.
583
* If so only assign the pointer to the internal variable aValue.
584
* If it is not aligned then we start by copying the value to tempData and
585
* use this as aValue instead.
586
*************************************************************************/
588
tReturnCode = insertATTRINFOloop((Uint32*)aValue, sizeInWords);
589
if (tReturnCode == -1) {
590
DBUG_RETURN(tReturnCode);
592
if (bitsInLastWord != 0) {
593
tData = *(Uint32*)(aValue + sizeInWords*4);
594
tData = convertEndian(tData);
595
tData = tData & ((1 << bitsInLastWord) - 1);
596
tData = convertEndian(tData);
597
tReturnCode = insertATTRINFO(tData);
598
if (tReturnCode == -1) {
599
DBUG_RETURN(tReturnCode);
604
}//NdbOperation::setValue()
608
NdbOperation::setAnyValue(Uint32 any_value)
610
const NdbColumnImpl* impl =
611
&NdbColumnImpl::getImpl(* NdbDictionary::Column::ANY_VALUE);
612
OperationType tOpType = theOperationType;
617
AttributeHeader::init(&ah, AttributeHeader::ANY_VALUE, 4);
618
if (insertATTRINFO(ah) != -1 && insertATTRINFO(any_value) != -1 )
624
return setValue(impl, (const char *)&any_value);
627
setErrorCodeAbort(4000);
633
NdbOperation::getBlobHandle(NdbTransaction* aCon, const NdbColumnImpl* tAttrInfo)
635
NdbBlob* tBlob = theBlobList;
636
NdbBlob* tLastBlob = NULL;
637
while (tBlob != NULL) {
638
if (tBlob->theColumn == tAttrInfo)
641
tBlob = tBlob->theNext;
643
tBlob = theNdb->getNdbBlob();
646
if (tBlob->atPrepare(aCon, this, tAttrInfo) == -1) {
647
theNdb->releaseNdbBlob(tBlob);
650
if (tLastBlob == NULL)
653
tLastBlob->theNext = tBlob;
654
tBlob->theNext = NULL;
655
theNdbCon->theBlobFlag = true;
659
/****************************************************************************
660
* int insertATTRINFO( Uint32 aData );
662
* Return Value: Return 0 : insertATTRINFO was succesful.
663
* Return -1: In all other case.
664
* Parameters: aData: the data to insert into ATTRINFO.
665
* Remark: Puts the the data into either TCKEYREQ signal or
667
*****************************************************************************/
669
NdbOperation::insertATTRINFO( Uint32 aData )
671
NdbApiSignal* tSignal;
672
register Uint32 tAI_LenInCurrAI = theAI_LenInCurrAI;
673
register Uint32* tAttrPtr = theATTRINFOptr;
674
register Uint32 tTotCurrAILen = theTotalCurrAI_Len;
676
if (tAI_LenInCurrAI >= 25) {
678
NdbApiSignal* tFirstAttrinfo = theFirstATTRINFO;
680
tSignal = tNdb->getSignal();
681
if (tSignal != NULL) {
682
tSignal->setSignal(m_attrInfoGSN);
683
tAttrPtr = &tSignal->getDataPtrSend()[3];
684
if (tFirstAttrinfo == NULL) {
686
theFirstATTRINFO = tSignal;
687
theCurrentATTRINFO = tSignal;
689
NdbApiSignal* tCurrentAttrinfoBeforeUpdate = theCurrentATTRINFO;
691
theCurrentATTRINFO = tSignal;
692
tCurrentAttrinfoBeforeUpdate->next(tSignal);
695
goto insertATTRINFO_error1;
702
theTotalCurrAI_Len = tTotCurrAILen;
703
theAI_LenInCurrAI = tAI_LenInCurrAI;
704
theATTRINFOptr = tAttrPtr;
707
insertATTRINFO_error1:
708
setErrorCodeAbort(4000);
711
}//NdbOperation::insertATTRINFO()
713
/*****************************************************************************
714
* int insertATTRINFOloop(Uint32* aDataPtr, Uint32 aLength );
716
* Return Value: Return 0 : insertATTRINFO was succesful.
717
* Return -1: In all other case.
718
* Parameters: aDataPtr: Pointer to the data to insert into ATTRINFO.
719
* aLength: Length of data to be copied
720
* Remark: Puts the the data into either TCKEYREQ signal or
722
*****************************************************************************/
724
NdbOperation::insertATTRINFOloop(register const Uint32* aDataPtr,
725
register Uint32 aLength)
727
NdbApiSignal* tSignal;
728
register Uint32 tAI_LenInCurrAI = theAI_LenInCurrAI;
729
register Uint32 tTotCurrAILen = theTotalCurrAI_Len;
730
register Uint32* tAttrPtr = theATTRINFOptr;
733
while (aLength > 0) {
734
if (tAI_LenInCurrAI >= 25) {
735
NdbApiSignal* tFirstAttrinfo = theFirstATTRINFO;
737
tSignal = tNdb->getSignal();
738
if (tSignal != NULL) {
739
tSignal->setSignal(m_attrInfoGSN);
740
tAttrPtr = &tSignal->getDataPtrSend()[3];
741
if (tFirstAttrinfo == NULL) {
743
theFirstATTRINFO = tSignal;
744
theCurrentATTRINFO = tSignal;
746
NdbApiSignal* tCurrentAttrinfoBeforeUpdate = theCurrentATTRINFO;
748
theCurrentATTRINFO = tSignal;
749
tCurrentAttrinfoBeforeUpdate->next(tSignal);
752
goto insertATTRINFO_error1;
756
register Uint32 tData = *aDataPtr;
765
theATTRINFOptr = tAttrPtr;
766
theTotalCurrAI_Len = tTotCurrAILen;
767
theAI_LenInCurrAI = tAI_LenInCurrAI;
770
insertATTRINFO_error1:
771
setErrorCodeAbort(4000);
774
}//NdbOperation::insertATTRINFOloop()
776
NdbOperation::AbortOption
777
NdbOperation::getAbortOption() const
779
return (AbortOption)m_abortOption;
783
NdbOperation::setAbortOption(AbortOption ao)