MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdbOperationExec.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 <ndb_global.h>
19 #include "API.hpp"
20 
21 #include "Interpreter.hpp"
22 #include <AttributeHeader.hpp>
23 #include <signaldata/TcKeyReq.hpp>
24 #include <signaldata/TcKeyRef.hpp>
25 #include <signaldata/KeyInfo.hpp>
26 #include <signaldata/AttrInfo.hpp>
27 #include <signaldata/ScanTab.hpp>
28 
29 #include <ndb_version.h>
30 
31 #include "API.hpp"
32 #include <NdbOut.hpp>
33 
34 
50 {
51 private :
52  STATIC_CONST(KeyAndAttrInfoHeaderLength = 3);
53 
54  const Uint32 firstSigDataLen; // Num words in first signal
55  Uint32* firstDataPtr; // Ptr to start of data in first signal
56  NdbApiSignal* secondSignal; // Second signal
57  // Nasty void* for current iterator position
58  void* currentPos; // start == firstDataPtr
59  // middle == NdbApiSignal*
60  // end == NULL
61 
62  void checkStaticAssertions()
63  {
64  STATIC_ASSERT(KeyInfo::HeaderLength == KeyAndAttrInfoHeaderLength);
65  STATIC_ASSERT(AttrInfo::HeaderLength == KeyAndAttrInfoHeaderLength);
66  };
67 
68 public :
70  Uint32 dataOffset,
71  Uint32 dataLen,
72  NdbApiSignal* nextSignal) :
73  firstSigDataLen(dataLen),
74  firstDataPtr(TCREQ->getDataPtrSend()+dataOffset),
75  secondSignal(nextSignal),
76  currentPos(firstDataPtr)
77  {
78  assert((dataOffset + dataLen) <= NdbApiSignal::MaxSignalWords);
79  }
80 
82  {};
83 
84  void reset()
85  {
86  currentPos= firstDataPtr;
87  }
88 
89  const Uint32* getNextWords(Uint32& sz)
90  {
91  /* In first TCKEY/INDXREQ, data is at offset depending
92  * on whether it's KEYINFO or ATTRINFO
93  * In following signals, data starts at offset 3
94  * regardless
95  */
96  if (likely(currentPos != NULL))
97  {
98  if (currentPos == firstDataPtr)
99  {
100  currentPos= secondSignal;
101  sz= firstSigDataLen;
102  return firstDataPtr;
103  }
104  /* Second signal is KeyInfo or AttrInfo
105  * Ignore header words
106  */
107  NdbApiSignal* sig= (NdbApiSignal*)currentPos;
108  assert(sig->getLength() >= KeyAndAttrInfoHeaderLength);
109  sz= sig->getLength() - KeyAndAttrInfoHeaderLength;
110  currentPos= sig->next();
111  return sig->getDataPtrSend() + KeyAndAttrInfoHeaderLength;
112  }
113  sz = 0;
114  return NULL;
115  }
116 };
117 
118 void
119 NdbOperation::setLastFlag(NdbApiSignal* signal, Uint32 lastFlag)
120 {
121  TcKeyReq * const req = CAST_PTR(TcKeyReq, signal->getDataPtrSend());
122  TcKeyReq::setExecuteFlag(req->requestInfo, lastFlag);
123 }
124 
125 int
126 NdbOperation::doSendKeyReq(int aNodeId,
127  GenericSectionPtr* secs,
128  Uint32 numSecs)
129 {
130  /* Send a KeyRequest - could be TCKEYREQ or TCINDXREQ
131  *
132  * Normally we send a single long signal with 1 or 2
133  * sections containing KeyInfo and AttrInfo.
134  * For backwards compatibility and testing purposes
135  * we can send signal trains instead.
136  */
137  NdbApiSignal* request = theTCREQ;
138  NdbImpl* impl = theNdb->theImpl;
139  Uint32 tcNodeVersion = impl->getNodeNdbVersion(aNodeId);
140  bool forceShort = impl->forceShortRequests;
141  bool sendLong = ( tcNodeVersion >= NDBD_LONG_TCKEYREQ ) &&
142  ! forceShort;
143 
144  if (sendLong)
145  {
146  return impl->sendSignal(request, aNodeId, secs, numSecs);
147  }
148  else
149  {
150  /* Send signal as short request - either for backwards
151  * compatibility or testing
152  */
153  Uint32 sigCount = 1;
154  Uint32 keyInfoLen = secs[0].sz;
155  Uint32 attrInfoLen = (numSecs == 2)?
156  secs[1].sz :
157  0;
158 
159  Uint32 keyInfoInReq = MIN(keyInfoLen, TcKeyReq::MaxKeyInfo);
160  Uint32 attrInfoInReq = MIN(attrInfoLen, TcKeyReq::MaxAttrInfo);
161  TcKeyReq* tcKeyReq = (TcKeyReq*) request->getDataPtrSend();
162  Uint32 connectPtr = tcKeyReq->apiConnectPtr;
163  Uint32 transId1 = tcKeyReq->transId1;
164  Uint32 transId2 = tcKeyReq->transId2;
165  bool indexReq = (request->theVerId_signalNumber == GSN_TCINDXREQ);
166 
167  Uint32 reqLen = request->theLength;
168 
169  /* Set TCKEYREQ flags */
170  TcKeyReq::setKeyLength(tcKeyReq->requestInfo, keyInfoLen);
171  TcKeyReq::setAIInTcKeyReq(tcKeyReq->requestInfo , attrInfoInReq);
172  TcKeyReq::setAttrinfoLen(tcKeyReq->attrLen, attrInfoLen);
173 
174  Uint32* writePtr = request->getDataPtrSend() + reqLen;
175 
176  GSIReader keyInfoReader(secs[0].sectionIter);
177  GSIReader attrInfoReader(secs[1].sectionIter);
178 
179  keyInfoReader.copyNWords(writePtr, keyInfoInReq);
180  writePtr += keyInfoInReq;
181  attrInfoReader.copyNWords(writePtr, attrInfoInReq);
182 
183  reqLen += keyInfoInReq + attrInfoInReq;
184  assert( reqLen <= TcKeyReq::SignalLength );
185 
186  request->setLength(reqLen);
187 
188  if (impl->sendSignal(request, aNodeId) == -1)
189  return -1;
190 
191  keyInfoLen -= keyInfoInReq;
192  attrInfoLen -= attrInfoInReq;
193 
194  if (keyInfoLen)
195  {
196  request->theVerId_signalNumber = indexReq ?
197  GSN_INDXKEYINFO : GSN_KEYINFO;
198  KeyInfo* keyInfo = (KeyInfo*) request->getDataPtrSend();
199  keyInfo->connectPtr = connectPtr;
200  keyInfo->transId[0] = transId1;
201  keyInfo->transId[1] = transId2;
202 
203  while(keyInfoLen)
204  {
205  Uint32 dataWords = MIN(keyInfoLen, KeyInfo::DataLength);
206 
207  keyInfoReader.copyNWords(&keyInfo->keyData[0], dataWords);
208  request->setLength(KeyInfo::HeaderLength + dataWords);
209 
210  if (impl->sendSignal(request, aNodeId) == -1)
211  return -1;
212 
213  keyInfoLen-= dataWords;
214  sigCount++;
215  }
216  }
217 
218  if (attrInfoLen)
219  {
220  request->theVerId_signalNumber = indexReq ?
221  GSN_INDXATTRINFO : GSN_ATTRINFO;
222  AttrInfo* attrInfo = (AttrInfo*) request->getDataPtrSend();
223  attrInfo->connectPtr = connectPtr;
224  attrInfo->transId[0] = transId1;
225  attrInfo->transId[1] = transId2;
226 
227  while(attrInfoLen)
228  {
229  Uint32 dataWords = MIN(attrInfoLen, AttrInfo::DataLength);
230 
231  attrInfoReader.copyNWords(&attrInfo->attrData[0], dataWords);
232  request->setLength(AttrInfo::HeaderLength + dataWords);
233 
234  if (impl->sendSignal(request, aNodeId) == -1)
235  return -1;
236 
237  attrInfoLen-= dataWords;
238  sigCount++;
239  }
240  }
241 
242  return sigCount;
243  }
244 }
245 
246 /******************************************************************************
247 int doSend()
248 
249 Return Value: Return >0 : send was succesful, returns number of signals sent
250  Return -1: In all other case.
251 Parameters: aProcessorId: Receiving processor node
252 Remark: Sends the TCKEYREQ signal and optional KEYINFO and ATTRINFO
253  signals.
254 ******************************************************************************/
255 int
256 NdbOperation::doSend(int aNodeId, Uint32 lastFlag)
257 {
258  assert(theTCREQ != NULL);
259  setLastFlag(theTCREQ, lastFlag);
260  Uint32 numSecs= 1;
261  GenericSectionPtr secs[2];
262 
263  if (m_attribute_record != NULL)
264  {
265  /*
266  * NdbRecord signal building code puts all KeyInfo and
267  * AttrInfo into the KeyInfo and AttrInfo signal lists.
268  */
269  SignalSectionIterator keyInfoIter(theTCREQ->next());
270  SignalSectionIterator attrInfoIter(theFirstATTRINFO);
271 
272  /* KeyInfo - always present for TCKEY/INDXREQ*/
273  secs[0].sz= theTupKeyLen;
274  secs[0].sectionIter= &keyInfoIter;
275 
276  /* AttrInfo - not always needed (e.g. Delete) */
277  if (theTotalCurrAI_Len != 0)
278  {
279  secs[1].sz= theTotalCurrAI_Len;
280  secs[1].sectionIter= &attrInfoIter;
281  numSecs++;
282  }
283 
284  if (doSendKeyReq(aNodeId, &secs[0], numSecs) == -1)
285  return -1;
286  }
287  else
288  {
289  /*
290  * Old Api signal building code puts first words of KeyInfo
291  * and AttrInfo into the initial request signal
292  * We use special iterators to extract this
293  */
294 
295  TcKeyReq* tcKeyReq= (TcKeyReq*) theTCREQ->getDataPtrSend();
296  const Uint32 inlineKIOffset= Uint32(tcKeyReq->keyInfo - (Uint32*)tcKeyReq);
297  const Uint32 inlineKILength= MIN(TcKeyReq::MaxKeyInfo,
298  theTupKeyLen);
299  const Uint32 inlineAIOffset = Uint32(tcKeyReq->attrInfo -(Uint32*)tcKeyReq);
300  const Uint32 inlineAILength= MIN(TcKeyReq::MaxAttrInfo,
301  theTotalCurrAI_Len);
302 
303  /* Create iterators which use the signal train to extract
304  * long sections from the short signal trains
305  */
306  OldNdbApiSectionIterator keyInfoIter(theTCREQ,
307  inlineKIOffset,
308  inlineKILength,
309  theTCREQ->next());
310  OldNdbApiSectionIterator attrInfoIter(theTCREQ,
311  inlineAIOffset,
312  inlineAILength,
313  theFirstATTRINFO);
314 
315  /* KeyInfo - always present for TCKEY/INDXREQ */
316  secs[0].sz= theTupKeyLen;
317  secs[0].sectionIter= &keyInfoIter;
318 
319  /* AttrInfo - not always needed (e.g. Delete) */
320  if (theTotalCurrAI_Len != 0)
321  {
322  secs[1].sz= theTotalCurrAI_Len;
323  secs[1].sectionIter= &attrInfoIter;
324  numSecs++;
325  }
326 
327  if (doSendKeyReq(aNodeId, &secs[0], numSecs) == -1)
328  return -1;
329  }
330 
331  /* Todo : Consider calling NdbOperation::postExecuteRelease()
332  * Ideally it should be called outside TP mutex, so not added
333  * here yet
334  */
335 
336  theNdbCon->OpSent();
337  return 1;
338 }//NdbOperation::doSend()
339 
340 
341 int
342 NdbOperation::prepareGetLockHandle()
343 {
344  /* Read LOCK_REF pseudo column */
345  assert(! theLockHandle->isLockRefValid() );
346 
347  theLockHandle->m_table = m_currentTable;
348 
349  /* Add read of TC_LOCKREF pseudo column */
350  NdbRecAttr* ra = getValue(NdbDictionary::Column::LOCK_REF,
351  (char*) &theLockHandle->m_lockRef);
352 
353  if (!ra)
354  {
355  /* Assume error code set */
356  return -1;
357  }
358 
359  theLockHandle->m_state = NdbLockHandle::PREPARED;
360 
361  /* Count Blob handles associated with this operation
362  * for LockHandle open Blob handles ref count
363  */
364  NdbBlob* blobHandle = theBlobList;
365 
366  while (blobHandle != NULL)
367  {
368  theLockHandle->m_openBlobCount ++;
369  blobHandle = blobHandle->theNext;
370  }
371 
372  return 0;
373 }
374 
375 /***************************************************************************
376 int prepareSend(Uint32 aTC_ConnectPtr,
377  Uint64 aTransactionId)
378 
379 Return Value: Return 0 : preparation of send was succesful.
380  Return -1: In all other case.
381 Parameters: aTC_ConnectPtr: the Connect pointer to TC.
382  aTransactionId: the Transaction identity of the transaction.
383 Remark: Puts the the data into TCKEYREQ signal and optional KEYINFO and ATTRINFO signals.
384 ***************************************************************************/
385 int
386 NdbOperation::prepareSend(Uint32 aTC_ConnectPtr,
387  Uint64 aTransId,
388  AbortOption ao)
389 {
390  Uint32 tTransId1, tTransId2;
391  Uint32 tReqInfo;
392  Uint8 tInterpretInd = theInterpretIndicator;
393  Uint8 tDirtyIndicator = theDirtyIndicator;
394  Uint32 tTotalCurrAI_Len = theTotalCurrAI_Len;
395  theErrorLine = 0;
396 
397  if (tInterpretInd != 1) {
398  OperationType tOpType = theOperationType;
399  OperationStatus tStatus = theStatus;
400  if ((tOpType == UpdateRequest) ||
401  (tOpType == InsertRequest) ||
402  (tOpType == WriteRequest)) {
403  if (tStatus != SetValue) {
404  setErrorCodeAbort(4116);
405  return -1;
406  }//if
407  } else if ((tOpType == ReadRequest) || (tOpType == ReadExclusive) ||
408  (tOpType == DeleteRequest)) {
409  if (tStatus != GetValue) {
410  setErrorCodeAbort(4116);
411  return -1;
412  }
413  else if(unlikely(tDirtyIndicator && tTotalCurrAI_Len == 0))
414  {
415  getValue(NdbDictionary::Column::FRAGMENT);
416  tTotalCurrAI_Len = theTotalCurrAI_Len;
417  assert(theTotalCurrAI_Len);
418  }
419  else if (tOpType != DeleteRequest)
420  {
421  assert(tOpType == ReadRequest || tOpType == ReadExclusive);
422  if (theLockHandle)
423  {
424  /* Take steps to read LockHandle info as part of read */
425  if (prepareGetLockHandle() != 0)
426  return -1;
427 
428  tTotalCurrAI_Len = theTotalCurrAI_Len;
429  }
430  tTotalCurrAI_Len = repack_read(tTotalCurrAI_Len);
431  }
432  } else {
433  setErrorCodeAbort(4005);
434  return -1;
435  }//if
436  } else {
437  if (prepareSendInterpreted() == -1) {
438  return -1;
439  }//if
440  tTotalCurrAI_Len = theTotalCurrAI_Len;
441  }//if
442 
443 //-------------------------------------------------------------
444 // We start by filling in the first 9 unconditional words of the
445 // TCKEYREQ signal.
446 //-------------------------------------------------------------
447  TcKeyReq * const tcKeyReq = CAST_PTR(TcKeyReq, theTCREQ->getDataPtrSend());
448 
449  Uint32 tTableId = m_accessTable->m_id;
450  Uint32 tSchemaVersion = m_accessTable->m_version;
451 
452  tcKeyReq->apiConnectPtr = aTC_ConnectPtr;
453  tcKeyReq->apiOperationPtr = ptr2int();
454  // Check if too much attrinfo have been defined
455  if (tTotalCurrAI_Len > TcKeyReq::MaxTotalAttrInfo){
456  setErrorCodeAbort(4257);
457  return -1;
458  }
459  Uint32 TattrLen = 0;
460  tcKeyReq->setAttrinfoLen(TattrLen, 0); // Not required for long signals.
461  tcKeyReq->setAPIVersion(TattrLen, NDB_VERSION);
462  tcKeyReq->attrLen = TattrLen;
463 
464  tcKeyReq->tableId = tTableId;
465  tcKeyReq->tableSchemaVersion = tSchemaVersion;
466  tTransId1 = (Uint32) aTransId;
467  tTransId2 = (Uint32) (aTransId >> 32);
468 
469  Uint8 tSimpleIndicator = theSimpleIndicator;
470  Uint8 tCommitIndicator = theCommitIndicator;
471  Uint8 tStartIndicator = theStartIndicator;
472  Uint8 tInterpretIndicator = theInterpretIndicator;
473  Uint8 tNoDisk = (m_flags & OF_NO_DISK) != 0;
474  Uint8 tQueable = (m_flags & OF_QUEUEABLE) != 0;
475  Uint8 tDeferred = (m_flags & OF_DEFERRED_CONSTRAINTS) != 0;
476 
480  Uint8 tReadInd = (theOperationType == ReadRequest);
481  Uint8 tDirtyState = tReadInd & tDirtyIndicator;
482 
483  tcKeyReq->transId1 = tTransId1;
484  tcKeyReq->transId2 = tTransId2;
485 
486  tReqInfo = 0;
487  tcKeyReq->setAIInTcKeyReq(tReqInfo, 0); // Not needed
488  tcKeyReq->setSimpleFlag(tReqInfo, tSimpleIndicator);
489  tcKeyReq->setCommitFlag(tReqInfo, tCommitIndicator);
490  tcKeyReq->setStartFlag(tReqInfo, tStartIndicator);
491  tcKeyReq->setInterpretedFlag(tReqInfo, tInterpretIndicator);
492  tcKeyReq->setNoDiskFlag(tReqInfo, tNoDisk);
493  tcKeyReq->setQueueOnRedoProblemFlag(tReqInfo, tQueable);
494  tcKeyReq->setDeferredConstraints(tReqInfo, tDeferred);
495 
496  OperationType tOperationType = theOperationType;
497  Uint8 abortOption = (ao == DefaultAbortOption) ? (Uint8) m_abortOption : (Uint8) ao;
498 
499  tcKeyReq->setDirtyFlag(tReqInfo, tDirtyIndicator);
500  tcKeyReq->setOperationType(tReqInfo, tOperationType);
501  tcKeyReq->setKeyLength(tReqInfo, 0); // Not needed
502  tcKeyReq->setViaSPJFlag(tReqInfo, 0);
503 
504  // A dirty read is always ignore error
505  abortOption = tDirtyState ? (Uint8) AO_IgnoreError : (Uint8) abortOption;
506  tcKeyReq->setAbortOption(tReqInfo, abortOption);
507  m_abortOption = abortOption;
508 
509  Uint8 tDistrKeyIndicator = theDistrKeyIndicator_;
510  Uint8 tScanIndicator = theScanInfo & 1;
511 
512  tcKeyReq->setDistributionKeyFlag(tReqInfo, tDistrKeyIndicator);
513  tcKeyReq->setScanIndFlag(tReqInfo, tScanIndicator);
514 
515  tcKeyReq->requestInfo = tReqInfo;
516 
517 //-------------------------------------------------------------
518 // The next step is to fill in the upto three conditional words.
519 //-------------------------------------------------------------
520  Uint32* tOptionalDataPtr = &tcKeyReq->scanInfo;
521  Uint32 tDistrGHIndex = tScanIndicator;
522  Uint32 tDistrKeyIndex = tDistrGHIndex;
523 
524  Uint32 tScanInfo = theScanInfo;
525  Uint32 tDistrKey = theDistributionKey;
526 
527  tOptionalDataPtr[0] = tScanInfo;
528  tOptionalDataPtr[tDistrKeyIndex] = tDistrKey;
529 
530  theTCREQ->setLength(TcKeyReq::StaticLength +
531  tDistrKeyIndex + // 1 for scan info present
532  theDistrKeyIndicator_); // 1 for distr key present
533 
534  /* Ensure the signal objects have the correct length
535  * information
536  */
537  if (theTupKeyLen > TcKeyReq::MaxKeyInfo) {
541  if (theLastKEYINFO == NULL)
542  theLastKEYINFO= theTCREQ->next();
543 
544  assert(theLastKEYINFO != NULL);
545 
546  Uint32 lastKeyInfoLen= ((theTupKeyLen - TcKeyReq::MaxKeyInfo)
547  % KeyInfo::DataLength);
548 
549  theLastKEYINFO->setLength(lastKeyInfoLen ?
550  KeyInfo::HeaderLength + lastKeyInfoLen :
551  KeyInfo::MaxSignalLength);
552  }
553 
554  /* Set the length on the last AttrInfo signal */
555  if (tTotalCurrAI_Len > TcKeyReq::MaxAttrInfo) {
556  // Set the last signal's length.
557  theCurrentATTRINFO->setLength(theAI_LenInCurrAI);
558  }//if
559  theTotalCurrAI_Len= tTotalCurrAI_Len;
560 
561  theStatus = WaitResponse;
562  theReceiver.prepareSend();
563  return 0;
564 }//NdbOperation::prepareSend()
565 
566 Uint32
567 NdbOperation::repack_read(Uint32 len)
568 {
569  Uint32 i;
570  Uint32 check = 0, prevId = 0;
571  Uint32 save = len;
573  NdbApiSignal *tSignal = theFirstATTRINFO;
574  TcKeyReq * const tcKeyReq = CAST_PTR(TcKeyReq, theTCREQ->getDataPtrSend());
575  Uint32 cols = m_currentTable->m_columns.size();
576 
577  Uint32 *ptr = tcKeyReq->attrInfo;
578  for (i = 0; len && i < 5; i++, len--)
579  {
580  AttributeHeader tmp(* ptr++);
581  Uint32 id = tmp.getAttributeId();
582  if (((i > 0) && // No prevId for first attrId
583  (id <= prevId)) ||
584  (id >= NDB_MAX_ATTRIBUTES_IN_TABLE))
585  {
586  // AttrIds not strictly ascending with no duplicates
587  // and no pseudo-columns == fallback
588  return save;
589  }
590  prevId = id;
591  mask.set(id);
592  }
593 
594  Uint32 cnt = 0;
595  while (len)
596  {
597  cnt++;
598  assert(tSignal);
599  ptr = tSignal->getDataPtrSend() + AttrInfo::HeaderLength;
600  for (i = 0; len && i<AttrInfo::DataLength; i++, len--)
601  {
602  AttributeHeader tmp(* ptr++);
603  Uint32 id = tmp.getAttributeId();
604  if ((id <= prevId) ||
605  (id >= NDB_MAX_ATTRIBUTES_IN_TABLE))
606  {
607  // AttrIds not strictly ascending with no duplicates
608  // and no pseudo-columns == fallback
609  return save;
610  }
611  prevId = id;
612 
613  mask.set(id);
614  }
615  tSignal = tSignal->next();
616  }
617  const Uint32 newlen = 1 + (prevId >> 5);
618  const bool all = cols == save;
619  if (check == 0)
620  {
621  /* AttrInfos are in ascending order, ok to use READ_ALL
622  * or READ_PACKED
623  * (Correct NdbRecAttrs will be used when data is received)
624  */
625  if (all == false && ((1 + newlen) > TcKeyReq::MaxAttrInfo))
626  {
627  return save;
628  }
629 
630  theNdb->releaseSignals(cnt, theFirstATTRINFO, theCurrentATTRINFO);
631  theFirstATTRINFO = 0;
632  theCurrentATTRINFO = 0;
633  ptr = tcKeyReq->attrInfo;
634  if (all)
635  {
636  AttributeHeader::init(ptr, AttributeHeader::READ_ALL, cols);
637  return 1;
638  }
639  else
640  {
641  AttributeHeader::init(ptr, AttributeHeader::READ_PACKED, 4*newlen);
642  memcpy(ptr + 1, &mask, 4*newlen);
643  return 1+newlen;
644  }
645  }
646 
647  return save;
648 }
649 
650 
651 /***************************************************************************
652 int prepareSendInterpreted()
653 
654 Make preparations to send an interpreted operation.
655 Return Value: Return 0 : succesful.
656  Return -1: In all other case.
657 ***************************************************************************/
658 int
659 NdbOperation::prepareSendInterpreted()
660 {
661  Uint32 tTotalCurrAI_Len = theTotalCurrAI_Len;
662  Uint32 tInitReadSize = theInitialReadSize;
663  assert (theStatus != UseNdbRecord); // Should never get here for NdbRecord.
664  if (theStatus == ExecInterpretedValue) {
665  if (insertATTRINFO(Interpreter::EXIT_OK) != -1) {
666 //-------------------------------------------------------------------------
667 // Since we read the total length before inserting the last entry in the
668 // signals we need to add one to the total length.
669 //-------------------------------------------------------------------------
670 
671  theInterpretedSize = (tTotalCurrAI_Len + 1) -
672  (tInitReadSize + AttrInfo::SectionSizeInfoLength);
673 
674  } else {
675  return -1;
676  }//if
677  } else if (theStatus == FinalGetValue) {
678 
679  theFinalReadSize = tTotalCurrAI_Len -
680  (tInitReadSize + theInterpretedSize + theFinalUpdateSize
681  + AttrInfo::SectionSizeInfoLength);
682 
683  } else if (theStatus == SetValueInterpreted) {
684 
685  theFinalUpdateSize = tTotalCurrAI_Len -
686  (tInitReadSize + theInterpretedSize
687  + AttrInfo::SectionSizeInfoLength);
688 
689  } else if (theStatus == SubroutineEnd) {
690 
691  theSubroutineSize = tTotalCurrAI_Len -
692  (tInitReadSize + theInterpretedSize +
693  theFinalUpdateSize + theFinalReadSize
694  + AttrInfo::SectionSizeInfoLength);
695 
696  } else if (theStatus == GetValue) {
697  theInitialReadSize = tTotalCurrAI_Len - AttrInfo::SectionSizeInfoLength;
698  } else {
699  setErrorCodeAbort(4116);
700  return -1;
701  }
702 
703  /*
704  Fix jumps by patching in the correct address for the corresponding label.
705  */
706  while (theFirstBranch != NULL) {
707  Uint32 tRelAddress;
708  Uint32 tLabelAddress = 0;
709  int tAddress = -1;
710  NdbBranch* tNdbBranch = theFirstBranch;
711  Uint32 tBranchLabel = tNdbBranch->theBranchLabel;
712  NdbLabel* tNdbLabel = theFirstLabel;
713  if (tBranchLabel >= theNoOfLabels) {
714  setErrorCodeAbort(4221);
715  return -1;
716  }//if
717 
718  // Find the label address
719  while (tNdbLabel != NULL) {
720  for(tLabelAddress = 0; tLabelAddress<16; tLabelAddress++){
721  const Uint32 labelNo = tNdbLabel->theLabelNo[tLabelAddress];
722  if(tBranchLabel == labelNo){
723  tAddress = tNdbLabel->theLabelAddress[tLabelAddress];
724  break;
725  }
726  }
727 
728  if(tAddress != -1)
729  break;
730  tNdbLabel = tNdbLabel->theNext;
731  }//while
732  if (tAddress == -1) {
733 //-------------------------------------------------------------------------
734 // We were unable to find any label which the branch refers to. This means
735 // that the application have not programmed the interpreter program correctly.
736 //-------------------------------------------------------------------------
737  setErrorCodeAbort(4222);
738  return -1;
739  }//if
740  if (tNdbLabel->theSubroutine[tLabelAddress] != tNdbBranch->theSubroutine) {
741  setErrorCodeAbort(4224);
742  return -1;
743  }//if
744  // Now it is time to update the signal data with the relative branch jump.
745  if (tAddress < int(tNdbBranch->theBranchAddress)) {
746  tRelAddress = (tNdbBranch->theBranchAddress - tAddress) << 16;
747 
748  // Indicate backward jump direction
749  tRelAddress = tRelAddress + (1 << 31);
750 
751  } else if (tAddress > int(tNdbBranch->theBranchAddress)) {
752  tRelAddress = (tAddress - tNdbBranch->theBranchAddress) << 16;
753  } else {
754  setErrorCodeAbort(4223);
755  return -1;
756  }//if
757 
758  NdbApiSignal* tSignal = tNdbBranch->theSignal;
759  Uint32 tReadData = tSignal->readData(tNdbBranch->theSignalAddress);
760  tSignal->setData((tRelAddress + tReadData), tNdbBranch->theSignalAddress);
761 
762  theFirstBranch = theFirstBranch->theNext;
763  theNdb->releaseNdbBranch(tNdbBranch);
764  }//while
765 
766  while (theFirstCall != NULL) {
767  Uint32 tSubroutineCount = 0;
768  int tAddress = -1;
769  NdbSubroutine* tNdbSubroutine;
770  NdbCall* tNdbCall = theFirstCall;
771  if (tNdbCall->theSubroutine >= theNoOfSubroutines) {
772  setErrorCodeAbort(4221);
773  return -1;
774  }//if
775 // Find the subroutine address
776  tNdbSubroutine = theFirstSubroutine;
777  while (tNdbSubroutine != NULL) {
778  tSubroutineCount += 16;
779  if (tNdbCall->theSubroutine < tSubroutineCount) {
780 // Subroutine Found
781  Uint32 tSubroutineAddress = tNdbCall->theSubroutine - (tSubroutineCount - 16);
782  tAddress = tNdbSubroutine->theSubroutineAddress[tSubroutineAddress];
783  break;
784  }//if
785  tNdbSubroutine = tNdbSubroutine->theNext;
786  }//while
787  if (tAddress == -1) {
788  setErrorCodeAbort(4222);
789  return -1;
790  }//if
791 // Now it is time to update the signal data with the relative branch jump.
792  NdbApiSignal* tSignal = tNdbCall->theSignal;
793  Uint32 tReadData = tSignal->readData(tNdbCall->theSignalAddress);
794  tSignal->setData(((tAddress << 16) + (tReadData & 0xffff)),
795  tNdbCall->theSignalAddress);
796 
797  theFirstCall = theFirstCall->theNext;
798  theNdb->releaseNdbCall(tNdbCall);
799  }//while
800 
801  Uint32 tInitialReadSize = theInitialReadSize;
802  Uint32 tInterpretedSize = theInterpretedSize;
803  Uint32 tFinalUpdateSize = theFinalUpdateSize;
804  Uint32 tFinalReadSize = theFinalReadSize;
805  Uint32 tSubroutineSize = theSubroutineSize;
806  if (theOperationType != OpenScanRequest &&
807  theOperationType != OpenRangeScanRequest) {
808  TcKeyReq * const tcKeyReq = CAST_PTR(TcKeyReq, theTCREQ->getDataPtrSend());
809 
810  tcKeyReq->attrInfo[0] = tInitialReadSize;
811  tcKeyReq->attrInfo[1] = tInterpretedSize;
812  tcKeyReq->attrInfo[2] = tFinalUpdateSize;
813  tcKeyReq->attrInfo[3] = tFinalReadSize;
814  tcKeyReq->attrInfo[4] = tSubroutineSize;
815  } else {
816  // If a scan is defined we use the first ATTRINFO instead of TCKEYREQ.
817  theFirstATTRINFO->setData(tInitialReadSize, 4);
818  theFirstATTRINFO->setData(tInterpretedSize, 5);
819  theFirstATTRINFO->setData(tFinalUpdateSize, 6);
820  theFirstATTRINFO->setData(tFinalReadSize, 7);
821  theFirstATTRINFO->setData(tSubroutineSize, 8);
822  }//if
823  theReceiver.prepareSend();
824  return 0;
825 }//NdbOperation::prepareSendInterpreted()
826 
827 
828 /*
829  Prepares TCKEYREQ and (if needed) KEYINFO and ATTRINFO signals for
830  operations using the NdbRecord API
831  Executed when the operation is defined for both PK, Unique index
832  and scan takeover operations.
833  @returns 0 for success
834 */
835 int
836 NdbOperation::buildSignalsNdbRecord(Uint32 aTC_ConnectPtr,
837  Uint64 aTransId,
838  const Uint32 * m_read_mask)
839 {
840  char buf[NdbRecord::Attr::SHRINK_VARCHAR_BUFFSIZE];
841  int res;
842  Uint32 no_disk_flag;
843  Uint32 *attrinfo_section_sizes_ptr= NULL;
844 
845  assert(theStatus==UseNdbRecord);
846  /* Interpreted operations not supported with NdbRecord
847  * use NdbInterpretedCode instead
848  */
849  assert(!theInterpretIndicator);
850 
851  const NdbRecord *key_rec= m_key_record;
852  const char *key_row= m_key_row;
853  const NdbRecord *attr_rec= m_attribute_record;
854  const char *updRow;
855  const bool isScanTakeover= (key_rec == NULL);
856  const bool isUnlock = (theOperationType == UnlockRequest);
857 
858  TcKeyReq *tcKeyReq= CAST_PTR(TcKeyReq, theTCREQ->getDataPtrSend());
859  Uint32 hdrSize= fillTcKeyReqHdr(tcKeyReq, aTC_ConnectPtr, aTransId);
860  /* No KeyInfo goes in the TCKEYREQ signal - it all goes into
861  * a separate KeyInfo section
862  */
863  assert(theTCREQ->next() == NULL);
864  theKEYINFOptr= NULL;
865  keyInfoRemain= 0;
866 
867  /* Fill in keyinfo */
868  if (isScanTakeover)
869  {
870  /* This means that key_row contains the KEYINFO20 data. */
871  /* i.e. lock takeover */
872  tcKeyReq->tableId= attr_rec->tableId;
873  tcKeyReq->tableSchemaVersion= attr_rec->tableVersion;
874  res= insertKEYINFO_NdbRecord(key_row, m_keyinfo_length*4);
875  if (res)
876  return res;
877  }
878  else if (!isUnlock)
879  {
880  /* Normal PK / unique index read */
881  tcKeyReq->tableId= key_rec->tableId;
882  tcKeyReq->tableSchemaVersion= key_rec->tableVersion;
883  theTotalNrOfKeyWordInSignal= 0;
884  for (Uint32 i= 0; i<key_rec->key_index_length; i++)
885  {
886  const NdbRecord::Attr *col;
887 
888  col= &key_rec->columns[key_rec->key_indexes[i]];
889 
890  /*
891  A unique index can index a nullable column (the primary key index
892  cannot). So we can get NULL here (but it is an error if we do).
893  */
894  if (col->is_null(key_row))
895  {
896  setErrorCodeAbort(4316);
897  return -1;
898  }
899 
900  Uint32 length=0;
901 
902  bool len_ok;
903  const char *src;
904  if (col->flags & NdbRecord::IsMysqldShrinkVarchar)
905  {
906  /* Used to support special varchar format for mysqld keys. */
907  len_ok= col->shrink_varchar(key_row, length, buf);
908  src= buf;
909  }
910  else
911  {
912  len_ok= col->get_var_length(key_row, length);
913  src= &key_row[col->offset];
914  }
915 
916  if (!len_ok)
917  {
918  /* Hm, corrupt varchar length. */
919  setErrorCodeAbort(4209);
920  return -1;
921  }
922  res= insertKEYINFO_NdbRecord(src, length);
923  if (res)
924  return res;
925  }
926  }
927  else
928  {
929  assert(isUnlock);
930  assert(theLockHandle);
931  assert(attr_rec);
932  assert(theLockHandle->isLockRefValid());
933 
934  tcKeyReq->tableId= attr_rec->tableId;
935  tcKeyReq->tableSchemaVersion= attr_rec->tableVersion;
936 
937  /* Copy key data from NdbLockHandle */
938  Uint32 keyInfoWords = 0;
939  const Uint32* keyInfoSrc = theLockHandle->getKeyInfoWords(keyInfoWords);
940  assert( keyInfoWords );
941 
942  res = insertKEYINFO_NdbRecord((const char*)keyInfoSrc,
943  keyInfoWords << 2);
944  if (res)
945  return res;
946  }
947 
948  /* For long TCKEYREQ, we don't need to set the key length in the
949  * header, as it is passed as the length of the KeyInfo section
950  */
951 
952  /* Fill in attrinfo
953  * If ATTRINFO includes interpreted code then the first 5 words are
954  * length information for 5 sections.
955  * If there is no interpreted code then there's only one section, and
956  * no length information
957  */
958  /* All ATTRINFO goes into a separate ATTRINFO section - none is placed
959  * into the TCKEYREQ signal
960  */
961  assert(theFirstATTRINFO == NULL);
962  attrInfoRemain= 0;
963  theATTRINFOptr= NULL;
964 
965  no_disk_flag = (m_flags & OF_NO_DISK) != 0;
966 
967  /* If we have an interpreted program then we add 5 words
968  * of section length information at the start of the
969  * ATTRINFO
970  */
971  const NdbInterpretedCode *code= m_interpreted_code;
972  if (code)
973  {
974  if (code->m_flags & NdbInterpretedCode::UsesDisk)
975  no_disk_flag = 0;
976 
977  /* Need to add section lengths info to the signal */
978  Uint32 sizes[AttrInfo::SectionSizeInfoLength];
979  sizes[0] = 0; // Initial read.
980  sizes[1] = 0; // Interpreted program
981  sizes[2] = 0; // Final update size.
982  sizes[3] = 0; // Final read size
983  sizes[4] = 0; // Subroutine size
984 
985  res = insertATTRINFOData_NdbRecord((const char *)sizes,
986  sizeof(sizes));
987  if (res)
988  return res;
989 
990  /* So that we can go back to set the actual sizes later... */
991  attrinfo_section_sizes_ptr= (theATTRINFOptr -
992  AttrInfo::SectionSizeInfoLength);
993 
994  }
995 
996  OperationType tOpType= theOperationType;
997 
998  /* Initial read signal words */
999  if (tOpType == ReadRequest || tOpType == ReadExclusive ||
1000  (tOpType == DeleteRequest &&
1001  m_attribute_row != NULL)) // Read as part of delete
1002  {
1004  Uint32 requestedCols= 0;
1005  Uint32 maxAttrId= 0;
1006  for (Uint32 i= 0; i<attr_rec->noOfColumns; i++)
1007  {
1008  const NdbRecord::Attr *col;
1009 
1010  col= &attr_rec->columns[i];
1011  Uint32 attrId= col->attrId;
1012 
1013  /* Pseudo columns not allowed for NdbRecord */
1014  assert(! (attrId & AttributeHeader::PSEUDO));
1015 
1016  if (!BitmaskImpl::get(MAXNROFATTRIBUTESINWORDS,
1017  m_read_mask, attrId))
1018  continue;
1019 
1020  /* Blob head reads are defined as extra GetValues,
1021  * processed below, not here.
1022  */
1023  if (unlikely(col->flags & NdbRecord::IsBlob))
1024  continue;
1025 
1026  if (col->flags & NdbRecord::IsDisk)
1027  no_disk_flag= 0;
1028 
1029  if (attrId > maxAttrId)
1030  maxAttrId= attrId;
1031 
1032  readMask.set(attrId);
1033  requestedCols++;
1034  }
1035 
1036  /* Are there any columns to read via NdbRecord? */
1037  if (requestedCols > 0)
1038  {
1039  bool all= (requestedCols == m_currentTable->m_columns.size());
1040 
1041  if (all)
1042  {
1043  res= insertATTRINFOHdr_NdbRecord(AttributeHeader::READ_ALL,
1044  requestedCols);
1045  if (res)
1046  return res;
1047  }
1048  else
1049  {
1050  /* How many bitmask words are significant? */
1051  Uint32 sigBitmaskWords= (maxAttrId>>5) + 1;
1052 
1053  res= insertATTRINFOHdr_NdbRecord(AttributeHeader::READ_PACKED,
1054  sigBitmaskWords << 2);
1055  if (res)
1056  return res;
1057 
1058  res= insertATTRINFOData_NdbRecord((const char*) &readMask.rep.data[0],
1059  sigBitmaskWords << 2);
1060  if (res)
1061  return res;
1062  }
1063  }
1064 
1065  /* Handle any additional getValue().
1066  * Note : This includes extra getValue()s to read Blob
1067  * header + inline data
1068  * Disk flag set when getValues were processed.
1069  */
1070  const NdbRecAttr *ra= theReceiver.theFirstRecAttr;
1071  while (ra)
1072  {
1073  res= insertATTRINFOHdr_NdbRecord(ra->attrId(), 0);
1074  if(res)
1075  return res;
1076  ra= ra->next();
1077  }
1078  }
1079 
1080  if (((m_flags & OF_USE_ANY_VALUE) != 0) &&
1081  (tOpType == DeleteRequest))
1082  {
1083  /* Special hack for delete and ANYVALUE pseudo-column
1084  * We want to be able set the ANYVALUE pseudo-column as
1085  * part of a delete, but deletes don't allow updates
1086  * So we perform a 'read' of the column, passing a value.
1087  * Code in TUP which handles this 'read' will set the
1088  * value when the read is processed.
1089  */
1090  res= insertATTRINFOHdr_NdbRecord(AttributeHeader::ANY_VALUE, 4);
1091  if(res)
1092  return res;
1093  res= insertATTRINFOData_NdbRecord((const char *)(&m_any_value), 4);
1094  if(res)
1095  return res;
1096  }
1097 
1098  /* Interpreted program main signal words */
1099  if (code)
1100  {
1101  /* Record length of Initial Read section */
1102  attrinfo_section_sizes_ptr[0]= theTotalCurrAI_Len -
1103  AttrInfo::SectionSizeInfoLength;
1104 
1105  Uint32 mainProgramWords= code->m_first_sub_instruction_pos ?
1106  code->m_first_sub_instruction_pos :
1107  code->m_instructions_length;
1108 
1109  res = insertATTRINFOData_NdbRecord((const char *)code->m_buffer,
1110  mainProgramWords << 2);
1111 
1112  if (res)
1113  return res;
1114 
1115  // Record length of Interpreted program section */
1116  attrinfo_section_sizes_ptr[1]= mainProgramWords;
1117  }
1118 
1119 
1120  /* Final update signal words */
1121  if ((tOpType == InsertRequest) ||
1122  (tOpType == WriteRequest) ||
1123  (tOpType == UpdateRequest) ||
1124  (tOpType == RefreshRequest))
1125  {
1126  updRow= m_attribute_row;
1127  NdbBlob *currentBlob= theBlobList;
1128 
1129  for (Uint32 i= 0; i<attr_rec->noOfColumns; i++)
1130  {
1131  const NdbRecord::Attr *col;
1132 
1133  col= &attr_rec->columns[i];
1134  Uint32 attrId= col->attrId;
1135 
1136  /* Pseudo columns not allowed for NdbRecord */
1137  assert(! (attrId & AttributeHeader::PSEUDO));
1138 
1139  if (!BitmaskImpl::get((NDB_MAX_ATTRIBUTES_IN_TABLE+31)>>5,
1140  m_read_mask, attrId))
1141  continue;
1142 
1143  if (col->flags & NdbRecord::IsDisk)
1144  no_disk_flag= 0;
1145 
1146  Uint32 length;
1147  const char *data;
1148 
1149  if (likely(!(col->flags & (NdbRecord::IsBlob|NdbRecord::IsMysqldBitfield))))
1150  {
1151  int idxColNum= -1;
1152  const NdbRecord::Attr* idxCol= NULL;
1153 
1154  /* Take data from the key row for key columns, attr row otherwise
1155  * Always attr row for scan takeover
1156  */
1157  if (( isScanTakeover ) ||
1158  ( ( key_rec->m_attrId_indexes_length <= attrId) ||
1159  ( (idxColNum= key_rec->m_attrId_indexes[attrId]) == -1 ) ||
1160  ( ! (idxCol= &key_rec->columns[idxColNum] )) ||
1161  ( ! (idxCol->flags & NdbRecord::IsKey)) ) )
1162  {
1163  /* Normal path where we get data from the attr row
1164  * Always get ATTRINFO data from the attr row for ScanTakeover
1165  * Update as there's no key row
1166  * This allows scan-takeover update to update pk within
1167  * collation rules
1168  */
1169  if (col->is_null(updRow))
1170  length= 0;
1171  else if (!col->get_var_length(updRow, length))
1172  {
1173  /* Hm, corrupt varchar length. */
1174  setErrorCodeAbort(4209);
1175  return -1;
1176  }
1177  data= &updRow[col->offset];
1178  }
1179  else
1180  {
1181  /* For Insert/Write where user provides key columns,
1182  * take them from the key record row to avoid sending different
1183  * values in KeyInfo and AttrInfo
1184  * Need the correct Attr struct from the key
1185  * record
1186  * Note that the key record could be for a unique index.
1187  */
1188  assert(key_rec != 0); /* Not scan takeover */
1189  assert(key_rec->m_attrId_indexes_length > attrId);
1190  assert(key_rec->m_attrId_indexes[attrId] != -1);
1191  assert(idxCol != NULL);
1192  col= idxCol;
1193  assert(col->attrId == attrId);
1194  assert(col->flags & NdbRecord::IsKey);
1195 
1196  /* Now get the data and length from the key row
1197  * Any issues with key nullness should've been
1198  * caught above
1199  */
1200  assert(!col->is_null(key_row));
1201  length= 0;
1202 
1203  bool len_ok;
1204 
1205  if (col->flags & NdbRecord::IsMysqldShrinkVarchar)
1206  {
1207  /* Used to support special varchar format for mysqld keys.
1208  * Ideally we'd avoid doing this shrink twice...
1209  */
1210  len_ok= col->shrink_varchar(key_row, length, buf);
1211  data= buf;
1212  }
1213  else
1214  {
1215  len_ok= col->get_var_length(key_row, length);
1216  data= &key_row[col->offset];
1217  }
1218 
1219  /* Should have 'seen' any length issues when generating keyinfo above */
1220  assert(len_ok);
1221  }
1222  }
1223  else
1224  {
1225  /* Blob or MySQLD bitfield handling */
1226  assert(! (col->flags & NdbRecord::IsKey));
1227  if (likely(col->flags & NdbRecord::IsMysqldBitfield))
1228  {
1229  /* Mysqld format bitfield. */
1230  if (col->is_null(updRow))
1231  length= 0;
1232  else
1233  {
1234  col->get_mysqld_bitfield(updRow, buf);
1235  data= buf;
1236  length= col->maxSize;
1237  }
1238  }
1239  else
1240  {
1241  NdbBlob *bh= currentBlob;
1242  currentBlob= currentBlob->theNext;
1243 
1244  /*
1245  * Blob column
1246  * We cannot prepare signals to update the Blob yet, as the
1247  * user has not had a chance to specify the data to write yet.
1248  *
1249  * Writes to the blob head, inline data and parts are handled
1250  * by separate operations, injected before and after this one
1251  * as part of the blob handling code in NdbTransaction::execute().
1252  * However, for Insert and Write to non-nullable columns, we must
1253  * write some BLOB data here in case the BLOB is non-nullable.
1254  * For this purpose, we write data of zero length
1255  * For nullable columns, we write null data. This is necessary
1256  * as it is valid for users to never call setValue() for nullable
1257  * blobs.
1258  */
1259  if (tOpType == UpdateRequest)
1260  continue; // Do nothing in this operation
1261 
1262  /*
1263  * Blob call that sets up a data pointer for blob header data
1264  * for an 'empty' blob - length zero or null depending on
1265  * Blob's 'nullability'
1266  */
1267  bh->getNullOrEmptyBlobHeadDataPtr(data, length);
1268  }
1269  } // if Blob or Bitfield
1270 
1271  res= insertATTRINFOHdr_NdbRecord(attrId, length);
1272  if(res)
1273  return res;
1274  if (length > 0)
1275  {
1276  res= insertATTRINFOData_NdbRecord(data, length);
1277  if(res)
1278  return res;
1279  }
1280  } // for noOfColumns
1281 
1282  /* Now handle any extra setValues passed in */
1283  if (m_extraSetValues != NULL)
1284  {
1285  for (Uint32 i=0; i<m_numExtraSetValues; i++)
1286  {
1287  const NdbDictionary::Column *extraCol=m_extraSetValues[i].column;
1288  const void * pvalue=m_extraSetValues[i].value;
1289 
1290  if (extraCol->getStorageType( )== NDB_STORAGETYPE_DISK)
1291  no_disk_flag=0;
1292 
1293  Uint32 length;
1294 
1295  if (pvalue==NULL)
1296  length=0;
1297  else
1298  {
1299  length=extraCol->getSizeInBytes();
1300  if (extraCol->getArrayType() != NdbDictionary::Column::ArrayTypeFixed)
1301  {
1302  Uint32 lengthInfoBytes;
1303  if (!NdbSqlUtil::get_var_length((Uint32) extraCol->getType(),
1304  pvalue,
1305  length,
1306  lengthInfoBytes,
1307  length))
1308  {
1309  // Length parameter in equal/setValue is incorrect
1310  setErrorCodeAbort(4209);
1311  return -1;
1312  }
1313  }
1314  }
1315 
1316  // Add ATTRINFO
1317  res= insertATTRINFOHdr_NdbRecord(extraCol->getAttrId(), length);
1318  if(res)
1319  return res;
1320 
1321  if(length>0)
1322  {
1323  res=insertATTRINFOData_NdbRecord((char*)pvalue, length);
1324  if(res)
1325  return res;
1326  }
1327  } // for numExtraSetValues
1328  }// if m_extraSetValues!=null
1329 
1330  /* Don't need these any more */
1331  m_extraSetValues = NULL;
1332  m_numExtraSetValues = 0;
1333  }
1334 
1335  if ((tOpType == InsertRequest) ||
1336  (tOpType == WriteRequest) ||
1337  (tOpType == UpdateRequest) ||
1338  (tOpType == RefreshRequest))
1339  {
1340  /* Handle setAnyValue() for all cases except delete */
1341  if ((m_flags & OF_USE_ANY_VALUE) != 0)
1342  {
1343  res= insertATTRINFOHdr_NdbRecord(AttributeHeader::ANY_VALUE, 4);
1344  if(res)
1345  return res;
1346  res= insertATTRINFOData_NdbRecord((const char *)(&m_any_value), 4);
1347  if(res)
1348  return res;
1349  }
1350  }
1351 
1352  /* Final read signal words */
1353  // Not currently used in NdbRecord
1354 
1355  /* Subroutine section signal words */
1356  if (code)
1357  {
1358  /* Even with no subroutine section signal words, we need to set
1359  * the size of the update section
1360  */
1361  Uint32 updateWords= theTotalCurrAI_Len - (AttrInfo::SectionSizeInfoLength +
1362  attrinfo_section_sizes_ptr[0] +
1363  attrinfo_section_sizes_ptr[1]);
1364  attrinfo_section_sizes_ptr[2]= updateWords;
1365 
1366  /* Do we have any subroutines ? */
1367  if (code->m_number_of_subs > 0)
1368  {
1369  assert(code->m_first_sub_instruction_pos);
1370 
1371  Uint32 *subroutineStart=
1372  &code->m_buffer[ code->m_first_sub_instruction_pos ];
1373  Uint32 subroutineWords=
1374  code->m_instructions_length -
1375  code->m_first_sub_instruction_pos;
1376 
1377  assert(subroutineWords > 0);
1378 
1379  res = insertATTRINFOData_NdbRecord((const char *)subroutineStart,
1380  subroutineWords << 2);
1381 
1382  if (res)
1383  return res;
1384 
1385  /* Update section length for subroutine section */
1386  attrinfo_section_sizes_ptr[4]= subroutineWords;
1387  }
1388  }
1389 
1390  /* Check if too much attrinfo have been defined. */
1391  if (theTotalCurrAI_Len > TcKeyReq::MaxTotalAttrInfo){
1392  setErrorCodeAbort(4257);
1393  return -1;
1394  }
1395 
1396  /* All KeyInfo and AttrInfo is in separate sections
1397  * Size information for Key and AttrInfo is taken from the section
1398  * lengths rather than from header information
1399  */
1400  theTCREQ->setLength(hdrSize);
1401  TcKeyReq::setNoDiskFlag(tcKeyReq->requestInfo, no_disk_flag);
1402  return 0;
1403 
1404 }
1405 
1406 /*
1407  Do final signal preparation before sending.
1408 */
1409 int
1410 NdbOperation::prepareSendNdbRecord(AbortOption ao)
1411 {
1412  // There are a number of flags in the TCKEYREQ header that
1413  // we have to set at this point...they are not correctly
1414  // defined before the call to execute().
1415  TcKeyReq *tcKeyReq=CAST_PTR(TcKeyReq, theTCREQ->getDataPtrSend());
1416 
1417  Uint8 abortOption= (ao == DefaultAbortOption) ?
1418  (Uint8) m_abortOption : (Uint8) ao;
1419 
1420  m_abortOption= theSimpleIndicator && theOperationType==ReadRequest ?
1421  (Uint8) AO_IgnoreError : (Uint8) abortOption;
1422 
1423  Uint8 tQueable = (m_flags & OF_QUEUEABLE) != 0;
1424  Uint8 tDeferred = (m_flags & OF_DEFERRED_CONSTRAINTS) != 0;
1425 
1426  TcKeyReq::setAbortOption(tcKeyReq->requestInfo, m_abortOption);
1427  TcKeyReq::setCommitFlag(tcKeyReq->requestInfo, theCommitIndicator);
1428  TcKeyReq::setStartFlag(tcKeyReq->requestInfo, theStartIndicator);
1429  TcKeyReq::setSimpleFlag(tcKeyReq->requestInfo, theSimpleIndicator);
1430  TcKeyReq::setDirtyFlag(tcKeyReq->requestInfo, theDirtyIndicator);
1431 
1432  TcKeyReq::setQueueOnRedoProblemFlag(tcKeyReq->requestInfo, tQueable);
1433  TcKeyReq::setDeferredConstraints(tcKeyReq->requestInfo, tDeferred);
1434 
1435  theStatus= WaitResponse;
1436  theReceiver.prepareSend();
1437 
1438  return 0;
1439 }
1440 
1441 /*
1442  Set up the header of the TCKEYREQ signal (except a few length fields,
1443  which are computed later in prepareSendNdbRecord()).
1444  Returns the length of the header, used to find the correct placement of
1445  keyinfo and attrinfo stored within TCKEYREQ.
1446 */
1447 Uint32
1448 NdbOperation::fillTcKeyReqHdr(TcKeyReq *tcKeyReq,
1449  Uint32 connectPtr,
1450  Uint64 transId)
1451 {
1452  Uint32 hdrLen;
1453  UintR *hdrPtr;
1454 
1455  tcKeyReq->apiConnectPtr= connectPtr;
1456  tcKeyReq->apiOperationPtr= ptr2int();
1457 
1458  /* With long TCKEYREQ, we do not need to set the attrlength
1459  * in the header since it is encoded as the AI section length
1460  */
1461  UintR attrLenAPIVer= 0;
1462  TcKeyReq::setAPIVersion(attrLenAPIVer, NDB_VERSION);
1463  tcKeyReq->attrLen= attrLenAPIVer;
1464 
1465  UintR reqInfo= 0;
1466  /* Dirty flag, Commit flag, Start flag, Simple flag set later
1467  * in prepareSendNdbRecord()
1468  */
1469  TcKeyReq::setInterpretedFlag(reqInfo, (m_interpreted_code != NULL));
1470  /* We will setNoDiskFlag() later when we have checked all columns. */
1471  TcKeyReq::setOperationType(reqInfo, theOperationType);
1472  // AbortOption set later in prepareSendNdbRecord()
1473  TcKeyReq::setDistributionKeyFlag(reqInfo, theDistrKeyIndicator_);
1474  TcKeyReq::setScanIndFlag(reqInfo, theScanInfo & 1);
1475  tcKeyReq->requestInfo= reqInfo;
1476 
1477  tcKeyReq->transId1= (Uint32)transId;
1478  tcKeyReq->transId2= (Uint32)(transId>>32);
1479 
1480  /*
1481  The next four words are optional, and included or not based on the flags
1482  passed earlier. At most two of them are possible here.
1483  */
1484  hdrLen= 8;
1485  hdrPtr= &(tcKeyReq->scanInfo);
1486  if (theScanInfo & 1)
1487  {
1488  *hdrPtr++= theScanInfo;
1489  hdrLen++;
1490  }
1491  if (theDistrKeyIndicator_)
1492  {
1493  *hdrPtr++= theDistributionKey;
1494  hdrLen++;
1495  }
1496 
1497  return hdrLen;
1498 }
1499 
1500 /*
1501  Link a new KEYINFO signal into the operation.
1502  This is used to store words for the KEYINFO section.
1503  // TODO : Unify with allocAttrInfo
1504  Return 0 on success, -1 on error.
1505 */
1506 int
1507 NdbOperation::allocKeyInfo()
1508 {
1509  NdbApiSignal *tSignal;
1510 
1511  tSignal= theNdb->getSignal();
1512  if (tSignal == NULL)
1513  {
1514  setErrorCodeAbort(4000);
1515  return -1;
1516  }
1517  tSignal->next(NULL);
1518  if (theRequest->next() != NULL)
1519  {
1520  theLastKEYINFO->setLength(NdbApiSignal::MaxSignalWords);
1521  theLastKEYINFO->next(tSignal);
1522  }
1523  else
1524  {
1525  theRequest->next(tSignal);
1526  }
1527  theLastKEYINFO= tSignal;
1528  keyInfoRemain= NdbApiSignal::MaxSignalWords;
1529  theKEYINFOptr= tSignal->getDataPtrSend();
1530 
1531  return 0;
1532 }
1533 
1534 /*
1535  Link a new signal into the operation.
1536  This is used to store words for the ATTRINFO section.
1537  // TODO : Unify with allocKeyInfo
1538  Return 0 on success, -1 on error.
1539 */
1540 int
1541 NdbOperation::allocAttrInfo()
1542 {
1543  NdbApiSignal *tSignal;
1544 
1545  tSignal= theNdb->getSignal();
1546  if (tSignal == NULL)
1547  {
1548  setErrorCodeAbort(4000);
1549  return -1;
1550  }
1551  tSignal->next(NULL);
1552  if (theFirstATTRINFO != NULL)
1553  {
1554  theCurrentATTRINFO->setLength(NdbApiSignal::MaxSignalWords);
1555  theCurrentATTRINFO->next(tSignal);
1556  }
1557  else
1558  {
1559  theFirstATTRINFO= tSignal;
1560  }
1561  theCurrentATTRINFO= tSignal;
1562  attrInfoRemain= NdbApiSignal::MaxSignalWords;
1563  theATTRINFOptr= tSignal->getDataPtrSend();
1564 
1565  return 0;
1566 }
1567 
1568 int
1569 NdbOperation::insertKEYINFO_NdbRecord(const char *value,
1570  Uint32 byteSize)
1571 {
1572  /* Words are added to a list of signal objects linked from
1573  * theRequest->next()
1574  * The list of objects is then used to form the KeyInfo
1575  * section of the TCKEYREQ/TCINDXREQ/SCANTABREQ long signal
1576  * No separate KeyInfo signal train is sent.
1577  */
1578  theTupKeyLen+= (byteSize+3)/4;
1579 
1580  while (byteSize > keyInfoRemain*4)
1581  {
1582  /* Need to link in extra objects */
1583  if (keyInfoRemain)
1584  {
1585  /* Fill remaining words in this object */
1586  assert(theKEYINFOptr != NULL);
1587  memcpy(theKEYINFOptr, value, keyInfoRemain*4);
1588  value+= keyInfoRemain*4;
1589  byteSize-= keyInfoRemain*4;
1590  }
1591 
1592  /* Link new object in */
1593  int res= allocKeyInfo();
1594  if(res)
1595  return res;
1596  }
1597 
1598  assert(theRequest->next() != NULL);
1599  assert(theLastKEYINFO != NULL);
1600 
1601  /* Remaining words fit in this object */
1602  assert(theKEYINFOptr != NULL);
1603  memcpy(theKEYINFOptr, value, byteSize);
1604  if((byteSize%4) != 0)
1605  memset(((char *)theKEYINFOptr)+byteSize, 0, 4-(byteSize%4));
1606  Uint32 sizeInWords= (byteSize+3)/4;
1607  theKEYINFOptr+= sizeInWords;
1608  keyInfoRemain-= sizeInWords;
1609 
1610  theLastKEYINFO->setLength(NdbApiSignal::MaxSignalWords
1611  - keyInfoRemain);
1612 
1613  return 0;
1614 }
1615 
1616 int
1617 NdbOperation::insertATTRINFOHdr_NdbRecord(Uint32 attrId,
1618  Uint32 attrLen)
1619 {
1620  /* Words are added to a list of Signal objects pointed to
1621  * by theFirstATTRINFO
1622  * This list is then used to form the ATTRINFO
1623  * section of the TCKEYREQ/TCINDXREQ/SCANTABREQ long signal
1624  * No ATTRINFO signal train is sent.
1625  */
1626 
1627  theTotalCurrAI_Len++;
1628 
1629  if (! attrInfoRemain)
1630  {
1631  /* Need to link in an extra object to store this
1632  * word
1633  */
1634  int res= allocAttrInfo();
1635  if (res)
1636  return res;
1637  }
1638 
1639  /* Word fits in remaining space */
1640  Uint32 ah;
1641  AttributeHeader::init(&ah, attrId, attrLen);
1642  assert(theFirstATTRINFO != NULL);
1643  assert(theCurrentATTRINFO != NULL);
1644  assert(theATTRINFOptr != NULL);
1645 
1646  *(theATTRINFOptr++)= ah;
1647  attrInfoRemain--;
1648 
1649  theCurrentATTRINFO->setLength(NdbApiSignal::MaxSignalWords
1650  - attrInfoRemain);
1651 
1652  return 0;
1653 }
1654 
1655 int
1656 NdbOperation::insertATTRINFOData_NdbRecord(const char *value,
1657  Uint32 byteSize)
1658 {
1659  /* Words are added to a list of Signal objects pointed to
1660  * by theFirstATTRINFO
1661  * This list is then used to form the ATTRINFO
1662  * section of the TCKEYREQ long signal
1663  * No ATTRINFO signal train is sent.
1664  */
1665  theTotalCurrAI_Len+= (byteSize+3)/4;
1666 
1667  while (byteSize > attrInfoRemain*4)
1668  {
1669  /* Need to link in extra objects */
1670  if (attrInfoRemain)
1671  {
1672  /* Fill remaining space in current object */
1673  memcpy(theATTRINFOptr, value, attrInfoRemain*4);
1674  value+= attrInfoRemain*4;
1675  byteSize-= attrInfoRemain*4;
1676  }
1677 
1678  int res= allocAttrInfo();
1679  if (res)
1680  return res;
1681  }
1682 
1683  /* Remaining words fit in current signal */
1684  assert(theFirstATTRINFO != NULL);
1685  assert(theCurrentATTRINFO != NULL);
1686  assert(theATTRINFOptr != NULL);
1687 
1688  memcpy(theATTRINFOptr, value, byteSize);
1689  if((byteSize%4) != 0)
1690  memset(((char *)theATTRINFOptr)+byteSize, 0, 4-(byteSize%4));
1691  Uint32 sizeInWords= (byteSize+3)/4;
1692  theATTRINFOptr+= sizeInWords;
1693  attrInfoRemain-= sizeInWords;
1694 
1695  theCurrentATTRINFO->setLength(NdbApiSignal::MaxSignalWords
1696  - attrInfoRemain);
1697 
1698  return 0;
1699 }
1700 
1701 int
1702 NdbOperation::checkState_TransId(const NdbApiSignal* aSignal)
1703 {
1704  Uint64 tRecTransId, tCurrTransId;
1705  Uint32 tTmp1, tTmp2;
1706 
1707  if (theStatus != WaitResponse) {
1708 #ifdef NDB_NO_DROPPED_SIGNAL
1709  abort();
1710 #endif
1711  return -1;
1712  }//if
1713 
1714  tTmp1 = aSignal->readData(2);
1715  tTmp2 = aSignal->readData(3);
1716 
1717  tRecTransId = (Uint64)tTmp1 + ((Uint64)tTmp2 << 32);
1718  tCurrTransId = theNdbCon->getTransactionId();
1719  if (tCurrTransId != tRecTransId) {
1720 #ifdef NDB_NO_DROPPED_SIGNAL
1721  abort();
1722 #endif
1723  return -1;
1724  }//if
1725  return 0;
1726 }//NdbOperation::checkState_TransId()
1727 
1728 /***************************************************************************
1729 int receiveTCKEYREF( NdbApiSignal* aSignal)
1730 
1731 Return Value: Return 0 : send was succesful.
1732  Return -1: In all other case.
1733 Parameters: aSignal: the signal object that contains the TCKEYREF signal from TC.
1734 Remark: Handles the reception of the TCKEYREF signal.
1735 ***************************************************************************/
1736 int
1738 {
1739  if (checkState_TransId(aSignal) == -1) {
1740  return -1;
1741  }//if
1742 
1743  setErrorCode(aSignal->readData(4));
1744  if (aSignal->getLength() == TcKeyRef::SignalLength)
1745  {
1746  // Signal may contain additional error data
1747  theError.details = (char *) aSignal->readData(5);
1748  }
1749 
1750  theStatus = Finished;
1751  theReceiver.m_received_result_length = ~0;
1752 
1753  // not dirty read
1754  if(! (theOperationType == ReadRequest && theDirtyIndicator))
1755  {
1756  theNdbCon->OpCompleteFailure();
1757  return -1;
1758  }
1759 
1764  if(theReceiver.m_expected_result_length)
1765  {
1766  return theNdbCon->OpCompleteFailure();
1767  }
1768 
1769  return -1;
1770 }