/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "HugoCalculator.hpp" #include <NDBT.hpp> /* ************************************************************* * HugoCalculator * * Comon class for the Hugo test suite, provides the functions * that is used for calculating values to load in to table and * also knows how to verify a row that's been read from db * * ************************************************************/ HugoCalculator::HugoCalculator(const NdbDictionary::Table& tab) : m_tab(tab) { // The "id" column of this table is found in the first integer column int i; for (i=0; i<m_tab.getNoOfColumns(); i++){ const NdbDictionary::Column* attr = m_tab.getColumn(i); if (attr->getType() == NdbDictionary::Column::Unsigned){ m_idCol = i; break; } } // The "number of updates" column for this table is found in the last column for (i=m_tab.getNoOfColumns()-1; i>=0; i--){ const NdbDictionary::Column* attr = m_tab.getColumn(i); if (attr->getType() == NdbDictionary::Column::Unsigned){ m_updatesCol = i; break; } } #if 0 ndbout << "idCol = " << m_idCol << endl; ndbout << "updatesCol = " << m_updatesCol << endl; #endif // Check that idCol is not conflicting with updatesCol assert(m_idCol != m_updatesCol && m_idCol != -1 && m_updatesCol != -1); } Int32 HugoCalculator::calcValue(int record, int attrib, int updates) const { const NdbDictionary::Column* attr = m_tab.getColumn(attrib); // If this is the "id" column if (attrib == m_idCol) return record; // If this is the update column if (attrib == m_updatesCol) return updates; Int32 val; if (attr->getPrimaryKey()) val = record + attrib; else val = record + attrib + updates; return val; } #if 0 HugoCalculator::U_Int32 calcValue(int record, int attrib, int updates) const; HugoCalculator::U_Int64 calcValue(int record, int attrib, int updates) const; HugoCalculator::Int64 calcValue(int record, int attrib, int updates) const; HugoCalculator::float calcValue(int record, int attrib, int updates) const; HugoCalculator::double calcValue(int record, int attrib, int updates) const; #endif const char* HugoCalculator::calcValue(int record, int attrib, int updates, char* buf) const { const char a[26] = {"UAWBORCTDPEFQGNYHISJMKXLZ"}; const NdbDictionary::Column* attr = m_tab.getColumn(attrib); int val = calcValue(record, attrib, updates); int len; if (attr->getPrimaryKey()){ // Create a string where val is printed as chars in the beginning // of the string, then fill with other chars // The string length is set to the same size as the attribute len = attr->getLength(); BaseString::snprintf(buf, len, "%d", val); for(int i=strlen(buf); i < len; i++) buf[i] = a[((val^i)%25)]; } else{ // Fill buf with some pattern so that we can detect // anomalies in the area that we don't fill with chars int i; for (i = 0; i<attr->getLength(); i++) buf[i] = ((i+2) % 255); // Calculate length of the string to create. We want the string // length to be varied between max and min of this attribute. len = val % (attr->getLength() + 1); // If len == 0 return NULL if this is a nullable attribute if (len == 0){ if(attr->getNullable() == true) return NULL; else len++; } for(i=0; i < len; i++) buf[i] = a[((val^i)%25)]; buf[len] = 0; } return buf; } int HugoCalculator::verifyRowValues(NDBT_ResultRow* const pRow) const{ int id, updates; id = pRow->attributeStore(m_idCol)->u_32_value(); updates = pRow->attributeStore(m_updatesCol)->u_32_value(); // Check the values of each column for (int i = 0; i<m_tab.getNoOfColumns(); i++){ if (i != m_updatesCol && id != m_idCol) { const NdbDictionary::Column* attr = m_tab.getColumn(i); switch (attr->getType()){ case NdbDictionary::Column::Char: case NdbDictionary::Column::Varchar: case NdbDictionary::Column::Binary: case NdbDictionary::Column::Varbinary:{ int result = 0; char* buf = new char[attr->getLength()+1]; const char* res = calcValue(id, i, updates, buf); if (res == NULL){ if (!pRow->attributeStore(i)->isNULL()){ g_err << "|- NULL ERROR: expected a NULL but the column was not null" << endl; g_err << "|- The row: \"" << (*pRow) << "\"" << endl; result = -1; } } else{ if (memcmp(res, pRow->attributeStore(i)->aRef(), pRow->attributeStore(i)->arraySize()) != 0){ // if (memcmp(res, pRow->attributeStore(i)->aRef(), pRow->attributeStore(i)->getLength()) != 0){ g_err << "arraySize(): " << pRow->attributeStore(i)->arraySize() << ", NdbDict::Column::getLength(): " << attr->getLength() << endl; const char* buf2 = pRow->attributeStore(i)->aRef(); for (Uint32 j = 0; j < pRow->attributeStore(i)->arraySize(); j++) { g_err << j << ":" << buf[j] << "[" << buf2[j] << "]"; if (buf[j] != buf2[j]) { g_err << "==>Match failed!"; } g_err << endl; } g_err << endl; g_err << "|- Invalid data found in attribute " << i << ": \"" << pRow->attributeStore(i)->aRef() << "\" != \"" << res << "\"" << endl << "Length of expected=" << (unsigned)strlen(res) << endl << "Lenght of read=" << (unsigned)strlen(pRow->attributeStore(i)->aRef()) << endl; g_err << "|- The row: \"" << (* pRow) << "\"" << endl; result = -1; } } delete []buf; if (result != 0) return result; } break; case NdbDictionary::Column::Int: case NdbDictionary::Column::Unsigned:{ Int32 cval = calcValue(id, i, updates); Int32 val = pRow->attributeStore(i)->int32_value(); if (val != cval){ g_err << "|- Invalid data found: \"" << val << "\" != \"" << cval << "\"" << endl; g_err << "|- The row: \"" << (* pRow) << "\"" << endl; return -1; } break; } case NdbDictionary::Column::Bigint: case NdbDictionary::Column::Bigunsigned:{ Uint64 cval = calcValue(id, i, updates); Uint64 val = pRow->attributeStore(i)->u_64_value(); if (val != cval){ g_err << "|- Invalid data found: \"" << val << "\" != \"" << cval << "\"" << endl; g_err << "|- The row: \"" << (* pRow) << "\"" << endl; return -1; } } break; case NdbDictionary::Column::Float:{ float cval = calcValue(id, i, updates); float val = pRow->attributeStore(i)->float_value(); if (val != cval){ g_err << "|- Invalid data found: \"" << val << "\" != \"" << cval << "\"" << endl; g_err << "|- The row: \"" << (* pRow) << "\"" << endl; return -1; } } break; case NdbDictionary::Column::Undefined: default: assert(false); break; } } } return 0; } int HugoCalculator::getIdValue(NDBT_ResultRow* const pRow) const { return pRow->attributeStore(m_idCol)->u_32_value(); } int HugoCalculator::getUpdatesValue(NDBT_ResultRow* const pRow) const { return pRow->attributeStore(m_updatesCol)->u_32_value(); }