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