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(<, &tm); 01531 // break; 01532 // case LOCAL: 01533 // localtime_r(<, &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 }
![]() |
MCS (My Customizable Server) ver. 0.3.3-alpha3
|