Data.cc

00001 // ----------------------------------------------------------------------^
00002 // Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Giorgio Calderone
00003 // (mailto: <gcalderone@ifc.inaf.it>)
00004 // 
00005 // This file is part of MCS.
00006 // 
00007 // MCS is free software; you can redistribute it and/or modify
00008 // it under the terms of the GNU General Public License as published by
00009 // the Free Software Foundation; either version 2 of the License, or
00010 // (at your option) any later version.
00011 // 
00012 // MCS is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 // 
00017 // You should have received a copy of the GNU General Public License
00018 // along with MCS; if not, write to the Free Software
00019 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 // 
00021 // ----------------------------------------------------------------------$
00022 
00023 #include "mcs.hh"
00024 using namespace mcs;
00025 
00026 //CFITSIO include
00027 #if ENABLE_CFITSIO
00028 #include <fitsio.h>
00029 #endif  //ENABLE_CFITSIO
00030 
00031 
00032 
00033 
00034 void copyTimeStruct(MYSQL_TIME mysql, struct tm* tm) {
00035   tm->tm_sec   = mysql.second;
00036   tm->tm_min   = mysql.minute;
00037   tm->tm_hour  = mysql.hour;
00038   tm->tm_mday  = mysql.day;
00039   tm->tm_mon   = mysql.month - 1;
00040   tm->tm_year  = mysql.year - 1900;
00041 
00042 }
00043 
00044 void copyTimeStruct(struct tm tm, MYSQL_TIME* mysql) {
00045   mysql->second = tm.tm_sec ;
00046   mysql->minute = tm.tm_min ;
00047   mysql->hour   = tm.tm_hour;
00048   mysql->day    = tm.tm_mday;
00049   mysql->month  = tm.tm_mon + 1;
00050   mysql->year   = tm.tm_year + 1900;
00051 }
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 const char* mcs::DateTime::parseTime(const char* s, struct tm* tm)
00061 {
00062   int i;
00063   const char* ret = NULL;
00064 
00065   static const char* templ[] = {
00066     "%x%n%X",
00067     "%x%n%T",
00068     "%x%n%r",
00069     
00070     "%D%n%X",
00071     "%D%n%T",
00072     "%D%n%r",
00073     
00074     "%F%n%X",
00075     "%F%n%T",
00076     "%F%n%r",
00077     
00078     "%x",    //The date using the locale's date format.
00079     "%D",    //Equivalent to `%m/%d/%y'
00080     "%F",    //Equivalent to `%Y-%m-%d'
00081     
00082     "%X",    //The time using the locale's time format.
00083     "%T",    //Equivalent to the use of `%H:%M:%S' in this place.
00084     "%r",    //Complete time using the AM/PM format of the current locale.
00085     
00086     "%s",    //number of seconds elapsed since epoch (1970-01-01 00:00:00 UTC).
00087   };
00088 
00089   static const int ntempl = sizeof(templ) / sizeof(char*);
00090 
00091 
00092 
00093   memset(tm, '\0', sizeof (*tm));
00094 
00095   for (i=0; i<ntempl; i++) {
00096     ret = strptime(s, templ[i], tm);
00097 
00098     if (ret != NULL) {
00099       ret = templ[i];
00100 
00101       if (i < 15) {
00102     if (i > 11) {  //Only time
00103       tm->tm_mday  = 1;
00104       tm->tm_mon   = 0;
00105       tm->tm_year  = 70;
00106       tm->tm_isdst = 0;
00107     }
00108     else if (i > 8) {  //Only date
00109       tm->tm_sec  = 0;
00110       tm->tm_min  = 0;
00111       tm->tm_hour = 0;
00112     }
00113       }
00114       break;
00115     }
00116   }
00117 
00118   return ret;
00119 }
00120 
00121 
00122 
00123 
00124 void mcs::DateTime::to_MYSQL_TIME()
00125 {
00126   if (mysql) {
00127     struct tm tm;
00128     switch(timemode) {
00129     case UTC:    gmtime_r(&time, &tm); break;
00130     case LOCAL:  localtime_r(&time, &tm);
00131     }
00132 
00133     copyTimeStruct(tm, mysql);
00134   }
00135 }
00136 
00137 
00138 
00139 
00140 time_t mcs::DateTime::getTime() const
00141 {
00142   time_t ret = time;
00143 
00144   if (mysql) {
00145     struct tm tm;
00146     memset(&tm, '\0', sizeof(tm));
00147     copyTimeStruct(*mysql, &tm);
00148 
00149     switch(timemode) {
00150     case UTC:   ret = timegm(&tm);      break;
00151     case LOCAL: ret = my_timelocal(&tm);
00152     }
00153   }
00154 
00155   return ret;
00156 }
00157 
00158 
00159 
00160 
00161 mcs::DateTime::DateTime()
00162 {
00163   timemode = UTC;
00164   mysql = NULL;
00165 }
00166 
00167 
00168 void mcs::DateTime::setMysqlBuffer(MYSQL_TIME* mysql)
00169 { this->mysql = mysql; }
00170 
00171 
00172 void mcs::DateTime::setTimeMode(enum TimeMode tm)
00173 {
00174     timemode = tm;
00175     to_MYSQL_TIME();
00176 }
00177 
00178 
00179 void mcs::DateTime::now()
00180 {
00181   time = ::time(NULL);
00182   to_MYSQL_TIME();
00183 }
00184 
00185 
00186 void mcs::DateTime::settval(time_t t)
00187 {
00188   time = t;
00189   to_MYSQL_TIME();
00190 }
00191 
00192 
00193 
00194 
00195 time_t mcs::my_timelocal(struct tm* tm) {
00196   bool h2 = (tm->tm_hour == 2);
00197   time_t time = timelocal(tm);
00198   
00199   //check for DST-related issues
00200   if (tm->tm_isdst == 1) {
00201     struct tm tm_before;
00202     time_t t;
00203 
00204     t = time-3600;
00205     localtime_r(&t, &tm_before);
00206 
00207     if (h2   &&   (tm_before.tm_isdst == 0)) 
00208       cout << "DST Warning: given datetime does not exists!" << endl;
00209 
00210     if (tm_before.tm_isdst == 1)
00211       time -= 3600;
00212   }
00213   else {
00214     struct tm tm_after;
00215     time_t t;
00216 
00217     t = time+3600;
00218     localtime_r(&t, &tm_after);
00219 
00220     if (h2   &&   (tm_after.tm_isdst == 0)) 
00221       cout << "DST Warning: given datetime is ambiguous!" << endl;
00222   }
00223 
00224   return time;
00225 }
00226 
00227 
00228 
00229 void mcs::DateTime::setsval(string s)
00230 {
00231   struct tm tm;
00232   parseTime(s.c_str(), &tm);
00233 
00234   switch(timemode) {
00235   case UTC:    time = timegm(&tm);        break;
00236   case LOCAL:  time = my_timelocal(&tm);  break;
00237   }
00238 
00239   to_MYSQL_TIME();
00240 }
00241 
00242 
00243 
00244 void mcs::DateTime::settmval(struct tm& ltm)
00245 {
00246   //Note: the timelocal function does not use tm_isdst flag to compute
00247   //return value, thus we use our wrapper my_timelocal to
00248   //eventually take care of DST issues
00249   struct tm tm = ltm;
00250   switch(timemode) {
00251       case UTC:   time = timegm(&tm);         break;
00252       case LOCAL: time = my_timelocal(&tm);   break;
00253   }
00254 
00255   to_MYSQL_TIME();
00256 }
00257 
00258 
00259 
00260 time_t mcs::DateTime::tval() const
00261 {
00262   return getTime();
00263 }
00264 
00265 
00266 struct tm mcs::DateTime::tmval() const
00267 {
00268   struct tm tm;
00269   time_t time = getTime();
00270 
00271   switch(timemode) {
00272       case UTC:   gmtime_r(&time, &tm);      break;
00273       case LOCAL: localtime_r(&time, &tm);   break;
00274   }
00275 
00276   return tm;
00277 }
00278 
00279 
00281 string mcs::DateTime::sval() const
00282 {
00283   struct tm tm;
00284   char buf[30];
00285   time_t time = getTime();
00286 
00287   switch(timemode) {
00288       case UTC:   gmtime_r(&time, &tm);      break;
00289       case LOCAL: localtime_r(&time, &tm);   break;
00290   }
00291 
00292   strftime(buf, 30, "%F %T", &tm);
00293 
00294   return string(buf);
00295 }
00296 
00297 
00298 
00299 
00300 
00301 
00302 
00303 
00304 
00305 
00306 
00307 
00308 
00309 
00310 
00311 
00312 
00313 string mcs::Types2Str(Types type, bool isunsigned)
00314 {
00315   string ret="";
00316   if (isunsigned) ret = "UNSIGNED ";
00317 
00318   switch (type) {
00319   case TINY:
00320     ret += "TINY";   break;
00321   case SMALL:
00322     ret += "SMALL";  break;
00323   case MEDIUM:
00324     ret += "MEDIUM"; break;
00325   case INT  :
00326     ret += "INT";    break;
00327   case BIGINT:
00328     ret += "BIGINT"; break;
00329   case FLOAT:
00330     ret = "FLOAT";  break;
00331   case DOUBLE:
00332     ret = "DOUBLE"; break;
00333   case STRING:
00334     ret = "STRING"; break;
00335   case TIME:
00336     ret = "TIME";   break;
00337   case TINY_BLOB:
00338     ret = "TINY_BLOB"; break;
00339   case BLOB:
00340     ret = "BLOB"  ; break;
00341   case POINTER:
00342     ret = "PTR"  ; break;
00343   }
00344 
00345   return ret;
00346 }
00347 
00348 
00349 bool mcs::VarLenType(Types type)
00350 {
00351   switch(type) {
00352   case STRING:
00353     return true;         break;
00354   case TINY_BLOB:
00355     return true;         break;
00356   case BLOB:
00357     return true;         break;
00358   default:
00359     return false;        break;
00360   }
00361 }
00362 
00363 
00364 bool mcs::IntType(Types type)
00365 {
00366   if (
00367       (type == TINY)       ||
00368       (type == SMALL)      ||
00369       (type == MEDIUM)     ||
00370       (type == INT)        ||
00371       (type == BIGINT)
00372       )
00373     return true;
00374   else
00375     return false;
00376 }
00377 
00378 
00379 bool mcs::FloatType(Types type)
00380 {
00381   if (
00382       (type == FLOAT)   ||
00383       (type == DOUBLE)
00384       )
00385     return true;
00386   else
00387     return false;
00388 }
00389 
00390 
00391 
00392 #if ENABLE_MYSQL
00393 string mcs::MYSQL2Str(enum_field_types type)
00394 {
00395   string ret;
00396 
00397   switch (type) {
00398   case MYSQL_TYPE_TINY:
00399     ret = "TINYINT";    break;
00400   case MYSQL_TYPE_SHORT:
00401     ret = "SMALLINT";   break;
00402   case MYSQL_TYPE_INT24:
00403     ret = "MEDIUMINT";  break;
00404   case MYSQL_TYPE_LONG:
00405     ret = "INT";        break;
00406   case MYSQL_TYPE_LONGLONG:
00407     ret = "BIGINT"; break;
00408   case MYSQL_TYPE_FLOAT:
00409     ret = "FLOAT";  break;
00410   case  MYSQL_TYPE_DOUBLE:
00411     ret = "DOUBLE"; break;
00412   case MYSQL_TYPE_STRING:
00413     ret = "CHAR";       break;
00414   case MYSQL_TYPE_VAR_STRING:
00415     ret = "CHAR";       break;
00416   case MYSQL_TYPE_TIME:
00417     ret = "TIME";       break;
00418   case MYSQL_TYPE_DATE:
00419     ret = "TIME";       break;
00420   case MYSQL_TYPE_DATETIME:
00421     ret = "TIME";       break;
00422   case MYSQL_TYPE_TIMESTAMP:
00423     ret = "TIME";       break;
00424   case MYSQL_TYPE_TINY_BLOB:
00425     ret = "TINYBLOB";   break;
00426   case MYSQL_TYPE_BLOB:
00427     ret = "BLOB";       break;
00428   default:
00429     ret ="";
00430   }
00431 
00432   return ret;
00433 }
00434 
00435 
00436 bool mcs::MYSQL2Types(enum_field_types mtype, Types& type)
00437 {
00438   switch (mtype) {
00439   case MYSQL_TYPE_TINY:
00440     type = TINY;     break;
00441   case MYSQL_TYPE_SHORT:
00442     type = SMALL;    break;
00443   case MYSQL_TYPE_INT24:
00444     type = MEDIUM;       break; 
00445   case MYSQL_TYPE_LONG:
00446     type = INT;          break;
00447   case MYSQL_TYPE_LONGLONG:
00448     type = BIGINT;   break;
00449   case MYSQL_TYPE_FLOAT:
00450     type = FLOAT;    break;
00451   case  MYSQL_TYPE_DOUBLE:
00452     type = DOUBLE;   break;
00453   case MYSQL_TYPE_STRING:
00454     type = STRING;       break;
00455   case MYSQL_TYPE_VAR_STRING:
00456     type = STRING;       break;
00457   case MYSQL_TYPE_TIME:
00458     type = TIME;         break;
00459   case MYSQL_TYPE_DATE:
00460     type = TIME;         break;
00461   case MYSQL_TYPE_DATETIME:
00462     type = TIME;         break;
00463   case MYSQL_TYPE_TIMESTAMP:
00464     type = TIME;         break;
00465   case MYSQL_TYPE_TINY_BLOB:
00466     type = TINY_BLOB;    break;
00467   case MYSQL_TYPE_BLOB:
00468     type = BLOB;         break;
00469   default:
00470     return false;        break;
00471   }
00472 
00473   return true;
00474 }
00475 
00476 
00477 bool mcs::Types2MYSQL(Types& type, enum_field_types& mtype)
00478 {
00479   switch (type) {
00480   case TINY:
00481     mtype = MYSQL_TYPE_TINY;      break;
00482   case SMALL:       
00483     mtype = MYSQL_TYPE_SHORT;     break;
00484   case MEDIUM:      
00485     mtype = MYSQL_TYPE_INT24;     break;
00486   case INT:     
00487     mtype = MYSQL_TYPE_LONG;      break;
00488   case BIGINT:      
00489     mtype = MYSQL_TYPE_LONGLONG;  break;
00490   case FLOAT:       
00491     mtype = MYSQL_TYPE_FLOAT;     break;
00492   case DOUBLE:      
00493     mtype = MYSQL_TYPE_DOUBLE;    break;
00494   case STRING:      
00495     mtype = MYSQL_TYPE_STRING;    break;
00496   case TIME:
00497     mtype = MYSQL_TYPE_DATETIME;  break;
00498   case TINY_BLOB:
00499     mtype = MYSQL_TYPE_TINY_BLOB; break;
00500   case BLOB:
00501     mtype = MYSQL_TYPE_BLOB;      break;
00502   default:
00503     return false;                 break;
00504   }
00505 
00506   return true;
00507 }
00508 
00509 string mcs::Types2MYSQLStr(Types& type, bool isunsigned)
00510 {
00511   enum enum_field_types mtype;
00512   string ret="";
00513 
00514   if (Types2MYSQL(type, mtype)) {
00515     ret = MYSQL2Str(mtype);
00516   }
00517 
00518   if (isunsigned)
00519     ret += " UNSIGNED";
00520 
00521   return ret;
00522 }
00523 
00524 
00525 #if ENABLE_CFITSIO
00526 bool mcs::FITS2Types(int fits, Types& dbt, bool& isunsigned)
00527 {
00528   isunsigned = false;
00529   switch (fits) {
00530   case TBYTE:
00531     dbt = TINY;    isunsigned = true ; break;
00532   case TSBYTE:
00533     dbt = TINY;                      ; break;
00534   case TSHORT:
00535     dbt = SMALL;                     ; break;
00536   case TUSHORT:
00537     dbt = SMALL;   isunsigned = true ; break;
00538   case TINT:
00539     dbt = INT;                       ; break;
00540   case TLONG:
00541     dbt = INT;                       ; break;
00542   case TUINT:
00543     dbt = INT;     isunsigned = true ; break;
00544   case TULONG:
00545     dbt = INT;     isunsigned = true ; break;
00546   case TLONGLONG:
00547     dbt = BIGINT;                    ; break;
00548   case TFLOAT:
00549     dbt = FLOAT;                       break;
00550   case TDOUBLE:
00551     dbt = DOUBLE;                      break;
00552   case TSTRING:
00553     dbt = STRING;                      break;
00554   default:
00555     return false;
00556   }
00557 
00558   return true;
00559 }
00560 
00561 
00562 bool mcs::Types2FITS(Types dbt, bool isunsigned, int& fits)
00563 {
00564   switch (dbt) {
00565   case TINY:
00566     if (isunsigned)   fits = TBYTE;
00567     else              fits = TSHORT;
00568     break;
00569   case SMALL:
00570     if (isunsigned)   fits = TLONG;
00571     else              fits = TSHORT;
00572     break;
00573   case MEDIUM:
00574     if (isunsigned)   fits = TLONGLONG;
00575     else              fits = TLONG;
00576     break;
00577   case INT  :
00578     if (isunsigned)   fits = TLONGLONG;
00579     else              fits = TLONG;
00580     break;
00581   case BIGINT:
00582     if (isunsigned)   return false;
00583     else              fits = TLONGLONG;
00584     break;
00585   case FLOAT:
00586     fits = TFLOAT;  break;
00587   case DOUBLE:
00588     fits = TDOUBLE; break;
00589   case STRING:
00590     fits = TSTRING; break;
00591   case TIME: //Substitute blanks with 't'
00592     fits = TSTRING; break;
00593   default:
00594     return false;
00595   }
00596 
00597   return true;
00598 }
00599 
00600 
00601 bool mcs::Types2S_FITS(Types dbt, int len, bool isunsigned, string& fits)
00602 {
00603   switch (dbt) {
00604 //  case TINY:
00605 //    if (isunsigned)   fits = "1B";
00606 //    else              fits = "1S";
00607 //    break;
00608 //  case SMALL:
00609 //    if (isunsigned)   fits = "1U";
00610 //    else              fits = "1I";
00611 //    break;
00612 //  case INT  :
00613 //    if (isunsigned)   fits = "1V";
00614 //    else              fits = "1J";
00615 //    break;
00616   case TINY:
00617     if (isunsigned)   fits = "1B";
00618     else              fits = "1I";
00619     break;
00620   case SMALL:
00621     if (isunsigned)   fits = "1J";
00622     else              fits = "1I";
00623     break;
00624   case MEDIUM  :
00625     if (isunsigned)   fits = "1K";
00626     else              fits = "1J";
00627   case INT  :
00628     if (isunsigned)   fits = "1K";
00629     else              fits = "1J";
00630     break;
00631   case BIGINT:
00632     if (isunsigned)   return false;
00633     else              fits = "1K"; break;
00634   case FLOAT:
00635     fits = "1E"; break;
00636   case DOUBLE:
00637     fits = "1D"; break;
00638   case STRING:
00639     fits = itos(len) + "A"; break;
00640   case TIME:
00641     fits = "20A"; break; //TODO: Implement
00642   default:
00643     return false;
00644   }
00645 
00646   return true;
00647 }
00648 #endif
00649 #endif
00650 
00651 
00652 
00653 
00654 unsigned int mcs::Data::howManyDim()
00655 { return ldimspec & 15; }
00656 
00657 
00658 
00659 unsigned int mcs::Data::varyingDim()
00660 { return ldimspec >> 4; }
00661 
00662 
00663 
00664 string buildDimSpec(int ldimspec, const unsigned short int ldim[MCS_DATA_NDIM])
00665 {
00666   string s = "";
00667   int i;
00668   int howManyDim = ldimspec & 15;
00669   int varyingDim = ldimspec >> 4;
00670 
00671   for (i=0; (i<howManyDim)   ||   (i<varyingDim); i++) {
00672     if (i > 0) s += "x";
00673     s += itos(ldim[i]);
00674   }
00675 
00676   if ((i > 0)   &&
00677       (i == varyingDim))
00678     s += "*";
00679 
00680   return s;
00681 }
00682 
00683 
00684 //NOTE: If this method is called on a variable length based Data
00685 //object the initial "maxLength" given in init() will be overrided
00686 void mcs::Data::resize(string dimSpec)
00687 {
00688   string err = "";
00689   unsigned int i;
00690   unsigned char howManyDim, varyingDim;
00691   howManyDim = 0;
00692   varyingDim = 0;
00693 
00694   if (dimSpec == "")
00695     return;
00696 
00697   //Multi-dimensional array are a VOTable feature, they're not allowed
00698   //on the DB side.
00699   if (lbind)
00700     throw MCS_ERROR( MSG_CANT_BIND_AND_HAVE_DIMSPEC );
00701 
00702   //Initialize all dim-related variables
00703   for (i=0; i<MCS_DATA_NDIM; i++)
00704     ldim[i] = 1;
00705 
00706   ldimspec = 0;
00707   arrsize = 1;
00708   arrpos = 0;
00709 
00710   //Split the spec at "x"
00711   vector<string> values = split(dimSpec, "x");
00712   if (values.size() > MCS_DATA_NDIM)
00713     throw MCS_ERROR( MSG_TOO_MANY_DIMSPEC, MCS_DATA_NDIM);
00714 
00715   //Analyze all dimension specs
00716   for (i=0; i<values.size(); i++) {
00717     string s = values[i];
00718 
00719     //In a dimension spec there can be a '*', meaning that effective
00720     //size will be determined during data reading.
00721     if (strchr(s.c_str(), '*')) {
00722 
00723       if (i != values.size() - 1)
00724     throw MCS_ERROR( MSG_VARYING_MUST_BE_LAST );
00725 
00726       //So this dimension can change its size, set varyingDim...
00727       varyingDim = i + 1;
00728 
00729       //If a number is present then it will be the maximum size,
00730       //else the size is completely dynamic.
00731       //Remove the '*'
00732       s.replace(s.find("*", 0), 1, " ");
00733 
00734       ldim[i] = stoi(s, 1);
00735     }
00736     else
00737       ldim[i] = stoi(s);
00738 
00739     howManyDim++;
00740   }
00741 
00742 
00743   if (VarLenType(ltype)) {
00744     //If the type is a STRING then the first dimension is to be taken
00745     //as "maxLength" (see VOTable docs)
00746     if (ltype == STRING) {
00747       lmaxlength = ldim[0];
00748 
00749       //Shift all other dimensions
00750       for (i=0; i<MCS_DATA_NDIM-2; i++)
00751     ldim[i] = ldim[i+1];
00752 
00753       ldim[MCS_DATA_NDIM-1] = 1;
00754       howManyDim--;
00755 
00756       lmaxlength++;  //Need to allocate space for NULL character
00757     }
00758     else
00759       lmaxlength = 1; //Lengths are completely driven by dim spec
00760   }
00761 
00762   reallocBuffer();
00763 
00764   if (ltype == STRING)  //See analogous note in Data::init
00765     lmaxlength--;
00766 
00767   llength = lmaxlength;
00768 
00769   ldimspec = (varyingDim << 4) + howManyDim;
00770 
00771   mult[0] = 1;
00772   for (i=1; i<MCS_DATA_NDIM-1; i++)
00773     mult[i] = mult[i-1] * ldim[i-1];
00774 }
00775 
00776 
00777 
00778 Data& mcs::Data::operator()(const int i1,
00779                 const int i2,
00780                 const int i3,
00781                 const int i4,
00782                 const int i5,
00783                 const int i6,
00784                 const int i7,
00785                 const int i8,
00786                 const int i9,
00787                 const int i10,
00788                 const int i11,
00789                 const int i12,
00790                 const int i13,
00791                 const int i14,
00792                 const int i15)
00793 {
00794   array(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);
00795   return *this;
00796 }
00797 
00798 
00799 unsigned int mcs::Data::array(unsigned short int i1,
00800                   unsigned short int i2,
00801                   unsigned short int i3,
00802                   unsigned short int i4,
00803                   unsigned short int i5,
00804                   unsigned short int i6,
00805                   unsigned short int i7,
00806                   unsigned short int i8,
00807                   unsigned short int i9,
00808                   unsigned short int i10,
00809                   unsigned short int i11,
00810                   unsigned short int i12,
00811                   unsigned short int i13,
00812                   unsigned short int i14,
00813                   unsigned short int i15)
00814 {
00815   if (ldim[0] <= i1)
00816       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 1, i1);
00817 
00818   if (ldim[1] <= i2)
00819       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 2, i2);
00820 
00821   if (ldim[2] <= i3)
00822       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 3, i3);
00823 
00824   if (ldim[3] <= i4)
00825       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 4, i4);
00826 
00827   if (ldim[4] <= i5)
00828       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 5, i5);
00829 
00830   if (ldim[5] <= i6)
00831       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 6, i6);
00832 
00833   if (ldim[6] <= i7)
00834       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 7, i7);
00835 
00836   if (ldim[7] <= i8)
00837       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 8, i8);
00838 
00839   if (ldim[8] <= i9)
00840       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 9, i9);
00841 
00842   if (ldim[9] <= i10)
00843       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 10, i10);
00844 
00845   if (ldim[10] <= i11)
00846       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 11, i11);
00847 
00848   if (ldim[11] <= i12)
00849       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 12, i12);
00850 
00851   if (ldim[12] <= i13)
00852       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 13, i13);
00853 
00854   if (ldim[13] <= i14)
00855       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 14, i14);
00856 
00857   if (ldim[14] <= i15)
00858       throw MCS_ERROR(MSG_WRONG_DIM_SPEC, 15, i15);
00859 
00860   arrpos =
00861     i1  * mult[ 0] +
00862     i2  * mult[ 1] +
00863     i3  * mult[ 2] +
00864     i4  * mult[ 3] +
00865     i5  * mult[ 4] +
00866     i6  * mult[ 5] +
00867     i7  * mult[ 6] +
00868     i8  * mult[ 7] +
00869     i9  * mult[ 8] +
00870     i10 * mult[ 9] +
00871     i11 * mult[10] +
00872     i12 * mult[11] +
00873     i13 * mult[12] +
00874     i14 * mult[13] +
00875     i15 * mult[14];
00876 
00877 
00878   //i1 +
00879   //  i2  * ldim[0 ] +
00880   //  i3  * ldim[0 ] * ldim[1 ] +
00881   //  i4  * ldim[0 ] * ldim[1 ] * ldim[2 ] +
00882   //  i5  * ldim[0 ] * ldim[1 ] * ldim[2 ] * ldim[3 ] +
00883   //  i6  * ldim[0 ] * ldim[1 ] * ldim[2 ] * ldim[3 ] * ldim[4 ] +
00884 
00885     return arrpos;
00886 }
00887 
00888 
00889 
00890 
00891 unsigned short int mcs::Data::dim(int d)
00892 {
00893   // 1 <= d <= MCS_DATA_NDIM
00894   if (d < 1)
00895     return 0;
00896   else if (d > MCS_DATA_NDIM)
00897     return 0;
00898   else
00899     return ldim[d-1];
00900 }
00901 
00902 
00903 unsigned int mcs::Data::arraySize()
00904 {
00905   return arrsize;
00906 }
00907 
00908 
00909 
00910 
00911 void mcs::Data::resizeVaryingDim(unsigned short int newsize)
00912 {
00913   if (newsize == 0)
00914     return;
00915 
00916   if (varyingDim() == 0)
00917     throw MCS_ERROR( MSG_NO_DIM_ALLOWED_TO_CHANGE );
00918 
00919   //Set new dimension
00920   ldim[varyingDim() - 1] = newsize;
00921 
00922   reallocBuffer();
00923 }
00924 
00925 
00926 
00927 void mcs::Data::reallocBuffer()
00928 {
00929   unsigned int old_bufsize = bufsize;
00930 
00931   //Calculate new array size
00932   arrsize = 1;
00933   for (int i=0; i<MCS_DATA_NDIM; i++)
00934     arrsize *= ldim[i];
00935 
00936   bufsize = lmaxlength * arrsize;
00937 
00938   if (buf == NULL) { //First time
00939     buf = (char*) malloc(bufsize);
00940     memset(buf, 0, bufsize);
00941   }
00942   else {
00943     buf = (char*) realloc(buf, bufsize);
00944 
00945     if (bufsize > old_bufsize) {
00946       //Set newly allocated memory to zero
00947       memset(buf + old_bufsize, 0, bufsize - old_bufsize);
00948     }
00949   }
00950 }
00951 
00952 
00953 
00954 void mcs::Data::init(MYSQL_BIND* bind, Types type, const char* name,
00955              unsigned short int maxLength, bool isunsigned,
00956              unsigned int flags)
00957 {
00958   MCS_DEBUG_SETUP(0, "Data");
00959 
00960   buf = NULL;
00961   bufsize = 0;
00962   ltype = type;
00963   lname = string(name);
00964   lisunsigned = isunsigned;
00965   lisnull = false;
00966   lautoincr = (bool) (flags & AUTO_INCREMENT_FLAG);
00967   lflags = flags;
00968   tag = 0;
00969   setSourceID(MCS_ID_UNKNOWN);
00970   setDestID(MCS_ID_UNKNOWN);
00971 
00972 
00973   //By default this object has no dimensions and no dimension should be varying
00974   ldimspec = 0;
00975   arrsize = 1;
00976   arrpos = 0;
00977   for (int i=0; i<MCS_DATA_NDIM; i++)
00978     ldim[i] = 1;
00979 
00980 
00981   switch (ltype) {
00982   case TINY:
00983       lmaxlength  = sizeof(char);            break;
00984   case SMALL:
00985       lmaxlength  = sizeof(short int);       break;
00986   case MEDIUM:
00987       lmaxlength  = sizeof(int);             break;
00988   case INT  :
00989       lmaxlength  = sizeof(int);             break;
00990   case BIGINT:
00991        lmaxlength = sizeof(long long int);  break;
00992   case FLOAT:
00993       lmaxlength  = sizeof(float);           break;
00994   case DOUBLE:
00995       lmaxlength  = sizeof(double);          break;
00996   case STRING:
00997       lmaxlength  = sizeof(char) * maxLength;
00998       lmaxlength++;  //Need to allocate space for NULL character
00999       break;
01000   case TIME:
01001     /*
01002       sizeof(MYSQL_TIME) is 36 on a 32bit processor, while it is 40 on
01003       a 64bit. This is due to the member <unsigned long second_part>
01004       of the structure, which will (not yet used) contain the
01005       fractional part of a second.
01006      */
01007     lmaxlength    = sizeof(MYSQL_TIME);
01008     break;
01009   case TINY_BLOB:
01010       lmaxlength  = sizeof(char) * maxLength;break;
01011   case BLOB:
01012       lmaxlength  = sizeof(char) * maxLength;break;
01013   case POINTER:
01014       lmaxlength  = sizeof(void*);           break;
01015   default:
01016       throw MCS_ERROR(MSG_TYPE_NOT_HANDLED, 0, ltype);
01017   }
01018 
01019   reallocBuffer();
01020 
01021   if (ltype == STRING)
01022     lmaxlength--; //Consider only the buffer without the trailing NULL.
01023                   //That's because the NULL is needed only on C side,
01024                   //not on mysql or user side.
01025 
01026   if (ltype == TIME)
01027     dt.setMysqlBuffer((MYSQL_TIME*) buf);
01028 
01029 
01030   llength = lmaxlength;
01031 
01032 #if ENABLE_MYSQL
01033   enum_field_types mytype;
01034   Types2MYSQL(ltype, mytype);
01035 
01036   lbind = bind;
01037   if (lbind) {
01038     memset(lbind, 0, sizeof(MYSQL_BIND));
01039     lbind->buffer = buf;
01040 
01041     lbind->buffer_type =
01042     (mytype == MYSQL_TYPE_INT24 ? MYSQL_TYPE_LONG : mytype);
01043 
01044     lbind->buffer_length = lmaxlength;
01045     lbind->is_unsigned = lisunsigned;
01046     lbind->is_null = &lisnull;
01047     lbind->length = &llength;
01048   }
01049 #endif
01050 }
01051 
01052 
01053 
01054 mcs::Data::Data() : Serializable(MCS_SERIAL_BUFFER)
01055 {
01056     init(NULL, STRING);
01057     setNull();
01058     setTag(0);
01059 }
01060 
01061 
01062 mcs::Data::Data(MYSQL_BIND* bind, Types type, const char* name,
01063         unsigned short int maxLength, bool isunsigned,
01064         unsigned int flags, unsigned char tag)
01065   : Serializable(MCS_SERIAL_BUFFER)
01066 
01067 {
01068   init(bind, type, name, maxLength, isunsigned, flags);
01069   setTag(tag);
01070   MCS_DEBUG("-> " << sval());
01071 }
01072 
01073 
01074 mcs::Data::Data(Types type, unsigned short int maxLength, bool isunsigned,
01075         string dimSpec)
01076   : Serializable(MCS_SERIAL_BUFFER)
01077 {
01078     MCS_DEBUG("-> ");
01079     init(NULL, type, "", maxLength, isunsigned, 0);
01080     resize(dimSpec);
01081     MCS_DEBUG("<- ");
01082 }
01083 
01084 
01085 
01086 mcs::Data::Data(const Data& from)
01087   : Serializable(MCS_SERIAL_BUFFER)
01088 {
01089   MCS_DEBUG("-> ");
01090   //cout << endl << endl << "Copy Constructor" << endl << endl;
01091 
01092   init(0,
01093        from.ltype,
01094        (char*) from.lname.c_str(),
01095        from.lmaxlength,
01096        from.lisunsigned,
01097        from.lflags);
01098 
01099   resize(buildDimSpec(from.ldimspec, from.ldim));
01100 
01101   memcpy(buf, from.buf, lmaxlength * arrsize);
01102   llength = from.llength;
01103   setTag(from.tag);
01104   lisnull = from.lisnull;
01105   lautoincr = from.lautoincr;
01106   MCS_DEBUG("<-");
01107 }
01108 
01109 
01110 mcs::Data::Data(int v, unsigned char tag)
01111   : Serializable(MCS_SERIAL_BUFFER)
01112 {
01113   init(NULL, INT, "", 0, false, 0);
01114   setival(v);
01115   setTag(tag);
01116   MCS_DEBUG("-> " << sval());
01117 }
01118 
01119 
01120 mcs::Data::Data(long long int v, unsigned char tag)
01121   : Serializable(MCS_SERIAL_BUFFER)
01122 {
01123   init(NULL, BIGINT, "", 0, false, 0);
01124   setlval(v);
01125   setTag(tag);
01126   MCS_DEBUG("-> " << sval());
01127 }
01128 
01129 
01130 mcs::Data::Data(double v, unsigned char tag)
01131   : Serializable(MCS_SERIAL_BUFFER)
01132 {
01133   init(NULL, DOUBLE, "", 0, false, 0);
01134   setdval(v);
01135   setTag(tag);
01136   MCS_DEBUG("-> " << sval());
01137 }
01138 
01139 
01140 mcs::Data::Data(string v, unsigned char tag)
01141   : Serializable(MCS_SERIAL_BUFFER)
01142 {
01143   init(NULL, STRING, "", v.length(), false, 0);
01144   if (v.length())
01145     setsval(v);
01146   else
01147     setNull();
01148   setTag(tag);
01149   MCS_DEBUG("-> " << sval());
01150 }
01151 
01152 mcs::Data::Data(struct tm v, unsigned char tag)
01153   : Serializable(MCS_SERIAL_BUFFER)
01154 {
01155   init(NULL, TIME, "", 0, false, 0);
01156   settimeval(v);
01157   setTag(tag);
01158   MCS_DEBUG("-> " << sval());
01159 }
01160 
01161 mcs::Data::Data(time_t v, unsigned char tag)
01162   : Serializable(MCS_SERIAL_BUFFER)
01163 {
01164   init(NULL, TIME, "", 0, false, 0);
01165   settimeval(v);
01166   setTag(tag);
01167   MCS_DEBUG("-> " << sval());
01168 }
01169 
01170 
01171 
01172 mcs::Data::~Data()
01173 {
01174   if (buf)
01175     free(buf);
01176 }
01177 
01178 void mcs::Data::emptyName()
01179 { lname = ""; }
01180 
01181 
01182 const char* mcs::Data::ifmt = "%d";
01183 const char* mcs::Data::lfmt = "%ld";
01184 const char* mcs::Data::ffmt = "%f";
01185 const char* mcs::Data::dfmt = "%lf";
01186 const char* mcs::Data::dtfmt = "%04d-%02d-%02d %02d:%02d:%02g";
01187 const char* mcs::Data::dafmt = "%04d-%02d-%02d";
01188 const char* mcs::Data::tmfmt = "%02d:%02d:%02g";
01189 
01190 
01191 string mcs::Data::name() { return lname; }
01192 void mcs::Data::setName(string name) { lname = name; }
01193 //unsigned int mcs::Data::flags() { return lflags; }
01194 Types mcs::Data::type() { return (Types) ltype; }
01195 unsigned short int mcs::Data::maxLength() { return lmaxlength; }
01196 unsigned short int mcs::Data::length() { return (unsigned short int) llength; }
01197 bool mcs::Data::isUnsigned() { return lisunsigned; }
01198 bool mcs::Data::isNull() { return lisnull; }
01199 bool mcs::Data::isAutoIncrement() { return lautoincr; }
01200 void* mcs::Data::buffer() const {
01201   unsigned int pos = arrpos;
01202   return (buf + pos * (lmaxlength + (ltype == STRING ?   1  :  0)));
01203 }
01204 
01205 
01206 
01207 int mcs::Data::ival() const
01208 {
01209   char* buf = (char*) buffer();
01210   int ret;
01211 
01212   switch (ltype) {
01213   case TINY:
01214     if (lisunsigned)  ret = (*((unsigned char*         ) buf));
01215     else              ret = (*((char*                  ) buf));
01216     break;
01217   case SMALL:                           
01218     if (lisunsigned)  ret = (*((unsigned short int*    ) buf));
01219     else              ret = (*((short int*             ) buf));
01220     break;
01221   case MEDIUM  :
01222     if (lisunsigned)  ret = (*((unsigned int*          ) buf));
01223     else              ret = (*((int*                   ) buf));
01224     break;
01225   case INT  :                           
01226     if (lisunsigned)  ret = (*((unsigned int*          ) buf));
01227     else              ret = (*((int*                   ) buf));
01228     break;
01229   case BIGINT:                          
01230     if (lisunsigned)  ret = (*((unsigned long long int*) buf));
01231     else              ret = (*((long long int*         ) buf));
01232     break;
01233   case FLOAT:
01234     ret = (int) rintf(*((float*) buf));
01235     break;
01236   case DOUBLE:
01237     ret = (int) rint(*((double*) buf));
01238     break;
01239   case STRING:
01240     if (sscanf(buf, ifmt, &ret) != 1)
01241     throw MCS_ERROR(MSG_CONVERSION_STRING_INT);
01242     break;
01243   case TIME:
01244     return (int) tval();
01245       break;
01246   case TINY_BLOB:
01247       throw MCS_ERROR(MSG_CONVERSION_BLOB_INT);
01248       break;
01249   case BLOB:
01250       throw MCS_ERROR(MSG_CONVERSION_BLOB_INT);
01251       break;
01252   case POINTER:
01253       throw MCS_ERROR(MSG_CONVERSION_BLOB_INT);
01254       break;
01255   }
01256 
01257 
01258   switch (ltype) {
01259   case TINY:
01260     if (lisunsigned)  ret = (*((unsigned char*         ) buf));
01261     else              ret = (*((char*                  ) buf));
01262     break;
01263   case SMALL:                           
01264     if (lisunsigned)  ret = (*((unsigned short int*    ) buf));
01265     else              ret = (*((short int*             ) buf));
01266     break;
01267   case MEDIUM  :
01268     if (lisunsigned)  ret = (*((unsigned int*          ) buf));
01269     else              ret = (*((int*                   ) buf));
01270     break;
01271   case INT  :                           
01272     if (lisunsigned)  ret = (*((unsigned int*          ) buf));
01273     else              ret = (*((int*                   ) buf));
01274     break;
01275   case BIGINT:                          
01276     if (lisunsigned)  ret = (*((unsigned long long int*) buf));
01277     else              ret = (*((long long int*         ) buf));
01278     break;
01279   case FLOAT:
01280     ret = (int) rintf(*((float*) buf));
01281     break;
01282   case DOUBLE:
01283     ret = (int) rint(*((double*) buf));
01284     break;
01285   case STRING:
01286     if (sscanf(buf, ifmt, &ret) != 1)
01287     throw MCS_ERROR(MSG_CONVERSION_STRING_INT);
01288     break;
01289   case TIME:
01290     return (int) tval();
01291       break;
01292   case TINY_BLOB:
01293       throw MCS_ERROR(MSG_CONVERSION_BLOB_INT);
01294       break;
01295   case BLOB:
01296       throw MCS_ERROR(MSG_CONVERSION_BLOB_INT);
01297       break;
01298   case POINTER:
01299       throw MCS_ERROR(MSG_CONVERSION_BLOB_INT);
01300       break;
01301   }
01302 
01303   return ret;
01304 }
01305 
01306 
01307 unsigned int mcs::Data::uival() const
01308 {
01309   char* buf = (char*) buffer();
01310   unsigned int ret;
01311 
01312   switch (ltype) {
01313   case TINY:
01314     if (lisunsigned)  ret = (*((unsigned char*         ) buf));
01315     else              ret = (*((char*                  ) buf));
01316     break;
01317   case SMALL:                           
01318     if (lisunsigned)  ret = (*((unsigned short int*    ) buf));
01319     else              ret = (*((short int*             ) buf));
01320     break;
01321   case MEDIUM  :                            
01322     if (lisunsigned)  ret = (*((unsigned int*          ) buf));
01323     else              ret = (*((int*                   ) buf));
01324     break;
01325   case INT  :                           
01326     if (lisunsigned)  ret = (*((unsigned int*          ) buf));
01327     else              ret = (*((int*                   ) buf));
01328     break;
01329   case BIGINT:                          
01330     if (lisunsigned)  ret = (*((unsigned long long int*) buf));
01331     else              ret = (*((long long int*         ) buf));
01332     break;
01333   case FLOAT:
01334     ret = (unsigned int) rintf(*((float*) buf));
01335     break;
01336   case DOUBLE:
01337     ret = (unsigned int) rint(*((double*) buf));
01338     break;
01339   case STRING:
01340     if (sscanf(buf, ifmt, &ret) != 1)
01341       throw MCS_ERROR(MSG_CONVERSION_STRING_INT);
01342     break;
01343   case TIME:
01344     return (unsigned int) tval();
01345   case TINY_BLOB:
01346       throw MCS_ERROR(MSG_CONVERSION_BLOB_INT);
01347       break;
01348   case BLOB:
01349       throw MCS_ERROR(MSG_CONVERSION_BLOB_INT);
01350       break;
01351   case POINTER:
01352       throw MCS_ERROR(MSG_CONVERSION_BLOB_INT);
01353       break;
01354   }
01355 
01356   return ret;
01357 }
01358 
01359 
01360 long long int mcs::Data::lval() const
01361 {
01362   char* buf = (char*) buffer();
01363   long long int ret;
01364 
01365   switch (ltype) {
01366       case TINY  :
01367       case SMALL :
01368       case MEDIUM:
01369       case INT   :
01370     if (lisunsigned)   ret = uival();
01371     else               ret =  ival();
01372     break;
01373       case BIGINT:
01374     if (lisunsigned)
01375       ret = (*((unsigned long long int*) buf));
01376     else
01377       ret = (*((long long int*) buf));
01378     break;
01379       case FLOAT :  ret = (long long int) rintf(*((float*) buf)); break;
01380       case DOUBLE:  ret = (long long int) rint(*((double*) buf)); break;
01381       case TIME  :  ret = (long long int) tval();                 break;
01382       case STRING:
01383     if (sscanf(buf, lfmt, &ret) != 1)
01384       throw MCS_ERROR(MSG_CONVERSION_STRING_INT);
01385     break;
01386       case TINY_BLOB:
01387       case BLOB:
01388       case POINTER:
01389     throw MCS_ERROR(MSG_CONVERSION_BLOB_INT);
01390   }
01391   return ret;
01392 }
01393 
01394 
01395 unsigned long long int mcs::Data::ulval() const
01396 {
01397   char* buf = (char*) buffer();
01398   unsigned long long int ret;
01399   //Same as preceding routine
01400 
01401     switch (ltype) {
01402       case TINY  :
01403       case SMALL :
01404       case MEDIUM:
01405       case INT   :
01406     if (lisunsigned)   ret = uival();
01407     else               ret =  ival();
01408     break;
01409       case BIGINT:
01410     if (lisunsigned)
01411       ret = (*((unsigned long long int*) buf));
01412     else
01413       ret = (*((long long int*) buf));
01414     break;
01415       case FLOAT :  ret = (long long int) rintf(*((float*) buf)); break;
01416       case DOUBLE:  ret = (long long int) rint(*((double*) buf)); break;
01417       case TIME  :  ret = (long long int) tval();                 break;
01418       case STRING:
01419     if (sscanf(buf, lfmt, &ret) != 1)
01420       throw MCS_ERROR(MSG_CONVERSION_STRING_INT);
01421     break;
01422       case TINY_BLOB:
01423       case BLOB:
01424       case POINTER:
01425     throw MCS_ERROR(MSG_CONVERSION_BLOB_INT);
01426   }
01427 
01428   return ret;
01429 }
01430 
01431 
01432 float mcs::Data::fval() const
01433 {
01434   char* buf = (char*) buffer();
01435   float ret;
01436 
01437   switch (ltype) {
01438       case TINY  :
01439       case SMALL :
01440       case MEDIUM:
01441       case INT   :
01442       case BIGINT:
01443       case TIME  :
01444     if (lisunsigned) ret = ulval();
01445     else             ret = lval();
01446     break;
01447       case FLOAT:   ret =          (*((float*) buf)); break;
01448       case DOUBLE:  ret = (float) (*((double*) buf)); break;
01449       case STRING:
01450     if (sscanf(buf, ffmt, &ret) != 1)
01451       throw MCS_ERROR(MSG_CONVERSION_STRING_FLOAT);
01452     break;
01453       case TINY_BLOB:
01454       case BLOB:
01455       case POINTER:
01456     throw MCS_ERROR(MSG_CONVERSION_BLOB_FLOAT);
01457   }
01458 
01459   return ret;
01460 }
01461 
01462 
01463 double mcs::Data::dval() const
01464 {
01465   char* buf = (char*) buffer();
01466   double ret;
01467 
01468   switch (ltype) {
01469       case TINY  :
01470       case SMALL :
01471       case MEDIUM:
01472       case INT   :
01473       case BIGINT:
01474       case TIME  :
01475     if (lisunsigned) ret = ulval();
01476     else             ret = lval();
01477     break;
01478       case FLOAT:   ret = fval();             break;
01479       case DOUBLE:  ret = (*((double*) buf)); break;
01480       case STRING:
01481     if (sscanf(buf, dfmt, &ret) != 1)
01482       throw MCS_ERROR(MSG_CONVERSION_STRING_FLOAT);
01483     break;
01484       case TINY_BLOB:
01485       case BLOB:
01486       case POINTER:
01487       throw MCS_ERROR(MSG_CONVERSION_BLOB_FLOAT);
01488   }
01489 
01490   return ret;
01491 }
01492 
01493 
01494 
01495 
01496 
01497 //void mcs::Data::MySQL_TIME_2_time_t(MYSQL_TIME* mtime, time_t* t)
01498 //{
01499 //  struct tm tm;
01500 //  memset(&tm, '\0', sizeof(tm));
01501 //
01502 //  tm.tm_sec   = mtime->second;
01503 //  tm.tm_min   = mtime->minute;
01504 //  tm.tm_hour  = mtime->hour;
01505 //  tm.tm_mday  = mtime->day;
01506 //  tm.tm_mon   = mtime->month - 1;
01507 //  tm.tm_year  = mtime->year - 1900;
01508 //
01509 //  switch (dbtimemode) {
01510 //      case GMT:
01511 //  *t = timegm(&tm);
01512 //  break;
01513 //      case LOCAL:
01514 //  *t = timelocal(&tm);
01515 //  break;
01516 //  }
01517 //}
01518 //
01519 //void mcs::Data::time_t_2_MySQL_TIME(time_t* t, MYSQL_TIME* mtime)
01520 //{
01521 //  struct tm tm;
01522 //  time_t lt = *t;
01523 //  int fl = 0;
01524 //
01525 //  while ( (fl == 0)                       ||
01526 //   ((fl == 1)  &&  (tm.tm_isdst))
01527 //        ) {
01528 //    switch (dbtimemode) {
01529 //  case GMT:
01530 //    gmtime_r(&lt, &tm);
01531 //    break;
01532 //  case LOCAL:
01533 //    localtime_r(&lt, &tm);
01534 //    break;
01535 //    }
01536 //    if (tm.tm_isdst) lt -= 3600;
01537 //    fl++;
01538 //  }
01539 //
01540 //  mtime->second = tm.tm_sec ;
01541 //  mtime->minute = tm.tm_min ;
01542 //  mtime->hour   = tm.tm_hour;
01543 //  mtime->day    = tm.tm_mday;
01544 //  mtime->month  = tm.tm_mon + 1;
01545 //  mtime->year   = tm.tm_year + 1900 ;
01546 //}
01547 
01548 
01549 
01550 
01551 
01552 
01553 string mcs::Data::sval(bool addWhiteSpaces) const
01554 {
01555   char* buf = (char*) buffer();
01556   char lbuf[30];
01557   long long int l;
01558   unsigned long long int ul;
01559   float f;
01560   double d;
01561   string ret;
01562 
01563   if (ltype == TINY     ||
01564       ltype == SMALL    ||
01565       ltype == MEDIUM   ||
01566       ltype == INT
01567       ) {
01568     l = lval();
01569     sprintf(lbuf, ifmt, l);
01570   }
01571 
01572   else if (ltype == BIGINT) {
01573     if (lisunsigned) {
01574       l = lval();
01575       sprintf(lbuf, lfmt, l);
01576     }
01577     else {
01578       ul = ulval();
01579       sprintf(lbuf, lfmt, ul);
01580     }
01581   }
01582   else if (ltype == FLOAT)  {
01583     f = fval();
01584     sprintf(lbuf, ffmt, f);
01585   }
01586   else if (ltype == DOUBLE) {
01587     d = dval();
01588     sprintf(lbuf, dfmt, d);
01589   }
01590   else if (ltype == TIME) {
01591     ret = (string) dt;
01592     //time_t t;
01593     //struct tm tm;
01594     //MySQL_TIME_2_time_t((MYSQL_TIME*) buf, &t);
01595     //localtime_r(&t, &tm);
01596     //strftime(lbuf, 30, "%F %T", &tm);
01597   }
01598   else if (ltype == STRING) {
01599     ret = string(buf); //, lmaxlength);
01600     if (! addWhiteSpaces)
01601       ret = trim(ret);
01602   }
01603   else if ((ltype == BLOB)   ||   (ltype == TINY_BLOB)) {
01604       ret = hexDump(buf, llength);
01605   }
01606   if (ltype != STRING   &&   ltype != TIME)
01607     ret = string(lbuf);
01608 
01609   ret = trim(ret);
01610   return ret;
01611 }
01612 
01613 
01614 int mcs::Data::cval(char* c, int maxlength) const
01615 {
01616     string s = sval();
01617     int l = s.length();
01618 
01619     if (l < maxlength) {
01620       memcpy(c, s.c_str(), l+1);
01621       return l;
01622     }
01623     else
01624       return 0;
01625 }
01626 
01627 
01628 
01629 void* mcs::Data::pval() const
01630 {
01631   void* p;
01632   memcpy(&p, buf, sizeof(void*));
01633   return p;
01634 }
01635 
01636 void mcs::Data::setpval(void* p)
01637 {
01638   memcpy(buf, &p, sizeof(void*));
01639 }
01640 
01641 
01642 
01643 
01644 /*
01645   Notes on TIME data type.
01646 
01647   MySQL handle 4 field type: MYSQL_TYPE_TIME, MYSQL_TYPE_DATE,
01648   MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP. In any case data is returned
01649   as a MySQL_TIME structure in local time zone. Also upon writing on DB data
01650   must be in local time zone.
01651 
01652   When converting to/from other data types we assume that:
01653   - strings express datetime in local time zone;
01654   - numbers express the number of seconds elapsed since 1970-01-01 00:00:00
01655     UTC.
01656 
01657 
01658   When a Data(TIME) object is serialized data are converted to MCS_TIME. It is
01659   convenient because it is only 64 bit long, but it has enough room to handle
01660   all dates in the year range 1900 +/- 32768, that is from 00:00:00 1 Jan
01661   30867BC to 23:59:59 31 Dec 34668AD, with microsecond resolution. Furthermore
01662   it refers to UTC, so it can be converted to local time zone when
01663   unserializing the object.
01664 */
01665 typedef int64_t MCS_TIME;
01666 
01667 #define MCS_TIME_MICROSEC 0xFFFFF  // 20 bit,  0 tot, microsecond resolution, not yet used.
01668 #define MCS_TIME_SEC         0x3F  //  6 bit, 20 tot
01669 #define MCS_TIME_MIN         0x3F  //  6 bit, 26 tot
01670 #define MCS_TIME_HOUR        0x1F  //  5 bit, 32 tot
01671 #define MCS_TIME_DAY         0x1F  //  5 bit, 37 tot
01672 #define MCS_TIME_MONTH        0xF  //  4 bit, 42 tot
01673 #define MCS_TIME_YEAR      0xFFFF  // 16 bit, 46 tot
01674 #define MCS_TIME_FLAGS        0x3  //  2 bit, 52 tot, not yet used
01675                                    // 64 bit, 64 tot
01676 
01677 MCS_TIME struct_tm2MCS_TIME(struct tm* ct)
01678 {
01679   //Convert to UTC
01680   time_t t = timelocal(ct);
01681   gmtime_r(&t, ct);
01682 
01683   MCS_TIME mt =
01684     (((MCS_TIME) ct->tm_sec ) << 20) +
01685     (((MCS_TIME) ct->tm_min ) << 26) +
01686     (((MCS_TIME) ct->tm_hour) << 32) +
01687     (((MCS_TIME) ct->tm_mday) << 37) +
01688     (((MCS_TIME) ct->tm_mon ) << 42) +
01689     (((MCS_TIME) ct->tm_year) << 46)  ;
01690 
01691   return mt;
01692 }
01693 
01694 
01695 int MCS_TIME2struct_tm(MCS_TIME mt, struct tm* ct)
01696 {
01697   ct->tm_sec   = (int)  ((mt >> 20)  &  MCS_TIME_SEC  );
01698   ct->tm_min   = (int)  ((mt >> 26)  &  MCS_TIME_MIN  );
01699   ct->tm_hour  = (int)  ((mt >> 32)  &  MCS_TIME_HOUR );
01700   ct->tm_mday  = (int)  ((mt >> 37)  &  MCS_TIME_DAY  );
01701   ct->tm_mon   = (int)  ((mt >> 42)  &  MCS_TIME_MONTH);
01702   ct->tm_year  = (int)  ((mt >> 46)  &  MCS_TIME_YEAR );
01703 
01704   //Convert to local time zone
01705   time_t t = timegm(ct);
01706   localtime_r(&t, ct);
01707   return 0;
01708 }
01709 
01710 
01711 
01712 
01713 #define DATETIME_PARSE_NTEMPL  16
01714 
01715 static const char* templ[DATETIME_PARSE_NTEMPL] = {
01716   "%x%n%X",
01717   "%x%n%T",
01718   "%x%n%r",
01719 
01720   "%D%n%X",
01721   "%D%n%T",
01722   "%D%n%r",
01723 
01724   "%F%n%X",
01725   "%F%n%T",
01726   "%F%n%r",
01727 
01728   "%x",                   //The date using the locale's date format.
01729   "%D",                   //Equivalent to `%m/%d/%y'
01730   "%F",                   //Equivalent to `%Y-%m-%d'
01731 
01732   "%X",                   //The time using the locale's time format.
01733   "%T",                   //Equivalent to the use of `%H:%M:%S' in this place.
01734   "%r",                   //The complete time using the AM/PM format of the current locale.
01735 
01736   "%s",                   //The number of seconds since the epoch, i.e., since 1970-01-01 00:00:00 UTC.
01737 };
01738 
01739 
01740 void mcs::Data::parseTime(string s, struct tm* tm)
01741 {
01742   int i;
01743   const char* ret = NULL;
01744 
01745   memset(tm, '\0', sizeof(*tm));
01746 
01747   for (i=0; i<DATETIME_PARSE_NTEMPL; i++) {
01748     ret = strptime(s.c_str(), templ[i], tm);
01749     if (ret != NULL) break;
01750   }
01751 
01752   if (ret == NULL)
01753     throw MCS_ERROR(MSG_CONVERSION_DATETIME, s.c_str());
01754 
01755 //  int ret;
01756 //  bool fl_riporto = false;
01757 //
01758 //  s = trim(s); // leading and trailing blanks
01759 //  s = subst(s, "  +", ""); // multiple blanks
01760 //  s = subst(s, "[^0-9:\\- ]", ""); //non-expected chars
01761 //
01762 //  const char* p = s.c_str();
01763 //  float sec;
01764 //
01765 //  ret = sscanf(p, dtfmt,
01766 //         &(ts->tm_year), &(ts->tm_mon), &(ts->tm_mday),
01767 //         &(ts->tm_hour), &(ts->tm_min), &sec);
01768 //
01769 //
01770 //  if (ret == 6) {  //Date and time
01771 //    ts->tm_year -= 1900;
01772 //    ts->tm_mon--;
01773 //  }
01774 //  else {
01775 //    ret = sscanf(p, dafmt,
01776 //       &(ts->tm_year), &(ts->tm_mon), &(ts->tm_mday));
01777 //    if (ret == 3) {  //Only date
01778 //      ts->tm_year -= 1900;
01779 //      ts->tm_mon--;
01780 //    }
01781 //    else {
01782 //      ret = sscanf(p, tmfmt, &(ts->tm_hour),
01783 //         &(ts->tm_min), &sec);
01784 //      if (ret != 3)
01785 //  throw MCS_ERROR(MSG_CONVERSION_DATETIME, s.c_str());
01786 //    }
01787 //  }
01788 //
01789 //  sec = rint(sec);
01790 //  if (sec == 60) {
01791 //    fl_riporto = true;
01792 //    sec = 59;
01793 //  }
01794 //  ts->tm_sec = (int) sec;
01795 //
01796 //  if (
01797 //    ((ts->tm_mon  < 0)   ||   (ts->tm_mon  > 11))             ||
01798 //    ((ts->tm_mday < 1)   ||   (ts->tm_mday > 31))             ||
01799 //    ((ts->tm_hour < 0)   ||   (ts->tm_hour > 23))             ||
01800 //    ((ts->tm_min  < 0)   ||   (ts->tm_min  > 59))             ||
01801 //    ((ts->tm_sec  < 0)   ||   (ts->tm_sec  > 59))
01802 //    )
01803 //    throw MCS_ERROR(MSG_CONVERSION_DATETIME, s.c_str());
01804 //
01805 //  //ts->tm_isdst = 0;
01806 //  ts->tm_gmtoff = 0;
01807 //  time_t t = timelocal(ts); //Normalize
01808 //
01809 //  if (fl_riporto) {
01810 //    t++;  //Add one second
01811 //    localtime_r(&t, ts);
01812 //  }
01813 }
01814 
01815 
01816 void mcs::Data::tval(struct tm* ts) const
01817 {
01818   if (ltype == STRING) {
01819     parseTime(sval(), ts);
01820   }
01821   else if (ltype == TIME) {
01822     *ts = dt;
01823     //time_t t;
01824     //MySQL_TIME_2_time_t((MYSQL_TIME*) buf, &t);
01825     //localtime_r(&t, ts);
01826   }
01827   else if ((ltype == BLOB)   ||   (ltype == TINY_BLOB))
01828     throw MCS_ERROR(MSG_CONVERSION_BLOB_DATETIME);
01829   else {
01830     time_t tt = (time_t) dval();
01831     localtime_r(&tt, ts);
01832   }
01833 }
01834 
01835 
01836 time_t mcs::Data::tval() const
01837 {
01838   struct tm ts;
01839   tval(&ts);
01840   return timelocal(&ts);
01841 }
01842 
01843 
01844 void mcs::Data::settimenow()
01845 { dt.now(); }
01846 
01847 
01848 void mcs::Data::setTimeMode(enum TimeMode tm)
01849 { dt.setTimeMode(tm); }
01850 
01851 
01852 
01853 void mcs::Data::settimeval(struct tm tm)
01854 {
01855   char* buf = (char*) buffer();
01856   time_t t;
01857 
01858   lisnull = false;
01859 
01860   //switch (dbtimemode) {
01861   //    case GMT:
01862   //    t = timegm(&tm);
01863   //    break;
01864   //    case LOCAL:
01865     t = timelocal(&tm);
01866   //    break;
01867   //}
01868 
01869   switch (ltype) {
01870       case TINY:
01871       case SMALL:
01872       case MEDIUM:
01873       case TINY_BLOB:
01874       case BLOB:
01875       case POINTER:
01876     throw MCS_ERROR(MSG_CONVERSION_TIME_LINT);
01877     break;
01878       case INT:
01879       case BIGINT:
01880     setival( t );
01881     break;
01882       case FLOAT:
01883       case DOUBLE:
01884     setdval( t );
01885     break;
01886       case STRING:
01887     if (lmaxlength < 30)
01888       throw MCS_ERROR(MSG_CONVERSION_STRING_TOO_LONG);
01889 
01890     strftime(buf, 30, "%F %T", &tm);
01891     break;
01892       case TIME:
01893     dt = tm;
01894     //time_t_2_MySQL_TIME(&t, (MYSQL_TIME*) buf);
01895   }
01896 }
01897 
01898 
01899 void mcs::Data::settimeval(time_t tt)
01900 {
01901   struct tm ts;
01902   localtime_r(&tt, &ts);
01903   settimeval(ts);
01904 }
01905 
01906 
01907 
01908 
01909 
01910 
01911 
01912 
01913 
01914 
01915 
01916 
01917 
01918 
01919 
01920 
01921 void mcs::Data::setNull(bool null)
01922 {
01923   lisnull = null;
01924 }
01925 
01926 
01927 void mcs::Data::setival(int v)
01928 {
01929   setlval(v);
01930 }
01931 
01932 void mcs::Data::setuival(unsigned int v)
01933 {
01934   setulval(v);
01935 }
01936 
01937 void mcs::Data::setlval(long long int v)
01938 {
01939   char* buf = (char*) buffer();
01940   lisnull = false;
01941   bool us = lisunsigned;
01942 
01943   switch (ltype) {
01944   case TINY:
01945     if (us) (*((unsigned char*)          buf)) = (unsigned char) v;
01946     else    (*((char*)                   buf)) = (char)          v;
01947     break;
01948   case SMALL:
01949     if (us) (*((unsigned short int*)     buf)) = (unsigned short int) v;
01950     else    (*((short int*)              buf)) = (short int)          v;
01951     break;
01952   case MEDIUM  :
01953     if (us) (*((unsigned int*)           buf)) = (unsigned int) v;
01954     else    (*((int*)                    buf)) = (int)          v;
01955     break;
01956   case INT  :
01957     if (us) (*((unsigned int*)           buf)) = (unsigned int) v;
01958     else    (*((int*)                    buf)) = (int)          v;
01959     break;
01960   case BIGINT:
01961     if (us) (*((unsigned long long int*) buf)) = (unsigned long long int) v;
01962     else    (*((long long int*)          buf)) = (long long int)          v;
01963     break;
01964   case FLOAT:
01965     (*((float*) buf)) = v; break;
01966   case DOUBLE:
01967     (*((double*) buf)) = v; break;
01968   case STRING:
01969     memset(buf, 32, lmaxlength);
01970     snprintf(buf, lmaxlength, lfmt, v);
01971     llength = strlen(buf);
01972     break;
01973   case TINY_BLOB:
01974       throw MCS_ERROR(MSG_CONVERSION_INT_BLOB); break;
01975   case BLOB:
01976       throw MCS_ERROR(MSG_CONVERSION_INT_BLOB); break;
01977   case POINTER:
01978       throw MCS_ERROR(MSG_CONVERSION_INT_BLOB); break;
01979   case TIME:
01980     time_t tt = (time_t) v;
01981     dt = tt;
01982     //time_t_2_MySQL_TIME(&tt, (MYSQL_TIME*) buf);
01983     break;
01984   }
01985 
01986   MCS_DEBUG("-> " << sval());
01987 }
01988 
01989 
01990 
01991 
01992 
01993 void mcs::Data::setulval(unsigned long long int v)
01994 {
01995   char* buf = (char*) buffer();
01996   lisnull = false;
01997   bool us = lisunsigned;
01998 
01999   switch (ltype) {
02000   case TINY:
02001     if (us) (*((unsigned char*)          buf)) = (unsigned char) v;
02002     else    (*((char*)                   buf)) = (char)          v;
02003     break;
02004   case SMALL:
02005     if (us) (*((unsigned short int*)     buf)) = (unsigned short int) v;
02006     else    (*((short int*)              buf)) = (short int)          v;
02007     break;
02008   case MEDIUM  :
02009     if (us) (*((unsigned int*)           buf)) = (unsigned int) v;
02010     else    (*((int*)                    buf)) = (int)          v;
02011     break;
02012   case INT  :
02013     if (us) (*((unsigned int*)           buf)) = (unsigned int) v;
02014     else    (*((int*)                    buf)) = (int)          v;
02015     break;
02016   case BIGINT:
02017     if (us) (*((unsigned long long int*) buf)) = (unsigned long long int) v;
02018     else    (*((long long int*)          buf)) = (long long int)          v;
02019     break;
02020   case FLOAT:
02021     (*((float*) buf)) = v; break;
02022   case DOUBLE:
02023     (*((double*) buf)) = v; break;
02024   case STRING:
02025     memset(buf, 32, lmaxlength);
02026     snprintf(buf, lmaxlength, lfmt, v);
02027     llength = strlen(buf);
02028     break;
02029   case TINY_BLOB:
02030       throw MCS_ERROR(MSG_CONVERSION_INT_BLOB); break;
02031   case BLOB:
02032       throw MCS_ERROR(MSG_CONVERSION_INT_BLOB); break;
02033   case POINTER:
02034       throw MCS_ERROR(MSG_CONVERSION_INT_BLOB); break;
02035   case TIME:
02036     time_t tt = (time_t) v;
02037     dt = tt;
02038     //time_t_2_MySQL_TIME(&tt, (MYSQL_TIME*) buf);
02039     break;
02040   }
02041 
02042   MCS_DEBUG("-> " << sval());
02043 }
02044 
02045 
02046 
02047 
02048 
02049 
02050 
02051 void mcs::Data::setdval(double v)
02052 {
02053   char* buf = (char*) buffer();
02054   lisnull = false;
02055   bool us = lisunsigned;
02056 
02057   switch (ltype) {
02058   case TINY:
02059     if (us) (*((unsigned char*)          buf)) = (unsigned char) nearbyint(v);
02060     else    (*((char*)                   buf)) = (char)          nearbyint(v);
02061     break;
02062   case SMALL:
02063     if (us) (*((unsigned short int*)     buf)) = (unsigned short int) nearbyint(v);
02064     else    (*((short int*)              buf)) = (short int)          nearbyint(v);
02065     break;
02066   case MEDIUM  :
02067     if (us) (*((unsigned int*)           buf)) = (unsigned int) nearbyint(v);
02068     else    (*((int*)                    buf)) = (int)          nearbyint(v);
02069     break;
02070   case INT  :
02071     if (us) (*((unsigned int*)           buf)) = (unsigned int) nearbyint(v);
02072     else    (*((int*)                    buf)) = (int)          nearbyint(v);
02073     break;
02074   case BIGINT:
02075     if (us) (*((unsigned long long int*) buf)) = (unsigned long long int) nearbyint(v);
02076     else    (*((long long int*)          buf)) = (long long int)          nearbyint(v);
02077     break;
02078   case FLOAT:
02079     (*((float*) buf)) = v; break;
02080   case DOUBLE:
02081     (*((double*) buf)) = v; break;
02082   case STRING:
02083     memset(buf, 32, lmaxlength);
02084     snprintf(buf, lmaxlength, dfmt, v);
02085     llength = strlen(buf);
02086     break;
02087   case TINY_BLOB:
02088       throw MCS_ERROR(MSG_CONVERSION_FLOAT_BLOB); break;
02089   case BLOB:
02090       throw MCS_ERROR(MSG_CONVERSION_FLOAT_BLOB); break;
02091   case POINTER:
02092       throw MCS_ERROR(MSG_CONVERSION_FLOAT_BLOB); break;
02093   case TIME:
02094     time_t tt = (time_t) nearbyint(v);
02095     dt = tt;
02096     //time_t_2_MySQL_TIME(&tt, (MYSQL_TIME*) buf);
02097     break;
02098   }
02099 
02100   MCS_DEBUG("-> " << sval());
02101 }
02102 
02103 
02104 void mcs::Data::setcval(const char* v)
02105 {
02106     setsval(string(v));
02107     MCS_DEBUG("-> " << sval());
02108 }
02109 
02110 
02111 void mcs::Data::setsval(string v)
02112 {
02113   char* buf = (char*) buffer();
02114   int ret=-1000;
02115   bool us = lisunsigned;
02116   lisnull = false;
02117 
02118   switch (ltype) {
02119   case TINY:
02120     if (us) ret=sscanf(v.c_str(), "%hhd", ((unsigned char*)          buf));
02121     else    ret=sscanf(v.c_str(), "%hhd", ((char*)                   buf));
02122     break;
02123   case SMALL:
02124     if (us) ret=sscanf(v.c_str(), "%hd" , ((unsigned short int*)     buf));
02125     else    ret=sscanf(v.c_str(), "%hd" , ((short int*)              buf));
02126     break;
02127   case MEDIUM  :
02128     if (us) ret=sscanf(v.c_str(), "%d" , ((unsigned int*)           buf));
02129     else    ret=sscanf(v.c_str(), "%d" , ((int*)                    buf));
02130     break;
02131   case INT  :
02132     if (us) ret=sscanf(v.c_str(), "%d" , ((unsigned int*)           buf));
02133     else    ret=sscanf(v.c_str(), "%d" , ((int*)                    buf));
02134     break;
02135   case BIGINT:
02136     if (us) ret=sscanf(v.c_str(), "%lld", ((unsigned long long int*) buf));
02137     else    ret=sscanf(v.c_str(), "%lld", ((long long int*)          buf));
02138     break;
02139   case FLOAT:
02140     ret=sscanf(v.c_str(), "%f" , ((float*)  buf)); break;
02141   case DOUBLE:
02142     ret=sscanf(v.c_str(), "%lf", ((double*) buf)); break;
02143   case TIME:
02144     dt = v;
02145     //struct tm ts;
02146     //time_t t;
02147     //parseTime(v, &ts);
02148     //
02149     //switch (dbtimemode) {
02150     //  case GMT:
02151     //    t = timegm(&ts);
02152     //    break;
02153     //  case LOCAL:
02154     //    t = timelocal(&ts);
02155     //    break;
02156     //}
02157     //time_t_2_MySQL_TIME(&t, (MYSQL_TIME*) buf);
02158     break;
02159   case STRING:
02160     if (v.length() > lmaxlength)
02161     throw MCS_ERROR(MSG_CONVERSION_STRING_TOO_LONG);
02162     else {
02163       memset(buf, 32, lmaxlength);
02164       llength = v.length();
02165       memcpy(buf, v.c_str(), llength);
02166     }
02167     break;
02168   case TINY_BLOB:
02169       throw MCS_ERROR(MSG_CONVERSION_STRING_BLOB); break;
02170   case BLOB:
02171       throw MCS_ERROR(MSG_CONVERSION_STRING_BLOB); break;
02172   case POINTER:
02173       throw MCS_ERROR(MSG_CONVERSION_STRING_BLOB); break;
02174   }
02175 
02176   if (ret!=-1000   &&   ret!=1)
02177       throw MCS_ERROR(MSG_CONVERSION_NAN);
02178 
02179   MCS_DEBUG("-> " << sval());
02180 }
02181 
02182 
02183 
02184 void mcs::Data::setblob(void* lbuf, unsigned int size)
02185 {
02186   char* buf = (char*) buffer();
02187 
02188   lisnull = false;
02189   if ((ltype != TINY_BLOB)   &&   (ltype != BLOB))
02190     throw MCS_ERROR(MSG_NOT_A_BLOB);
02191 
02192   if (size > lmaxlength)
02193     throw MCS_ERROR(MSG_NOT_ENOUGH_SPACE, size, lmaxlength);
02194 
02195   memcpy(buf, lbuf, size);
02196 }
02197 
02198 
02199 
02200 long long int mcs::Data::MinValue(Types ltype, bool flunsigned)
02201 {
02202   int nbit;
02203   switch (ltype) {
02204   case TINY:
02205     nbit =  8;   break;
02206   case SMALL:
02207     nbit = 16;   break;
02208   case MEDIUM:
02209     nbit = 24;   break;
02210   case INT:
02211     nbit = 32;   break;
02212   case BIGINT:
02213     nbit = 64;   break;
02214   default:
02215     return 0;
02216   }
02217   if (flunsigned)
02218     return 0;
02219   else
02220     return (long long int) (-1 * (pow(2.0, nbit) / 2));
02221 }
02222 
02223 
02224 long long int mcs::Data::MaxValue(Types ltype, bool flunsigned)
02225 {
02226   int nbit;
02227   switch (ltype) {
02228   case TINY:
02229     nbit =  8;   break;
02230   case SMALL:
02231     nbit = 16;   break;
02232   case MEDIUM:
02233     nbit = 24;   break;
02234   case INT:
02235     nbit = 32;   break;
02236   case BIGINT:
02237     nbit = 64;   break;
02238   default:
02239     return 0;
02240   }
02241   if (flunsigned)
02242     return (long long int) (pow(2.0, nbit) - 1);
02243   else
02244     return (long long int) ((pow(2.0, nbit) / 2) - 1);
02245 }
02246 
02247 
02248 
02249 
02250 Data& mcs::Data::operator=(Data& d)
02251 {
02252   //cout << endl << endl << "Operator assignment" << endl << endl;
02253   if (this == &d)
02254     return *this; //Self assignment
02255 
02256   if (d.isNull()) {
02257     setNull();
02258     return *this;
02259   }
02260 
02261   switch(d.type()) {
02262       case TINY:
02263       case SMALL:
02264       case MEDIUM:
02265     setival( d.ival() );
02266     break;
02267       case INT:
02268     if (d.isUnsigned())
02269       setdval( d.lval() );
02270     else
02271       setival( d.ival() );
02272         break;
02273       case BIGINT:
02274     if (d.isUnsigned())
02275       setdval( d.ulval() );
02276     else
02277       setdval( d.lval() );
02278     break;
02279       case FLOAT:
02280       case DOUBLE:
02281     setdval( d.dval() );
02282     break;
02283       case STRING:
02284     setsval( d.sval() );
02285     break;
02286       case TIME:
02287     settimeval( d.tval() );
02288     break;
02289       case TINY_BLOB:
02290       case BLOB:
02291     setblob( d.buffer(), d.length() );
02292       case POINTER:
02293     setpval(d.pval());
02294     break;
02295   }
02296 
02297   return *this;
02298 }
02299 
02300 
02301 
02302 
02303 unsigned int mcs::Data::objSize()
02304 {
02305     //For (bits): ltype (4), lisunsigned (1), lisnul (1), autoincrement(1)
02306     unsigned int size = 1;
02307 
02308     if (VarLenType(ltype)) {
02309     size += sizeof(lmaxlength);
02310     size += sizeof(unsigned short int); //llength
02311     }
02312     size += sizeof(tag);
02313     size += lname.length()+1; //NULL character
02314 
02315     //Data buffer
02316     if (ltype == TIME)
02317       size += sizeof(MCS_TIME);
02318     else
02319       size += lmaxlength;
02320 
02321     return size;
02322 }
02323 
02324 
02325 
02326 bool mcs::Data::serialize_buffer(char*& buf, unsigned int& size)
02327 {
02328   Buffer abuf(DONT_FREE); //*
02329 
02330   unsigned char tmp_mix = 0;
02331 
02332   tmp_mix += (unsigned char) ltype;
02333 
02334   if (lisunsigned)
02335     tmp_mix += 16;
02336   if (lisnull)
02337     tmp_mix += 32;
02338   if (lautoincr)
02339     tmp_mix += 64;
02340 
02341   if (ldimspec > 1) //Send also ldimspec
02342     tmp_mix += 128;
02343 
02344   abuf(sizeof(tmp_mix)) << &tmp_mix;
02345 
02346   if (ldimspec > 1) {
02347     abuf(sizeof(ldimspec)) << &ldimspec;
02348 
02349     unsigned short int dim;
02350     for (unsigned int i=0; (i<howManyDim())   ||   (i<varyingDim()); i++) {
02351       dim = ldim[i];
02352       abuf(sizeof(dim)) << &dim;
02353     }
02354   }
02355 
02356   if (VarLenType(ltype)) {
02357     abuf(sizeof(lmaxlength)) << &lmaxlength;
02358 
02359     unsigned short int tmp_llength = llength;
02360     abuf(sizeof(tmp_llength)) << &tmp_llength;
02361   }
02362 
02363   abuf(sizeof(tag)) << &tag;
02364   abuf(lname.length()+1) << lname.c_str();
02365 
02366   if (ltype == TIME) { /*
02367              In this case we trasform data in a MCS_TIME
02368              value, so it will be shorter. It also solve a
02369              compatibility problem between different
02370              platform when MYSQL_TIME has different size.
02371             */
02372     //struct tm ts;
02373     //char* ll = this->buf;
02374     //for (unsigned int i=0; i<arrsize; i++) {
02375     //  MySQL_TIME_2_struct_tm((MYSQL_TIME*) ll, &ts);
02376     //  ll += lmaxlength;
02377     //
02378     //  MCS_TIME mt = struct_tm2MCS_TIME(&ts);
02379     //  abuf(sizeof(MCS_TIME)) << &mt;
02380     //}
02381     time_t t;
02382     char* ll = this->buf;
02383     for (unsigned int i=0; i<arrsize; i++) {
02384       //MySQL_TIME_2_time_t((MYSQL_TIME*) ll, &t);
02385       //ll += lmaxlength;
02386 
02387       dt.setMysqlBuffer((MYSQL_TIME*) ll);
02388       t = dt;
02389       abuf(sizeof(time_t)) << &t;
02390     }
02391   }
02392   else
02393     abuf(lmaxlength * arrsize) << this->buf;
02394 
02395   size = abuf.size();
02396   buf = abuf[0];
02397   return true;  //* = will be freed when not needed anymore
02398 }
02399 
02400 
02401 
02402 mcs::Data::Data(void* llbuf) : Serializable(MCS_SERIAL_BUFFER)
02403 {
02404   if (! llbuf) {
02405       init(NULL, TINY);
02406       setNull();
02407       return;
02408   }
02409   char* lbuf = (char*) llbuf;
02410 
02411   unsigned char tmp_mix;
02412   memcpy(&tmp_mix, lbuf, sizeof(tmp_mix));
02413   lbuf += sizeof(tmp_mix);
02414 
02415   ltype           =  (Types) (tmp_mix  &  15);
02416   lisunsigned     =   (bool) (tmp_mix  &  16);
02417   bool lisnull    =   (bool) (tmp_mix  &  32); //This value must be set AFTER init()
02418   bool lautoincr  =   (bool) (tmp_mix  &  64); //This value must be set AFTER init()
02419   bool hasDimSpec =  ((bool) (tmp_mix  &  128));
02420   string dimspec = "";
02421 
02422   if (hasDimSpec) {
02423     memcpy(&ldimspec, lbuf, sizeof(ldimspec));
02424     lbuf += sizeof(ldimspec);
02425 
02426     for (unsigned int i=0; i<MCS_DATA_NDIM; i++) {
02427       if ((i<howManyDim())   ||   (i<varyingDim())) {
02428     memcpy(&(ldim[i]), lbuf, sizeof(unsigned short int));
02429     lbuf += sizeof(unsigned short int);
02430       }
02431       else
02432     ldim[i] = 1;
02433     }
02434 
02435     dimspec = buildDimSpec(ldimspec, ldim);
02436   }
02437 
02438 
02439   lmaxlength = 0;
02440   unsigned short int tmp_llength = 0;
02441   if (VarLenType(ltype)) {
02442       memcpy(&lmaxlength , lbuf, sizeof(lmaxlength) );
02443       lbuf += sizeof(lmaxlength) ;
02444 
02445       memcpy(&tmp_llength, lbuf, sizeof(tmp_llength));
02446       lbuf += sizeof(tmp_llength);
02447       llength = tmp_llength;
02448   }
02449 
02450 
02451   unsigned char tmp_ltag;
02452   memcpy(&tmp_ltag , lbuf, sizeof(tag) ); lbuf += sizeof(tmp_ltag) ;
02453 
02454   string tmp_lname = string(lbuf);
02455   lbuf += tmp_lname.length()+1;
02456 
02457   init(NULL,
02458        ltype,
02459        (char*) tmp_lname.c_str(),
02460        lmaxlength,
02461        lisunsigned,
02462        0);
02463 
02464   resize(dimspec);
02465 
02466   if (ltype == TIME) { //See note in Data::serialize_buffer
02467     //MCS_TIME mt;
02468     //char* ll = this->buf;
02469     //
02470     //for (unsigned int i=0; i<arrsize; i++) {
02471     //  memcpy(&mt, lbuf, sizeof(MCS_TIME));
02472     //  lbuf += sizeof(MCS_TIME);
02473     //
02474     //  struct tm ts;
02475     //  MCS_TIME2struct_tm(mt, &ts);
02476     //  Struct_tm_2_MySQL_TIME(&ts, (MYSQL_TIME*) ll);
02477     //  ll += lmaxlength;
02478     //}
02479 
02480     time_t t;
02481     char* ll = this->buf;
02482 
02483     for (unsigned int i=0; i<arrsize; i++) {
02484       memcpy(&t, lbuf, sizeof(time_t));
02485       lbuf += sizeof(size_t);
02486 
02487       dt = t;
02488       //time_t_2_MySQL_TIME(&t, (MYSQL_TIME*) ll);
02489       ll += lmaxlength;
02490     }
02491   }
02492   else
02493     memcpy(buf, lbuf, lmaxlength * arrsize);
02494 
02495   if (VarLenType(ltype))
02496       llength = tmp_llength;
02497 
02498   setTag(tmp_ltag);
02499   this->lisnull   = lisnull;
02500   this->lautoincr = lautoincr;
02501 }
02502 
02503 
02504 mcs::Data::Data(void* lbuf, unsigned int size, unsigned char tag)
02505   : Serializable(MCS_SERIAL_BUFFER)
02506 {
02507     if (size < 256)
02508     init(NULL, TINY_BLOB, "", size, false, 0);
02509     else if (size < 65536)
02510     init(NULL, BLOB, "", size, false, 0);
02511     else
02512     throw MCS_ERROR(MSG_BLOB_TOO_BIG, size);
02513 
02514     setblob(lbuf, size);
02515     setTag(tag);
02516 }
02517 
02518 string mcs::Data::print()
02519 {
02520     string s;
02521     char* p;
02522     unsigned int i;
02523 
02524     s = string( "N=") + name() +
02525     string(" T=") + Types2Str(type(), isUnsigned()) +
02526     string(" L=") + itos(maxLength()) +
02527     string(" l=") + itos(length()) +
02528     string(" n=") + itos(isNull()) +
02529     string(" D=") ;
02530 
02531     if ((type() == BLOB)   ||   (type() == TINY_BLOB)) {
02532     p = (char*) buffer();
02533     for (i=0; i<length(); i++)
02534         s += itos(p[i]) + string(" ");
02535     }
02536     else
02537     s += sval();
02538 
02539     return s;
02540 }
02541 
02542 void mcs::Data::setTag(unsigned char ltag)
02543 {
02544     tag = ltag;
02545 }
02546 
02547 unsigned char mcs::Data::getTag()
02548 {
02549     return tag;
02550 }
02551 
02552 
02553 int mcs::Data::getSourceID()
02554 {
02555   return id_source;
02556 }
02557 
02558 void mcs::Data::setSourceID(int id)
02559 {
02560   id_source = id;
02561 }
02562 
02563 int mcs::Data::getDestID()
02564 {
02565   return id_dest;
02566 }
02567 
02568 void mcs::Data::setDestID(int id)
02569 {
02570   id_dest = id;
02571 }

mcslogo

MCS (My Customizable Server) ver. 0.3.3-alpha3
Documentation generated on Thu Mar 22 13:22:23 UTC 2012