Db.cc

00001 // ----------------------------------------------------------------------^
00002 // Copyright (C) 2004, 2005, 2006, 2007, 2008 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 #if ENABLE_MYSQL
00027 
00028 
00029 //--------------------------------------------------------------------
00030 mcs::DBConn::DBConn()
00031 {
00032   MCS_DEBUG_SETUP(0, "DBConn");
00033 
00034   lconnInitialized = false;
00035   lconnOpened = false;
00036 }
00037 
00038 
00039 mcs::DBConn::~DBConn()
00040 {
00041   close();
00042 }
00043 
00044 void mcs::DBConn::connect(string user, string pass, string db, string host)
00045 {
00046   MYSQL* ret;
00047 
00048   close();
00049 
00050   luser = user;
00051   lpass = pass;
00052   ldb   = db  ;
00053   lhost = host;
00054 
00055   lconn = mysql_init(lconn);
00056   if (! lconn)
00057       throw MCS_ERROR(MSG_CANT_ALLOCATE_MYSQL);
00058 
00059   lconnInitialized = true;
00060   mysql_options(lconn, MYSQL_OPT_CONNECT_TIMEOUT, "5");
00061 
00062   ret = mysql_real_connect(lconn, lhost.c_str(), luser.c_str(), lpass.c_str(),
00063                ldb.c_str(), 0, MYSQL_SOCK, 0);
00064   if (ret)
00065       lconnOpened = true;
00066   else
00067       throw MCS_ERROR(MSG_CANT_OPEN_MYSQL_CONNECTION, mysql_error(lconn));
00068 }
00069 
00070 
00071 void mcs::DBConn::close()
00072 {
00073   if (lconnInitialized) {
00074 
00075     //To prevent SIGSEGV in mysql_close()
00076     //unsigned int n, f;
00077     //MYSQL_RES* res = mysql_list_processes(lconn);
00078     //vector<string> v = Query::printResultSet(res, n, f);
00079     //mysql_free_result(res);
00080     //------------------------------------
00081 
00082     mysql_close(lconn);
00083     lconnInitialized = false;
00084     lconnOpened = false;
00085   }
00086   lconn = NULL;
00087 }
00088 
00089 
00090 
00091 bool mcs::DBConn::isOpen()
00092 {
00093   return lconnOpened;
00094 }
00095 
00096 
00097 unsigned long mcs::DBConn::id()
00098 {
00099   unsigned long lid = mysql_thread_id(lconn);
00100   return lid;
00101 }
00102 
00103 DBConn* mcs::DBConn::newDBConn()
00104 {
00105   DBConn* dbc = NULL;
00106   try {
00107     dbc = new DBConn();
00108     dbc->connect(luser, lpass, ldb, lhost);
00109 
00110     if (mysql_errno(dbc->lconn))
00111       throw MCS_ERROR(MSG_CANT_OPEN_MYSQL_CONNECTION, mysql_error(dbc->lconn));
00112     return dbc;
00113   }
00114   catch (Event& e) {
00115     if (dbc) delete dbc;
00116     throw;
00117   }
00118 }
00119 
00120 
00121 
00122 
00123 
00124 
00125 
00126 
00127 
00128 
00129 
00130 
00131 //--------------------------------------------------------------------
00132 mcs::Query::Query(DBConn* conn, bool handleNewDBConn) : RecordSet()
00133 {
00134   MCS_DEBUG_SETUP(0, "Query");
00135 
00136   lhandleNewDBConn = handleNewDBConn;
00137   if (lhandleNewDBConn) {
00138     try {
00139       ldbc = conn->newDBConn();
00140     }
00141     catch (Event& e) {
00142       delete this;
00143       throw;
00144     }
00145   }
00146   else
00147     ldbc = conn;
00148 
00149   lconn = ldbc->lconn;  //Friendness of Query to DBConn class
00150   ldbc->id();
00151 
00152   gotStmtInitialized = false;
00153   gotResult = false;
00154 
00155   nlparam = 0;
00156   lbparam  = NULL;
00157   lbrec = NULL;
00158 
00159   laffectedRows = 0;
00160 
00161   readTableList();
00162 }
00163 
00164 
00165 mcs::Query::~Query()
00166 {
00167   close();
00168   if (lhandleNewDBConn) delete ldbc;
00169 }
00170 
00171 
00172 
00173 
00174 
00175 //Implementation of RecorSet's virtual methods
00176 Record* mcs::Query::newRecord()
00177 {
00178   return myrec;
00179 }
00180 
00181 
00182 bool mcs::Query::fetch(unsigned int newpos, bool random)
00183 {
00184   if (random)
00185     mysql_stmt_data_seek(lstmt, newpos);
00186 
00187   int ret = mysql_stmt_fetch(lstmt);
00188 
00189   if (ret == 1)
00190     throw MCS_ERROR(MSG_MYSQL_ERROR, mysql_stmt_error(lstmt));
00191 
00192   return ! (ret == MYSQL_NO_DATA);
00193 }
00194 
00195 
00196 
00197 
00198 
00199 unsigned int mcs::Query::nAffectedRows()
00200 {
00201   return laffectedRows;
00202 }
00203 
00204 
00205 Record& mcs::Query::param()
00206 {
00207     return lparam;
00208 }
00209 
00210 
00211 bool mcs::Query::gotRecordSet()
00212 {
00213   return gotResult;
00214 }
00215 
00216 
00217 
00218 
00219 
00220 
00221 void mcs::Query::prepare(string SQL)
00222 {
00223   string s;
00224   int i, n, numfields;
00225   MYSQL_RES* res = NULL;
00226   MYSQL_FIELD* fields;
00227   Types type;
00228 
00229   string s2 = SQL;
00230 
00231   this->SQL = s2;
00232 
00233   if (SQL.empty())
00234     throw MCS_ERROR(MSG_EMPTY_STRING);
00235 
00236   close();
00237 
00238   lstmt = mysql_stmt_init(lconn);
00239   if (!lstmt)
00240     throw MCS_ERROR(MSG_OUT_OF_MEMORY);
00241   gotStmtInitialized = true;
00242 
00243   if (mysql_stmt_prepare(lstmt, SQL.c_str(), SQL.length()))
00244     throw MCS_ERROR(MSG_MYSQL_ERROR, mysql_stmt_error(lstmt));
00245 
00246 
00247   //Allocate binding structures for parameters
00248   nlparam = mysql_stmt_param_count(lstmt);
00249   if (nlparam > 0) {
00250     lbparam = (MYSQL_BIND*) malloc(sizeof(MYSQL_BIND) * nlparam);
00251 
00252     /*  ****PARAM_METADATA****
00253     res = mysql_stmt_param_metadata(lstmt);
00254     
00255     if (res) {
00256     
00257     }
00258     */
00259 
00260   }
00261 
00262 
00263   //Allocate binding structures for records in the result
00264   n = mysql_stmt_field_count(lstmt);
00265   if (n > 0) {
00266     res = mysql_stmt_result_metadata(lstmt);
00267     if (res) {
00268 
00269       gotResult = true;
00270       lbrec = (MYSQL_BIND*) malloc(sizeof(MYSQL_BIND) * n);
00271 
00272       //Will be destroyed by the underlying RecordSet object
00273       myrec = new Record(false);
00274 
00275       fields    = mysql_fetch_fields(res);
00276       numfields = mysql_num_fields(res);
00277     
00278       for (i=0; i<numfields; i++) {
00279     if (! MYSQL2Types(fields[i].type, type))
00280       throw MCS_ERROR(MSG_TYPE_NOT_HANDLED, i, fields[i].type);
00281     
00282     Data* d = new Data(&(lbrec[i]),
00283                type,
00284                fields[i].name,
00285                (VarLenType(type) ? fields[i].length : 1),
00286                ((bool) (fields[i].flags & UNSIGNED_FLAG)),
00287                fields[i].flags
00288                );
00289     
00290     myrec->addField(d);
00291       }
00292       mysql_free_result(res);
00293 
00294       RecordSet::init(MCS_RS_USEMETAREC | MCS_RS_RANDOM, 0, myrec);
00295     }
00296   }
00297 }
00298 
00299 
00300 
00301 void mcs::Query::bind()
00302 {
00303   if (mysql_stmt_bind_param(lstmt, lbparam))
00304       throw MCS_ERROR(MSG_BIND_FAILED, mysql_stmt_error(lstmt));
00305 }
00306 
00307 
00308 
00309 
00310 
00311 Data& mcs::Query::lookup(string field, string table, string where)
00312 {
00313   SQL = string("SELECT ") + field + string(" FROM ") + table;
00314 
00315   if (! where.empty())
00316     SQL += string(" WHERE ") + where ;
00317 
00318   SQL += string(" LIMIT 1");
00319 
00320   query(SQL, true);
00321 
00322   if (nRows() != 1)
00323     throw MCS_ERROR(MSG_NO_RESULT);
00324 
00325   return rec()[0];
00326 }
00327 
00328 
00329 
00330 
00331 
00332 void mcs::Query::execute(bool StoreResult)
00333 {
00334   string s;
00335 
00336   if (! lstmt)
00337     throw MCS_ERROR(MSG_STMT_NOT_YET_PREPARED);
00338 
00339   if (mysql_stmt_execute(lstmt))
00340     throw MCS_ERROR(MSG_MYSQL_ERROR, mysql_stmt_error(lstmt));
00341 
00342   if (gotResult) {
00343     if (mysql_stmt_bind_result(lstmt, lbrec))
00344       throw MCS_ERROR(MSG_BIND_FAILED, mysql_stmt_error(lstmt));
00345 
00346     if (StoreResult) {
00347       if (mysql_stmt_store_result(lstmt))
00348     throw MCS_ERROR(MSG_MYSQL_ERROR, mysql_stmt_error(lstmt));
00349 
00350       RecordSet::init(MCS_RS_USEMETAREC | MCS_RS_RANDOM | MCS_RS_KNOW_NROWS,
00351               mysql_stmt_num_rows(lstmt), myrec);
00352     }
00353     else
00354       RecordSet::init(MCS_RS_USEMETAREC | MCS_RS_RANDOM,
00355               0, myrec);
00356 
00357     myrec->emptyName();
00358     startFetch();
00359   }
00360   else {
00361     lastid = mysql_insert_id(lconn);
00362     laffectedRows = mysql_stmt_affected_rows(lstmt);
00363   }
00364 }
00365 
00366 
00367 void mcs::Query::query(string SQL, bool StoreResult)
00368 {
00369   string scmp;
00370 
00371   SQL = trim(SQL);
00372   scmp = SQL.substr(0, 6);
00373 
00374   if ((strcasecmp(scmp.c_str(), "SELECT") == 0)   ||
00375       (strcasecmp(scmp.c_str(), "INSERT") == 0)   ||
00376       (strcasecmp(scmp.c_str(), "REPLAC") == 0)   ||
00377       (strcasecmp(scmp.c_str(), "UPDATE") == 0)   ||
00378       (strcasecmp(scmp.c_str(), "DELETE") == 0)
00379     ) {
00380     prepare(SQL);
00381     execute(StoreResult);
00382   }
00383   else {
00384     simpleQuery(SQL);
00385   }
00386 }
00387 
00388 
00389 
00390 
00391 void mcs::Query::close()
00392 {
00393   if (lbparam) {
00394     free(lbparam) ; 
00395     nlparam = 0;
00396     lbparam  = NULL;
00397     lparam.clear();
00398   }
00399 
00400 
00401   if (gotResult) {
00402     mysql_stmt_free_result(lstmt);
00403     free(lbrec);
00404     lbrec = NULL;
00405     gotResult = false;
00406     RecordSet::init(0);
00407   }
00408 
00409 
00410   if (gotStmtInitialized) {
00411     mysql_stmt_close(lstmt);
00412     lstmt = NULL;
00413     gotStmtInitialized = false;
00414   }
00415 
00416   laffectedRows = 0;
00417 }
00418 
00419 
00420 
00421 void mcs::Query::readTableList()
00422 {
00423   MYSQL_RES* res;
00424   MYSQL_ROW record;
00425   unsigned int ntbl, i;
00426 
00427   tableList.clear();
00428 
00429   res = mysql_list_tables(lconn, "%");
00430   if (res) {
00431     ntbl = mysql_num_rows(res);
00432     for (i=0; i<ntbl; i++) {
00433       record = mysql_fetch_row(res);
00434       tableList.push_back(record[0]);
00435     }
00436 
00437     mysql_free_result(res);
00438   }
00439 }
00440 
00441 
00442 vector<string> mcs::Query::tableInfo(string tbl)
00443 {
00444   unsigned int i, j;
00445   string s = "SHOW COLUMNS FROM " + tbl;
00446   try {
00447     return simpleQuery(s, i, j);
00448   }
00449   catch (...) {
00450     throw MCS_ERROR(MSG_CANT_GET_INFO_TABLE, tbl.csz);
00451   }
00452 }
00453 
00454 
00455 vector<string> mcs::Query::printResultSet(unsigned int& nrows,
00456                       unsigned int& nfields,
00457                       MYSQL_RES* res)
00458 {
00459   static string tab  = "\t";
00460   static string null = "NULL";
00461   string s;
00462   unsigned int i, j, f;
00463   vector<string> v;
00464 
00465   if (res) {  //Result coming from simpleQuery
00466     MYSQL_FIELD* fields;
00467     MYSQL_ROW record;
00468 
00469     nrows = 0;
00470     if (res) {
00471       nrows  = mysql_num_rows(res);
00472       f      = mysql_num_fields(res);  nfields = f;
00473       fields = mysql_fetch_fields(res);
00474 
00475       s = "#";
00476       for (j=0; j<f; j++)
00477     s += fields[j].name + tab;
00478       v.push_back(s);
00479 
00480       for (i=0; i<nrows; i++) {
00481     record = mysql_fetch_row(res);
00482     s = "";
00483     for (j=0; j<f; j++)
00484       if (record[j])
00485         s+=string(record[j]) + tab;
00486       else
00487         s+=null + tab;
00488     
00489     v.push_back(s);
00490       }
00491     }
00492   }
00493 
00494 
00495   else { //Result coming from prepare, execute
00496     if (! gotResult)
00497       throw MCS_ERROR(MSG_NO_RESULT);
00498 
00499     nfields = metarec().count();
00500 
00501     s = "#";
00502     for (i=0; i<nfields; i++)
00503       s += metarec()[i].name() + tab;
00504     v.push_back(s);
00505 
00506     setFirst();
00507     do {
00508       s = "";
00509       for (int i=0; i<rec().count(); i++)
00510     if (rec()[i].isNull())
00511       s += null + tab;
00512     else
00513       s += rec()[i].sval() + tab;
00514 
00515       v.push_back(s);
00516     }
00517     while (setNext());
00518 
00519     nrows = v.size();
00520   }
00521 
00522   return v;
00523 
00524 //  return v;
00525 }
00526 
00527 
00528 vector<string> mcs::Query::simpleQuery(string SQL)
00529 {
00530   unsigned int i, j;
00531   return simpleQuery(SQL, i, j);
00532 }
00533 
00534 
00535 vector<string> mcs::Query::simpleQuery(string SQL,
00536                        unsigned int& nrows,
00537                        unsigned int& nfields)
00538 {
00539   MYSQL_RES* res;
00540   vector<string> v;
00541 
00542   this->SQL = SQL;
00543   close();
00544   if (mysql_query(lconn, SQL.c_str()))
00545       throw MCS_ERROR(MSG_MYSQL_ERROR, mysql_error(lconn), mysql_errno(lconn));
00546 
00547   res = mysql_store_result(lconn);
00548   if (res) {
00549     v = printResultSet(nrows, nfields, res);
00550     mysql_free_result(res);
00551   }
00552   return v;
00553 }
00554 
00555 
00556 //#if ENABLE_CFITSIO
00557 //void mcs::Query::Result2Fits(string fn, string HDUName, bool compressed)
00558 //{
00559 //  fitsfile *fptr;
00560 //  bool fitsfileOpened = false;
00561 //  bool memAllocated   = false;
00562 //  int i;
00563 //  int status = 0;
00564 //  int  j, fitstype;
00565 //  string s;
00566 //
00567 //  char** ttype = NULL;
00568 //  char** tform = NULL;
00569 //  char*  buf   = NULL;
00570 //  char* p1;
00571 //  char* p2;
00572 //
00573 //  try {
00574 //    if (! gotResult)
00575 //      throw MCS_ERROR(MSG_NO_RESULT);
00576 //
00577 //    if (rec().count() == 0)
00578 //      throw MCS_ERROR(MSG_NO_FIELDS);
00579 //
00580 //    if (HDUName.empty())
00581 //      HDUName = "QUERY";
00582 //
00583 //    fn = "!" + fn;
00584 //    if (compressed) fn += ".gz";
00585 //
00586 //    fits_create_file(&fptr, fn.c_str(), &status);
00587 //    CHECK_FITS_ERROR;
00588 //
00589 //    fitsfileOpened = true;
00590 //
00591 //#define FIELD_NAME_LEN 50
00592 //#define FIELD_TYPE_LEN 10
00593 //    ttype = (char**) malloc(sizeof(char*) * rec().count());
00594 //    tform = (char**) malloc(sizeof(char*) * rec().count());
00595 //    buf = (char*)   malloc((FIELD_NAME_LEN + FIELD_TYPE_LEN + 2) *
00596 //             rec().count());
00597 //    memset(buf, 0, (FIELD_NAME_LEN + FIELD_TYPE_LEN + 2) * rec().count());
00598 //
00599 //    p1 = buf;
00600 //    p2 = buf + FIELD_NAME_LEN * rec().count();
00601 //    memAllocated = true;
00602 //
00603 //    for (i=0; i<rec().count(); i++) {
00604 //      ttype[i] = p1;
00605 //      p1 = stpcpy(p1, rec()[i].name().c_str());
00606 //      p1++;
00607 //
00608 //      if (! Types2S_FITS(rec()[i].type(), rec()[i].maxLength(),
00609 //           rec()[i].isUnsigned(), s))
00610 //    throw MCS_ERROR(MSG_TYPE_NOT_HANDLED, i, rec()[i].type());
00611 //
00612 //      tform[i] = p2;
00613 //      p2 = stpcpy(p2, s.c_str());
00614 //      p2++;
00615 //    }
00616 //
00617 //    fits_create_tbl(fptr, BINARY_TBL, 0, rec().count(),
00618 //          ttype, tform,
00619 //          NULL, (char*) HDUName.c_str(), &status);
00620 //    CHECK_FITS_ERROR;
00621 //
00622 //    i = 0;
00623 //    while (! eof()) {
00624 //      unsigned char lluc;
00625 //      short int llsi;
00626 //      int lli;
00627 //      long long int llli;
00628 //      char* llp;
00629 //      char* aux;
00630 //
00631 //      for (j=0; j<rec().count(); j++) {
00632 //  Types2FITS(rec()[j].type(), rec()[j].isUnsigned(), fitstype);
00633 //  
00634 //  switch (fitstype) {
00635 //  case TBYTE:
00636 //    lluc = (unsigned char) rec()[j].lval();
00637 //    llp = (char*) &lluc;     break;
00638 //  case TSHORT:
00639 //    llsi = (short int) rec()[j].lval();
00640 //    llp = (char*) &llsi;     break;
00641 //  case TLONG:
00642 //    lli = (int) rec()[j].lval();
00643 //    llp = (char*) &lli;      break;
00644 //  case TLONGLONG:
00645 //    llli= rec()[j].lval();
00646 //    llp = (char*) &llli;      break;  
00647 //  case TSTRING:
00648 //    aux = (char*) rec()[j].buffer();
00649 //    llp = (char*) &aux;
00650 //    break;
00651 //  default:
00652 //    llp = (char*) rec()[j].buffer();
00653 //  }
00654 //  
00655 //  fits_write_col(fptr, fitstype, j+1, i+1, 1, 1, llp, &status);
00656 //  CHECK_FITS_ERROR;
00657 //      }
00658 //      setNext();
00659 //      i++;
00660 //    }
00661 //
00662 //    free(ttype);
00663 //    free(tform);
00664 //    free(buf);
00665 //    memAllocated = false;
00666 //    fits_close_file(fptr, &status);
00667 //    CHECK_FITS_ERROR;
00668 //
00669 //    fitsfileOpened = false;
00670 //  }
00671 //  catch (Event& e) {
00672 //    if (memAllocated) {
00673 //      free(ttype);
00674 //      free(tform);
00675 //      free(buf);
00676 //    }
00677 //    if (fitsfileOpened) fits_close_file(fptr, &status);
00678 //  }
00679 //}
00680 //#endif
00681 
00682 
00683 vector<string> mcs::Query::ExecutionDetails(string pre)
00684 {
00685   vector<string> buf;
00686   int i;
00687   string nl = "\n";
00688 
00689   buf.push_back( pre + "Prepared query: " + SQL );
00690   buf.push_back( pre + "Number of parameters: " + itos(param().count()) );
00691 
00692   for (i=0; i<param().count(); i++)
00693     buf.push_back( "Param #" + itos(i) + string(" value: ") + lparam[i].sval() );
00694 
00695   if (gotResult) {
00696     buf.push_back( pre + "SELECT-LIKE query: " + SQL );
00697     buf.push_back( pre + "Number of records: " + itos(nRows())   );
00698     buf.push_back( pre + "Number of fields:  " + itos(nFields()) );
00699     buf.push_back( pre + "Fields detail follows:" );
00700 
00701     for (i=0; i<nFields(); i++) {
00702       buf.push_back( pre + "Field #" + itos(i) + ":" );
00703       buf.push_back( pre + "  Name      : " + metarec()[i].name() );
00704       buf.push_back( pre + "  Type      : " + Types2Str(rec()[i].type(), false) );
00705       buf.push_back( pre + "  Unsigned  : " + btos(rec()[i].isUnsigned()) );
00706       buf.push_back( pre + "  Max length: " + itos(rec()[i].maxLength()) );
00707       buf.push_back( pre + "  Length    : " + itos(rec()[i].length()) );
00708     }
00709   }
00710   else {
00711     buf.push_back( pre + "INSERT-LIKE query" );
00712     buf.push_back( pre + "Number of affected rows: " + itos(nAffectedRows())   );
00713   }
00714 
00715   return buf;
00716 }
00717 
00718 
00719 
00720 void mcs::Query::customFillBuffer(char* buf, unsigned int& chunksize, bool firstTime)
00721 {
00722   int i;
00723   string det = "";
00724   string data, s;
00725   string null = "NULL";
00726   string tab  = "\t";
00727   string nl   = "\n";
00728 
00729   MCS_DEBUG(chunksize << " " << firstTime);
00730 
00731   if (firstTime) {
00732       if (! gotResult)
00733       throw MCS_ERROR(MSG_NO_RESULT);
00734 
00735       det = vtos(ExecutionDetails());
00736       if (det.length() > chunksize) 
00737       throw MCS_ERROR(MSG_NOT_ENOUGH_SPACE, det.length(), chunksize);
00738 
00739       memcpy(buf, det.c_str(), det.length());
00740       chunksize = det.length();
00741       return;
00742   }
00743 
00744   else {
00745       if (eof()) {
00746       chunksize = 0;
00747       return;
00748       }
00749 
00750       data = "";
00751       while (! eof()) {
00752       s = "";
00753       for (i=0; i<nFields(); i++) {
00754           if (rec()[i].isNull())
00755           s += null;
00756           else
00757           s += rec()[i].sval();
00758           s += tab;
00759       }
00760       s += nl;
00761     
00762       if (data.length() + s.length() < chunksize) {
00763           data += s;
00764           setNext();
00765       }
00766       else
00767           break;
00768       }
00769 
00770       memcpy(buf, data.c_str(), data.length());
00771       chunksize = data.length();
00772       return;
00773   }
00774 }
00775 
00776 
00777 
00778 void mcs::Query::Result2Ascii(string fn)
00779 {
00780   unsigned int chunk = MCS_DEFAULTCHUNKSIZE;
00781   ofstream of(fn.c_str());
00782   bool firstTime = true;
00783 
00784   if (! of.is_open())
00785       throw MCS_ERROR(MSG_CANT_OPEN_FILE, fn.csz);
00786 
00787   char* p = (char*) malloc(chunk);
00788   while (chunk) {
00789     customFillBuffer(p, chunk, firstTime);
00790     of.write(p, chunk);
00791     firstTime = false;
00792   }
00793   free(p);
00794 
00795   of.close();
00796 }
00797 
00798 
00799 
00800 void mcs::Query::prepare_with_parameters(int op, char** fields, int nfields,
00801                      string table, string where)
00802 {
00803   int i;
00804   string s = "";
00805   for (i=0; i<nfields; i++) {
00806     if (i>0) s += " " ;
00807     s += fields[i];
00808   }
00809   prepare_with_parameters(op, s, table, where);
00810 }
00811 
00812 
00813 void mcs::Query::parseFieldList(int op, string& fields, string& values,
00814                 int& autoIncr)
00815 {
00816   int i;
00817   bool first = true;
00818   autoIncr = -1;
00819 
00820   fields = "";
00821   values = "";
00822 
00823   for (i=0; i<nFields(); i++) {
00824     if (metarec()[i].isAutoIncrement())
00825       autoIncr = i;
00826 
00827     if (! first) {
00828       fields += ", ";
00829       values += ", ";
00830     }
00831     first = false;
00832 
00833     fields += "`"+ metarec()[i].name() +"`";
00834     values += "?";
00835 
00836     if (op == MCS_PAB_UPDATE)
00837       fields += " = ?";
00838   }
00839 }
00840 
00841 
00842 
00843 void mcs::Query::prepare_with_parameters(int op, string fields, string table,
00844                      string where)
00845 {
00846   int i, autoIncr;
00847   string sql, comma_fields, marks = "";
00848   Record tmprec(false);
00849 
00850   fields = trim(fields);
00851 
00852   comma_fields = "*";
00853   if (fields != "*")
00854     comma_fields = subst(fields, " +", ", ");
00855 
00856   sql = "SELECT " + comma_fields + " FROM " + table;
00857   if (! where.empty())
00858     sql += " WHERE " + where;
00859   sql += " LIMIT 1";
00860 
00861   query(sql);
00862 
00863 
00864   if (eof())
00865     tmprec = metarec();
00866   else
00867     tmprec = rec();
00868 
00869   parseFieldList(op, fields, marks, autoIncr);
00870 
00871   switch(op) {
00872   case MCS_PAB_INSERT:
00873     sql = "INSERT INTO " + table + "(" + fields + ") VALUES (" + marks + ")";
00874     break;
00875   case MCS_PAB_REPLACE:
00876     sql = "REPLACE INTO " + table + "(" + fields + ") VALUES (" + marks + ")";
00877     break;
00878   case MCS_PAB_UPDATE:
00879     sql = "UPDATE " + table + " SET " + fields + " WHERE " + where;
00880     break;
00881   default:
00882     throw MCS_ERROR(MSG_UNEXPECTED);
00883   }
00884 
00885   prepare(sql);
00886 
00887   for (i=0; i<tmprec.count(); i++) {
00888     Data* d = new Data(&(lbparam[i]),
00889                tmprec[i].type(),
00890                (char*) tmprec[i].name().c_str(),
00891                tmprec[i].maxLength(),
00892                tmprec[i].isUnsigned());
00893 
00894     lparam.addField(d);
00895 
00896     memcpy(lparam[i].buffer(), tmprec[i].buffer(),
00897        lparam[i].maxLength());
00898   }
00899   bind();
00900 }
00901 
00902 
00903 
00904 long long int mcs::Query::last_id()
00905 {
00906   return lastid;
00907 }
00908 
00909 
00910 
00911 
00912 
00913 
00914 
00915 
00916 
00917 
00918 //--------------------------------------------------------
00919 mcs::Table::Table(DBConn* db, string table, string fieldkey) :
00920   Query(db, true), newrec(false)
00921 {
00922   MCS_DEBUG_SETUP(0, "Table");
00923 
00924   ltable = trim(table);
00925   lfieldkey = trim(fieldkey);
00926 
00927   loadTable();
00928 }
00929 
00930 
00931 mcs::Table::~Table()
00932 {}
00933 
00934 
00935 void mcs::Table::loadTable()
00936 {
00937   query("SELECT * FROM " + ltable, true);
00938 
00939   //Check for lfieldkey
00940   posfieldkey = metarec().posWhoseNameIs(lfieldkey);
00941 
00942   newrec = rec();
00943   newrec.setNull();
00944 }
00945 
00946 
00947 Record& mcs::Table::newRec()
00948 {
00949   return newrec;
00950 }
00951 
00952 
00953 
00954 void mcs::Table::insert()
00955 {
00956   insert_or_update(MCS_PAB_INSERT);
00957 }
00958 
00959 
00960 
00961 void mcs::Table::update()
00962 {
00963   insert_or_update(MCS_PAB_UPDATE);
00964 }
00965 
00966 
00967 void mcs::Table::replace()
00968 {
00969   insert_or_update(MCS_PAB_REPLACE);
00970 }
00971 
00972 
00973 void mcs::Table::insert_or_update(int op)
00974 {
00975   string where = "";
00976   int i;
00977 
00978   //Dynamic_Array<int> origmap(false);
00979   //origmap = rec().getFieldMap();
00980   //rec().setFieldMap();
00981 
00982   if (op == MCS_PAB_UPDATE) { //Data are written in current record
00983     newrec = rec();
00984     where = lfieldkey + " = " + rec()[posfieldkey].sval();
00985   }
00986 
00987   prepare_with_parameters(op, "*", ltable, where);
00988 
00989   //Copy values from newrec in the parameters
00990   for (i=0; i<param().count(); i++) {
00991     if ( param()[i].isAutoIncrement()   ||
00992          newrec[i].isNull()
00993          )
00994       param()[i].setNull();
00995     else
00996       memcpy(param()[i].buffer(), newrec[i].buffer(), param()[i].maxLength());
00997   }
00998 
00999   execute();
01000   loadTable();
01001 
01002   //rec().setFieldMap(origmap);
01003 }
01004 
01005 
01006 
01007 #endif

mcslogo

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