1 /*
2    Copyright (c) 2003, 2019, 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, 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 
26 /******************************************************************************
27 Name:          NdbOperationSearch.C
28 Include:
29 Link:
30 Author:        UABMNST Mona Natterkvist UAB/B/SD
31 Date:          970829
32 Version:       0.1
33 Description:   Interface between TIS and NDB
34 Documentation:
35 Adjust:  971022  UABMNST   First version.
36 	 971206  UABRONM
37  *****************************************************************************/
38 #include "API.hpp"
39 
40 
41 #include <AttributeHeader.hpp>
42 #include <signaldata/TcKeyReq.hpp>
43 #include <signaldata/KeyInfo.hpp>
44 
45 /******************************************************************************
46 CondIdType equal(const char* anAttrName, char* aValue, Uint32 aVarKeylen);
47 
48 Return Value    Return 0 : Equal was successful.
49                 Return -1: In all other case.
50 Parameters:     anAttrName : Attribute name for search condition..
51                 aValue : Referense to the search value.
52 		aVariableKeylen : The length of key in bytes
53 Remark:         Defines search condition with equality anAttrName.
54 ******************************************************************************/
55 int
equal_impl(const NdbColumnImpl * tAttrInfo,const char * aValuePassed)56 NdbOperation::equal_impl(const NdbColumnImpl* tAttrInfo,
57                          const char* aValuePassed)
58 {
59   DBUG_ENTER("NdbOperation::equal_impl");
60   DBUG_PRINT("enter", ("col: %s  op: %d  val: 0x%lx",
61                        (tAttrInfo == NULL) ? "NULL" :
62                        tAttrInfo->m_name.c_str(),
63                        theOperationType,
64                        (long) aValuePassed));
65 
66   const char* aValue = aValuePassed;
67   const Uint32 MaxKeyLenInLongWords= (NDB_MAX_KEY_SIZE + 7)/8;
68   Uint64 tempData[ MaxKeyLenInLongWords ];
69 
70   if ((theStatus == OperationDefined) &&
71       (aValue != NULL) &&
72       (tAttrInfo != NULL )) {
73 /******************************************************************************
74  *	Start by checking that the attribute is a tuple key.
75  *      This value is also the word order in the tuple key of this
76  *      tuple key attribute.
77  *      Then check that this tuple key has not already been defined.
78  *      Finally check if all tuple key attributes have been defined. If
79  *	this is true then set Operation state to tuple key defined.
80  *****************************************************************************/
81 
82     /*
83      * For each call theTupleKeyDefined stores 3 items:
84      *
85      * [0] = m_column_no (external column id)
86      * [1] = 1-based index of first word of accumulating keyinfo
87      * [2] = number of words of keyinfo
88      *
89      * This is used to re-order keyinfo if not in m_attrId order.
90      *
91      * Note: No point to "clean up" this code.  The upcoming
92      * record-based ndb api makes it obsolete.
93      */
94 
95     Uint32 tAttrId = tAttrInfo->m_column_no; // not m_attrId;
96     Uint32 i = 0;
97     if (tAttrInfo->m_pk) {
98       Uint32 tKeyDefined = theTupleKeyDefined[0][2];
99       Uint32 tKeyAttrId = theTupleKeyDefined[0][0];
100       do {
101 	if (tKeyDefined == false) {
102 	  goto keyEntryFound;
103 	} else {
104 	  if (tKeyAttrId != tAttrId) {
105 	    /******************************************************************
106 	     * We read the key defined variable in advance.
107 	     * It could potentially read outside its area when
108 	     * i = MAXNROFTUPLEKEY - 1,
109 	     * it is not a problem as long as the variable
110 	     * theTupleKeyDefined is defined
111 	     * in the middle of the object.
112 	     * Reading wrong data and not using it causes no problems.
113 	     *****************************************************************/
114 	    i++;
115 	    tKeyAttrId = theTupleKeyDefined[i][0];
116 	    tKeyDefined = theTupleKeyDefined[i][2];
117 	    continue;
118 	  } else {
119 	    goto equal_error2;
120 	  }//if
121 	}//if
122       } while (i < NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY);
123       goto equal_error2;
124     } else {
125       goto equal_error1;
126     }
127     /*************************************************************************
128      *	Now it is time to retrieve the tuple key data from the pointer supplied
129      *      by the application.
130      *      We have to retrieve the size of the attribute in words and bits.
131      *************************************************************************/
132   keyEntryFound:
133     Uint32 sizeInBytes;
134     if (! tAttrInfo->get_var_length(aValue, sizeInBytes)) {
135       setErrorCodeAbort(4209);
136       DBUG_RETURN(-1);
137     }
138 
139     Uint32 tKeyInfoPosition =
140       i == 0 ? 1 : theTupleKeyDefined[i-1][1] + theTupleKeyDefined[i-1][2];
141     theTupleKeyDefined[i][0] = tAttrId;
142     theTupleKeyDefined[i][1] = tKeyInfoPosition;
143     theTupleKeyDefined[i][2] = (sizeInBytes + 3) / 4;
144 
145     {
146       /************************************************************************
147        * Check if the pointer of the value passed is aligned on a 4 byte
148        * boundary. If so only assign the pointer to the internal variable
149        * aValue. If it is not aligned then we start by copying the value to
150        * tempData and use this as aValue instead.
151        ***********************************************************************/
152       const bool tDistrKey = tAttrInfo->m_distributionKey;
153       const int attributeSize = sizeInBytes;
154       const int slack = sizeInBytes & 3;
155       const int align = Uint32(UintPtr(aValue)) & 7;
156 
157       if (((align & 3) != 0) || (slack != 0) || (tDistrKey && (align != 0)))
158       {
159 	((Uint32*)tempData)[attributeSize >> 2] = 0;
160 	memcpy(&tempData[0], aValue, attributeSize);
161 	aValue = (char*)&tempData[0];
162       }//if
163     }
164 
165     Uint32 totalSizeInWords = (sizeInBytes + 3)/4; // Inc. bits in last word
166     theTupKeyLen += totalSizeInWords;
167 #if 0
168     else {
169       /************************************************************************
170        * The attribute is a variable array. We need to use the length parameter
171        * to know the size of this attribute in the key information and
172        * variable area. A key is however not allowed to be larger than 4
173        * kBytes and this is checked for variable array attributes
174        * used as keys.
175        ************************************************************************/
176       Uint32 tMaxVariableKeyLenInWord = (MAXTUPLEKEYLENOFATTERIBUTEINWORD -
177 					 tKeyInfoPosition);
178       tAttrSizeInBits = aVariableKeyLen << 3;
179       tAttrSizeInWords = tAttrSizeInBits >> 5;
180       tAttrBitsInLastWord = tAttrSizeInBits - (tAttrSizeInWords << 5);
181       tAttrLenInWords = ((tAttrSizeInBits + 31) >> 5);
182       if (tAttrLenInWords > tMaxVariableKeyLenInWord) {
183 	setErrorCodeAbort(4207);
184 	return -1;
185       }//if
186       theTupKeyLen = theTupKeyLen + tAttrLenInWords;
187     }//if
188 #endif
189 
190     /**************************************************************************
191      *	If the operation is an insert request and the attribute is stored then
192      *      we also set the value in the stored part through putting the
193      *      information in the ATTRINFO signals.
194      *************************************************************************/
195     OperationType tOpType = theOperationType;
196     if ((tOpType == InsertRequest) ||
197 	(tOpType == WriteRequest)) {
198       Uint32 ahValue;
199 
200       if(m_accessTable == m_currentTable) {
201 	AttributeHeader::init(&ahValue, tAttrInfo->m_attrId, sizeInBytes);
202       } else {
203 	assert(tOpType == WriteRequest && m_accessTable->m_index);
204         // use attrId of primary table column
205 	int column_no_current_table =
206 	  m_accessTable->m_index->m_columns[tAttrId]->m_keyInfoPos;
207         int attr_id_current_table =
208           m_currentTable->m_columns[column_no_current_table]->m_attrId;
209 	AttributeHeader::init(&ahValue, attr_id_current_table, sizeInBytes);
210       }
211 
212       insertATTRINFO( ahValue );
213       insertATTRINFOloop((Uint32*)aValue, totalSizeInWords);
214     }//if
215 
216     /**************************************************************************
217      *	Store the Key information in the TCKEYREQ and KEYINFO signals.
218      *************************************************************************/
219     if (insertKEYINFO(aValue, tKeyInfoPosition, totalSizeInWords) != -1) {
220       /************************************************************************
221        * Add one to number of tuple key attributes defined.
222        * If all have been defined then set the operation state to indicate
223        * that tuple key is defined.
224        * Thereby no more search conditions are allowed in this version.
225        ***********************************************************************/
226       Uint32 tNoKeysDef = theNoOfTupKeyLeft - 1;
227       Uint32 tErrorLine = theErrorLine;
228       unsigned char tInterpretInd = theInterpretIndicator;
229       theNoOfTupKeyLeft = tNoKeysDef;
230       tErrorLine++;
231       theErrorLine = tErrorLine;
232 
233       if (tNoKeysDef == 0) {
234 
235         // re-order keyinfo if not entered in order
236         if (m_accessTable->m_noOfKeys != 1) {
237           for (Uint32 i = 0; i < m_accessTable->m_noOfKeys; i++) {
238             Uint32 k = theTupleKeyDefined[i][0]; // column_no
239             if (m_accessTable->m_columns[k]->m_keyInfoPos != i) {
240               DBUG_PRINT("info", ("key disorder at %d", i));
241               reorderKEYINFO();
242               break;
243             }
244           }
245         }
246 
247 	if (tOpType == UpdateRequest) {
248 	  if (tInterpretInd == 1) {
249 	    theStatus = GetValue;
250 	  } else {
251 	    theStatus = SetValue;
252 	  }//if
253 	  DBUG_RETURN(0);
254 	} else if ((tOpType == ReadRequest) || (tOpType == DeleteRequest) ||
255 		   (tOpType == ReadExclusive)) {
256 	  theStatus = GetValue;
257           // create blob handles automatically
258           if (tOpType == DeleteRequest && m_currentTable->m_noOfBlobs != 0) {
259             for (unsigned i = 0; i < m_currentTable->m_columns.size(); i++) {
260               NdbColumnImpl* c = m_currentTable->m_columns[i];
261               assert(c != 0);
262               if (c->getBlobType()) {
263                 if (getBlobHandle(theNdbCon, c) == NULL)
264                   DBUG_RETURN(-1);
265               }
266             }
267           }
268 	  DBUG_RETURN(0);
269 	} else if ((tOpType == InsertRequest) || (tOpType == WriteRequest)) {
270 	  theStatus = SetValue;
271 	  DBUG_RETURN(0);
272 	} else {
273 	  setErrorCodeAbort(4005);
274 	  DBUG_RETURN(-1);
275 	}//if
276 	DBUG_RETURN(0);
277       }//if
278     } else {
279       DBUG_RETURN(-1);
280     }//if
281     DBUG_RETURN(0);
282   }
283 
284   if (aValue == NULL) {
285     // NULL value in primary key
286     setErrorCodeAbort(4505);
287     DBUG_RETURN(-1);
288   }//if
289 
290   if ( tAttrInfo == NULL ) {
291     // Attribute name not found in table
292     setErrorCodeAbort(4004);
293     DBUG_RETURN(-1);
294   }//if
295 
296   if (theStatus == GetValue || theStatus == SetValue){
297     // All pk's defined
298     setErrorCodeAbort(4225);
299     DBUG_RETURN(-1);
300   }//if
301 
302   ndbout_c("theStatus: %d", theStatus);
303 
304   // If we come here, set a general errorcode
305   // and exit
306   setErrorCodeAbort(4200);
307   DBUG_RETURN(-1);
308 
309  equal_error1:
310   setErrorCodeAbort(4205);
311   DBUG_RETURN(-1);
312 
313  equal_error2:
314   setErrorCodeAbort(4206);
315   DBUG_RETURN(-1);
316 }
317 
318 /******************************************************************************
319  * int insertKEYINFO(const char* aValue, aStartPosition,
320  *                   anAttrSizeInWords, Uint32 anAttrBitsInLastWord);
321  *
322  * Return Value:   Return 0 : insertKEYINFO was succesful.
323  *                 Return -1: In all other case.
324  * Parameters:     aValue: the data to insert into KEYINFO.
325  *    		   aStartPosition : Start position for Tuplekey in
326  *                                  KEYINFO (TCKEYREQ).
327  *                 aKeyLenInByte : Length of tuplekey or part of tuplekey
328  *                 anAttrBitsInLastWord : Nr of bits in last word.
329  * Remark:         Puts the the data into either TCKEYREQ signal
330  *                 or KEYINFO signal.
331  *****************************************************************************/
332 int
insertKEYINFO(const char * aValue,Uint32 aStartPosition,Uint32 anAttrSizeInWords)333 NdbOperation::insertKEYINFO(const char* aValue,
334 			    Uint32 aStartPosition,
335 			    Uint32 anAttrSizeInWords)
336 {
337   NdbApiSignal* tSignal;
338   NdbApiSignal* tCurrentKEYINFO;
339   //register NdbApiSignal* tTCREQ = theTCREQ;
340   Uint32 tAttrPos;
341   Uint32 tPosition;
342   Uint32 tEndPos;
343   Uint32 tPos;
344   Uint32 signalCounter;
345 
346 /*****************************************************************************
347  *	Calculate the end position of the attribute in the key information.  *
348  *	Since the first attribute starts at position one we need to subtract *
349  *	one to get the correct end position.				     *
350  *	We must also remember the last word with only partial information.   *
351  *****************************************************************************/
352   tEndPos = aStartPosition + anAttrSizeInWords - 1;
353 
354   if ((tEndPos < 9)) {
355     Uint32 tkeyData = *(Uint32*)aValue;
356     //TcKeyReq* tcKeyReq = CAST_PTR(TcKeyReq, tTCREQ->getDataPtrSend());
357     Uint32* tDataPtr = (Uint32*)aValue;
358     tAttrPos = 1;
359     Uint32* tkeyDataPtr = theKEYINFOptr + aStartPosition - 1;
360     // (Uint32*)&tcKeyReq->keyInfo[aStartPosition - 1];
361     do {
362       tDataPtr++;
363       *tkeyDataPtr = tkeyData;
364       if (tAttrPos < anAttrSizeInWords) {
365         ;
366       } else {
367         return 0;
368       }//if
369       tkeyData = *tDataPtr;
370       tkeyDataPtr++;
371       tAttrPos++;
372     } while (1);
373     return 0;
374   }//if
375 /*****************************************************************************
376  *	Allocate all the KEYINFO signals needed for this key before starting *
377  *	to fill the signals with data. This simplifies error handling and    *
378  *      avoids duplication of code.					     *
379  *****************************************************************************/
380   tAttrPos = 0;
381   signalCounter = 1;
382   while(tEndPos > theTotalNrOfKeyWordInSignal)
383   {
384     tSignal = theNdb->getSignal();
385     if (tSignal == NULL)
386     {
387       setErrorCodeAbort(4000);
388       return -1;
389     }
390     if (tSignal->setSignal(m_keyInfoGSN, refToBlock(theNdbCon->m_tcRef)) == -1)
391     {
392       setErrorCodeAbort(4001);
393       return -1;
394     }
395     tSignal->setLength(KeyInfo::MaxSignalLength);
396     if (theTCREQ->next() != NULL)
397        theLastKEYINFO->next(tSignal);
398     else
399       theTCREQ->next(tSignal);
400 
401     theLastKEYINFO = tSignal;
402     theLastKEYINFO->next(NULL);
403     theTotalNrOfKeyWordInSignal += 20;
404   }
405 
406 /*****************************************************************************
407  *	Change to variable tPosition for more appropriate naming of rest of  *
408  *	the code. We must set up current KEYINFO already here if the last    *
409  *	word is a word which is set at LastWordLabel and at the same time    *
410  *	this is the first word in a KEYINFO signal.			     *
411  *****************************************************************************/
412   tPosition = aStartPosition;
413   tCurrentKEYINFO = theTCREQ->next();
414 
415 /*****************************************************************************
416  *	Start by filling up Key information in the 8 words allocated in the  *
417  *	TC[KEY/INDX]REQ signal.						     *
418  *****************************************************************************/
419   while (tPosition < 9)
420   {
421     theKEYINFOptr[tPosition-1] = * (Uint32*)(aValue + (tAttrPos << 2));
422     tAttrPos++;
423     if (anAttrSizeInWords == tAttrPos)
424       goto LastWordLabel;
425     tPosition++;
426   }
427 
428 /*****************************************************************************
429  *	We must set up the start position of the writing of Key information  *
430  *	before we start the writing of KEYINFO signals. If the start is not  *
431  *	the first word of the first KEYINFO signals then we must step forward*
432  *	to the proper KEYINFO signal and set the signalCounter properly.     *
433  *	signalCounter is set to the actual position in the signal ( = 4 for  *
434  *	first key word in KEYINFO signal.				     *
435  *****************************************************************************/
436   tPos = 8;
437   while ((tPosition - tPos) > 20)
438   {
439     tCurrentKEYINFO = tCurrentKEYINFO->next();
440     tPos += 20;
441   }
442   signalCounter = tPosition - tPos + 3;
443 
444 /*****************************************************************************
445  *	The loop that actually fills in the Key information into the KEYINFO *
446  *	signals. Can be optimised by writing larger chunks than 4 bytes at a *
447  *	time.								     *
448  *****************************************************************************/
449   do
450   {
451     if (signalCounter > 23)
452     {
453       tCurrentKEYINFO = tCurrentKEYINFO->next();
454       signalCounter = 4;
455     }
456     tCurrentKEYINFO->setData(*(Uint32*)(aValue + (tAttrPos << 2)),
457 			     signalCounter);
458     tAttrPos++;
459     if (anAttrSizeInWords == tAttrPos)
460       goto LastWordLabel;
461     tPosition++;
462     signalCounter++;
463   } while (1);
464 
465 LastWordLabel:
466   return 0;
467 }
468 
469 void
reorderKEYINFO()470 NdbOperation::reorderKEYINFO()
471 {
472   Uint32 data[ NDB_MAX_KEYSIZE_IN_WORDS ];
473   Uint32 size = NDB_MAX_KEYSIZE_IN_WORDS;
474   int rc = getKeyFromTCREQ(data, size);
475   (void)rc;
476   assert(rc == 0);
477   Uint32 pos = 1;
478   Uint32 k;
479   for (k = 0; k < m_accessTable->m_noOfKeys; k++) {
480     Uint32 i;
481     for (i = 0; i < m_accessTable->m_columns.size(); i++) {
482       NdbColumnImpl* col = m_accessTable->m_columns[i];
483       if (col->m_pk && col->m_keyInfoPos == k) {
484         Uint32 j;
485         for (j = 0; j < m_accessTable->m_noOfKeys; j++) {
486           if (theTupleKeyDefined[j][0] == i) {
487             Uint32 off = theTupleKeyDefined[j][1] - 1;
488             Uint32 len = theTupleKeyDefined[j][2];
489             assert(off < NDB_MAX_KEYSIZE_IN_WORDS &&
490                    off + len <= NDB_MAX_KEYSIZE_IN_WORDS);
491             int ret = insertKEYINFO((char*)&data[off], pos, len);
492             (void)ret;
493             assert(ret == 0);
494             pos += len;
495             break;
496           }
497         }
498         assert(j < m_accessTable->m_columns.size());
499         break;
500       }
501     }
502     assert(i < m_accessTable->m_columns.size());
503   }
504 }
505 
506 int
getKeyFromTCREQ(Uint32 * data,Uint32 & size)507 NdbOperation::getKeyFromTCREQ(Uint32* data, Uint32 & size)
508 {
509   /* Check that we can correctly return a valid key */
510   if ((size < theTupKeyLen) || (theTupKeyLen == 0))
511     return -1;
512 
513   size = theTupKeyLen;
514   unsigned pos = 0;
515   while (pos < 8 && pos < size) {
516     data[pos] = theKEYINFOptr[pos];
517     pos++;
518   }
519   NdbApiSignal* tSignal = theTCREQ->next();
520   unsigned n = 0;
521   while (pos < size) {
522     if (n == KeyInfo::DataLength) {
523       tSignal = tSignal->next();
524       n = 0;
525     }
526     data[pos++] =
527       tSignal->getDataPtrSend()[KeyInfo::HeaderLength + n++];
528   }
529   return 0;
530 }
531 
532 void
setPartitionId(Uint32 value)533 NdbOperation::setPartitionId(Uint32 value)
534 {
535   if (theStatus == UseNdbRecord)
536   {
537     /* Method not allowed for NdbRecord, use OperationOptions or
538        ScanOptions structure instead */
539     setErrorCodeAbort(4515);
540     return; // TODO : Consider adding int rc for error
541   }
542 
543   /* We only allow setPartitionId() for :
544    *   PrimaryKey ops on a UserDefined partitioned table
545    *   Ordered index scans
546    *   Table scans
547    *
548    * It is not allowed on :
549    *   Primary key access to Natively partitioned tables
550    *   Any unique key access
551    */
552   assert(((m_type == PrimaryKeyAccess) &&
553           (m_currentTable->getFragmentType() ==
554            NdbDictionary::Object::UserDefined)) ||
555          (m_type == OrderedIndexScan) ||
556          (m_type == TableScan));
557 
558   theDistributionKey = value;
559   theDistrKeyIndicator_ = 1;
560   DBUG_PRINT("info", ("NdbOperation::setPartitionId: %u",
561                        theDistributionKey));
562 }
563 
564 Uint32
getPartitionId() const565 NdbOperation::getPartitionId() const
566 {
567   DBUG_PRINT("info", ("NdbOperation::getPartitionId: %u ind=%d",
568                       theDistributionKey, theDistrKeyIndicator_));
569   return theDistributionKey;
570 }
571