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
![]() |
MCS (My Customizable Server) ver. 0.3.3-alpha3
|