1 /* Copyright (c) 2003-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
16 #include <ndb_global.h>
17 #include <NdbOperation.hpp>
18 #include <NdbTransaction.hpp>
19 #include "NdbApiSignal.hpp"
21 #include <NdbRecAttr.hpp>
22 #include "NdbUtil.hpp"
24 #include "Interpreter.hpp"
25 #include <AttributeHeader.hpp>
26 #include <signaldata/TcKeyReq.hpp>
27 #include <signaldata/TcKeyRef.hpp>
28 #include <signaldata/KeyInfo.hpp>
29 #include <signaldata/AttrInfo.hpp>
30 #include <signaldata/ScanTab.hpp>
32 #include <ndb_version.h>
40 NdbOperation::setLastFlag(NdbApiSignal
* signal
, Uint32 lastFlag
)
42 TcKeyReq
* const req
= CAST_PTR(TcKeyReq
, signal
->getDataPtrSend());
43 TcKeyReq::setExecuteFlag(req
->requestInfo
, lastFlag
);
46 /******************************************************************************
49 Return Value: Return >0 : send was succesful, returns number of signals sent
50 Return -1: In all other case.
51 Parameters: aProcessorId: Receiving processor node
52 Remark: Sends the TCKEYREQ signal and optional KEYINFO and ATTRINFO
54 ******************************************************************************/
56 NdbOperation::doSend(int aNodeId
, Uint32 lastFlag
)
60 assert(theTCREQ
!= NULL
);
61 setLastFlag(theTCREQ
, lastFlag
);
62 TransporterFacade
*tp
= theNdb
->theImpl
->m_transporter_facade
;
63 tReturnCode
= tp
->sendSignal(theTCREQ
, aNodeId
);
65 if (tReturnCode
== -1) {
68 NdbApiSignal
*tSignal
= theTCREQ
->next();
69 while (tSignal
!= NULL
) {
70 NdbApiSignal
* tnextSignal
= tSignal
->next();
71 tReturnCode
= tp
->sendSignal(tSignal
, aNodeId
);
72 tSignal
= tnextSignal
;
73 if (tReturnCode
== -1) {
78 tSignal
= theFirstATTRINFO
;
79 while (tSignal
!= NULL
) {
80 NdbApiSignal
* tnextSignal
= tSignal
->next();
81 tReturnCode
= tp
->sendSignal(tSignal
, aNodeId
);
82 tSignal
= tnextSignal
;
83 if (tReturnCode
== -1) {
90 }//NdbOperation::doSend()
92 /***************************************************************************
93 int prepareSend(Uint32 aTC_ConnectPtr,
94 Uint64 aTransactionId)
96 Return Value: Return 0 : preparation of send was succesful.
97 Return -1: In all other case.
98 Parameters: aTC_ConnectPtr: the Connect pointer to TC.
99 aTransactionId: the Transaction identity of the transaction.
100 Remark: Puts the the data into TCKEYREQ signal and optional KEYINFO and ATTRINFO signals.
101 ***************************************************************************/
103 NdbOperation::prepareSend(Uint32 aTC_ConnectPtr
,
107 Uint32 tTransId1
, tTransId2
;
109 Uint8 tInterpretInd
= theInterpretIndicator
;
110 Uint8 tDirtyIndicator
= theDirtyIndicator
;
111 Uint32 tTotalCurrAI_Len
= theTotalCurrAI_Len
;
114 if (tInterpretInd
!= 1) {
115 OperationType tOpType
= theOperationType
;
116 OperationStatus tStatus
= theStatus
;
117 if ((tOpType
== UpdateRequest
) ||
118 (tOpType
== InsertRequest
) ||
119 (tOpType
== WriteRequest
)) {
120 if (tStatus
!= SetValue
) {
121 setErrorCodeAbort(4116);
124 } else if ((tOpType
== ReadRequest
) || (tOpType
== ReadExclusive
) ||
125 (tOpType
== DeleteRequest
)) {
126 if (tStatus
!= GetValue
) {
127 setErrorCodeAbort(4116);
130 else if(unlikely(tDirtyIndicator
&& tTotalCurrAI_Len
== 0))
132 getValue(NdbDictionary::Column::FRAGMENT
);
133 tTotalCurrAI_Len
= theTotalCurrAI_Len
;
134 assert(theTotalCurrAI_Len
);
137 setErrorCodeAbort(4005);
141 if (prepareSendInterpreted() == -1) {
144 tTotalCurrAI_Len
= theTotalCurrAI_Len
;
147 //-------------------------------------------------------------
148 // We start by filling in the first 9 unconditional words of the
150 //-------------------------------------------------------------
151 TcKeyReq
* const tcKeyReq
= CAST_PTR(TcKeyReq
, theTCREQ
->getDataPtrSend());
153 Uint32 tTableId
= m_accessTable
->m_id
;
154 Uint32 tSchemaVersion
= m_accessTable
->m_version
;
156 tcKeyReq
->apiConnectPtr
= aTC_ConnectPtr
;
157 tcKeyReq
->apiOperationPtr
= ptr2int();
158 // Check if too much attrinfo have been defined
159 if (tTotalCurrAI_Len
> TcKeyReq::MaxTotalAttrInfo
){
160 setErrorCodeAbort(4257);
164 tcKeyReq
->setAttrinfoLen(TattrLen
, tTotalCurrAI_Len
);
165 tcKeyReq
->setAPIVersion(TattrLen
, NDB_VERSION
);
166 tcKeyReq
->attrLen
= TattrLen
;
168 tcKeyReq
->tableId
= tTableId
;
169 tcKeyReq
->tableSchemaVersion
= tSchemaVersion
;
170 tTransId1
= (Uint32
) aTransId
;
171 tTransId2
= (Uint32
) (aTransId
>> 32);
173 Uint8 tSimpleIndicator
= theSimpleIndicator
;
174 Uint8 tCommitIndicator
= theCommitIndicator
;
175 Uint8 tStartIndicator
= theStartIndicator
;
176 Uint8 tInterpretIndicator
= theInterpretIndicator
;
177 Uint8 tNoDisk
= m_no_disk_flag
;
180 * A dirty read, can not abort the transaction
182 Uint8 tReadInd
= (theOperationType
== ReadRequest
);
183 Uint8 tDirtyState
= tReadInd
& tDirtyIndicator
;
185 tcKeyReq
->transId1
= tTransId1
;
186 tcKeyReq
->transId2
= tTransId2
;
189 if (tTotalCurrAI_Len
<= TcKeyReq::MaxAttrInfo
) {
190 tcKeyReq
->setAIInTcKeyReq(tReqInfo
, tTotalCurrAI_Len
);
192 tcKeyReq
->setAIInTcKeyReq(tReqInfo
, TcKeyReq::MaxAttrInfo
);
195 tcKeyReq
->setSimpleFlag(tReqInfo
, tSimpleIndicator
);
196 tcKeyReq
->setCommitFlag(tReqInfo
, tCommitIndicator
);
197 tcKeyReq
->setStartFlag(tReqInfo
, tStartIndicator
);
198 tcKeyReq
->setInterpretedFlag(tReqInfo
, tInterpretIndicator
);
199 tcKeyReq
->setNoDiskFlag(tReqInfo
, tNoDisk
);
201 OperationType tOperationType
= theOperationType
;
202 Uint32 tTupKeyLen
= theTupKeyLen
;
203 Uint8 abortOption
= (ao
== DefaultAbortOption
) ? (Uint8
) m_abortOption
: (Uint8
) ao
;
205 tcKeyReq
->setDirtyFlag(tReqInfo
, tDirtyIndicator
);
206 tcKeyReq
->setOperationType(tReqInfo
, tOperationType
);
207 tcKeyReq
->setKeyLength(tReqInfo
, tTupKeyLen
);
209 // A dirty read is always ignore error
210 abortOption
= tDirtyState
? (Uint8
) AO_IgnoreError
: (Uint8
) abortOption
;
211 tcKeyReq
->setAbortOption(tReqInfo
, abortOption
);
212 m_abortOption
= abortOption
;
214 Uint8 tDistrKeyIndicator
= theDistrKeyIndicator_
;
215 Uint8 tScanIndicator
= theScanInfo
& 1;
217 tcKeyReq
->setDistributionKeyFlag(tReqInfo
, tDistrKeyIndicator
);
218 tcKeyReq
->setScanIndFlag(tReqInfo
, tScanIndicator
);
220 tcKeyReq
->requestInfo
= tReqInfo
;
222 //-------------------------------------------------------------
223 // The next step is to fill in the upto three conditional words.
224 //-------------------------------------------------------------
225 Uint32
* tOptionalDataPtr
= &tcKeyReq
->scanInfo
;
226 Uint32 tDistrGHIndex
= tScanIndicator
;
227 Uint32 tDistrKeyIndex
= tDistrGHIndex
;
229 Uint32 tScanInfo
= theScanInfo
;
230 Uint32 tDistrKey
= theDistributionKey
;
232 tOptionalDataPtr
[0] = tScanInfo
;
233 tOptionalDataPtr
[tDistrKeyIndex
] = tDistrKey
;
235 //-------------------------------------------------------------
236 // The next is step is to compress the key data part of the
238 //-------------------------------------------------------------
239 Uint32 tKeyIndex
= tDistrKeyIndex
+ tDistrKeyIndicator
;
240 Uint32
* tKeyDataPtr
= &tOptionalDataPtr
[tKeyIndex
];
241 Uint32 Tdata1
= tcKeyReq
->keyInfo
[0];
242 Uint32 Tdata2
= tcKeyReq
->keyInfo
[1];
243 Uint32 Tdata3
= tcKeyReq
->keyInfo
[2];
244 Uint32 Tdata4
= tcKeyReq
->keyInfo
[3];
247 tKeyDataPtr
[0] = Tdata1
;
248 tKeyDataPtr
[1] = Tdata2
;
249 tKeyDataPtr
[2] = Tdata3
;
250 tKeyDataPtr
[3] = Tdata4
;
251 if (tTupKeyLen
> 4) {
252 Tdata1
= tcKeyReq
->keyInfo
[4];
253 Tdata2
= tcKeyReq
->keyInfo
[5];
254 Tdata3
= tcKeyReq
->keyInfo
[6];
255 Tdata4
= tcKeyReq
->keyInfo
[7];
257 tKeyDataPtr
[4] = Tdata1
;
258 tKeyDataPtr
[5] = Tdata2
;
259 tKeyDataPtr
[6] = Tdata3
;
260 tKeyDataPtr
[7] = Tdata4
;
262 //-------------------------------------------------------------
263 // Finally we also compress the ATTRINFO part of the signal.
264 // We optimise by using the if-statement for sending KEYINFO
265 // signals to calculating the new Attrinfo Index.
266 //-------------------------------------------------------------
267 Uint32 tAttrInfoIndex
;
269 if (tTupKeyLen
> TcKeyReq::MaxKeyInfo
) {
271 * Set transid, TC connect ptr and length in the KEYINFO signals
273 NdbApiSignal
* tSignal
= theTCREQ
->next();
274 Uint32 remainingKey
= tTupKeyLen
- TcKeyReq::MaxKeyInfo
;
276 Uint32
* tSigDataPtr
= tSignal
->getDataPtrSend();
277 NdbApiSignal
* tnextSignal
= tSignal
->next();
278 tSigDataPtr
[0] = aTC_ConnectPtr
;
279 tSigDataPtr
[1] = tTransId1
;
280 tSigDataPtr
[2] = tTransId2
;
281 if (remainingKey
> KeyInfo::DataLength
) {
282 // The signal is full
283 tSignal
->setLength(KeyInfo::MaxSignalLength
);
284 remainingKey
-= KeyInfo::DataLength
;
288 tSignal
->setLength(KeyInfo::HeaderLength
+ remainingKey
);
291 tSignal
= tnextSignal
;
292 } while (tSignal
!= NULL
);
293 tAttrInfoIndex
= tKeyIndex
+ TcKeyReq::MaxKeyInfo
;
295 tAttrInfoIndex
= tKeyIndex
+ tTupKeyLen
;
298 //-------------------------------------------------------------
299 // Perform the Attrinfo packing in the TCKEYREQ signal started
301 //-------------------------------------------------------------
302 Uint32
* tAIDataPtr
= &tOptionalDataPtr
[tAttrInfoIndex
];
303 Tdata1
= tcKeyReq
->attrInfo
[0];
304 Tdata2
= tcKeyReq
->attrInfo
[1];
305 Tdata3
= tcKeyReq
->attrInfo
[2];
306 Tdata4
= tcKeyReq
->attrInfo
[3];
307 Tdata5
= tcKeyReq
->attrInfo
[4];
309 theTCREQ
->setLength(tcKeyReq
->getAIInTcKeyReq(tReqInfo
) +
310 tAttrInfoIndex
+ TcKeyReq::StaticLength
);
312 tAIDataPtr
[0] = Tdata1
;
313 tAIDataPtr
[1] = Tdata2
;
314 tAIDataPtr
[2] = Tdata3
;
315 tAIDataPtr
[3] = Tdata4
;
316 tAIDataPtr
[4] = Tdata5
;
318 /***************************************************
319 * Send the ATTRINFO signals.
320 ***************************************************/
321 if (tTotalCurrAI_Len
> 5) {
322 // Set the last signal's length.
323 NdbApiSignal
* tSignal
= theFirstATTRINFO
;
324 theCurrentATTRINFO
->setLength(theAI_LenInCurrAI
);
326 Uint32
* tSigDataPtr
= tSignal
->getDataPtrSend();
327 NdbApiSignal
* tnextSignal
= tSignal
->next();
328 tSigDataPtr
[0] = aTC_ConnectPtr
;
329 tSigDataPtr
[1] = tTransId1
;
330 tSigDataPtr
[2] = tTransId2
;
331 tSignal
= tnextSignal
;
332 } while (tSignal
!= NULL
);
334 theStatus
= WaitResponse
;
335 theReceiver
.prepareSend();
337 }//NdbOperation::prepareSend()
339 /***************************************************************************
340 int prepareSendInterpreted()
342 Make preparations to send an interpreted operation.
343 Return Value: Return 0 : succesful.
344 Return -1: In all other case.
345 ***************************************************************************/
347 NdbOperation::prepareSendInterpreted()
349 Uint32 tTotalCurrAI_Len
= theTotalCurrAI_Len
;
350 Uint32 tInitReadSize
= theInitialReadSize
;
351 if (theStatus
== ExecInterpretedValue
) {
352 if (insertATTRINFO(Interpreter::EXIT_OK
) != -1) {
353 //-------------------------------------------------------------------------
354 // Since we read the total length before inserting the last entry in the
355 // signals we need to add one to the total length.
356 //-------------------------------------------------------------------------
358 theInterpretedSize
= (tTotalCurrAI_Len
+ 1) -
364 } else if (theStatus
== FinalGetValue
) {
366 theFinalReadSize
= tTotalCurrAI_Len
-
367 (tInitReadSize
+ theInterpretedSize
+ theFinalUpdateSize
+ 5);
369 } else if (theStatus
== SetValueInterpreted
) {
371 theFinalUpdateSize
= tTotalCurrAI_Len
-
372 (tInitReadSize
+ theInterpretedSize
+ 5);
374 } else if (theStatus
== SubroutineEnd
) {
376 theSubroutineSize
= tTotalCurrAI_Len
-
377 (tInitReadSize
+ theInterpretedSize
+
378 theFinalUpdateSize
+ theFinalReadSize
+ 5);
380 } else if (theStatus
== GetValue
) {
381 theInitialReadSize
= tTotalCurrAI_Len
- 5;
383 setErrorCodeAbort(4116);
387 while (theFirstBranch
!= NULL
) {
389 Uint32 tLabelAddress
= 0;
391 NdbBranch
* tNdbBranch
= theFirstBranch
;
392 Uint32 tBranchLabel
= tNdbBranch
->theBranchLabel
;
393 NdbLabel
* tNdbLabel
= theFirstLabel
;
394 if (tBranchLabel
>= theNoOfLabels
) {
395 setErrorCodeAbort(4221);
399 // Find the label address
400 while (tNdbLabel
!= NULL
) {
401 for(tLabelAddress
= 0; tLabelAddress
<16; tLabelAddress
++){
402 const Uint32 labelNo
= tNdbLabel
->theLabelNo
[tLabelAddress
];
403 if(tBranchLabel
== labelNo
){
404 tAddress
= tNdbLabel
->theLabelAddress
[tLabelAddress
];
411 tNdbLabel
= tNdbLabel
->theNext
;
413 if (tAddress
== -1) {
414 //-------------------------------------------------------------------------
415 // We were unable to find any label which the branch refers to. This means
416 // that the application have not programmed the interpreter program correctly.
417 //-------------------------------------------------------------------------
418 setErrorCodeAbort(4222);
421 if (tNdbLabel
->theSubroutine
[tLabelAddress
] != tNdbBranch
->theSubroutine
) {
422 setErrorCodeAbort(4224);
425 // Now it is time to update the signal data with the relative branch jump.
426 if (tAddress
< int(tNdbBranch
->theBranchAddress
)) {
427 tRelAddress
= (tNdbBranch
->theBranchAddress
- tAddress
) << 16;
429 // Indicate backward jump direction
430 tRelAddress
= tRelAddress
+ (1 << 31);
432 } else if (tAddress
> int(tNdbBranch
->theBranchAddress
)) {
433 tRelAddress
= (tAddress
- tNdbBranch
->theBranchAddress
) << 16;
435 setErrorCodeAbort(4223);
438 NdbApiSignal
* tSignal
= tNdbBranch
->theSignal
;
439 Uint32 tReadData
= tSignal
->readData(tNdbBranch
->theSignalAddress
);
440 tSignal
->setData((tRelAddress
+ tReadData
), tNdbBranch
->theSignalAddress
);
442 theFirstBranch
= theFirstBranch
->theNext
;
443 theNdb
->releaseNdbBranch(tNdbBranch
);
446 while (theFirstCall
!= NULL
) {
447 Uint32 tSubroutineCount
= 0;
449 NdbSubroutine
* tNdbSubroutine
;
450 NdbCall
* tNdbCall
= theFirstCall
;
451 if (tNdbCall
->theSubroutine
>= theNoOfSubroutines
) {
452 setErrorCodeAbort(4221);
455 // Find the subroutine address
456 tNdbSubroutine
= theFirstSubroutine
;
457 while (tNdbSubroutine
!= NULL
) {
458 tSubroutineCount
+= 16;
459 if (tNdbCall
->theSubroutine
< tSubroutineCount
) {
461 Uint32 tSubroutineAddress
= tNdbCall
->theSubroutine
- (tSubroutineCount
- 16);
462 tAddress
= tNdbSubroutine
->theSubroutineAddress
[tSubroutineAddress
];
465 tNdbSubroutine
= tNdbSubroutine
->theNext
;
467 if (tAddress
== -1) {
468 setErrorCodeAbort(4222);
471 // Now it is time to update the signal data with the relative branch jump.
472 NdbApiSignal
* tSignal
= tNdbCall
->theSignal
;
473 Uint32 tReadData
= tSignal
->readData(tNdbCall
->theSignalAddress
);
474 tSignal
->setData(((tAddress
<< 16) + tReadData
), tNdbCall
->theSignalAddress
);
476 theFirstCall
= theFirstCall
->theNext
;
477 theNdb
->releaseNdbCall(tNdbCall
);
480 Uint32 tInitialReadSize
= theInitialReadSize
;
481 Uint32 tInterpretedSize
= theInterpretedSize
;
482 Uint32 tFinalUpdateSize
= theFinalUpdateSize
;
483 Uint32 tFinalReadSize
= theFinalReadSize
;
484 Uint32 tSubroutineSize
= theSubroutineSize
;
485 if (theOperationType
!= OpenScanRequest
&&
486 theOperationType
!= OpenRangeScanRequest
) {
487 TcKeyReq
* const tcKeyReq
= CAST_PTR(TcKeyReq
, theTCREQ
->getDataPtrSend());
489 tcKeyReq
->attrInfo
[0] = tInitialReadSize
;
490 tcKeyReq
->attrInfo
[1] = tInterpretedSize
;
491 tcKeyReq
->attrInfo
[2] = tFinalUpdateSize
;
492 tcKeyReq
->attrInfo
[3] = tFinalReadSize
;
493 tcKeyReq
->attrInfo
[4] = tSubroutineSize
;
495 // If a scan is defined we use the first ATTRINFO instead of TCKEYREQ.
496 theFirstATTRINFO
->setData(tInitialReadSize
, 4);
497 theFirstATTRINFO
->setData(tInterpretedSize
, 5);
498 theFirstATTRINFO
->setData(tFinalUpdateSize
, 6);
499 theFirstATTRINFO
->setData(tFinalReadSize
, 7);
500 theFirstATTRINFO
->setData(tSubroutineSize
, 8);
502 theReceiver
.prepareSend();
504 }//NdbOperation::prepareSendInterpreted()
507 NdbOperation::checkState_TransId(NdbApiSignal
* aSignal
)
509 Uint64 tRecTransId
, tCurrTransId
;
512 if (theStatus
!= WaitResponse
) {
513 #ifdef NDB_NO_DROPPED_SIGNAL
519 tTmp1
= aSignal
->readData(2);
520 tTmp2
= aSignal
->readData(3);
522 tRecTransId
= (Uint64
)tTmp1
+ ((Uint64
)tTmp2
<< 32);
523 tCurrTransId
= theNdbCon
->getTransactionId();
524 if (tCurrTransId
!= tRecTransId
) {
525 #ifdef NDB_NO_DROPPED_SIGNAL
531 }//NdbOperation::checkState_TransId()
533 /***************************************************************************
534 int receiveTCKEYREF( NdbApiSignal* aSignal)
536 Return Value: Return 0 : send was succesful.
537 Return -1: In all other case.
538 Parameters: aSignal: the signal object that contains the TCKEYREF signal from TC.
539 Remark: Handles the reception of the TCKEYREF signal.
540 ***************************************************************************/
542 NdbOperation::receiveTCKEYREF( NdbApiSignal
* aSignal
)
544 if (checkState_TransId(aSignal
) == -1) {
548 setErrorCode(aSignal
->readData(4));
549 if (aSignal
->getLength() == TcKeyRef::SignalLength
)
551 // Signal may contain additional error data
552 theError
.details
= (char *) aSignal
->readData(5);
555 theStatus
= Finished
;
556 theReceiver
.m_received_result_length
= ~0;
559 if(! (theOperationType
== ReadRequest
&& theDirtyIndicator
))
561 theNdbCon
->OpCompleteFailure(this);
566 * If TCKEYCONF has arrived
567 * op has completed (maybe trans has completed)
569 if(theReceiver
.m_expected_result_length
)
571 return theNdbCon
->OpCompleteFailure(this);