MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HugoCalculator.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 "HugoCalculator.hpp"
20 #include <NDBT.hpp>
21 
22 static
23 Uint32
24 myRand(Uint64 * seed)
25 {
26  const Uint64 mul= 0x5deece66dull;
27  const Uint64 add= 0xb;
28  Uint64 loc_result = *seed * mul + add;
29 
30  * seed= loc_result;
31  return (Uint32)(loc_result >> 1);
32 }
33 
34 static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
35  "abcdefghijklmnopqrstuvwxyz"
36  "0123456789+/";
37 
38 /* *************************************************************
39  * HugoCalculator
40  *
41  * Comon class for the Hugo test suite, provides the functions
42  * that is used for calculating values to load in to table and
43  * also knows how to verify a row that's been read from db
44  *
45  * ************************************************************/
46 HugoCalculator::HugoCalculator(const NdbDictionary::Table& tab) : m_tab(tab) {
47 
48  // The "id" column of this table is found in the first integer column
49  int i;
50  for (i=0; i<m_tab.getNoOfColumns(); i++){
51  const NdbDictionary::Column* attr = m_tab.getColumn(i);
53  m_idCol = i;
54  break;
55  }
56  }
57 
58  // The "number of updates" column for this table is found in the last column
59  for (i=m_tab.getNoOfColumns()-1; i>=0; i--){
60  const NdbDictionary::Column* attr = m_tab.getColumn(i);
61  if (attr->getType() == NdbDictionary::Column::Unsigned &&
62  !attr->getPrimaryKey()){
63  m_updatesCol = i;
64  break;
65  }
66  }
67 #if 0
68  ndbout << "idCol = " << m_idCol << endl;
69  ndbout << "updatesCol = " << m_updatesCol << endl;
70 #endif
71  // Check that idCol is not conflicting with updatesCol
72  assert(m_idCol != m_updatesCol && m_idCol != -1 && m_updatesCol != -1);
73 }
74 
75 Int32
76 HugoCalculator::calcValue(int record,
77  int attrib,
78  int updates) const {
79 
80  Int32 i;
81  Uint32 j;
82  calcValue(record, attrib, updates, (char*)&i, sizeof(i), &j);
83 
84  return i;
85 }
86 #if 0
87 HugoCalculator::U_Int32 calcValue(int record, int attrib, int updates) const;
88 HugoCalculator::U_Int64 calcValue(int record, int attrib, int updates) const;
89 HugoCalculator::Int64 calcValue(int record, int attrib, int updates) const;
90 HugoCalculator::float calcValue(int record, int attrib, int updates) const;
91 HugoCalculator::double calcValue(int record, int attrib, int updates) const;
92 #endif
93 
94 static
95 Uint32
96 calc_len(Uint32 rvalue, int maxlen)
97 {
98  Uint32 minlen = 25;
99 
100  if ((rvalue >> 16) < 4096)
101  minlen = 15;
102  else if ((rvalue >> 16) < 8192)
103  minlen = 25;
104  else if ((rvalue >> 16) < 16384)
105  minlen = 35;
106  else
107  minlen = 64;
108 
109  if ((Uint32)maxlen <= minlen)
110  return maxlen;
111 
112  /* Ensure coverage of maxlen */
113  if ((rvalue & 64) == 0)
114  return maxlen;
115 
116  return minlen + (rvalue % (maxlen - minlen));
117 }
118 
119 static
120 Uint32
121 calc_blobLen(Uint32 rvalue, int maxlen)
122 {
123  int minlen = 1000;
124 
125  if ((rvalue >> 16) < 4096)
126  minlen = 5000;
127  else if ((rvalue >> 16) < 8192)
128  minlen = 8000;
129  else if ((rvalue >> 16) < 16384)
130  minlen = 12000;
131  else
132  minlen = 16000;
133 
134  if (maxlen <= minlen)
135  return maxlen;
136 
137  return minlen + (rvalue % (maxlen - minlen));
138 }
139 
140 const char*
141 HugoCalculator::calcValue(int record,
142  int attrib,
143  int updates,
144  char* buf,
145  int len,
146  Uint32 *outlen) const {
147  Uint64 seed;
148  const NdbDictionary::Column* attr = m_tab.getColumn(attrib);
149  Uint32 val;
150  * outlen = len;
151  do
152  {
153  if (attrib == m_idCol)
154  {
155  val= record;
156  memcpy(buf, &val, 4);
157  return buf;
158  }
159 
160  // If this is the update column
161  if (attrib == m_updatesCol)
162  {
163  val= updates;
164  memcpy(buf, &val, 4);
165  return buf;
166  }
167 
168  if (attr->getPrimaryKey())
169  {
170  seed = record + attrib;
171  }
172  else
173  {
174  seed = record + attrib + updates;
175  }
176  } while (0);
177 
178  val = myRand(&seed);
179 
180  if(attr->getNullable() && (((val >> 16) & 255) > 220))
181  {
182  * outlen = 0;
183  return NULL;
184  }
185 
186  int pos= 0;
187  char* dst= buf;
188  switch(attr->getType()){
200  case NdbDictionary::Column::Olddecimalunsigned:
202  case NdbDictionary::Column::Decimalunsigned:
208  while (len > 4)
209  {
210  memcpy(buf+pos, &val, 4);
211  pos += 4;
212  len -= 4;
213  val= myRand(&seed);
214  }
215 
216  memcpy(buf+pos, &val, len);
217  if(attr->getType() == NdbDictionary::Column::Bit)
218  {
219  Uint32 bits= attr->getLength();
220  Uint32 tmp = bits >> 5;
221  Uint32 size = bits & 31;
222  Uint32 copy;
223  memcpy(&copy, ((Uint32*)buf)+tmp, 4);
224  copy &= ((1 << size) - 1);
225  memcpy(((Uint32*)buf)+tmp, &copy, 4);
226  }
227  break;
229  {
230  float x = (float)myRand(&seed);
231  memcpy(buf+pos, &x, 4);
232  pos += 4;
233  len -= 4;
234  }
235  break;
237  {
238  double x = (double)myRand(&seed);
239  memcpy(buf+pos, &x, 8);
240  pos += 8;
241  len -= 8;
242  }
243  break;
246  len = calc_len(myRand(&seed), len - 1);
247  assert(len < 256);
248  * outlen = len + 1;
249  * buf = len;
250  dst++;
251  goto write_char;
254  len = calc_len(myRand(&seed), len - 2);
255  assert(len < 65536);
256  * outlen = len + 2;
257  int2store(buf, len);
258  dst += 2;
259 write_char:
261  {
262  char* ptr= (char*)&val;
263  while(len >= 4)
264  {
265  len -= 4;
266  dst[pos++] = base64_table[ptr[0] & 0x3f];
267  dst[pos++] = base64_table[ptr[1] & 0x3f];
268  dst[pos++] = base64_table[ptr[2] & 0x3f];
269  dst[pos++] = base64_table[ptr[3] & 0x3f];
270  val= myRand(&seed);
271  }
272 
273  for(; len; len--, pos++)
274  dst[pos] = base64_table[ptr[len] & 0x3f];
275 
276  pos--;
277  break;
278  }
280  * outlen = calc_blobLen(myRand(&seed), len);
281  // Don't set any actual data...
282  break;
287  abort();
288  break;
289  }
290 
291  return buf;
292 }
293 
294 int
295 HugoCalculator::verifyRowValues(NDBT_ResultRow* const pRow) const{
296  int id, updates;
297 
298  id = pRow->attributeStore(m_idCol)->u_32_value();
299  updates = pRow->attributeStore(m_updatesCol)->u_32_value();
300  int result = 0;
301 
302  // Check the values of each column
303  for (int i = 0; i<m_tab.getNoOfColumns(); i++){
304  if (i != m_updatesCol && id != m_idCol) {
305  const NdbDictionary::Column* attr = m_tab.getColumn(i);
306  Uint32 len = attr->getSizeInBytes(), real_len;
307  char buf[NDB_MAX_TUPLE_SIZE];
308  const char* res = calcValue(id, i, updates, buf, len, &real_len);
309  if (res == NULL){
310  if (!pRow->attributeStore(i)->isNULL()){
311  g_err << "|- NULL ERROR: expected a NULL but the column was not null" << endl;
312  g_err << "|- The row: \"" << (*pRow) << "\"" << endl;
313  result = -1;
314  }
315  } else{
316  if (real_len != pRow->attributeStore(i)->get_size_in_bytes())
317  {
318  g_err << "|- Invalid data found in attribute " << i << ": \""
319  << "Length of expected=" << real_len << endl
320  << "Lenght of read="
321  << pRow->attributeStore(i)->get_size_in_bytes() << endl;
322  result= -1;
323  }
324  else if (memcmp(res, pRow->attributeStore(i)->aRef(), real_len) != 0)
325  {
326  g_err << "Column: " << attr->getName() << endl;
327  const char* buf2 = pRow->attributeStore(i)->aRef();
328  for (Uint32 j = 0; j < len; j++)
329  {
330  g_err << j << ":" << hex << (Uint32)(Uint8)buf[j] << "[" << hex << (Uint32)(Uint8)buf2[j] << "]";
331  if (buf[j] != buf2[j])
332  {
333  g_err << "==>Match failed!";
334  }
335  g_err << endl;
336  }
337  g_err << endl;
338  g_err << "|- Invalid data found in attribute " << i << ": \""
339  << pRow->attributeStore(i)->aRef()
340  << "\" != \"" << res << "\"" << endl
341  << "Length of expected=" << (unsigned)strlen(res) << endl
342  << "Lenght of read="
343  << pRow->attributeStore(i)->get_size_in_bytes() << endl;
344  g_err << "|- The row: \"" << (* pRow) << "\"" << endl;
345  result = -1;
346  }
347  }
348  }
349  }
350  return result;
351 }
352 
353 
354 int
355 HugoCalculator::verifyRecAttr(int record,
356  int updates,
357  const NdbRecAttr* recAttr)
358 {
359  const char* valPtr = NULL;
360  int attrib = recAttr->getColumn()->getAttrId();
361  Uint32 valLen = recAttr->get_size_in_bytes();
362  if (!recAttr->isNULL())
363  valPtr= (const char*) recAttr->aRef();
364 
365  return verifyColValue(record,
366  attrib,
367  updates,
368  valPtr,
369  valLen);
370 }
371 
372 int
373 HugoCalculator::verifyColValue(int record,
374  int attrib,
375  int updates,
376  const char* valPtr,
377  Uint32 valLen)
378 {
379  int result = 0;
380 
381  if (attrib == m_updatesCol)
382  {
383  int val= *((const int*) valPtr);
384  if (val != updates)
385  {
386  g_err << "|- Updates column (" << attrib << ")" << endl;
387  g_err << "|- Expected " << updates << " but found " << val << endl;
388  result = -1;
389  }
390  }
391  else if (attrib == m_idCol)
392  {
393  int val= *((const int*) valPtr);
394  if (val != record)
395  {
396  g_err << "|- Identity column (" << attrib << ")" << endl;
397  g_err << "|- Expected " << record << " but found " << val << endl;
398  result = -1;
399  }
400  }
401  else
402  {
403  /* 'Normal' data column */
404  const NdbDictionary::Column* attr = m_tab.getColumn(attrib);
405  Uint32 len = attr->getSizeInBytes(), real_len;
406  char buf[NDB_MAX_TUPLE_SIZE];
407  const char* res = calcValue(record, attrib, updates, buf, len, &real_len);
408  if (res == NULL){
409  if (valPtr != NULL){
410  g_err << "|- NULL ERROR: expected a NULL but the column was not null" << endl;
411  g_err << "|- Column length is " << valLen << " bytes" << endl;
412  g_err << "|- Column data follows :" << endl;
413  for (Uint32 j = 0; j < valLen; j ++)
414  {
415  g_err << j << ":" << hex << (Uint32)(Uint8)valPtr[j] << endl;
416  }
417  result = -1;
418  }
419  } else{
420  if (real_len != valLen)
421  {
422  g_err << "|- Invalid data found in attribute " << attrib << ": \""
423  << "Length of expected=" << real_len << endl
424  << "Length of passed="
425  << valLen << endl;
426  result= -1;
427  }
428  else if (memcmp(res, valPtr, real_len) != 0)
429  {
430  g_err << "|- Expected data mismatch on column "
431  << attr->getName() << " length " << real_len
432  << " bytes " << endl;
433  g_err << "|- Bytewise comparison follows :" << endl;
434  for (Uint32 j = 0; j < real_len; j++)
435  {
436  g_err << j << ":" << hex << (Uint32)(Uint8)buf[j] << "[" << hex << (Uint32)(Uint8)valPtr[j] << "]";
437  if (buf[j] != valPtr[j])
438  {
439  g_err << "==>Match failed!";
440  }
441  g_err << endl;
442  }
443  g_err << endl;
444  result = -1;
445  }
446  }
447  }
448 
449  return result;
450 }
451 
452 int
453 HugoCalculator::getIdValue(NDBT_ResultRow* const pRow) const {
454  return pRow->attributeStore(m_idCol)->u_32_value();
455 }
456 
457 int
458 HugoCalculator::getUpdatesValue(NDBT_ResultRow* const pRow) const {
459  return pRow->attributeStore(m_updatesCol)->u_32_value();
460 }
461 
462 int
463 HugoCalculator::equalForRow(Uint8 * pRow,
464  const NdbRecord* pRecord,
465  int rowId)
466 {
467  for(int attrId = 0; attrId < m_tab.getNoOfColumns(); attrId++)
468  {
469  const NdbDictionary::Column* attr = m_tab.getColumn(attrId);
470 
471  if (attr->getPrimaryKey() == true)
472  {
473  char buf[8000];
474  int len = attr->getSizeInBytes();
475  memset(buf, 0, sizeof(buf));
476  Uint32 real_len;
477  const char * value = calcValue(rowId, attrId, 0, buf,
478  len, &real_len);
479  assert(value != 0); // NULLable PK not supported...
480  Uint32 off = 0;
481  bool ret = NdbDictionary::getOffset(pRecord, attrId, off);
482  if (!ret)
483  abort();
484  memcpy(pRow + off, buf, real_len);
485  }
486  }
487  return NDBT_OK;
488 }
489 
490 int
491 HugoCalculator::setValues(Uint8 * pRow,
492  const NdbRecord* pRecord,
493  int rowId,
494  int updateVal)
495 {
496  int res = equalForRow(pRow, pRecord, rowId);
497  if (res != 0)
498  {
499  return res;
500  }
501 
502  for(int attrId = 0; attrId < m_tab.getNoOfColumns(); attrId++)
503  {
504  const NdbDictionary::Column* attr = m_tab.getColumn(attrId);
505 
506  if (attr->getPrimaryKey() == false)
507  {
508  char buf[8000];
509  int len = attr->getSizeInBytes();
510  memset(buf, 0, sizeof(buf));
511  Uint32 real_len;
512  const char * value = calcValue(rowId, attrId, updateVal, buf,
513  len, &real_len);
514  if (value != 0)
515  {
516  Uint32 off = 0;
517  bool ret = NdbDictionary::getOffset(pRecord, attrId, off);
518  if (!ret)
519  abort();
520  memcpy(pRow + off, buf, real_len);
521  if (attr->getNullable())
522  NdbDictionary::setNull(pRecord, (char*)pRow, attrId, false);
523  }
524  else
525  {
526  assert(attr->getNullable());
527  NdbDictionary::setNull(pRecord, (char*)pRow, attrId, true);
528  }
529  }
530  }
531 
532  return NDBT_OK;
533 }