1 /*
2    Copyright (c) 2003, 2021, Oracle and/or its affiliates.
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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include "API.hpp"
26 #include <signaldata/TcKeyReq.hpp>
27 
28 
29 /******************************************************************************
30  * NdbOperation(Ndb* aNdb, Table* aTable);
31  *
32  * Return Value:  None
33  * Parameters:    aNdb: Pointers to the Ndb object.
34  *                aTable: Pointers to the Table object
35  * Remark:        Creat an object of NdbOperation.
36  ****************************************************************************/
NdbOperation(Ndb * aNdb,NdbOperation::Type aType)37 NdbOperation::NdbOperation(Ndb* aNdb, NdbOperation::Type aType) :
38   m_type(aType),
39   theReceiver(aNdb),
40   theErrorLine(0),
41   theNdb(aNdb),
42   //theTable(aTable),
43   theNdbCon(NULL),
44   theNext(NULL),
45   theTCREQ(NULL),
46   theFirstATTRINFO(NULL),
47   theCurrentATTRINFO(NULL),
48   theTotalCurrAI_Len(0),
49   theAI_LenInCurrAI(0),
50   theLastKEYINFO(NULL),
51 
52   theFirstLabel(NULL),
53   theLastLabel(NULL),
54   theFirstBranch(NULL),
55   theLastBranch(NULL),
56   theFirstCall(NULL),
57   theLastCall(NULL),
58   theFirstSubroutine(NULL),
59   theLastSubroutine(NULL),
60   theNoOfLabels(0),
61   theNoOfSubroutines(0),
62 
63   m_currentTable(NULL), //theTableId(0xFFFF),
64   m_accessTable(NULL), //theAccessTableId(0xFFFF),
65   //theSchemaVersion(0),
66   theTotalNrOfKeyWordInSignal(8),
67   theTupKeyLen(0),
68   theNoOfTupKeyLeft(0),
69   theOperationType(NotDefined),
70   theStatus(Init),
71   theMagicNumber(0xFE11D0),
72   theScanInfo(0),
73   m_tcReqGSN(GSN_TCKEYREQ),
74   m_keyInfoGSN(GSN_KEYINFO),
75   m_attrInfoGSN(GSN_ATTRINFO),
76   theBlobList(NULL),
77   m_abortOption(-1),
78   m_noErrorPropagation(false),
79   theLockHandle(NULL),
80   m_blob_lock_upgraded(false)
81 {
82   theReceiver.init(NdbReceiver::NDB_OPERATION, this);
83   theError.code = 0;
84   m_customData = NULL;
85 }
86 /*****************************************************************************
87  * ~NdbOperation();
88  *
89  * Remark:         Delete tables for connection pointers (id).
90  *****************************************************************************/
~NdbOperation()91 NdbOperation::~NdbOperation( )
92 {
93 }
94 /******************************************************************************
95  *void setErrorCode(int anErrorCode);
96  *
97  * Remark:         Set an Error Code on operation and
98  *                 on connection set an error status.
99  *****************************************************************************/
100 void
setErrorCode(int anErrorCode) const101 NdbOperation::setErrorCode(int anErrorCode) const
102 {
103   /* Setting an error is considered to be a const
104      operation, hence the nasty cast here */
105   NdbOperation *pnonConstThis=const_cast<NdbOperation *>(this);
106 
107   pnonConstThis->theError.code = anErrorCode;
108   theNdbCon->theErrorLine = theErrorLine;
109   theNdbCon->theErrorOperation = pnonConstThis;
110   if (!(m_abortOption == AO_IgnoreError && m_noErrorPropagation))
111     theNdbCon->setOperationErrorCode(anErrorCode);
112 }
113 
114 /******************************************************************************
115  * void setErrorCodeAbort(int anErrorCode);
116  *
117  * Remark:         Set an Error Code on operation and on connection set
118  *                 an error status.
119  *****************************************************************************/
120 void
setErrorCodeAbort(int anErrorCode) const121 NdbOperation::setErrorCodeAbort(int anErrorCode) const
122 {
123   /* Setting an error is considered to be a const
124      operation, hence the nasty cast here */
125   NdbOperation *pnonConstThis=const_cast<NdbOperation *>(this);
126 
127   pnonConstThis->theError.code = anErrorCode;
128   theNdbCon->theErrorLine = theErrorLine;
129   theNdbCon->theErrorOperation = pnonConstThis;
130   // ignore m_noErrorPropagation
131   theNdbCon->setOperationErrorCodeAbort(anErrorCode);
132 }
133 
134 /*****************************************************************************
135  * int init();
136  *
137  * Return Value:  Return 0 : init was successful.
138  *                Return -1: In all other case.
139  * Remark:        Initiates operation record after allocation.
140  *****************************************************************************/
141 
142 int
init(const NdbTableImpl * tab,NdbTransaction * myConnection)143 NdbOperation::init(const NdbTableImpl* tab, NdbTransaction* myConnection)
144 {
145   NdbApiSignal* tSignal;
146   theStatus		= Init;
147   theError.code		= 0;
148   theErrorLine		= 1;
149   m_currentTable = m_accessTable = tab;
150 
151   theNdbCon = myConnection;
152   for (Uint32 i=0; i<NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY; i++)
153     for (int j=0; j<3; j++)
154       theTupleKeyDefined[i][j] = 0;
155 
156   theFirstATTRINFO    = NULL;
157   theCurrentATTRINFO  = NULL;
158   theLastKEYINFO      = NULL;
159 
160 
161   theTupKeyLen	    = 0;
162   theNoOfTupKeyLeft = tab->getNoOfPrimaryKeys();
163 
164   theTotalCurrAI_Len	= 0;
165   theAI_LenInCurrAI	= 0;
166   theStartIndicator	= 0;
167   theCommitIndicator	= 0;
168   theSimpleIndicator	= 0;
169   theDirtyIndicator	= 0;
170   theInterpretIndicator	= 0;
171   theDistrKeyIndicator_  = 0;
172   theScanInfo        	= 0;
173   theTotalNrOfKeyWordInSignal = 8;
174   theMagicNumber        = getMagicNumber();
175   m_attribute_record= NULL;
176   theBlobList = NULL;
177   m_abortOption = -1;
178   m_noErrorPropagation = false;
179   m_flags = 0;
180   m_flags |= OF_NO_DISK;
181   m_interpreted_code = NULL;
182   m_extraSetValues = NULL;
183   m_numExtraSetValues = 0;
184 
185   tSignal = theNdb->getSignal();
186   if (tSignal == NULL)
187   {
188     setErrorCode(4000);
189     return -1;
190   }
191   theTCREQ = tSignal;
192   theTCREQ->setSignal(m_tcReqGSN, refToBlock(theNdbCon->m_tcRef));
193 
194   theAI_LenInCurrAI = 20;
195   TcKeyReq * const tcKeyReq = CAST_PTR(TcKeyReq, theTCREQ->getDataPtrSend());
196   tcKeyReq->scanInfo = 0;
197   theKEYINFOptr = &tcKeyReq->keyInfo[0];
198   theATTRINFOptr = &tcKeyReq->attrInfo[0];
199   if (theReceiver.init(NdbReceiver::NDB_OPERATION, this))
200   {
201     // theReceiver sets the error code of its owner
202     return -1;
203   }
204   m_customData = NULL;
205 
206   if (theNdb->theImpl->get_ndbapi_config_parameters().m_default_queue_option)
207     m_flags |= OF_QUEUEABLE;
208 
209   return 0;
210 }
211 
212 
213 /******************************************************************************
214  * void release();
215  *
216  * Remark:        Release all objects connected to the operation object.
217  *****************************************************************************/
218 void
release()219 NdbOperation::release()
220 {
221   NdbBlob* tBlob;
222   NdbBlob* tSaveBlob;
223 
224   /* In case we didn't execute... */
225   postExecuteRelease();
226 
227   tBlob = theBlobList;
228   while (tBlob != NULL)
229   {
230     tSaveBlob = tBlob;
231     tBlob = tBlob->theNext;
232     theNdb->releaseNdbBlob(tSaveBlob);
233   }
234   theBlobList = NULL;
235   theReceiver.release();
236 
237   theLockHandle = NULL;
238   m_blob_lock_upgraded = false;
239 }
240 
241 void
postExecuteRelease()242 NdbOperation::postExecuteRelease()
243 {
244   NdbApiSignal* tSignal;
245   NdbApiSignal* tSaveSignal;
246   NdbBranch*	tBranch;
247   NdbBranch*	tSaveBranch;
248   NdbLabel*	tLabel;
249   NdbLabel*	tSaveLabel;
250   NdbCall*	tCall;
251   NdbCall*	tSaveCall;
252   NdbSubroutine* tSubroutine;
253   NdbSubroutine* tSaveSubroutine;
254 
255   tSignal = theRequest; /* TCKEYREQ/TCINDXREQ/SCANTABREQ */
256   while (tSignal != NULL)
257   {
258     tSaveSignal = tSignal;
259     tSignal = tSignal->next();
260     theNdb->releaseSignal(tSaveSignal);
261   }
262   theRequest = NULL;
263   theLastKEYINFO = NULL;
264 #ifdef TODO
265   /**
266    * Compute correct #cnt signals between theFirstATTRINFO/theCurrentATTRINFO
267    */
268   if (theFirstATTRINFO)
269   {
270     theNdb->releaseSignals(1, theFirstATTRINFO, theCurrentATTRINFO);
271   }
272 #else
273   tSignal = theFirstATTRINFO;
274   while (tSignal != NULL)
275   {
276     tSaveSignal = tSignal;
277     tSignal = tSignal->next();
278     theNdb->releaseSignal(tSaveSignal);
279   }
280 #endif
281   theFirstATTRINFO = NULL;
282   theCurrentATTRINFO = NULL;
283 
284   if (theInterpretIndicator == 1)
285   {
286     tBranch = theFirstBranch;
287     while (tBranch != NULL)
288     {
289       tSaveBranch = tBranch;
290       tBranch = tBranch->theNext;
291       theNdb->releaseNdbBranch(tSaveBranch);
292     }
293     tLabel = theFirstLabel;
294     while (tLabel != NULL)
295     {
296       tSaveLabel = tLabel;
297       tLabel = tLabel->theNext;
298       theNdb->releaseNdbLabel(tSaveLabel);
299     }
300     tCall = theFirstCall;
301     while (tCall != NULL)
302     {
303       tSaveCall = tCall;
304       tCall = tCall->theNext;
305       theNdb->releaseNdbCall(tSaveCall);
306     }
307     tSubroutine = theFirstSubroutine;
308     while (tSubroutine != NULL)
309     {
310       tSaveSubroutine = tSubroutine;
311       tSubroutine = tSubroutine->theNext;
312       theNdb->releaseNdbSubroutine(tSaveSubroutine);
313     }
314   }
315 }
316 
317 NdbRecAttr*
getValue(const char * anAttrName,char * aValue)318 NdbOperation::getValue(const char* anAttrName, char* aValue)
319 {
320   return getValue_impl(m_currentTable->getColumn(anAttrName), aValue);
321 }
322 
323 NdbRecAttr*
getValue(Uint32 anAttrId,char * aValue)324 NdbOperation::getValue(Uint32 anAttrId, char* aValue)
325 {
326   return getValue_impl(m_currentTable->getColumn(anAttrId), aValue);
327 }
328 
329 NdbRecAttr*
getValue(const NdbDictionary::Column * col,char * aValue)330 NdbOperation::getValue(const NdbDictionary::Column* col, char* aValue)
331 {
332   if (theStatus != UseNdbRecord)
333     return getValue_impl(&NdbColumnImpl::getImpl(*col), aValue);
334 
335   setErrorCodeAbort(4508);
336   /* GetValue not allowed for NdbRecord defined operation */
337   return NULL;
338 }
339 
340 int
equal(const char * anAttrName,const char * aValuePassed)341 NdbOperation::equal(const char* anAttrName, const char* aValuePassed)
342 {
343   const NdbColumnImpl* col = m_accessTable->getColumn(anAttrName);
344   if (col == NULL)
345   {
346     setErrorCode(4004);
347     return -1;
348   }
349   else
350   {
351     return equal_impl(col, aValuePassed);
352   }
353 }
354 
355 int
equal(Uint32 anAttrId,const char * aValuePassed)356 NdbOperation::equal(Uint32 anAttrId, const char* aValuePassed)
357 {
358     const NdbColumnImpl* col = m_accessTable->getColumn(anAttrId);
359   if (col == NULL)
360   {
361     setErrorCode(4004);
362     return -1;
363   }
364   else
365   {
366     return equal_impl(col, aValuePassed);
367   }
368 }
369 
370 int
setValue(const char * anAttrName,const char * aValuePassed)371 NdbOperation::setValue(const char* anAttrName, const char* aValuePassed)
372 {
373   const NdbColumnImpl* col = m_currentTable->getColumn(anAttrName);
374   if (col == NULL)
375   {
376     setErrorCode(4004);
377     return -1;
378   }
379   else
380   {
381     return setValue(col, aValuePassed);
382   }
383 }
384 
385 
386 int
setValue(Uint32 anAttrId,const char * aValuePassed)387 NdbOperation::setValue(Uint32 anAttrId, const char* aValuePassed)
388 {
389   const NdbColumnImpl* col = m_currentTable->getColumn(anAttrId);
390   if (col == NULL)
391   {
392     setErrorCode(4004);
393     return -1;
394   }
395   else
396   {
397     return setValue(col, aValuePassed);
398   }
399 }
400 
401 NdbBlob*
getBlobHandle(const char * anAttrName)402 NdbOperation::getBlobHandle(const char* anAttrName)
403 {
404   // semantics differs from overloaded 'getBlobHandle(const char*) const'
405   // by delegating to the non-const variant of internal getBlobHandle(...),
406   // which may create a new BlobHandle
407   const NdbColumnImpl* col = m_currentTable->getColumn(anAttrName);
408   if (col == NULL)
409   {
410     setErrorCode(4004);
411     return NULL;
412   }
413   else
414   {
415     return getBlobHandle(theNdbCon, col);
416   }
417 }
418 
419 NdbBlob*
getBlobHandle(Uint32 anAttrId)420 NdbOperation::getBlobHandle(Uint32 anAttrId)
421 {
422   // semantics differs from overloaded 'getBlobHandle(Uint32) const'
423   // by delegating to the non-const variant of internal getBlobHandle(...),
424   // which may create a new BlobHandle
425   const NdbColumnImpl* col = m_currentTable->getColumn(anAttrId);
426   if (col == NULL)
427   {
428     setErrorCode(4004);
429     return NULL;
430   }
431   else
432   {
433     return getBlobHandle(theNdbCon, col);
434   }
435 }
436 
437 NdbBlob*
getBlobHandle(const char * anAttrName) const438 NdbOperation::getBlobHandle(const char* anAttrName) const
439 {
440   const NdbColumnImpl* col = m_currentTable->getColumn(anAttrName);
441   if (col == NULL)
442   {
443     setErrorCode(4004);
444     return NULL;
445   }
446   else
447   {
448     return getBlobHandle(theNdbCon, col);
449   }
450 }
451 
452 NdbBlob*
getBlobHandle(Uint32 anAttrId) const453 NdbOperation::getBlobHandle(Uint32 anAttrId) const
454 {
455   const NdbColumnImpl* col = m_currentTable->getColumn(anAttrId);
456   if (col == NULL)
457   {
458     setErrorCode(4004);
459     return NULL;
460   }
461   else
462   {
463     return getBlobHandle(theNdbCon, col);
464   }
465 }
466 
467 
468 int
incValue(const char * anAttrName,Uint32 aValue)469 NdbOperation::incValue(const char* anAttrName, Uint32 aValue)
470 {
471   return incValue(m_currentTable->getColumn(anAttrName), aValue);
472 }
473 
474 int
incValue(const char * anAttrName,Uint64 aValue)475 NdbOperation::incValue(const char* anAttrName, Uint64 aValue)
476 {
477   return incValue(m_currentTable->getColumn(anAttrName), aValue);
478 }
479 
480 int
incValue(Uint32 anAttrId,Uint32 aValue)481 NdbOperation::incValue(Uint32 anAttrId, Uint32 aValue)
482 {
483   return incValue(m_currentTable->getColumn(anAttrId), aValue);
484 }
485 
486 int
incValue(Uint32 anAttrId,Uint64 aValue)487 NdbOperation::incValue(Uint32 anAttrId, Uint64 aValue)
488 {
489   return incValue(m_currentTable->getColumn(anAttrId), aValue);
490 }
491 
492 int
subValue(const char * anAttrName,Uint32 aValue)493 NdbOperation::subValue( const char* anAttrName, Uint32 aValue)
494 {
495   return subValue(m_currentTable->getColumn(anAttrName), aValue);
496 }
497 
498 int
subValue(const char * anAttrName,Uint64 aValue)499 NdbOperation::subValue( const char* anAttrName, Uint64 aValue)
500 {
501   return subValue(m_currentTable->getColumn(anAttrName), aValue);
502 }
503 
504 int
subValue(Uint32 anAttrId,Uint32 aValue)505 NdbOperation::subValue(Uint32 anAttrId, Uint32 aValue)
506 {
507   return subValue(m_currentTable->getColumn(anAttrId), aValue);
508 }
509 
510 int
subValue(Uint32 anAttrId,Uint64 aValue)511 NdbOperation::subValue(Uint32 anAttrId, Uint64 aValue)
512 {
513   return subValue(m_currentTable->getColumn(anAttrId), aValue);
514 }
515 
516 int
read_attr(const char * anAttrName,Uint32 RegDest)517 NdbOperation::read_attr(const char* anAttrName, Uint32 RegDest)
518 {
519   return read_attr(m_currentTable->getColumn(anAttrName), RegDest);
520 }
521 
522 int
read_attr(Uint32 anAttrId,Uint32 RegDest)523 NdbOperation::read_attr(Uint32 anAttrId, Uint32 RegDest)
524 {
525   return read_attr(m_currentTable->getColumn(anAttrId), RegDest);
526 }
527 
528 int
write_attr(const char * anAttrName,Uint32 RegDest)529 NdbOperation::write_attr(const char* anAttrName, Uint32 RegDest)
530 {
531   return write_attr(m_currentTable->getColumn(anAttrName), RegDest);
532 }
533 
534 int
write_attr(Uint32 anAttrId,Uint32 RegDest)535 NdbOperation::write_attr(Uint32 anAttrId, Uint32 RegDest)
536 {
537   return write_attr(m_currentTable->getColumn(anAttrId), RegDest);
538 }
539 
540 const char*
getTableName() const541 NdbOperation::getTableName() const
542 {
543   return m_currentTable->m_externalName.c_str();
544 }
545 
546 const NdbDictionary::Table*
getTable() const547 NdbOperation::getTable() const
548 {
549   return m_currentTable;
550 }
551 
552 NdbTransaction*
getNdbTransaction() const553 NdbOperation::getNdbTransaction() const
554 {
555   return theNdbCon;
556 }
557 
558 int
getLockHandleImpl()559 NdbOperation::getLockHandleImpl()
560 {
561   assert(! theLockHandle);
562 
563   if (unlikely(theNdb->getMinDbNodeVersion() <
564                NDBD_UNLOCK_OP_SUPPORTED))
565   {
566     /* Function not implemented yet */
567     return 4003;
568   }
569 
570   if (likely(((theOperationType == ReadRequest) ||
571               (theOperationType == ReadExclusive)) &&
572              (m_type == PrimaryKeyAccess) &&
573              ((theLockMode == LM_Read) |
574               (theLockMode == LM_Exclusive))))
575   {
576     theLockHandle = theNdbCon->getLockHandle();
577     if (!theLockHandle)
578     {
579       return 4000;
580     }
581 
582     /* Now operation has a LockHandle - it'll be
583      * filled-in when the operation is prepared prior
584      * to execution.
585      */
586     assert(theLockHandle->m_state == NdbLockHandle::ALLOCATED);
587     assert(! theLockHandle->isLockRefValid());
588 
589     return 0;
590   }
591   else
592   {
593     /* getLockHandle only supported for primary key read with a lock */
594     return 4549;
595   }
596 }
597 
598 const NdbLockHandle*
getLockHandle()599 NdbOperation::getLockHandle()
600 {
601   if (likely (! m_blob_lock_upgraded))
602   {
603     if (theLockHandle == NULL)
604     {
605       int rc = getLockHandleImpl();
606 
607       if (likely(rc == 0))
608         return theLockHandle;
609       else
610       {
611         setErrorCode(rc);
612         return NULL;
613       }
614     }
615     /* Return existing LockHandle */
616     return theLockHandle;
617   }
618   else
619   {
620     /* Not allowed to call getLockHandle() on a Blob-upgraded
621      * read
622      */
623     setErrorCode(4549);
624     return NULL;
625   }
626 }
627 
628 const NdbLockHandle*
getLockHandle() const629 NdbOperation::getLockHandle() const
630 {
631   /* NdbRecord / handle already exists variant */
632   return theLockHandle;
633 }
634