You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-10-30 07:25:34 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			3226 lines
		
	
	
		
			87 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			3226 lines
		
	
	
		
			87 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (C) 2014 InfiniDB, Inc.
 | |
| 
 | |
|    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; version 2 of
 | |
|    the License.
 | |
| 
 | |
|    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., 51 Franklin Street, Fifth Floor, Boston,
 | |
|    MA 02110-1301, USA. */
 | |
| 
 | |
| /****************************************************************************
 | |
| * $Id: dataconvert.cpp 3901 2013-06-17 20:59:13Z rdempsey $
 | |
| *
 | |
| *
 | |
| ****************************************************************************/
 | |
| 
 | |
| #include <string>
 | |
| #include <cmath>
 | |
| #include <errno.h>
 | |
| #include <ctime>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| using namespace std;
 | |
| #include <boost/algorithm/string/case_conv.hpp>
 | |
| #include <boost/algorithm/string.hpp>
 | |
| using namespace boost::algorithm;
 | |
| #include <boost/tokenizer.hpp>
 | |
| #include "calpontsystemcatalog.h"
 | |
| #include "calpontselectexecutionplan.h"
 | |
| #include "columnresult.h"
 | |
| using namespace execplan;
 | |
| 
 | |
| #include "joblisttypes.h"
 | |
| 
 | |
| #define DATACONVERT_DLLEXPORT
 | |
| #include "dataconvert.h"
 | |
| #undef DATACONVERT_DLLEXPORT
 | |
| 
 | |
| #ifndef __linux__
 | |
| typedef uint32_t ulong;
 | |
| #endif
 | |
| 
 | |
| using namespace logging;
 | |
| 
 | |
| namespace
 | |
| {
 | |
| 
 | |
| const int64_t infinidb_precision[19] =
 | |
| {
 | |
|     0,
 | |
|     9,
 | |
|     99,
 | |
|     999,
 | |
|     9999,
 | |
|     99999,
 | |
|     999999,
 | |
|     9999999,
 | |
|     99999999,
 | |
|     999999999,
 | |
|     9999999999LL,
 | |
|     99999999999LL,
 | |
|     999999999999LL,
 | |
|     9999999999999LL,
 | |
|     99999999999999LL,
 | |
|     999999999999999LL,
 | |
|     9999999999999999LL,
 | |
|     99999999999999999LL,
 | |
|     999999999999999999LL
 | |
| };
 | |
| 
 | |
| template <class T>
 | |
| bool from_string(T& t, const std::string& s, std::ios_base & (*f)(std::ios_base&))
 | |
| {
 | |
|     std::istringstream iss(s);
 | |
|     return !(iss >> f >> t).fail();
 | |
| }
 | |
| 
 | |
| uint64_t pow10_(int32_t scale)
 | |
| {
 | |
|     if (scale <= 0) return 1;
 | |
| 
 | |
|     idbassert(scale < 20);
 | |
|     uint64_t res = 1;
 | |
| 
 | |
|     for (int32_t i = 0; i < scale; i++)
 | |
|         res *= 10;
 | |
| 
 | |
|     return res;
 | |
| }
 | |
| 
 | |
| bool number_value ( const string& data )
 | |
| {
 | |
|     for (unsigned int i = 0; i < strlen(data.c_str()); i++)
 | |
|     {
 | |
|         if (data[i] > '9' || data[i] < '0')
 | |
|         {
 | |
|             if (data[i] != '+' && data[i] != '-' && data[i] != '.' && data[i] != ' ' &&
 | |
|                     data[i] != 'E' && data[i] != 'e')
 | |
|             {
 | |
|                 throw QueryDataExcept("value is not numerical.", formatErr);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| int64_t number_int_value(const string& data,
 | |
|                          const CalpontSystemCatalog::ColType& ct,
 | |
|                          bool& pushwarning,
 | |
|                          bool  noRoundup)
 | |
| {
 | |
|     // copy of the original input
 | |
|     string valStr(data);
 | |
| 
 | |
|     // in case, the values are in parentheses
 | |
|     string::size_type x = valStr.find('(');
 | |
|     string::size_type y = valStr.find(')');
 | |
| 
 | |
|     while (x < string::npos)
 | |
|     {
 | |
|         // erase y first
 | |
|         if (y == string::npos)
 | |
|             throw QueryDataExcept("'(' is not matched.", formatErr);
 | |
| 
 | |
|         valStr.erase(y, 1);
 | |
|         valStr.erase(x, 1);
 | |
|         x = valStr.find('(');
 | |
|         y = valStr.find(')');
 | |
|     }
 | |
| 
 | |
|     if (y != string::npos)
 | |
|         throw QueryDataExcept("')' is not matched.", formatErr);
 | |
| 
 | |
|     if (boost::iequals(valStr, "true"))
 | |
|     {
 | |
|         return 1;
 | |
|     }
 | |
|     if (boost::iequals(valStr, "false"))
 | |
|     {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     // convert to fixed-point notation if input is in scientific notation
 | |
|     if (valStr.find('E') < string::npos || valStr.find('e') < string::npos)
 | |
|     {
 | |
|         size_t epos = valStr.find('E');
 | |
| 
 | |
|         if (epos == string::npos)
 | |
|             epos = valStr.find('e');
 | |
| 
 | |
|         // get the coefficient
 | |
|         string coef = valStr.substr(0, epos);
 | |
|         // get the exponent
 | |
|         string exp = valStr.substr(epos + 1);
 | |
|         bool overflow = false;
 | |
|         int64_t exponent = dataconvert::string_to_ll(exp, overflow);
 | |
| 
 | |
|         // if the exponent can not be held in 64-bit, not supported or saturated.
 | |
|         if (overflow)
 | |
|             throw QueryDataExcept("value is invalid.", formatErr);
 | |
| 
 | |
|         // find the optional "." point
 | |
|         size_t dpos = coef.find('.');
 | |
| 
 | |
|         if (dpos != string::npos)
 | |
|         {
 | |
|             // move "." to the end by mutiply 10 ** (# of fraction digits)
 | |
|             coef.erase(dpos, 1);
 | |
|             exponent -= coef.length() - dpos;
 | |
|         }
 | |
| 
 | |
|         if (exponent >= 0)
 | |
|         {
 | |
|             coef.resize(coef.length() + exponent, '0');
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             size_t bpos = coef.find_first_of("0123456789");
 | |
|             size_t epos = coef.length();
 | |
|             size_t mpos = -exponent;
 | |
|             dpos = epos - mpos;
 | |
|             int64_t padding = (int64_t)mpos - (int64_t)(epos - bpos);
 | |
| 
 | |
|             if (padding > 0)
 | |
|             {
 | |
|                 coef.insert(bpos, padding, '0');
 | |
|                 dpos = bpos;
 | |
|             }
 | |
| 
 | |
|             coef.insert(dpos, ".");
 | |
|         }
 | |
| 
 | |
|         valStr = coef;
 | |
|     }
 | |
| 
 | |
|     // apply the scale
 | |
|     if (ct.scale != 0)
 | |
|     {
 | |
|         uint64_t scale = (uint64_t) (ct.scale < 0) ? (-ct.scale) : (ct.scale);
 | |
|         size_t dpos = valStr.find('.');
 | |
|         string intPart = valStr.substr(0, dpos);
 | |
|         string leftStr;
 | |
| 
 | |
|         if (ct.scale > 0)
 | |
|         {
 | |
|             if (dpos != string::npos)
 | |
|             {
 | |
|                 // decimal point exist, prepare "#scale" digits in fraction part
 | |
|                 ++dpos;
 | |
|                 string frnStr = valStr.substr(dpos, scale);
 | |
| 
 | |
|                 if (frnStr.length() < scale)
 | |
|                     frnStr.resize(scale, '0');  // padding digit 0, not null.
 | |
| 
 | |
|                 // effectly shift "#scale" digits to left.
 | |
|                 intPart += frnStr;
 | |
|                 leftStr = valStr.substr(dpos);
 | |
|                 leftStr.erase(0, scale);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // no decimal point, shift "#scale" digits to left.
 | |
|                 intPart.resize(intPart.length() + scale, '0'); // padding digit 0, not null.
 | |
|             }
 | |
|         }
 | |
|         else // if (ct.scale < 0) -- in ct.scale != 0 block
 | |
|         {
 | |
|             if (dpos != string::npos)
 | |
|             {
 | |
|                 // decimal point exist, get the fraction part
 | |
|                 ++dpos;
 | |
|                 leftStr = valStr.substr(dpos);
 | |
|             }
 | |
| 
 | |
| // add above to keep the old behavior, to comply with tdriver
 | |
| // uncomment code below to support negative scale
 | |
| #if 0
 | |
|             // check if enough digits in the integer part
 | |
|             size_t spos = intPart.find_first_of("0123456789");
 | |
| 
 | |
|             if (string::npos == spos)
 | |
|                 spos = intPart.length();
 | |
| 
 | |
|             size_t len = intPart.substr(spos).length();
 | |
| 
 | |
|             if (len < scale)
 | |
|                 intPart.insert(spos, scale - len, '0');  // padding digit 0, not null.
 | |
| 
 | |
|             leftStr = intPart.substr(intPart.length() - scale) + leftStr;
 | |
|             intPart.erase(intPart.length() - scale, scale);
 | |
| #endif
 | |
|         }
 | |
| 
 | |
|         valStr = intPart;
 | |
| 
 | |
|         if (leftStr.length() > 0)
 | |
|             valStr += "." + leftStr;
 | |
|     }
 | |
| 
 | |
|     // now, convert to long long int
 | |
|     string intStr(valStr);
 | |
|     string frnStr = "";
 | |
|     size_t dp = valStr.find('.');
 | |
|     int    roundup = 0;
 | |
| 
 | |
|     if (dp != string::npos)
 | |
|     {
 | |
|         //Check if need round up
 | |
|         int frac1 = dataconvert::string_to_ll(valStr.substr(dp + 1, 1), pushwarning);
 | |
| 
 | |
|         if ((!noRoundup) && frac1 >= 5)
 | |
|             roundup = 1;
 | |
| 
 | |
|         intStr.erase(dp);
 | |
|         frnStr = valStr.substr(dp + 1);
 | |
| 
 | |
|         if ( intStr.length() == 0 )
 | |
|             intStr = "0";
 | |
|         else if (( intStr.length() == 1 ) && ( (intStr[0] == '+') || (intStr[0] == '-') ) )
 | |
|         {
 | |
|             intStr.insert( 1, 1, '0');
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     int64_t intVal = dataconvert::string_to_ll(intStr, pushwarning);
 | |
|     //@Bug 3350 negative value round up.
 | |
|     intVal += intVal >= 0 ? roundup : -roundup;
 | |
|     bool dummy = false;
 | |
|     int64_t frnVal = (frnStr.length() > 0) ? dataconvert::string_to_ll(frnStr, dummy) : 0;
 | |
| 
 | |
|     if (frnVal != 0)
 | |
|         pushwarning = true;
 | |
| 
 | |
|     switch (ct.colDataType)
 | |
|     {
 | |
|         case CalpontSystemCatalog::TINYINT:
 | |
|             if (intVal < MIN_TINYINT)
 | |
|             {
 | |
|                 intVal = MIN_TINYINT;
 | |
|                 pushwarning = true;
 | |
|             }
 | |
|             else if (intVal > MAX_TINYINT)
 | |
|             {
 | |
|                 intVal = MAX_TINYINT;
 | |
|                 pushwarning = true;
 | |
|             }
 | |
| 
 | |
|             break;
 | |
| 
 | |
|         case CalpontSystemCatalog::SMALLINT:
 | |
|             if (intVal < MIN_SMALLINT)
 | |
|             {
 | |
|                 intVal = MIN_SMALLINT;
 | |
|                 pushwarning = true;
 | |
|             }
 | |
|             else if (intVal > MAX_SMALLINT)
 | |
|             {
 | |
|                 intVal = MAX_SMALLINT;
 | |
|                 pushwarning = true;
 | |
|             }
 | |
| 
 | |
|             break;
 | |
| 
 | |
|         case CalpontSystemCatalog::MEDINT:
 | |
|         case CalpontSystemCatalog::INT:
 | |
|             if (intVal < MIN_INT)
 | |
|             {
 | |
|                 intVal = MIN_INT;
 | |
|                 pushwarning = true;
 | |
|             }
 | |
|             else if (intVal > MAX_INT)
 | |
|             {
 | |
|                 intVal = MAX_INT;
 | |
|                 pushwarning = true;
 | |
|             }
 | |
| 
 | |
|             break;
 | |
| 
 | |
|         case CalpontSystemCatalog::BIGINT:
 | |
|             if (intVal < MIN_BIGINT)
 | |
|             {
 | |
|                 intVal = MIN_BIGINT;
 | |
|                 pushwarning = true;
 | |
|             }
 | |
| 
 | |
|             break;
 | |
| 
 | |
|         case CalpontSystemCatalog::DECIMAL:
 | |
|         case CalpontSystemCatalog::UDECIMAL:
 | |
|             if (ct.colWidth == 1)
 | |
|             {
 | |
|                 if (intVal < MIN_TINYINT)
 | |
|                 {
 | |
|                     intVal = MIN_TINYINT;
 | |
|                     pushwarning = true;
 | |
|                 }
 | |
|                 else if (intVal > MAX_TINYINT)
 | |
|                 {
 | |
|                     intVal = MAX_TINYINT;
 | |
|                     pushwarning = true;
 | |
|                 }
 | |
|             }
 | |
|             else if (ct.colWidth == 2)
 | |
|             {
 | |
|                 if (intVal < MIN_SMALLINT)
 | |
|                 {
 | |
|                     intVal = MIN_SMALLINT;
 | |
|                     pushwarning = true;
 | |
|                 }
 | |
|                 else if (intVal > MAX_SMALLINT)
 | |
|                 {
 | |
|                     intVal = MAX_SMALLINT;
 | |
|                     pushwarning = true;
 | |
|                 }
 | |
|             }
 | |
|             else if (ct.colWidth == 4)
 | |
|             {
 | |
|                 if (intVal < MIN_INT)
 | |
|                 {
 | |
|                     intVal = MIN_INT;
 | |
|                     pushwarning = true;
 | |
|                 }
 | |
|                 else if (intVal > MAX_INT)
 | |
|                 {
 | |
|                     intVal = MAX_INT;
 | |
|                     pushwarning = true;
 | |
|                 }
 | |
|             }
 | |
|             else if (ct.colWidth == 8)
 | |
|             {
 | |
|                 if (intVal < MIN_BIGINT)
 | |
|                 {
 | |
|                     intVal = MIN_BIGINT;
 | |
|                     pushwarning = true;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             break;
 | |
|     }
 | |
| 
 | |
|     // @ bug 3285 make sure the value is in precision range for decimal data type
 | |
|     if ( (ct.colDataType == CalpontSystemCatalog::DECIMAL) ||
 | |
|             (ct.colDataType == CalpontSystemCatalog::UDECIMAL) ||
 | |
|             (ct.scale > 0))
 | |
|     {
 | |
|         int64_t rangeUp = infinidb_precision[ct.precision];
 | |
|         int64_t rangeLow = -rangeUp;
 | |
| 
 | |
|         if (intVal > rangeUp)
 | |
|         {
 | |
|             intVal = rangeUp;
 | |
|             pushwarning = true;
 | |
|         }
 | |
|         else if (intVal < rangeLow)
 | |
|         {
 | |
|             intVal = rangeLow;
 | |
|             pushwarning = true;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return intVal;
 | |
| }
 | |
| 
 | |
| uint64_t number_uint_value(const string& data,
 | |
|                            const CalpontSystemCatalog::ColType& ct,
 | |
|                            bool& pushwarning,
 | |
|                            bool  noRoundup)
 | |
| {
 | |
|     // copy of the original input
 | |
|     string valStr(data);
 | |
| 
 | |
|     // in case, the values are in parentheses
 | |
|     string::size_type x = valStr.find('(');
 | |
|     string::size_type y = valStr.find(')');
 | |
| 
 | |
|     while (x < string::npos)
 | |
|     {
 | |
|         // erase y first
 | |
|         if (y == string::npos)
 | |
|             throw QueryDataExcept("'(' is not matched.", formatErr);
 | |
| 
 | |
|         valStr.erase(y, 1);
 | |
|         valStr.erase(x, 1);
 | |
|         x = valStr.find('(');
 | |
|         y = valStr.find(')');
 | |
|     }
 | |
| 
 | |
|     if (y != string::npos)
 | |
|         throw QueryDataExcept("')' is not matched.", formatErr);
 | |
| 
 | |
|     // convert to fixed-point notation if input is in scientific notation
 | |
|     if (valStr.find('E') < string::npos || valStr.find('e') < string::npos)
 | |
|     {
 | |
|         size_t epos = valStr.find('E');
 | |
| 
 | |
|         if (epos == string::npos)
 | |
|             epos = valStr.find('e');
 | |
| 
 | |
|         // get the coefficient
 | |
|         string coef = valStr.substr(0, epos);
 | |
|         // get the exponent
 | |
|         string exp = valStr.substr(epos + 1);
 | |
|         bool overflow = false;
 | |
|         int64_t exponent = dataconvert::string_to_ll(exp, overflow);
 | |
| 
 | |
|         // if the exponent can not be held in 64-bit, not supported or saturated.
 | |
|         if (overflow)
 | |
|             throw QueryDataExcept("value is invalid.", formatErr);
 | |
| 
 | |
|         // find the optional "." point
 | |
|         size_t dpos = coef.find('.');
 | |
| 
 | |
|         if (dpos != string::npos)
 | |
|         {
 | |
|             // move "." to the end by mutiply 10 ** (# of fraction digits)
 | |
|             coef.erase(dpos, 1);
 | |
|             exponent -= coef.length() - dpos;
 | |
|         }
 | |
| 
 | |
|         if (exponent >= 0)
 | |
|         {
 | |
|             coef.resize(coef.length() + exponent, '0');
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             size_t bpos = coef.find_first_of("0123456789");
 | |
|             size_t epos = coef.length();
 | |
|             size_t mpos = -exponent;
 | |
|             dpos = epos - mpos;
 | |
|             int64_t padding = (int64_t)mpos - (int64_t)(epos - bpos);
 | |
| 
 | |
|             if (padding > 0)
 | |
|             {
 | |
|                 coef.insert(bpos, padding, '0');
 | |
|                 dpos = bpos;
 | |
|             }
 | |
| 
 | |
|             coef.insert(dpos, ".");
 | |
|         }
 | |
| 
 | |
|         valStr = coef;
 | |
|     }
 | |
| 
 | |
|     // now, convert to uint64_t
 | |
|     string intStr(valStr);
 | |
|     string frnStr = "";
 | |
|     size_t dp = valStr.find('.');
 | |
| 
 | |
|     if (dp != string::npos)
 | |
|     {
 | |
|         intStr.erase(dp);
 | |
|         frnStr = valStr.substr(dp + 1);
 | |
| 
 | |
|         if ( intStr.length() == 0 )
 | |
|             intStr = "0";
 | |
|         else if (( intStr.length() == 1 ) && ( (intStr[0] == '+') || (intStr[0] == '-') ) )
 | |
|         {
 | |
|             intStr.insert( 1, 1, '0');
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     uint64_t uintVal = dataconvert::string_to_ull(intStr, pushwarning);
 | |
| 
 | |
|     bool dummy = false;
 | |
|     uint64_t frnVal = (frnStr.length() > 0) ? dataconvert::string_to_ull(frnStr, dummy) : 0;
 | |
| 
 | |
|     if (frnVal != 0)
 | |
|         pushwarning = true;
 | |
| 
 | |
|     switch (ct.colDataType)
 | |
|     {
 | |
|         case CalpontSystemCatalog::UTINYINT:
 | |
|             if (uintVal > MAX_UTINYINT)
 | |
|             {
 | |
|                 uintVal = MAX_UTINYINT;
 | |
|                 pushwarning = true;
 | |
|             }
 | |
| 
 | |
|             break;
 | |
| 
 | |
|         case CalpontSystemCatalog::USMALLINT:
 | |
|             if (uintVal > MAX_USMALLINT)
 | |
|             {
 | |
|                 uintVal = MAX_USMALLINT;
 | |
|                 pushwarning = true;
 | |
|             }
 | |
| 
 | |
|             break;
 | |
| 
 | |
|         case CalpontSystemCatalog::UMEDINT:
 | |
|         case CalpontSystemCatalog::UINT:
 | |
|             if (uintVal > MAX_UINT)
 | |
|             {
 | |
|                 uintVal = MAX_UINT;
 | |
|                 pushwarning = true;
 | |
|             }
 | |
| 
 | |
|             break;
 | |
| 
 | |
|         case CalpontSystemCatalog::UBIGINT:
 | |
|             if (uintVal > MAX_UBIGINT)
 | |
|             {
 | |
|                 uintVal = MAX_UBIGINT;
 | |
|                 pushwarning = true;
 | |
|             }
 | |
| 
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             break;
 | |
|     }
 | |
| 
 | |
|     return uintVal;
 | |
| }
 | |
| 
 | |
| } // namespace anon
 | |
| 
 | |
| namespace dataconvert
 | |
| {
 | |
| 
 | |
| /**
 | |
|  * This function reads a decimal value from a string.  It will stop processing
 | |
|  * in 3 cases:
 | |
|  *     1) end of input string (null-terminated)
 | |
|  *     2) non-digit hit
 | |
|  *     3) max characters read (if max != 0 then at most max characters read)
 | |
|  *
 | |
|  * It's up to the caller to figure out whether an error occurred based on
 | |
|  * their definition of an error and how many characters were read
 | |
|  */
 | |
| uint32_t readDecimal( const char*& str, int32_t& value, uint32_t max = 0 )
 | |
| {
 | |
|     value = 0;
 | |
|     uint32_t numread = 0;
 | |
| 
 | |
|     while ( (!max || numread < max) && *str && isdigit(*str) )
 | |
|     {
 | |
|         value = value * 10 + ((*str) - '0');
 | |
|         ++numread;
 | |
|         ++str;
 | |
|     }
 | |
| 
 | |
|     return numread;
 | |
| }
 | |
| 
 | |
| bool mysql_str_to_datetime( const string& input, DateTime& output, bool& isDate )
 | |
| {
 | |
|     /**
 | |
|      *  First we are going to identify the stop/start of the date portion.
 | |
|      *  The rules are:
 | |
|      *      - Date portion must come before anything else
 | |
|      *      - Date portion may only contain numbers and '-'
 | |
|      *      - Date portion ends with ' ', 'T', or '\0'
 | |
|      *      - Date portion always starts with Year
 | |
|      *      - Without date separators ('-'):
 | |
|      *            YYMMDD
 | |
|      *            YYYYMMDD
 | |
|      *      - With date separators there are no specific field length
 | |
|      *        requirements
 | |
|      */
 | |
|     int32_t datesepct = 0;
 | |
|     uint32_t dtend = 0;
 | |
| 
 | |
|     for ( ; dtend < input.length(); ++dtend )
 | |
|     {
 | |
|         char c = input[dtend];
 | |
| 
 | |
|         if ( isdigit( c ) )
 | |
|         {
 | |
|             continue;
 | |
|         }
 | |
| //		else if( dtend != 0 && c == '-' )
 | |
|         else if ( dtend != 0 && ispunct(c) )
 | |
|         {
 | |
|             ++datesepct;
 | |
|         }
 | |
|         else if ( c == 'T' || c == ' ' )
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // some other character showed up
 | |
|             output.reset();
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     int32_t year = -1;
 | |
|     int32_t mon = -1;
 | |
|     int32_t day = -1;
 | |
|     const char* ptr = input.c_str();
 | |
| 
 | |
|     if ( datesepct == 0 )
 | |
|     {
 | |
|         if ( dtend == 6 || dtend == 12 )
 | |
|         {
 | |
|             readDecimal(ptr, year, 2);
 | |
|             readDecimal(ptr, mon, 2);
 | |
|             readDecimal(ptr, day, 2);
 | |
|             year += 2000;
 | |
| 
 | |
|             if ( year > 2069 )
 | |
|                 year -= 100;
 | |
| 
 | |
|             if ( dtend == 12 )
 | |
|                 dtend -= 6;
 | |
|         }
 | |
|         else if ( dtend == 8 || dtend == 14 )
 | |
|         {
 | |
|             readDecimal(ptr, year, 4);
 | |
|             readDecimal(ptr, mon, 2);
 | |
|             readDecimal(ptr, day, 2);
 | |
| 
 | |
|             if ( dtend == 14 )
 | |
|                 dtend -= 6;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             output.reset();
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
|     else if ( datesepct == 2 )
 | |
|     {
 | |
|         uint32_t numread = readDecimal(ptr, year);
 | |
| 
 | |
|         if ( numread == 2 )
 | |
|         {
 | |
|             // special handling if we read a 2-byte year
 | |
|             year += 2000;
 | |
| 
 | |
|             if ( year > 2069 )
 | |
|                 year -= 100;
 | |
|         }
 | |
| 
 | |
|         ++ptr; // skip one separator
 | |
|         readDecimal(ptr, mon);
 | |
|         ++ptr; // skip one separator
 | |
|         readDecimal(ptr, day); // skip two separators
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         output.reset();
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (!isDateValid(day, mon, year))
 | |
|     {
 | |
|         output.reset();
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     output.year = year;
 | |
|     output.month = mon;
 | |
|     output.day = day;
 | |
| 
 | |
|     /**
 | |
|      *  Now we need to deal with the time portion.
 | |
|      *  The rules are:
 | |
|      *      - Time portion may be empty
 | |
|      *      - Time portion may start with 'T'
 | |
|      *      - Time portion always ends with '\0'
 | |
|      *      - Time portion always starts with hour
 | |
|      *      - Without time separators (':'):
 | |
|      *            HHMMSS
 | |
|      *      - All Times can end with option .[microseconds]
 | |
|      *      - With time separators there are no specific field length
 | |
|      *        requirements
 | |
|      */
 | |
|     while ( input[dtend] == ' ' && dtend < input.length() )
 | |
|     {
 | |
|         ++dtend;
 | |
|     }
 | |
| 
 | |
|     if ( dtend == input.length() )
 | |
|     {
 | |
|         isDate = true;
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     uint32_t timesep_ct = 0;
 | |
|     bool has_usec = false;
 | |
|     uint32_t len_before_msec = 0;
 | |
|     uint32_t tmstart = ( input[dtend] == ' ' || input[dtend] == 'T' ) ? dtend + 1 : dtend;
 | |
|     uint32_t tmend = tmstart;
 | |
| 
 | |
|     for ( ; tmend < input.length(); ++tmend )
 | |
|     {
 | |
|         char c = input[tmend];
 | |
| 
 | |
|         if ( isdigit( c ) )
 | |
|         {
 | |
|             // digits always ok
 | |
|             continue;
 | |
|         }
 | |
| //		else if( c == ':' )
 | |
| //		{
 | |
| //			timesep_ct++;
 | |
| //		}
 | |
| //		else if( c == '.' )
 | |
| //		{
 | |
| //			len_before_msec = ( tmend - tmstart );
 | |
| //			has_usec = true;
 | |
| //		}
 | |
|         else if ( ispunct(c) )
 | |
|         {
 | |
|             if ( c == '.' && timesep_ct == 2 )
 | |
|             {
 | |
|                 len_before_msec = ( tmend - tmstart );
 | |
|                 has_usec = true;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 timesep_ct++;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // some other character showed up
 | |
|             output.reset();
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if ( !len_before_msec )
 | |
|         len_before_msec = ( tmend - tmstart );
 | |
| 
 | |
|     int32_t hour = -1;
 | |
|     int32_t min = 0;
 | |
|     int32_t sec = 0;
 | |
|     int32_t usec = 0;
 | |
|     const char* tstart = input.c_str() + tmstart;
 | |
| 
 | |
|     if ( timesep_ct == 2 )
 | |
|     {
 | |
|         readDecimal(tstart, hour);
 | |
|         ++tstart; // skip one separator
 | |
|         readDecimal(tstart, min);
 | |
|         ++tstart; // skip one separator
 | |
|         readDecimal(tstart, sec);
 | |
|     }
 | |
|     else if ( timesep_ct == 1 )
 | |
|     {
 | |
|         readDecimal(tstart, hour);
 | |
|         ++tstart; // skip one separator
 | |
|         readDecimal(tstart, min);
 | |
|     }
 | |
|     else if ( timesep_ct == 0 && len_before_msec == 6 )
 | |
|     {
 | |
|         readDecimal(tstart, hour, 2);
 | |
|         readDecimal(tstart, min, 2);
 | |
|         readDecimal(tstart, sec, 2);
 | |
|     }
 | |
|     else if ( timesep_ct == 0 && len_before_msec == 4 )
 | |
|     {
 | |
|         readDecimal(tstart, hour, 2);
 | |
|         readDecimal(tstart, min, 2);
 | |
|     }
 | |
|     else if ( timesep_ct == 0 && len_before_msec == 2 )
 | |
|     {
 | |
|         readDecimal(tstart, hour, 2);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         output.reset();
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if ( has_usec )
 | |
|     {
 | |
|         ++tstart; // skip '.' character.  We could error check if we wanted to
 | |
|         uint32_t numread = readDecimal(tstart, usec);
 | |
| 
 | |
|         if ( numread > 6 || numread < 1 )
 | |
|         {
 | |
|             // don't allow more than 6 digits when specifying microseconds
 | |
|             output.reset();
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         // usec have to be scaled up so that it always represents microseconds
 | |
|         for ( int i = numread; i < 6; i++ )
 | |
|             usec *= 10;
 | |
|     }
 | |
| 
 | |
|     if ( !isDateTimeValid( hour, min, sec, usec ) )
 | |
|     {
 | |
|         output.reset();
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     output.hour = hour;
 | |
|     output.minute = min;
 | |
|     output.second = sec;
 | |
|     output.msecond = usec;
 | |
|     isDate = false;
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool mysql_str_to_time( const string& input, Time& output, long decimals )
 | |
| {
 | |
|     int32_t datesepct = 0;
 | |
|     uint32_t dtend = 0;
 | |
|     bool isNeg = false;
 | |
| 
 | |
|     /**
 | |
|      *  We need to deal with the time portion.
 | |
|      *  The rules are:
 | |
|      *      - Time portion always ends with '\0'
 | |
|      *      - Time portion always starts with hour
 | |
|      *      - Without time separators (':'):
 | |
|      *            HHMMSS
 | |
|      *      - All Times can end with option .[microseconds]
 | |
|      *      - With time separators there are no specific field length
 | |
|      *        requirements
 | |
|      */
 | |
|     while ( input[dtend] == ' ' && dtend < input.length() )
 | |
|     {
 | |
|         ++dtend;
 | |
|     }
 | |
| 
 | |
|     if ( dtend == input.length() )
 | |
|     {
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     uint32_t timesep_ct = 0;
 | |
|     bool has_usec = false;
 | |
|     uint32_t len_before_msec = 0;
 | |
|     uint32_t tmstart = dtend;
 | |
|     uint32_t tmend = tmstart;
 | |
| 
 | |
|     for ( ; tmend < input.length(); ++tmend )
 | |
|     {
 | |
|         char c = input[tmend];
 | |
| 
 | |
|         if ( isdigit( c ) )
 | |
|         {
 | |
|             // digits always ok
 | |
|             continue;
 | |
|         }
 | |
| //		else if( c == ':' )
 | |
| //		{
 | |
| //			timesep_ct++;
 | |
| //		}
 | |
| //		else if( c == '.' )
 | |
| //		{
 | |
| //			len_before_msec = ( tmend - tmstart );
 | |
| //			has_usec = true;
 | |
| //		}
 | |
|         else if ( ispunct(c) )
 | |
|         {
 | |
|             if ( c == '.' && timesep_ct == 2 )
 | |
|             {
 | |
|                 len_before_msec = ( tmend - tmstart );
 | |
|                 has_usec = true;
 | |
|             }
 | |
|             else if (c == '-' && (tmend == tmstart))
 | |
|             {
 | |
|                 isNeg = true;
 | |
|                 ++tmstart;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 timesep_ct++;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // some other character showed up
 | |
|             output.reset();
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if ( !len_before_msec )
 | |
|         len_before_msec = ( tmend - tmstart );
 | |
| 
 | |
|     int32_t hour = -1;
 | |
|     int32_t min = 0;
 | |
|     int32_t sec = 0;
 | |
|     int32_t usec = 0;
 | |
|     const char* tstart = input.c_str() + tmstart;
 | |
| 
 | |
|     if ( timesep_ct == 2 )
 | |
|     {
 | |
|         readDecimal(tstart, hour);
 | |
|         ++tstart; // skip one separator
 | |
|         readDecimal(tstart, min);
 | |
|         ++tstart; // skip one separator
 | |
|         readDecimal(tstart, sec);
 | |
|     }
 | |
|     else if ( timesep_ct == 1 )
 | |
|     {
 | |
|         readDecimal(tstart, hour);
 | |
|         ++tstart; // skip one separator
 | |
|         readDecimal(tstart, min);
 | |
|     }
 | |
|     else if ( timesep_ct == 0 && len_before_msec == 6 )
 | |
|     {
 | |
|         readDecimal(tstart, hour, 2);
 | |
|         readDecimal(tstart, min, 2);
 | |
|         readDecimal(tstart, sec, 2);
 | |
|     }
 | |
|     else if ( timesep_ct == 0 && len_before_msec == 4 )
 | |
|     {
 | |
|         readDecimal(tstart, hour, 2);
 | |
|         readDecimal(tstart, min, 2);
 | |
|     }
 | |
|     else if ( timesep_ct == 0 && len_before_msec == 2 )
 | |
|     {
 | |
|         readDecimal(tstart, hour, 2);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         output.reset();
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if ( has_usec )
 | |
|     {
 | |
|         ++tstart; // skip '.' character.  We could error check if we wanted to
 | |
|         uint32_t numread = readDecimal(tstart, usec);
 | |
| 
 | |
|         if ( numread > 6 || numread < 1 )
 | |
|         {
 | |
|             // don't allow more than 6 digits when specifying microseconds
 | |
|             output.reset();
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         // usec have to be scaled up so that it always represents microseconds
 | |
|         for ( int i = numread; i < 6; i++ )
 | |
|             usec *= 10;
 | |
|     }
 | |
| 
 | |
|     if ( !isTimeValid( hour, min, sec, usec ) )
 | |
|     {
 | |
|         // Emulate MariaDB's time saturation
 | |
|         // TODO: msec saturation
 | |
|         if ((hour > 838) && !isNeg)
 | |
|         {
 | |
|             output.hour = 838;
 | |
|             output.minute = 59;
 | |
|             output.second = 59;
 | |
|             output.msecond = exp10(decimals) - 1;
 | |
|             output.is_neg = 0;
 | |
|         }
 | |
|         else if ((hour < -838) || ((hour > 838) && isNeg))
 | |
|         {
 | |
|             output.hour = -838;
 | |
|             output.minute = 59;
 | |
|             output.second = 59;
 | |
|             output.msecond = exp10(decimals) - 1;
 | |
|             output.is_neg = 1;
 | |
|         }
 | |
|         // If neither of the above match then we return a 0 time
 | |
|         else
 | |
|         {
 | |
|             output.reset();
 | |
|         }
 | |
| 
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     output.hour = isNeg ? 0 - hour : hour;
 | |
|     output.minute = min;
 | |
|     output.second = sec;
 | |
|     output.msecond = usec;
 | |
|     output.is_neg = isNeg;
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool stringToDateStruct( const string& data, Date& date )
 | |
| {
 | |
|     bool isDate;
 | |
|     DateTime dt;
 | |
| 
 | |
|     if ( !mysql_str_to_datetime( data, dt, isDate ))
 | |
|         return false;
 | |
| 
 | |
|     date.year = dt.year;
 | |
|     date.month = dt.month;
 | |
|     date.day = dt.day;
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool stringToDatetimeStruct(const string& data, DateTime& dtime, bool* date)
 | |
| {
 | |
|     bool isDate;
 | |
| 
 | |
|     if ( !mysql_str_to_datetime( data, dtime, isDate ) )
 | |
|         return false;
 | |
| 
 | |
|     if ( isDate )
 | |
|     {
 | |
|         if (date)
 | |
|             *date = true;
 | |
| 
 | |
|         dtime.hour = 0;
 | |
|         dtime.minute = 0;
 | |
|         dtime.second = 0;
 | |
|         dtime.msecond = 0;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool stringToTimeStruct(const string& data, Time& dtime, long decimals)
 | |
| {
 | |
|     if ( !mysql_str_to_time( data, dtime, decimals ) )
 | |
|         return false;
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| boost::any
 | |
| DataConvert::convertColumnData(const CalpontSystemCatalog::ColType& colType,
 | |
|                                const std::string& dataOrig, bool& pushWarning, bool nulFlag, bool noRoundup, bool isUpdate )
 | |
| {
 | |
|     boost::any value;
 | |
|     std::string data( dataOrig );
 | |
|     pushWarning = false;
 | |
|     CalpontSystemCatalog::ColDataType type = colType.colDataType;
 | |
| 
 | |
|     //if ( !data.empty() )
 | |
|     if (!nulFlag)
 | |
|     {
 | |
|         switch (type)
 | |
|         {
 | |
|             case CalpontSystemCatalog::BIT:
 | |
|             {
 | |
|                 unsigned int x = data.find("(");
 | |
| 
 | |
|                 if (x <= data.length())
 | |
|                 {
 | |
|                     data.replace ( x, 1, " ");
 | |
|                 }
 | |
| 
 | |
|                 x = data.find(")");
 | |
| 
 | |
|                 if (x <= data.length())
 | |
|                 {
 | |
|                     data.replace (x, 1, " ");
 | |
|                 }
 | |
| 
 | |
|                 if (number_int_value (data, colType, pushWarning, noRoundup))
 | |
|                 {
 | |
|                     bool bitvalue;
 | |
| 
 | |
|                     if (from_string<bool>(bitvalue, data, std::dec ))
 | |
|                     {
 | |
|                         value = bitvalue;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         throw QueryDataExcept("range, valid value or conversion error on BIT type.", formatErr);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::TINYINT:
 | |
|                 value = (char) number_int_value(data, colType, pushWarning, noRoundup);
 | |
|                 break;
 | |
| 
 | |
|             case CalpontSystemCatalog::SMALLINT:
 | |
|                 value = (short) number_int_value(data, colType, pushWarning, noRoundup);
 | |
|                 break;
 | |
| 
 | |
|             case CalpontSystemCatalog::MEDINT:
 | |
|             case CalpontSystemCatalog::INT:
 | |
|                 value = (int) number_int_value(data, colType, pushWarning, noRoundup);
 | |
|                 break;
 | |
| 
 | |
|             case CalpontSystemCatalog::BIGINT:
 | |
|                 value = (long long) number_int_value(data, colType, pushWarning, noRoundup);
 | |
|                 break;
 | |
| 
 | |
|             case CalpontSystemCatalog::DECIMAL:
 | |
|                 if (colType.colWidth == 1)
 | |
|                     value = (char) number_int_value(data, colType, pushWarning, noRoundup);
 | |
|                 else if (colType.colWidth == 2)
 | |
|                     value = (short) number_int_value(data, colType, pushWarning, noRoundup);
 | |
|                 else if (colType.colWidth == 4)
 | |
|                     value = (int) number_int_value(data, colType, pushWarning, noRoundup);
 | |
|                 else if (colType.colWidth == 8)
 | |
|                     value = (long long) number_int_value(data, colType, pushWarning, noRoundup);
 | |
| 
 | |
|                 break;
 | |
| 
 | |
|             case CalpontSystemCatalog::UDECIMAL:
 | |
| 
 | |
|                 // UDECIMAL numbers may not be negative
 | |
|                 if (colType.colWidth == 1)
 | |
|                 {
 | |
|                     char ival = (char) number_int_value(data, colType, pushWarning, noRoundup);
 | |
| 
 | |
|                     if (ival < 0 &&
 | |
|                             ival != static_cast<int8_t>(joblist::TINYINTEMPTYROW) &&
 | |
|                             ival != static_cast<int8_t>(joblist::TINYINTNULL))
 | |
|                     {
 | |
|                         ival = 0;
 | |
|                         pushWarning = true;
 | |
|                     }
 | |
| 
 | |
|                     value = ival;
 | |
|                 }
 | |
|                 else if (colType.colWidth == 2)
 | |
|                 {
 | |
|                     short ival = (short) number_int_value(data, colType, pushWarning, noRoundup);
 | |
| 
 | |
|                     if (ival < 0 &&
 | |
|                             ival != static_cast<int16_t>(joblist::SMALLINTEMPTYROW) &&
 | |
|                             ival != static_cast<int16_t>(joblist::SMALLINTNULL))
 | |
|                     {
 | |
|                         ival = 0;
 | |
|                         pushWarning = true;
 | |
|                     }
 | |
| 
 | |
|                     value = ival;
 | |
|                 }
 | |
|                 else if (colType.colWidth == 4)
 | |
|                 {
 | |
|                     int ival = static_cast<int>(number_int_value(data, colType, pushWarning, noRoundup));
 | |
| 
 | |
|                     if (ival < 0 &&
 | |
|                             ival != static_cast<int>(joblist::INTEMPTYROW) &&
 | |
|                             ival != static_cast<int>(joblist::INTNULL))
 | |
|                     {
 | |
|                         ival = 0;
 | |
|                         pushWarning = true;
 | |
|                     }
 | |
| 
 | |
|                     value = ival;
 | |
|                 }
 | |
|                 else if (colType.colWidth == 8)
 | |
|                 {
 | |
|                     long long ival = static_cast<long long>(number_int_value(data, colType, pushWarning, noRoundup));
 | |
| 
 | |
|                     if (ival < 0 &&
 | |
|                             ival != static_cast<long long>(joblist::BIGINTEMPTYROW) &&
 | |
|                             ival != static_cast<long long>(joblist::BIGINTNULL))
 | |
|                     {
 | |
|                         ival = 0;
 | |
|                         pushWarning = true;
 | |
|                     }
 | |
| 
 | |
|                     value = ival;
 | |
|                 }
 | |
| 
 | |
|                 break;
 | |
| 
 | |
|             case CalpontSystemCatalog::FLOAT:
 | |
|             case CalpontSystemCatalog::UFLOAT:
 | |
|             {
 | |
|                 string::size_type x = data.find('(');
 | |
| 
 | |
|                 if (x < string::npos)
 | |
|                     data.erase(x, 1);
 | |
| 
 | |
|                 x = data.find(')');
 | |
| 
 | |
|                 if (x < string::npos)
 | |
|                     data.erase(x, 1);
 | |
| 
 | |
|                 if ( number_value ( data ) )
 | |
|                 {
 | |
|                     float floatvalue;
 | |
|                     errno = 0;
 | |
| #ifdef _MSC_VER
 | |
|                     double dval = strtod(data.c_str(), 0);
 | |
| 
 | |
|                     if (dval > MAX_FLOAT)
 | |
|                     {
 | |
|                         pushWarning = true;
 | |
|                         floatvalue = MAX_FLOAT;
 | |
|                     }
 | |
|                     else if (dval < MIN_FLOAT)
 | |
|                     {
 | |
|                         pushWarning = true;
 | |
|                         floatvalue = MIN_FLOAT;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         floatvalue = (float)dval;
 | |
|                     }
 | |
| 
 | |
| #else
 | |
|                     floatvalue = strtof(data.c_str(), 0);
 | |
| #endif
 | |
| 
 | |
|                     if (errno == ERANGE)
 | |
|                     {
 | |
|                         pushWarning = true;
 | |
| #ifdef _MSC_VER
 | |
| 
 | |
|                         if ( abs(floatvalue) == HUGE_VAL )
 | |
| #else
 | |
|                         if ( abs(floatvalue) == HUGE_VALF )
 | |
| #endif
 | |
|                         {
 | |
|                             if ( floatvalue > 0 )
 | |
|                                 floatvalue = MAX_FLOAT;
 | |
|                             else
 | |
|                                 floatvalue = MIN_FLOAT;
 | |
|                         }
 | |
|                         else
 | |
|                             floatvalue = 0;
 | |
|                     }
 | |
| 
 | |
|                     if (floatvalue < 0.0 && type == CalpontSystemCatalog::UFLOAT &&
 | |
|                             floatvalue != joblist::FLOATEMPTYROW && floatvalue != joblist::FLOATNULL)
 | |
|                     {
 | |
|                         value = 0.0;
 | |
|                         pushWarning = true;
 | |
|                     }
 | |
| 
 | |
|                     value = floatvalue;
 | |
|                 }
 | |
|                 else
 | |
|                     throw QueryDataExcept("range, valid value or conversion error on FLOAT type.", formatErr);
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::DOUBLE:
 | |
|             case CalpontSystemCatalog::UDOUBLE:
 | |
|             {
 | |
|                 string::size_type x = data.find('(');
 | |
| 
 | |
|                 if (x < string::npos)
 | |
|                     data.erase(x, 1);
 | |
| 
 | |
|                 x = data.find(')');
 | |
| 
 | |
|                 if (x < string::npos)
 | |
|                     data.erase(x, 1);
 | |
| 
 | |
|                 if ( number_value ( data ) )
 | |
|                 {
 | |
|                     double doublevalue;
 | |
|                     errno = 0;
 | |
|                     doublevalue = strtod(data.c_str(), 0);
 | |
| 
 | |
|                     if (errno == ERANGE)
 | |
|                     {
 | |
|                         pushWarning = true;
 | |
| #ifdef _MSC_VER
 | |
| 
 | |
|                         if ( abs(doublevalue) == HUGE_VAL )
 | |
| #else
 | |
|                         if ( abs(doublevalue) == HUGE_VALL )
 | |
| #endif
 | |
|                         {
 | |
|                             if ( doublevalue > 0 )
 | |
|                                 value = MAX_DOUBLE;
 | |
|                             else
 | |
|                                 value = MIN_DOUBLE;
 | |
|                         }
 | |
|                         else
 | |
|                             value = 0;
 | |
|                     }
 | |
|                     else
 | |
|                         value = doublevalue;
 | |
| 
 | |
|                     if (doublevalue < 0.0 && type == CalpontSystemCatalog::UDOUBLE &&
 | |
|                             doublevalue != joblist::DOUBLEEMPTYROW && doublevalue != joblist::DOUBLENULL)
 | |
|                     {
 | |
|                         doublevalue = 0.0;
 | |
|                         pushWarning = true;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     throw QueryDataExcept("range, valid value or conversion error on DOUBLE type.", formatErr);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::UTINYINT:
 | |
|                 value = (uint8_t)number_uint_value(data, colType, pushWarning, noRoundup);
 | |
|                 break;
 | |
| 
 | |
|             case CalpontSystemCatalog::USMALLINT:
 | |
|                 value = (uint16_t)number_uint_value(data, colType, pushWarning, noRoundup);
 | |
|                 break;
 | |
| 
 | |
|             case CalpontSystemCatalog::UMEDINT:
 | |
|             case CalpontSystemCatalog::UINT:
 | |
|                 value = (uint32_t)number_uint_value(data, colType, pushWarning, noRoundup);
 | |
|                 break;
 | |
| 
 | |
|             case CalpontSystemCatalog::UBIGINT:
 | |
|                 value = (uint64_t)number_uint_value(data, colType, pushWarning, noRoundup);
 | |
|                 break;
 | |
| 
 | |
|             case CalpontSystemCatalog::CHAR:
 | |
|             case CalpontSystemCatalog::VARCHAR:
 | |
|             case CalpontSystemCatalog::TEXT:
 | |
|             {
 | |
|                 //check data length
 | |
|                 if ( data.length() > (unsigned int)colType.colWidth )
 | |
|                 {
 | |
|                     data = data.substr(0, colType.colWidth);
 | |
|                     pushWarning = true;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if ( (unsigned int)colType.colWidth > data.length())
 | |
|                     {
 | |
|                         //Pad null character to the string
 | |
|                         data.resize(colType.colWidth, 0);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 value = data;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::DATE:
 | |
|             {
 | |
|                 Date aDay;
 | |
| 
 | |
|                 if (stringToDateStruct(data, aDay))
 | |
|                 {
 | |
|                     value = (*(reinterpret_cast<uint32_t*> (&aDay)));
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     value = (uint32_t) 0;
 | |
|                     pushWarning = true;
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::DATETIME:
 | |
|             {
 | |
|                 DateTime aDatetime;
 | |
| 
 | |
|                 if (stringToDatetimeStruct(data, aDatetime, 0))
 | |
|                 {
 | |
|                     value = *(reinterpret_cast<uint64_t*>(&aDatetime));
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     value = (uint64_t) 0;
 | |
|                     pushWarning = true;
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::TIME:
 | |
|             {
 | |
|                 Time aTime;
 | |
| 
 | |
|                 if (!stringToTimeStruct(data, aTime, colType.precision))
 | |
|                 {
 | |
|                     pushWarning = true;
 | |
|                 }
 | |
| 
 | |
|                 value = (int64_t) * (reinterpret_cast<int64_t*>(&aTime));
 | |
|             }
 | |
|             break;
 | |
| 
 | |
| 
 | |
|             case CalpontSystemCatalog::BLOB:
 | |
|             case CalpontSystemCatalog::CLOB:
 | |
|                 value = data;
 | |
|                 break;
 | |
| 
 | |
|             case CalpontSystemCatalog::VARBINARY:
 | |
|                 value = data;
 | |
|                 break;
 | |
| 
 | |
|             default:
 | |
|                 throw QueryDataExcept("convertColumnData: unknown column data type.", dataTypeErr);
 | |
|                 break;
 | |
|         }
 | |
|     }
 | |
|     else									//null
 | |
|     {
 | |
|         switch (type)
 | |
|         {
 | |
|             case CalpontSystemCatalog::BIT:
 | |
|             {
 | |
|                 //TODO: How to communicate with write engine?
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::TINYINT:
 | |
|             {
 | |
|                 char tinyintvalue = joblist::TINYINTNULL;
 | |
|                 value = tinyintvalue;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::SMALLINT:
 | |
|             {
 | |
|                 short smallintvalue = joblist::SMALLINTNULL;
 | |
|                 value = smallintvalue;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::MEDINT:
 | |
|             case CalpontSystemCatalog::INT:
 | |
|             {
 | |
|                 int intvalue = joblist::INTNULL;
 | |
|                 value = intvalue;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::BIGINT:
 | |
|             {
 | |
|                 long long bigint = joblist::BIGINTNULL;
 | |
|                 value = bigint;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::DECIMAL:
 | |
|             case CalpontSystemCatalog::UDECIMAL:
 | |
|             {
 | |
|                 if (colType.colWidth == CalpontSystemCatalog::ONE_BYTE)
 | |
|                 {
 | |
|                     char tinyintvalue = joblist::TINYINTNULL;
 | |
|                     value = tinyintvalue;
 | |
|                 }
 | |
|                 else if (colType.colWidth == CalpontSystemCatalog::TWO_BYTE)
 | |
|                 {
 | |
|                     short smallintvalue = joblist::SMALLINTNULL;
 | |
|                     value = smallintvalue;
 | |
|                 }
 | |
|                 else if (colType.colWidth == CalpontSystemCatalog::FOUR_BYTE)
 | |
|                 {
 | |
|                     int intvalue = joblist::INTNULL;
 | |
|                     value = intvalue;
 | |
|                 }
 | |
|                 else if (colType.colWidth == CalpontSystemCatalog::EIGHT_BYTE)
 | |
|                 {
 | |
|                     long long eightbyte = joblist::BIGINTNULL;
 | |
|                     value = eightbyte;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     WriteEngine::Token nullToken;
 | |
|                     value = nullToken;
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::FLOAT:
 | |
|             case CalpontSystemCatalog::UFLOAT:
 | |
|             {
 | |
|                 uint32_t tmp = joblist::FLOATNULL;
 | |
|                 float* floatvalue = (float*)&tmp;
 | |
|                 value = *floatvalue;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::DOUBLE:
 | |
|             case CalpontSystemCatalog::UDOUBLE:
 | |
|             {
 | |
|                 uint64_t tmp = joblist::DOUBLENULL;
 | |
|                 double* doublevalue = (double*)&tmp;
 | |
|                 value = *doublevalue;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::DATE:
 | |
|             {
 | |
|                 uint32_t d = joblist::DATENULL;
 | |
|                 value = d;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::DATETIME:
 | |
|             {
 | |
|                 uint64_t d = joblist::DATETIMENULL;
 | |
|                 value = d;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::TIME:
 | |
|             {
 | |
|                 uint64_t d = joblist::TIMENULL;
 | |
|                 value = d;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::CHAR:
 | |
|             {
 | |
|                 std::string charnull;
 | |
| 
 | |
|                 if (colType.colWidth == 1)
 | |
|                 {
 | |
|                     //charnull = joblist::CHAR1NULL;
 | |
|                     charnull = '\376';
 | |
|                     value = charnull;
 | |
|                 }
 | |
|                 else if (colType.colWidth == 2)
 | |
|                 {
 | |
|                     //charnull = joblist::CHAR2NULL;
 | |
|                     charnull = "\377\376";
 | |
|                     value = charnull;
 | |
|                 }
 | |
|                 else if (( colType.colWidth < 5 ) && ( colType.colWidth > 2 ))
 | |
|                 {
 | |
|                     //charnull = joblist::CHAR4NULL;
 | |
|                     charnull = "\377\377\377\376";
 | |
|                     value = charnull;
 | |
|                 }
 | |
|                 else if (( colType.colWidth < 9 ) && ( colType.colWidth > 4 ))
 | |
|                 {
 | |
|                     //charnull = joblist::CHAR8NULL;
 | |
|                     charnull = "\377\377\377\377\377\377\377\376";
 | |
|                     value = charnull;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     WriteEngine::Token nullToken;
 | |
|                     value = nullToken;
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::VARCHAR:
 | |
|             case CalpontSystemCatalog::TEXT:
 | |
|             {
 | |
|                 std::string charnull;
 | |
| 
 | |
|                 if (colType.colWidth == 1 )
 | |
|                 {
 | |
|                     //charnull = joblist::CHAR2NULL;
 | |
|                     charnull = "\377\376";
 | |
|                     value = charnull;
 | |
|                 }
 | |
|                 else if ((colType.colWidth < 4)  && (colType.colWidth > 1))
 | |
|                 {
 | |
|                     //charnull = joblist::CHAR4NULL;
 | |
|                     charnull = "\377\377\377\376";
 | |
|                     value = charnull;
 | |
|                 }
 | |
|                 else if ((colType.colWidth < 8)  && (colType.colWidth > 3))
 | |
|                 {
 | |
|                     //charnull = joblist::CHAR8NULL;
 | |
|                     charnull = "\377\377\377\377\377\377\377\376";
 | |
|                     value = charnull;
 | |
|                 }
 | |
|                 else if ( colType.colWidth > 7 )
 | |
|                 {
 | |
|                     WriteEngine::Token nullToken;
 | |
|                     value = nullToken;
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::VARBINARY:
 | |
|             case CalpontSystemCatalog::BLOB:
 | |
|             {
 | |
|                 WriteEngine::Token nullToken;
 | |
|                 value = nullToken;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::UTINYINT:
 | |
|             {
 | |
|                 uint8_t utinyintvalue = joblist::UTINYINTNULL;
 | |
|                 value = utinyintvalue;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::USMALLINT:
 | |
|             {
 | |
|                 uint16_t usmallintvalue = joblist::USMALLINTNULL;
 | |
|                 value = usmallintvalue;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::UMEDINT:
 | |
|             case CalpontSystemCatalog::UINT:
 | |
|             {
 | |
|                 uint32_t uintvalue = joblist::UINTNULL;
 | |
|                 value = uintvalue;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             case CalpontSystemCatalog::UBIGINT:
 | |
|             {
 | |
|                 uint64_t ubigint = joblist::UBIGINTNULL;
 | |
|                 value = ubigint;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|             default:
 | |
|                 throw QueryDataExcept("convertColumnData: unknown column data type.", dataTypeErr);
 | |
|                 break;
 | |
| 
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return value;
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Convert date string to binary date.  Used by BulkLoad.
 | |
| //------------------------------------------------------------------------------
 | |
| int32_t DataConvert::convertColumnDate(
 | |
|     const char* dataOrg,
 | |
|     CalpontDateTimeFormat dateFormat,
 | |
|     int& status,
 | |
|     unsigned int dataOrgLen )
 | |
| {
 | |
|     status = 0;
 | |
|     const char* p;
 | |
|     p = dataOrg;
 | |
|     char fld[10];
 | |
|     int32_t value = 0;
 | |
| 
 | |
|     if ( dateFormat != CALPONTDATE_ENUM )
 | |
|     {
 | |
|         status = -1;
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     // @bug 5787: allow for leading blanks
 | |
|     unsigned int dataLen = dataOrgLen;
 | |
| 
 | |
|     if ((dataOrgLen > 0) && (dataOrg[0] == ' '))
 | |
|     {
 | |
|         unsigned nblanks = 0;
 | |
| 
 | |
|         for (unsigned nn = 0; nn < dataOrgLen; nn++)
 | |
|         {
 | |
|             if (dataOrg[nn] == ' ')
 | |
|                 nblanks++;
 | |
|             else
 | |
|                 break;
 | |
|         }
 | |
| 
 | |
|         p       = dataOrg    + nblanks;
 | |
|         dataLen = dataOrgLen - nblanks;
 | |
|     }
 | |
| 
 | |
|     if ( dataLen < 10)
 | |
|     {
 | |
|         status = -1;
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     int inYear, inMonth, inDay;
 | |
|     memcpy( fld, p, 4);
 | |
|     fld[4] = '\0';
 | |
| 
 | |
|     inYear = strtol(fld, 0, 10);
 | |
| 
 | |
|     memcpy( fld, p + 5, 2);
 | |
|     fld[2] = '\0';
 | |
| 
 | |
|     inMonth = strtol(fld, 0, 10);
 | |
| 
 | |
|     memcpy( fld, p + 8, 2);
 | |
|     fld[2] = '\0';
 | |
| 
 | |
|     inDay = strtol(fld, 0, 10);
 | |
| 
 | |
|     if ( isDateValid (inDay, inMonth, inYear))
 | |
|     {
 | |
|         Date aDay;
 | |
|         aDay.year = inYear;
 | |
|         aDay.month = inMonth;
 | |
|         aDay.day = inDay;
 | |
|         memcpy( &value, &aDay, 4);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         status = -1;
 | |
|     }
 | |
| 
 | |
|     return value;
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Verify that specified date is valid
 | |
| //------------------------------------------------------------------------------
 | |
| bool DataConvert::isColumnDateValid( int32_t date )
 | |
| {
 | |
|     Date d;
 | |
|     memcpy(&d, &date, sizeof(int32_t));
 | |
|     return (isDateValid(d.day, d.month, d.year));
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Convert date/time string to binary date/time.  Used by BulkLoad.
 | |
| //------------------------------------------------------------------------------
 | |
| int64_t DataConvert::convertColumnDatetime(
 | |
|     const char* dataOrg,
 | |
|     CalpontDateTimeFormat datetimeFormat,
 | |
|     int& status,
 | |
|     unsigned int dataOrgLen )
 | |
| {
 | |
|     status = 0;
 | |
|     const char* p;
 | |
|     p = dataOrg;
 | |
|     char fld[10];
 | |
|     int64_t value = 0;
 | |
| 
 | |
|     if ( datetimeFormat != CALPONTDATETIME_ENUM )
 | |
|     {
 | |
|         status = -1;
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     // @bug 5787: allow for leading blanks
 | |
|     unsigned int dataLen = dataOrgLen;
 | |
| 
 | |
|     if ((dataOrgLen > 0) && (dataOrg[0] == ' '))
 | |
|     {
 | |
|         unsigned nblanks = 0;
 | |
| 
 | |
|         for (unsigned nn = 0; nn < dataOrgLen; nn++)
 | |
|         {
 | |
|             if (dataOrg[nn] == ' ')
 | |
|                 nblanks++;
 | |
|             else
 | |
|                 break;
 | |
|         }
 | |
| 
 | |
|         p       = dataOrg    + nblanks;
 | |
|         dataLen = dataOrgLen - nblanks;
 | |
|     }
 | |
| 
 | |
|     if ( dataLen < 10)
 | |
|     {
 | |
|         status = -1;
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     int inYear, inMonth, inDay, inHour, inMinute, inSecond, inMicrosecond;
 | |
|     memcpy( fld, p, 4);
 | |
|     fld[4] = '\0';
 | |
| 
 | |
|     inYear = strtol(fld, 0, 10);
 | |
| 
 | |
|     memcpy( fld, p + 5, 2);
 | |
|     fld[2] = '\0';
 | |
| 
 | |
|     inMonth = strtol(fld, 0, 10);
 | |
| 
 | |
|     memcpy( fld, p + 8, 2);
 | |
|     fld[2] = '\0';
 | |
| 
 | |
|     inDay = strtol(fld, 0, 10);
 | |
| 
 | |
|     inHour        = 0;
 | |
|     inMinute      = 0;
 | |
|     inSecond      = 0;
 | |
|     inMicrosecond = 0;
 | |
| 
 | |
|     if (dataLen > 12)
 | |
|     {
 | |
|         // For backwards compatability we still allow leading blank
 | |
|         if ((!isdigit(p[11]) && (p[11] != ' ')) ||
 | |
|                 !isdigit(p[12]))
 | |
|         {
 | |
|             status = -1;
 | |
|             return value;
 | |
|         }
 | |
| 
 | |
|         memcpy( fld, p + 11, 2);
 | |
|         fld[2] = '\0';
 | |
| 
 | |
|         inHour = strtol(fld, 0, 10);
 | |
| 
 | |
|         if (dataLen > 15)
 | |
|         {
 | |
|             if (!isdigit(p[14]) || !isdigit(p[15]))
 | |
|             {
 | |
|                 status = -1;
 | |
|                 return value;
 | |
|             }
 | |
| 
 | |
|             memcpy( fld, p + 14, 2);
 | |
|             fld[2] = '\0';
 | |
| 
 | |
|             inMinute = strtol(fld, 0, 10);
 | |
| 
 | |
|             if (dataLen > 18)
 | |
|             {
 | |
|                 if (!isdigit(p[17]) || !isdigit(p[18]))
 | |
|                 {
 | |
|                     status = -1;
 | |
|                     return value;
 | |
|                 }
 | |
| 
 | |
|                 memcpy( fld, p + 17, 2);
 | |
|                 fld[2] = '\0';
 | |
| 
 | |
|                 inSecond = strtol(fld, 0, 10);
 | |
| 
 | |
|                 if (dataLen > 20)
 | |
|                 {
 | |
|                     unsigned int microFldLen = dataLen - 20;
 | |
| 
 | |
|                     if (microFldLen > (sizeof(fld) - 1))
 | |
|                         microFldLen = sizeof(fld) - 1;
 | |
| 
 | |
|                     memcpy( fld, p + 20, microFldLen);
 | |
|                     fld[microFldLen] = '\0';
 | |
|                     inMicrosecond = strtol(fld, 0, 10);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if ( isDateValid (inDay, inMonth, inYear) &&
 | |
|             isDateTimeValid (inHour, inMinute, inSecond, inMicrosecond) )
 | |
|     {
 | |
|         DateTime aDatetime;
 | |
|         aDatetime.year = inYear;
 | |
|         aDatetime.month = inMonth;
 | |
|         aDatetime.day = inDay;
 | |
|         aDatetime.hour = inHour;
 | |
|         aDatetime.minute = inMinute;
 | |
|         aDatetime.second = inSecond;
 | |
|         aDatetime.msecond = inMicrosecond;
 | |
| 
 | |
|         memcpy( &value, &aDatetime, 8);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         status = -1;
 | |
|     }
 | |
| 
 | |
|     return value;
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Convert time string to binary time.  Used by BulkLoad.
 | |
| // Most of this is taken from str_to_time in sql-common/my_time.c
 | |
| //------------------------------------------------------------------------------
 | |
| int64_t DataConvert::convertColumnTime(
 | |
|     const char* dataOrg,
 | |
|     CalpontDateTimeFormat datetimeFormat,
 | |
|     int& status,
 | |
|     unsigned int dataOrgLen )
 | |
| {
 | |
|     status = 0;
 | |
|     char* p;
 | |
|     char* retp = NULL;
 | |
|     char* savePoint = NULL;
 | |
|     p = const_cast<char*>(dataOrg);
 | |
|     int64_t value = 0;
 | |
|     int inHour, inMinute, inSecond, inMicrosecond;
 | |
|     inHour        = 0;
 | |
|     inMinute      = 0;
 | |
|     inSecond      = 0;
 | |
|     inMicrosecond = 0;
 | |
|     bool isNeg = false;
 | |
| 
 | |
|     if ( datetimeFormat != CALPONTTIME_ENUM )
 | |
|     {
 | |
|         status = -1;
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     if (dataOrgLen == 0)
 | |
|     {
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     if (dataOrgLen < 3)
 | |
|     {
 | |
|         // Not enough chars to be a time
 | |
|         status = -1;
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     if (p[0] == '-')
 | |
|     {
 | |
|         isNeg = true;
 | |
|     }
 | |
| 
 | |
|     errno = 0;
 | |
| 
 | |
|     p = strtok_r(p, ":.", &savePoint);
 | |
|     inHour = strtol(p, &retp, 10);
 | |
| 
 | |
|     if (errno || !retp)
 | |
|     {
 | |
|         status = -1;
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     p = strtok_r(NULL, ":.", &savePoint);
 | |
| 
 | |
|     if (p == NULL)
 | |
|     {
 | |
|         status = -1;
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     inMinute = strtol(p, &retp, 10);
 | |
| 
 | |
|     if (errno || !retp)
 | |
|     {
 | |
|         status = -1;
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     p = strtok_r(NULL, ":.", &savePoint);
 | |
| 
 | |
|     if (p == NULL)
 | |
|     {
 | |
|         status = -1;
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     inSecond = strtol(p, &retp, 10);
 | |
| 
 | |
|     if (errno || !retp)
 | |
|     {
 | |
|         status = -1;
 | |
|         return value;
 | |
|     }
 | |
| 
 | |
|     p = strtok_r(NULL, ":.", &savePoint);
 | |
| 
 | |
|     if (p != NULL)
 | |
|     {
 | |
|         inMicrosecond = strtol(p, &retp, 10);
 | |
| 
 | |
|         if (errno || !retp)
 | |
|         {
 | |
|             status = -1;
 | |
|             return value;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if ( isTimeValid (inHour, inMinute, inSecond, inMicrosecond) )
 | |
|     {
 | |
|         Time atime;
 | |
|         atime.hour = inHour;
 | |
|         atime.minute = inMinute;
 | |
|         atime.second = inSecond;
 | |
|         atime.msecond = inMicrosecond;
 | |
|         atime.is_neg = isNeg;
 | |
| 
 | |
|         memcpy( &value, &atime, 8);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         // Emulate MariaDB's time saturation
 | |
|         if (inHour > 838)
 | |
|         {
 | |
|             Time atime;
 | |
|             atime.hour = 838;
 | |
|             atime.minute = 59;
 | |
|             atime.second = 59;
 | |
|             atime.msecond = 999999;
 | |
|             atime.is_neg = false;
 | |
|             memcpy( &value, &atime, 8);
 | |
|         }
 | |
|         else if (inHour < -838)
 | |
|         {
 | |
|             Time atime;
 | |
|             atime.hour = -838;
 | |
|             atime.minute = 59;
 | |
|             atime.second = 59;
 | |
|             atime.msecond = 999999;
 | |
|             atime.is_neg = false;
 | |
|             memcpy( &value, &atime, 8);
 | |
|         }
 | |
| 
 | |
|         // If neither of the above match then we return a 0 time
 | |
| 
 | |
|         status = -1;
 | |
|     }
 | |
| 
 | |
|     return value;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Verify that specified datetime is valid
 | |
| //------------------------------------------------------------------------------
 | |
| bool DataConvert::isColumnDateTimeValid( int64_t dateTime )
 | |
| {
 | |
|     DateTime dt;
 | |
|     memcpy(&dt, &dateTime, sizeof(uint64_t));
 | |
| 
 | |
|     if (isDateValid(dt.day, dt.month, dt.year))
 | |
|         return isDateTimeValid(dt.hour, dt.minute, dt.second, dt.msecond);
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| bool DataConvert::isColumnTimeValid( int64_t time )
 | |
| {
 | |
|     Time dt;
 | |
|     memcpy(&dt, &time, sizeof(uint64_t));
 | |
| 
 | |
|     return isTimeValid(dt.hour, dt.minute, dt.second, dt.msecond);
 | |
| }
 | |
| 
 | |
| std::string DataConvert::dateToString( int  datevalue )
 | |
| {
 | |
|     // @bug 4703 abandon multiple ostringstream's for conversion
 | |
|     Date d(datevalue);
 | |
|     const int DATETOSTRING_LEN = 12; // YYYY-MM-DD\0
 | |
|     char buf[DATETOSTRING_LEN];
 | |
| 
 | |
|     sprintf(buf, "%04d-%02d-%02d", d.year, d.month, d.day);
 | |
|     return buf;
 | |
| }
 | |
| 
 | |
| std::string DataConvert::datetimeToString( long long  datetimevalue, long decimals )
 | |
| {
 | |
|     // 10 is default which means we don't need microseconds
 | |
|     if (decimals > 6 || decimals < 0)
 | |
|     {
 | |
|         decimals = 0;
 | |
|     }
 | |
| 
 | |
|     // @bug 4703 abandon multiple ostringstream's for conversion
 | |
|     DateTime dt(datetimevalue);
 | |
|     const int DATETIMETOSTRING_LEN = 28; // YYYY-MM-DD HH:MM:SS.mmmmmm\0
 | |
|     char buf[DATETIMETOSTRING_LEN];
 | |
| 
 | |
|     sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second);
 | |
| 
 | |
|     if (dt.msecond && decimals)
 | |
|     {
 | |
|         // Pad start with zeros
 | |
|         sprintf(buf + strlen(buf), ".%0*d", (int)decimals, dt.msecond);
 | |
|     }
 | |
| 
 | |
|     return buf;
 | |
| }
 | |
| 
 | |
| std::string DataConvert::timeToString( long long  timevalue, long decimals )
 | |
| {
 | |
|     // 10 is default which means we don't need microseconds
 | |
|     if (decimals > 6 || decimals < 0)
 | |
|     {
 | |
|         decimals = 0;
 | |
|     }
 | |
| 
 | |
|     // @bug 4703 abandon multiple ostringstream's for conversion
 | |
|     Time dt(timevalue);
 | |
|     const int TIMETOSTRING_LEN = 19; // (-H)HH:MM:SS.mmmmmm\0
 | |
|     char buf[TIMETOSTRING_LEN];
 | |
|     char* outbuf = buf;
 | |
| 
 | |
|     if ((dt.hour >= 0) && dt.is_neg)
 | |
|     {
 | |
|         outbuf[0] = '-';
 | |
|         outbuf++;
 | |
|     }
 | |
| 
 | |
|     sprintf(outbuf, "%02d:%02d:%02d", dt.hour, dt.minute, dt.second);
 | |
| 
 | |
|     if (dt.msecond && decimals)
 | |
|     {
 | |
|         // Pad start with zeros
 | |
|         sprintf(buf + strlen(buf), ".%0*d", (int)decimals, dt.msecond);
 | |
|     }
 | |
| 
 | |
|     return buf;
 | |
| }
 | |
| 
 | |
| std::string DataConvert::dateToString1( int  datevalue )
 | |
| {
 | |
|     // @bug 4703 abandon multiple ostringstream's for conversion
 | |
|     Date d(datevalue);
 | |
|     const int DATETOSTRING1_LEN = 10; // YYYYMMDD\0
 | |
|     char buf[DATETOSTRING1_LEN];
 | |
| 
 | |
|     sprintf(buf, "%04d%02d%02d", d.year, d.month, d.day);
 | |
|     return buf;
 | |
| }
 | |
| 
 | |
| std::string DataConvert::datetimeToString1( long long  datetimevalue )
 | |
| {
 | |
|     // @bug 4703 abandon multiple ostringstream's for conversion
 | |
|     DateTime dt(datetimevalue);
 | |
|     const int DATETIMETOSTRING1_LEN = 22; // YYYYMMDDHHMMSSmmmmmm\0
 | |
|     char buf[DATETIMETOSTRING1_LEN];
 | |
| 
 | |
|     sprintf(buf, "%04d%02d%02d%02d%02d%02d%06d", dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.msecond);
 | |
|     return buf;
 | |
| }
 | |
| 
 | |
| std::string DataConvert::timeToString1( long long  datetimevalue )
 | |
| {
 | |
|     // @bug 4703 abandon multiple ostringstream's for conversion
 | |
|     DateTime dt(datetimevalue);
 | |
|     const int TIMETOSTRING1_LEN = 14; // HHMMSSmmmmmm\0
 | |
|     char buf[TIMETOSTRING1_LEN];
 | |
| 
 | |
|     char* outbuf = buf;
 | |
| 
 | |
|     sprintf(outbuf, "%02d%02d%02d%06d", dt.hour, dt.minute, dt.second, dt.msecond);
 | |
|     return buf;
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| bool DataConvert::isNullData(ColumnResult* cr, int rownum, CalpontSystemCatalog::ColType colType)
 | |
| {
 | |
|     switch (colType.colDataType)
 | |
|     {
 | |
|         case CalpontSystemCatalog::TINYINT:
 | |
|             if (cr->GetData(rownum) == joblist::TINYINTNULL)
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         case CalpontSystemCatalog::SMALLINT:
 | |
|             if (cr->GetData(rownum) == joblist::SMALLINTNULL)
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         case CalpontSystemCatalog::MEDINT:
 | |
|         case CalpontSystemCatalog::INT:
 | |
|             if (cr->GetData(rownum) == joblist::INTNULL)
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         case CalpontSystemCatalog::BIGINT:
 | |
|             if (cr->GetData(rownum) == static_cast<int64_t>(joblist::BIGINTNULL))
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         case CalpontSystemCatalog::DECIMAL:
 | |
|         case CalpontSystemCatalog::UDECIMAL:
 | |
|         {
 | |
|             if (colType.colWidth <= CalpontSystemCatalog::FOUR_BYTE)
 | |
|             {
 | |
|                 if (cr->GetData(rownum) == joblist::SMALLINTNULL)
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|             else if (colType.colWidth <= 9)
 | |
|             {
 | |
|                 if (cr->GetData(rownum) == joblist::INTNULL)
 | |
|                     return true;
 | |
|                 else return false;
 | |
|             }
 | |
|             else if (colType.colWidth <= 18)
 | |
|             {
 | |
|                 if (cr->GetData(rownum) == static_cast<int64_t>(joblist::BIGINTNULL))
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (cr->GetStringData(rownum) == "\376\377\377\377\377\377\377\377")
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         case CalpontSystemCatalog::FLOAT:
 | |
|         case CalpontSystemCatalog::UFLOAT:
 | |
| 
 | |
|             //if (cr->GetStringData(rownum) == joblist::FLOATNULL)
 | |
|             if (cr->GetStringData(rownum).compare("null") == 0 )
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         case CalpontSystemCatalog::DOUBLE:
 | |
|         case CalpontSystemCatalog::UDOUBLE:
 | |
| 
 | |
|             //if (cr->GetStringData(rownum) == joblist::DOUBLENULL)
 | |
|             if (cr->GetStringData(rownum).compare("null") == 0 )
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         case CalpontSystemCatalog::DATE:
 | |
|             if (cr->GetData(rownum) == joblist::DATENULL)
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         case CalpontSystemCatalog::DATETIME:
 | |
|             if (cr->GetData(rownum) == static_cast<int64_t>(joblist::DATETIMENULL))
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         case CalpontSystemCatalog::CHAR:
 | |
|         {
 | |
|             std::string charnull;
 | |
| 
 | |
|             if ( cr->GetStringData(rownum) == "")
 | |
|             {
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             if (colType.colWidth == 1)
 | |
|             {
 | |
|                 if (cr->GetStringData(rownum) == "\376")
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|             else if (colType.colWidth == 2)
 | |
|             {
 | |
|                 if (cr->GetStringData(rownum) == "\377\376")
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|             else if (( colType.colWidth < 5 ) && ( colType.colWidth > 2 ))
 | |
|             {
 | |
|                 if (cr->GetStringData(rownum) == "\377\377\377\376")
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|             else if (( colType.colWidth < 9 ) && ( colType.colWidth > 4 ))
 | |
|             {
 | |
|                 if (cr->GetStringData(rownum) == "\377\377\377\377\377\377\377\376")
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (cr->GetStringData(rownum) == "\376\377\377\377\377\377\377\377")
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         case CalpontSystemCatalog::VARCHAR:
 | |
|         {
 | |
|             std::string charnull;
 | |
| 
 | |
|             if ( cr->GetStringData(rownum) == "")
 | |
|             {
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             if (colType.colWidth == 1)
 | |
|             {
 | |
|                 if (cr->GetStringData(rownum) == "\377\376")
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|             else if ((colType.colWidth < 4)  && (colType.colWidth > 1))
 | |
|             {
 | |
|                 if (cr->GetStringData(rownum) == "\377\377\377\376")
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|             else if ((colType.colWidth < 8)  && (colType.colWidth > 3))
 | |
|             {
 | |
|                 if (cr->GetStringData(rownum) == "\377\377\377\377\377\377\377\376")
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 WriteEngine::Token nullToken;
 | |
| 
 | |
|                 // bytes reversed
 | |
|                 if (cr->GetStringData(rownum) == "\376\377\377\377\377\377\377\377")
 | |
|                     return true;
 | |
| 
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         case CalpontSystemCatalog::UTINYINT:
 | |
|             if (cr->GetData(rownum) == joblist::UTINYINTNULL)
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         case CalpontSystemCatalog::USMALLINT:
 | |
|             if (cr->GetData(rownum) == joblist::USMALLINTNULL)
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         case CalpontSystemCatalog::UMEDINT:
 | |
|         case CalpontSystemCatalog::UINT:
 | |
|             if (cr->GetData(rownum) == joblist::UINTNULL)
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         case CalpontSystemCatalog::UBIGINT:
 | |
|             if (cr->GetData(rownum) == joblist::UBIGINTNULL)
 | |
|                 return true;
 | |
| 
 | |
|             return false;
 | |
| 
 | |
|         default:
 | |
|             throw QueryDataExcept("convertColumnData: unknown column data type.", dataTypeErr);
 | |
|     }
 | |
| }
 | |
| #endif
 | |
| int64_t DataConvert::dateToInt(const string& date)
 | |
| {
 | |
|     return stringToDate(date);
 | |
| }
 | |
| 
 | |
| int64_t DataConvert::datetimeToInt(const string& datetime)
 | |
| {
 | |
|     return stringToDatetime(datetime);
 | |
| }
 | |
| 
 | |
| int64_t DataConvert::timeToInt(const string& time)
 | |
| {
 | |
|     return stringToTime(time);
 | |
| }
 | |
| 
 | |
| int64_t DataConvert::stringToDate(const string& data)
 | |
| {
 | |
|     Date aDay;
 | |
| 
 | |
|     if ( stringToDateStruct( data, aDay ) )
 | |
|         return (((*(reinterpret_cast<uint32_t*> (&aDay))) & 0xFFFFFFC0) | 0x3E);
 | |
|     else
 | |
|         return -1;
 | |
| }
 | |
| 
 | |
| int64_t DataConvert::stringToDatetime(const string& data, bool* date)
 | |
| {
 | |
|     DateTime dtime;
 | |
| 
 | |
|     if ( stringToDatetimeStruct( data, dtime, date ) )
 | |
|         return *(reinterpret_cast<uint64_t*>(&dtime));
 | |
|     else
 | |
|         return -1;
 | |
| }
 | |
| 
 | |
| int64_t DataConvert::intToDate(int64_t data)
 | |
| {
 | |
|     //char buf[10] = {0};
 | |
|     //snprintf( buf, 10, "%llu", (long long unsigned int)data);
 | |
|     //string date = buf;
 | |
|     char buf[21] = {0};
 | |
|     Date aday;
 | |
| 
 | |
|     if (data == 0)
 | |
|     {
 | |
|         aday.year = 0;
 | |
|         aday.month = 0;
 | |
|         aday.day = 0;
 | |
|         return *(reinterpret_cast<uint32_t*>(&aday));
 | |
|     }
 | |
| 
 | |
|     snprintf( buf, 15, "%llu", (long long unsigned int)data);
 | |
| 
 | |
|     string year, month, day, hour, min, sec, msec;
 | |
|     int64_t y = 0, m = 0, d = 0, h = 0, minute = 0, s = 0, ms = 0;
 | |
| 
 | |
|     switch (strlen(buf))
 | |
|     {
 | |
|         case 14:
 | |
|             year = string(buf, 4);
 | |
|             month = string(buf + 4, 2);
 | |
|             day = string(buf + 6, 2);
 | |
|             hour = string(buf + 8, 2);
 | |
|             min = string(buf + 10, 2);
 | |
|             sec = string(buf + 12, 2);
 | |
|             msec = string(buf + 14, 6);
 | |
|             break;
 | |
| 
 | |
|         case 12:
 | |
|             year = string(buf, 2);
 | |
|             month = string(buf + 2, 2);
 | |
|             day = string(buf + 4, 2);
 | |
|             hour = string(buf + 6, 2);
 | |
|             min = string(buf + 8, 2);
 | |
|             sec = string(buf + 10, 2);
 | |
|             msec = string(buf + 12, 6);
 | |
|             break;
 | |
| 
 | |
|         case 10:
 | |
|             month = string(buf, 2);
 | |
|             day = string(buf + 2, 2);
 | |
|             hour = string(buf + 4, 2);
 | |
|             min = string(buf + 6, 2);
 | |
|             sec = string(buf + 8, 2);
 | |
|             msec = string(buf + 10, 6);
 | |
|             break;
 | |
| 
 | |
|         case 9:
 | |
|             month = string(buf, 1);
 | |
|             day = string(buf + 1, 2);
 | |
|             hour = string(buf + 3, 2);
 | |
|             min = string(buf + 5, 2);
 | |
|             sec = string(buf + 7, 2);
 | |
|             msec = string(buf + 9, 6);
 | |
|             break;
 | |
| 
 | |
|         case 8:
 | |
|             year = string(buf, 4);
 | |
|             month = string(buf + 4, 2);
 | |
|             day = string(buf + 6, 2);
 | |
|             break;
 | |
| 
 | |
|         case 6:
 | |
|             year = string(buf, 2);
 | |
|             month = string(buf + 2, 2);
 | |
|             day = string(buf + 4, 2);
 | |
|             break;
 | |
| 
 | |
|         case 4:
 | |
|             month = string(buf, 2);
 | |
|             day = string(buf + 2, 2);
 | |
|             break;
 | |
| 
 | |
|         case 3:
 | |
|             month = string(buf, 1);
 | |
|             day = string(buf + 1, 2);
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             return -1;
 | |
|     }
 | |
| 
 | |
|     if (year.empty())
 | |
|     {
 | |
|         // MMDD format. assume current year
 | |
|         time_t calender_time;
 | |
|         struct tm todays_date;
 | |
|         calender_time = time(NULL);
 | |
|         localtime_r(&calender_time, &todays_date);
 | |
|         y = todays_date.tm_year + 1900;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         y = atoi(year.c_str());
 | |
|     }
 | |
| 
 | |
|     m = atoi(month.c_str());
 | |
|     d = atoi(day.c_str());
 | |
|     h = atoi(hour.c_str());
 | |
|     minute = atoi(min.c_str());
 | |
|     s = atoi(sec.c_str());
 | |
|     ms = atoi(msec.c_str());
 | |
| 
 | |
|     //if (!isDateValid(d, m, y))
 | |
|     //	return -1;
 | |
|     if (!isDateValid(d, m, y) || !isDateTimeValid(h, minute, s, ms))
 | |
|         return -1;
 | |
| 
 | |
|     aday.year = y;
 | |
|     aday.month = m;
 | |
|     aday.day = d;
 | |
|     return *(reinterpret_cast<uint32_t*>(&aday));
 | |
| }
 | |
| 
 | |
| int64_t DataConvert::intToDatetime(int64_t data, bool* date)
 | |
| {
 | |
|     bool isDate = false;
 | |
|     char buf[21] = {0};
 | |
|     DateTime adaytime;
 | |
| 
 | |
|     if (data == 0)
 | |
|     {
 | |
|         adaytime.year = 0;
 | |
|         adaytime.month = 0;
 | |
|         adaytime.day = 0;
 | |
|         adaytime.hour = 0;
 | |
|         adaytime.minute = 0;
 | |
|         adaytime.second = 0;
 | |
|         adaytime.msecond = 0;
 | |
| 
 | |
|         if (date)
 | |
|             *date = true;
 | |
| 
 | |
|         return *(reinterpret_cast<uint64_t*>(&adaytime));
 | |
|     }
 | |
| 
 | |
|     snprintf( buf, 15, "%llu", (long long unsigned int)data);
 | |
|     //string date = buf;
 | |
|     string year, month, day, hour, min, sec, msec;
 | |
|     int64_t y = 0, m = 0, d = 0, h = 0, minute = 0, s = 0, ms = 0;
 | |
| 
 | |
|     switch (strlen(buf))
 | |
|     {
 | |
|         case 14:
 | |
|             year = string(buf, 4);
 | |
|             month = string(buf + 4, 2);
 | |
|             day = string(buf + 6, 2);
 | |
|             hour = string(buf + 8, 2);
 | |
|             min = string(buf + 10, 2);
 | |
|             sec = string(buf + 12, 2);
 | |
|             break;
 | |
| 
 | |
|         case 12:
 | |
|             year = string(buf, 2);
 | |
|             month = string(buf + 2, 2);
 | |
|             day = string(buf + 4, 2);
 | |
|             hour = string(buf + 6, 2);
 | |
|             min = string(buf + 8, 2);
 | |
|             sec = string(buf + 10, 2);
 | |
|             break;
 | |
| 
 | |
|         case 10:
 | |
|             month = string(buf, 2);
 | |
|             day = string(buf + 2, 2);
 | |
|             hour = string(buf + 4, 2);
 | |
|             min = string(buf + 6, 2);
 | |
|             sec = string(buf + 8, 2);
 | |
|             break;
 | |
| 
 | |
|         case 9:
 | |
|             month = string(buf, 1);
 | |
|             day = string(buf + 1, 2);
 | |
|             hour = string(buf + 3, 2);
 | |
|             min = string(buf + 5, 2);
 | |
|             sec = string(buf + 7, 2);
 | |
|             break;
 | |
| 
 | |
|         case 8:
 | |
|             year = string(buf, 4);
 | |
|             month = string(buf + 4, 2);
 | |
|             day = string(buf + 6, 2);
 | |
|             isDate = true;
 | |
|             break;
 | |
| 
 | |
|         case 6:
 | |
|             year = string(buf, 2);
 | |
|             month = string(buf + 2, 2);
 | |
|             day = string(buf + 4, 2);
 | |
|             isDate = true;
 | |
|             break;
 | |
| 
 | |
|         case 4:
 | |
|             month = string(buf, 2);
 | |
|             day = string(buf + 2, 2);
 | |
|             break;
 | |
| 
 | |
|         case 3:
 | |
|             month = string(buf, 1);
 | |
|             day = string(buf + 1, 2);
 | |
|             isDate = true;
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             return -1;
 | |
|     }
 | |
| 
 | |
|     if (year.empty())
 | |
|     {
 | |
|         // MMDD format. assume current year
 | |
|         time_t calender_time;
 | |
|         struct tm todays_date;
 | |
|         calender_time = time(NULL);
 | |
|         localtime_r(&calender_time, &todays_date);
 | |
|         y = todays_date.tm_year + 1900;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         y = atoi(year.c_str());
 | |
|     }
 | |
| 
 | |
|     m = atoi(month.c_str());
 | |
|     d = atoi(day.c_str());
 | |
|     h = atoi(hour.c_str());
 | |
|     minute = atoi(min.c_str());
 | |
|     s = atoi(sec.c_str());
 | |
|     ms = 0;
 | |
| 
 | |
|     if (!isDateValid(d, m, y) || !isDateTimeValid(h, minute, s, ms))
 | |
|         return -1;
 | |
| 
 | |
|     adaytime.year = y;
 | |
|     adaytime.month = m;
 | |
|     adaytime.day = d;
 | |
|     adaytime.hour = h;
 | |
|     adaytime.minute = minute;
 | |
|     adaytime.second = s;
 | |
|     adaytime.msecond = ms;
 | |
| 
 | |
|     if (date)
 | |
|         *date = isDate;
 | |
| 
 | |
|     return *(reinterpret_cast<uint64_t*>(&adaytime));
 | |
| }
 | |
| 
 | |
| int64_t DataConvert::intToTime(int64_t data, bool fromString)
 | |
| {
 | |
|     char buf[21] = {0};
 | |
|     char* bufread = buf;
 | |
|     Time atime;
 | |
|     bool isNeg = false;
 | |
| 
 | |
|     if (data == 0)
 | |
|     {
 | |
|         atime.hour = 0;
 | |
|         atime.minute = 0;
 | |
|         atime.second = 0;
 | |
|         atime.msecond = 0;
 | |
|         atime.is_neg = 0;
 | |
| 
 | |
|         return *(reinterpret_cast<int64_t*>(&atime));
 | |
|     }
 | |
| 
 | |
|     snprintf( buf, 15, "%llu", (long long unsigned int)data);
 | |
|     //string date = buf;
 | |
|     string hour, min, sec, msec;
 | |
|     int64_t h = 0, minute = 0, s = 0, ms = 0;
 | |
| 
 | |
|     if (bufread[0] == '-')
 | |
|     {
 | |
|         isNeg = true;
 | |
|         bufread++;
 | |
|     }
 | |
| 
 | |
|     bool zero = false;
 | |
| 
 | |
|     switch (strlen(bufread))
 | |
|     {
 | |
|         // A full datetime
 | |
|         case 14:
 | |
|             hour = string(buf + 8, 2);
 | |
|             min = string(buf + 10, 2);
 | |
|             sec = string(buf + 12, 2);
 | |
|             break;
 | |
| 
 | |
|         // Date so this is all 0
 | |
|         case 8:
 | |
|             zero = true;
 | |
|             break;
 | |
| 
 | |
|         case 7:
 | |
|             hour = string(bufread, 3);
 | |
|             min = string(bufread + 2, 2);
 | |
|             sec = string(bufread + 4, 2);
 | |
|             break;
 | |
| 
 | |
|         case 6:
 | |
|             hour = string(bufread, 2);
 | |
|             min = string(bufread + 2, 2);
 | |
|             sec = string(bufread + 4, 2);
 | |
|             break;
 | |
| 
 | |
|         case 5:
 | |
|             hour = string(bufread, 1);
 | |
|             min = string(bufread + 1, 2);
 | |
|             sec = string(bufread + 3, 2);
 | |
|             break;
 | |
| 
 | |
|         case 4:
 | |
|             min = string(bufread, 2);
 | |
|             sec = string(bufread + 2, 2);
 | |
|             break;
 | |
| 
 | |
|         case 3:
 | |
|             min = string(bufread, 1);
 | |
|             sec = string(bufread + 1, 2);
 | |
|             break;
 | |
| 
 | |
|         case 2:
 | |
|             sec = string(bufread, 2);
 | |
|             break;
 | |
| 
 | |
|         case 1:
 | |
|             sec = string(bufread, 1);
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             return -1;
 | |
|     }
 | |
| 
 | |
|     if (!zero)
 | |
|     {
 | |
|         h = atoi(hour.c_str());
 | |
|         minute = atoi(min.c_str());
 | |
|         s = atoi(sec.c_str());
 | |
|     }
 | |
|     else if (fromString)
 | |
|     {
 | |
|         // Saturate fromString
 | |
|         h = 838;
 | |
|         minute = 59;
 | |
|         s = 59;
 | |
|         ms = 999999;
 | |
|     }
 | |
| 
 | |
|     if (!isTimeValid(h, minute, s, 0))
 | |
|         return -1;
 | |
| 
 | |
|     atime.hour = h;
 | |
|     atime.minute = minute;
 | |
|     atime.second = s;
 | |
|     atime.msecond = ms;
 | |
|     atime.is_neg = isNeg;
 | |
| 
 | |
|     return *(reinterpret_cast<uint64_t*>(&atime));
 | |
| }
 | |
| 
 | |
| int64_t DataConvert::stringToTime(const string& data)
 | |
| {
 | |
|     // MySQL supported time value format 'D HHH:MM:SS.fraction'
 | |
|     // -34 <= D <= 34
 | |
|     // -838 <= H <= 838
 | |
|     uint64_t min = 0, sec = 0, msec = 0;
 | |
|     int64_t day = -1, hour = 0;
 | |
|     bool isNeg = false;
 | |
|     bool hasDate = false;
 | |
|     string time, hms, ms;
 | |
|     char* end = NULL;
 | |
| 
 | |
| 
 | |
|     size_t pos = data.find("-");
 | |
| 
 | |
|     if (pos != string::npos)
 | |
|     {
 | |
|         isNeg = true;
 | |
|     }
 | |
| 
 | |
|     if (data.substr(pos+1, data.length()-pos-1).find("-") != string::npos)
 | |
|     {
 | |
|         // A second dash, this has a date
 | |
|         hasDate = true;
 | |
|         isNeg = false;
 | |
|     }
 | |
|     // Day
 | |
|     pos = data.find(" ");
 | |
| 
 | |
|     if (pos != string::npos)
 | |
|     {
 | |
|         if (!hasDate)
 | |
|         {
 | |
|             day = strtol(data.substr(0, pos).c_str(), &end, 10);
 | |
| 
 | |
|             if (*end != '\0')
 | |
|                 return -1;
 | |
| 
 | |
|             hour = day * 24;
 | |
|             day = -1;
 | |
|         }
 | |
|         time = data.substr(pos + 1, data.length() - pos - 1);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         time = data;
 | |
|     }
 | |
| 
 | |
|     if (time.find(":") == string::npos)
 | |
|     {
 | |
|         if (hasDate)
 | |
|         {
 | |
|             // Has dashes, no colons. This is just a date!
 | |
|             // Or the length < 6 (MariaDB returns NULL)
 | |
|             return -1;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // This is an int time
 | |
|             return intToTime(atoll(time.c_str()), true);
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     // Fraction
 | |
|     pos = time.find(".");
 | |
| 
 | |
|     if (pos != string::npos)
 | |
|     {
 | |
|         msec = strtoll(time.substr(pos + 1, time.length() - pos - 1).c_str(), 0, 10);
 | |
|         hms = time.substr(0, pos);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         hms = time;
 | |
|     }
 | |
| 
 | |
|     // HHH:MM:SS
 | |
|     pos = hms.find(":");
 | |
| 
 | |
|     if (pos == string::npos)
 | |
|     {
 | |
|         if (hour >= 0)
 | |
|             hour += atoi(hms.c_str());
 | |
|         else
 | |
|             hour -= atoi(hms.c_str());
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         if (hour >= 0)
 | |
|             hour += atoi(hms.substr(0, pos).c_str());
 | |
|         else
 | |
|             hour -= atoi(hms.substr(0, pos).c_str());
 | |
| 
 | |
|         ms = hms.substr(pos + 1, hms.length() - pos - 1);
 | |
|     }
 | |
| 
 | |
|     // MM:SS
 | |
|     pos = ms.find(":");
 | |
| 
 | |
|     if (pos != string::npos)
 | |
|     {
 | |
|         min = atoi(ms.substr(0, pos).c_str());
 | |
|         sec = atoi(ms.substr(pos + 1, ms.length() - pos - 1).c_str());
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         min = atoi(ms.c_str());
 | |
|     }
 | |
| 
 | |
|     Time atime;
 | |
|     atime.day = day;
 | |
|     atime.hour = hour;
 | |
|     atime.minute = min;
 | |
|     atime.second = sec;
 | |
|     atime.msecond = msec;
 | |
|     atime.is_neg = isNeg;
 | |
|     return *(reinterpret_cast<int64_t*>(&atime));
 | |
| }
 | |
| 
 | |
| CalpontSystemCatalog::ColType DataConvert::convertUnionColType(vector<CalpontSystemCatalog::ColType>& types)
 | |
| {
 | |
|     idbassert(types.size());
 | |
| 
 | |
|     CalpontSystemCatalog::ColType unionedType = types[0];
 | |
| 
 | |
|     for (uint64_t i = 1; i < types.size(); i++)
 | |
|     {
 | |
|         // limited support for VARBINARY, no implicit conversion.
 | |
|         if (types[i].colDataType == CalpontSystemCatalog::VARBINARY ||
 | |
|                 unionedType.colDataType == CalpontSystemCatalog::VARBINARY)
 | |
|         {
 | |
|             if (types[i].colDataType != unionedType.colDataType ||
 | |
|                     types[i].colWidth != unionedType.colWidth)
 | |
|                 throw runtime_error("VARBINARY in UNION must be the same width.");
 | |
|         }
 | |
| 
 | |
|         switch (types[i].colDataType)
 | |
|         {
 | |
|             case CalpontSystemCatalog::TINYINT:
 | |
|             case CalpontSystemCatalog::SMALLINT:
 | |
|             case CalpontSystemCatalog::MEDINT:
 | |
|             case CalpontSystemCatalog::INT:
 | |
|             case CalpontSystemCatalog::BIGINT:
 | |
|             case CalpontSystemCatalog::DECIMAL:
 | |
|             case CalpontSystemCatalog::UTINYINT:
 | |
|             case CalpontSystemCatalog::USMALLINT:
 | |
|             case CalpontSystemCatalog::UMEDINT:
 | |
|             case CalpontSystemCatalog::UINT:
 | |
|             case CalpontSystemCatalog::UBIGINT:
 | |
|             case CalpontSystemCatalog::UDECIMAL:
 | |
|             {
 | |
|                 switch (unionedType.colDataType)
 | |
|                 {
 | |
|                     case CalpontSystemCatalog::TINYINT:
 | |
|                     case CalpontSystemCatalog::SMALLINT:
 | |
|                     case CalpontSystemCatalog::MEDINT:
 | |
|                     case CalpontSystemCatalog::INT:
 | |
|                     case CalpontSystemCatalog::BIGINT:
 | |
|                     case CalpontSystemCatalog::DECIMAL:
 | |
|                     case CalpontSystemCatalog::UTINYINT:
 | |
|                     case CalpontSystemCatalog::USMALLINT:
 | |
|                     case CalpontSystemCatalog::UMEDINT:
 | |
|                     case CalpontSystemCatalog::UINT:
 | |
|                     case CalpontSystemCatalog::UBIGINT:
 | |
|                     case CalpontSystemCatalog::UDECIMAL:
 | |
|                         if (types[i].colWidth > unionedType.colWidth)
 | |
|                         {
 | |
|                             unionedType.colDataType = types[i].colDataType;
 | |
|                             unionedType.colWidth = types[i].colWidth;
 | |
|                         }
 | |
| 
 | |
|                         // If same size and result is signed but source is unsigned...
 | |
|                         if (types[i].colWidth == unionedType.colWidth && !isUnsigned(unionedType.colDataType) && isUnsigned(types[i].colDataType))
 | |
|                         {
 | |
|                             unionedType.colDataType = types[i].colDataType;
 | |
|                         }
 | |
| 
 | |
|                         if (types[i].colDataType == CalpontSystemCatalog::DECIMAL || types[i].colDataType == CalpontSystemCatalog::UDECIMAL)
 | |
|                         {
 | |
|                             unionedType.colDataType = CalpontSystemCatalog::DECIMAL;
 | |
|                         }
 | |
| 
 | |
|                         unionedType.scale = (types[i].scale > unionedType.scale) ? types[i].scale : unionedType.scale;
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::DATE:
 | |
|                         unionedType.colDataType = CalpontSystemCatalog::CHAR;
 | |
|                         unionedType.colWidth = 20;
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::TIME:
 | |
|                     case CalpontSystemCatalog::DATETIME:
 | |
|                         unionedType.colDataType = CalpontSystemCatalog::CHAR;
 | |
|                         unionedType.colWidth = 26;
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::CHAR:
 | |
|                         if (unionedType.colWidth < 20)
 | |
|                             unionedType.colWidth = 20;
 | |
| 
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::VARCHAR:
 | |
|                         if (unionedType.colWidth < 21)
 | |
|                             unionedType.colWidth = 21;
 | |
| 
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::FLOAT:
 | |
|                     case CalpontSystemCatalog::DOUBLE:
 | |
|                     case CalpontSystemCatalog::UFLOAT:
 | |
|                     case CalpontSystemCatalog::UDOUBLE:
 | |
|                     default:
 | |
|                         break;
 | |
|                 }
 | |
| 
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case CalpontSystemCatalog::DATE:
 | |
|             {
 | |
|                 switch (unionedType.colDataType)
 | |
|                 {
 | |
|                     case CalpontSystemCatalog::TINYINT:
 | |
|                     case CalpontSystemCatalog::SMALLINT:
 | |
|                     case CalpontSystemCatalog::MEDINT:
 | |
|                     case CalpontSystemCatalog::INT:
 | |
|                     case CalpontSystemCatalog::BIGINT:
 | |
|                     case CalpontSystemCatalog::DECIMAL:
 | |
|                     case CalpontSystemCatalog::FLOAT:
 | |
|                     case CalpontSystemCatalog::DOUBLE:
 | |
|                     case CalpontSystemCatalog::UTINYINT:
 | |
|                     case CalpontSystemCatalog::USMALLINT:
 | |
|                     case CalpontSystemCatalog::UMEDINT:
 | |
|                     case CalpontSystemCatalog::UINT:
 | |
|                     case CalpontSystemCatalog::UBIGINT:
 | |
|                     case CalpontSystemCatalog::UDECIMAL:
 | |
|                     case CalpontSystemCatalog::UFLOAT:
 | |
|                     case CalpontSystemCatalog::UDOUBLE:
 | |
|                         unionedType.colDataType = CalpontSystemCatalog::CHAR;
 | |
|                         unionedType.scale = 0;
 | |
|                         unionedType.colWidth = 20;
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::CHAR:
 | |
|                         if (unionedType.colWidth < 10)
 | |
|                             unionedType.colWidth = 10;
 | |
| 
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::VARCHAR:
 | |
|                         if (unionedType.colWidth < 11)
 | |
|                             unionedType.colWidth = 11;
 | |
| 
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::DATE:
 | |
|                     case CalpontSystemCatalog::DATETIME:
 | |
|                     case CalpontSystemCatalog::TIME:
 | |
|                     default:
 | |
|                         break;
 | |
|                 }
 | |
| 
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case CalpontSystemCatalog::DATETIME:
 | |
|             {
 | |
|                 switch (unionedType.colDataType)
 | |
|                 {
 | |
|                     case CalpontSystemCatalog::TINYINT:
 | |
|                     case CalpontSystemCatalog::SMALLINT:
 | |
|                     case CalpontSystemCatalog::MEDINT:
 | |
|                     case CalpontSystemCatalog::INT:
 | |
|                     case CalpontSystemCatalog::BIGINT:
 | |
|                     case CalpontSystemCatalog::DECIMAL:
 | |
|                     case CalpontSystemCatalog::FLOAT:
 | |
|                     case CalpontSystemCatalog::DOUBLE:
 | |
|                     case CalpontSystemCatalog::UTINYINT:
 | |
|                     case CalpontSystemCatalog::USMALLINT:
 | |
|                     case CalpontSystemCatalog::UMEDINT:
 | |
|                     case CalpontSystemCatalog::UINT:
 | |
|                     case CalpontSystemCatalog::UBIGINT:
 | |
|                     case CalpontSystemCatalog::UDECIMAL:
 | |
|                     case CalpontSystemCatalog::UFLOAT:
 | |
|                     case CalpontSystemCatalog::UDOUBLE:
 | |
|                     case CalpontSystemCatalog::TIME:
 | |
|                         unionedType.colDataType = CalpontSystemCatalog::CHAR;
 | |
|                         unionedType.scale = 0;
 | |
|                         unionedType.colWidth = 26;
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::DATE:
 | |
|                         unionedType.colDataType = CalpontSystemCatalog::DATETIME;
 | |
|                         unionedType.colWidth = types[i].colWidth;
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::CHAR:
 | |
|                         if (unionedType.colWidth < 26)
 | |
|                             unionedType.colWidth = 26;
 | |
| 
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::VARCHAR:
 | |
|                         if (unionedType.colWidth < 27)
 | |
|                             unionedType.colWidth = 27;
 | |
| 
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::DATETIME:
 | |
|                     default:
 | |
|                         break;
 | |
|                 }
 | |
| 
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case CalpontSystemCatalog::FLOAT:
 | |
|             case CalpontSystemCatalog::DOUBLE:
 | |
|             case CalpontSystemCatalog::UFLOAT:
 | |
|             case CalpontSystemCatalog::UDOUBLE:
 | |
|             {
 | |
|                 switch (unionedType.colDataType)
 | |
|                 {
 | |
|                     case CalpontSystemCatalog::DATE:
 | |
|                         unionedType.colDataType = CalpontSystemCatalog::CHAR;
 | |
|                         unionedType.scale = 0;
 | |
|                         unionedType.colWidth = 20;
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::DATETIME:
 | |
|                         unionedType.colDataType = CalpontSystemCatalog::CHAR;
 | |
|                         unionedType.scale = 0;
 | |
|                         unionedType.colWidth = 26;
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::CHAR:
 | |
|                         if (unionedType.colWidth < 20)
 | |
|                             unionedType.colWidth = 20;
 | |
| 
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::VARCHAR:
 | |
|                         if (unionedType.colWidth < 21)
 | |
|                             unionedType.colWidth = 21;
 | |
| 
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::TINYINT:
 | |
|                     case CalpontSystemCatalog::SMALLINT:
 | |
|                     case CalpontSystemCatalog::MEDINT:
 | |
|                     case CalpontSystemCatalog::INT:
 | |
|                     case CalpontSystemCatalog::BIGINT:
 | |
|                     case CalpontSystemCatalog::DECIMAL:
 | |
|                     case CalpontSystemCatalog::FLOAT:
 | |
|                     case CalpontSystemCatalog::DOUBLE:
 | |
|                     case CalpontSystemCatalog::UTINYINT:
 | |
|                     case CalpontSystemCatalog::USMALLINT:
 | |
|                     case CalpontSystemCatalog::UMEDINT:
 | |
|                     case CalpontSystemCatalog::UINT:
 | |
|                     case CalpontSystemCatalog::UBIGINT:
 | |
|                     case CalpontSystemCatalog::UDECIMAL:
 | |
|                     case CalpontSystemCatalog::UFLOAT:
 | |
|                     case CalpontSystemCatalog::UDOUBLE:
 | |
|                         unionedType.colDataType = CalpontSystemCatalog::DOUBLE;
 | |
|                         unionedType.scale = 0;
 | |
|                         unionedType.colWidth = sizeof(double);
 | |
|                         break;
 | |
| 
 | |
|                     default:
 | |
|                         break;
 | |
|                 }
 | |
| 
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case CalpontSystemCatalog::CHAR:
 | |
|             case CalpontSystemCatalog::VARCHAR:
 | |
|             {
 | |
|                 switch (unionedType.colDataType)
 | |
|                 {
 | |
|                     case CalpontSystemCatalog::TINYINT:
 | |
|                     case CalpontSystemCatalog::SMALLINT:
 | |
|                     case CalpontSystemCatalog::MEDINT:
 | |
|                     case CalpontSystemCatalog::INT:
 | |
|                     case CalpontSystemCatalog::BIGINT:
 | |
|                     case CalpontSystemCatalog::DECIMAL:
 | |
|                     case CalpontSystemCatalog::FLOAT:
 | |
|                     case CalpontSystemCatalog::DOUBLE:
 | |
|                     case CalpontSystemCatalog::UTINYINT:
 | |
|                     case CalpontSystemCatalog::USMALLINT:
 | |
|                     case CalpontSystemCatalog::UMEDINT:
 | |
|                     case CalpontSystemCatalog::UINT:
 | |
|                     case CalpontSystemCatalog::UBIGINT:
 | |
|                     case CalpontSystemCatalog::UDECIMAL:
 | |
|                     case CalpontSystemCatalog::UFLOAT:
 | |
|                     case CalpontSystemCatalog::UDOUBLE:
 | |
|                         unionedType.scale = 0;
 | |
|                         unionedType.colWidth = (types[i].colWidth > 20) ? types[i].colWidth : 20;
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::DATE:
 | |
|                         unionedType.colWidth = (types[i].colWidth > 10) ? types[i].colWidth : 10;
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::DATETIME:
 | |
|                         unionedType.colWidth = (types[i].colWidth > 26) ? types[i].colWidth : 26;
 | |
|                         break;
 | |
| 
 | |
|                     case CalpontSystemCatalog::CHAR:
 | |
|                     case CalpontSystemCatalog::VARCHAR:
 | |
| 
 | |
|                         // VARCHAR will fit in CHAR of the same width
 | |
|                         if (unionedType.colWidth < types[i].colWidth)
 | |
|                             unionedType.colWidth = types[i].colWidth;
 | |
| 
 | |
|                         break;
 | |
| 
 | |
|                     default:
 | |
|                         break;
 | |
|                 }
 | |
| 
 | |
|                 // MariaDB bug 651. Setting to CHAR broke union in subquery
 | |
|                 unionedType.colDataType = CalpontSystemCatalog::VARCHAR;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             default:
 | |
|             {
 | |
|                 break;
 | |
|             }
 | |
|         } // switch
 | |
|     } // for
 | |
| 
 | |
|     return unionedType;
 | |
| }
 | |
| 
 | |
| } // namespace dataconvert
 | |
| // vim:ts=4 sw=4:
 | |
| 
 |