00001 // $Header: /bes/bes/BossCvs/Calibration/rdbModel/src/Tables/Datatype.cxx,v 1.1.1.1 2005/10/17 06:10:53 maqm Exp $ 00002 #include <iostream> 00003 #include "rdbModel/Tables/Datatype.h" 00004 #include "facilities/Util.h" 00005 #include "facilities/Timestamp.h" 00006 00007 namespace { 00008 00009 using rdbModel::Datatype; 00010 00011 bool initDone = false; 00012 const unsigned int N_SUPPORTED_TYPES = rdbModel::Datatype::TYPEchar + 1; 00013 std::string typenames[N_SUPPORTED_TYPES]; 00014 void init() { 00015 if (!initDone) { 00016 typenames[Datatype::TYPEenum] = std::string("enum"); 00017 typenames[Datatype::TYPEdatetime] = std::string("datetime"); 00018 typenames[Datatype::TYPEtimestamp] = std::string("timestamp"); 00019 typenames[Datatype::TYPEint] = std::string("int"); 00020 typenames[Datatype::TYPEmediumint] = std::string("mediumint"); 00021 typenames[Datatype::TYPEsmallint] = std::string("smallint"); 00022 typenames[Datatype::TYPEreal] = std::string("real"); 00023 typenames[Datatype::TYPEdouble] = std::string("double"); 00024 typenames[Datatype::TYPEvarchar] = std::string("varchar"); 00025 typenames[Datatype::TYPEchar] = std::string("char"); 00026 initDone = true; 00027 } 00028 } 00029 int findType(std::string aType) { 00030 if (!initDone) init(); 00031 for (unsigned int i = 0; i < N_SUPPORTED_TYPES; i++) { 00032 if (aType == typenames[i]) return i; 00033 } 00034 return (int) Datatype::TYPEnotFound; 00035 } 00036 enum TYPE_OF_TYPE { 00037 TOTinteger = 0, 00038 TOTreal, 00039 TOTchar, 00040 TOTdate 00041 }; 00042 int findTOT(Datatype::TYPES aType) { 00043 if ((aType == Datatype::TYPEint) || (aType == Datatype::TYPEmediumint) || 00044 (aType == Datatype::TYPEsmallint)) return TOTinteger; 00045 else if ((aType == Datatype::TYPEreal) || (aType == Datatype::TYPEdouble)) 00046 return TOTreal; 00047 else if ((aType == Datatype::TYPEdatetime) || 00048 (aType == Datatype::TYPEtimestamp)) 00049 return TOTdate; 00050 else return TOTchar; 00051 } 00052 00053 } 00054 00055 namespace rdbModel { 00056 00057 int Datatype::setType(std::string name) { 00058 m_type = (TYPES) findType(name); 00059 if (m_type >=0 ) { 00060 m_typename = name; 00061 } 00062 00063 // Set up initial restrictions for integer-like types. These 00064 // values come from the MySQL doc. See e.g. 00065 // http://www.mysql.com/documentation/mysql/bychapter/manual_Column_types.html#Numeric_types 00066 switch (m_type) { 00067 case TYPEint: { 00068 m_maxInt = 2147483647; 00069 m_minInt = -2147483647; 00070 m_isInt = true; 00071 break; 00072 } 00073 case TYPEmediumint: { 00074 m_maxInt = 8388607; 00075 m_minInt = -8388608; 00076 m_isInt = true; 00077 break; 00078 } 00079 case TYPEsmallint: { 00080 m_maxInt = 32767; 00081 m_minInt = -32768; 00082 m_isInt = true; 00083 break; 00084 } 00085 default: 00086 break; 00087 } 00088 return m_type; 00089 } 00090 00091 // Makes sense only for numeric types or for datetime [or timestamp] 00092 bool Datatype::setInterval(const std::string& min, const std::string& max) { 00093 bool ret = false; 00094 // if ((m_type == TYPEtimestamp) || (m_type == TYPEenum) || 00095 if ( (m_type == TYPEenum) || 00096 (m_type == TYPEchar) || (m_type == TYPEvarchar)) { 00097 std::cerr << "From rdbModel::Datatype::setInterval " << std::endl; 00098 std::cerr << "Cannot set interval restriction for type " << 00099 typenames[m_type] << std::endl; 00100 return false; 00101 } 00102 00103 m_restrict = RESTRICTinterval; 00104 m_min = min; 00105 m_max = max; 00106 00107 // In case data is some integer type, convert min and max to integers, 00108 // store. Return false if anything about them is unreasonable. 00109 if (m_isInt) { 00110 try { 00111 int minInt = facilities::Util::stringToInt(min); 00112 int maxInt = facilities::Util::stringToInt(max); 00113 if (minInt > m_minInt) m_minInt = minInt; 00114 if (maxInt < m_maxInt) m_maxInt = maxInt; 00115 } 00116 catch (facilities::WrongType ex) { 00117 std::cerr << "Error detected in XercesBuilder::buildDatatype " 00118 << std::endl; 00119 std::cerr << ex.getMsg() << std::endl; 00120 return false; 00121 } 00122 ret = (m_min < m_max); 00123 } 00124 // Don't expect to encounter interval restriction for floating point, 00125 // so don't bother to cache values, but at least check for validity 00126 if ((m_type == TYPEdouble) || (m_type == TYPEreal)) { 00127 try { 00128 double minFloat = facilities::Util::stringToDouble(min); 00129 double maxFloat = facilities::Util::stringToDouble(max); 00130 ret = (minFloat < maxFloat); 00131 } 00132 catch (facilities::WrongType ex) { 00133 std::cerr << "Error detected in XercesBuilder::buildDatatype " 00134 << std::endl; 00135 std::cerr << ex.getMsg() << std::endl; 00136 return false; 00137 } 00138 } 00139 if (m_type == TYPEdatetime) { 00140 try { 00141 facilities::Timestamp minTime(min); 00142 facilities::Timestamp maxTime(max); 00143 ret = (minTime < maxTime); 00144 } 00145 catch (facilities::BadTimeInput ex) { 00146 std::cerr << "From rdbModel::Datatype::setInterval" << std::endl; 00147 std::cerr << ex.complaint << std::endl; 00148 return false; 00149 } 00150 } 00151 return ret; 00152 } 00153 00154 bool Datatype::getInterval(std::string& min, std::string& max) { 00155 if (m_restrict == RESTRICTinterval) { 00156 min = m_min; 00157 max = m_max; 00158 return true; 00159 } 00160 return false; 00161 } 00162 00163 00164 bool Datatype::okValue(const std::string& val) const { 00165 using facilities::Util; 00166 00167 switch (m_type) { 00168 case TYPEreal: 00169 case TYPEdouble: { 00170 double doubleVal; 00171 try { 00172 doubleVal = Util::stringToDouble(val); 00173 } 00174 catch (facilities::WrongType ex) { 00175 return false; 00176 } 00177 if (m_restrict == RESTRICTnonneg) return (doubleVal >= 0.0 ); 00178 else if (m_restrict == RESTRICTpos) return (doubleVal > 0.0); 00179 else if (m_restrict == RESTRICTinterval) { 00180 double min = Util::stringToDouble(m_min); 00181 double max = Util::stringToDouble(m_max); 00182 return ((min <= doubleVal) && (doubleVal <= max)); 00183 } 00184 return true; 00185 00186 } 00187 00188 case TYPEint: 00189 case TYPEmediumint: 00190 case TYPEsmallint: { 00191 int intVal; 00192 00193 try { 00194 intVal = Util::stringToInt(val); 00195 } 00196 catch (facilities::WrongType ex) { 00197 return false; 00198 } 00199 return ((intVal >= m_minInt) && (intVal <= m_maxInt)); 00200 } 00201 case TYPEvarchar: 00202 case TYPEchar: 00203 if (m_restrict == RESTRICTnone) return true; 00204 // for now, don't attempt to parse file path 00205 if (m_restrict == RESTRICTfile) return true; 00206 if (!m_enum->choicesRequired()) return true; 00207 case TYPEenum: { 00208 unsigned nChoice = m_enum->getChoices().size(); 00209 for (unsigned i = 0; i < nChoice; i++) { 00210 if (val == m_enum->getChoices()[i]) return true; 00211 } 00212 return false; 00213 } 00214 case TYPEdatetime: 00215 case TYPEtimestamp: { 00216 try { 00217 facilities::Timestamp aTime(val); 00218 if (m_restrict == RESTRICTinterval) { 00219 facilities::Timestamp min(m_min); 00220 facilities::Timestamp max(m_max); 00221 return ((min <= aTime) && (aTime <= max)); 00222 } 00223 return true; 00224 } 00225 catch (facilities::BadTimeInput ex) { 00226 std::cerr << "From rdbModel::Datatype::okValue" << std::endl; 00227 std::cerr << ex.complaint << std::endl; 00228 return false; 00229 } 00230 00231 } 00232 default: 00233 return false; 00234 } 00235 } 00236 00237 bool Datatype::isCompatible(const Datatype* other) const { 00238 // The ten distinct types can be partitioned into 4 sorts: integer, 00239 // real, character, and date. Call two types compatible if they're 00240 // in the same partition. 00241 return (findTOT(m_type) == findTOT(other->m_type)); 00242 } 00243 }