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