MCS  0.3.3-alpha7
Db.cc
1 // ----------------------------------------------------------------------^
2 // Copyright (C) 2004, 2005, 2006, 2007, 2008 Giorgio Calderone
3 // (mailto: <gcalderone@ifc.inaf.it>)
4 //
5 // This file is part of MCS.
6 //
7 // MCS is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // MCS is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with MCS; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 // ----------------------------------------------------------------------$
22 
23 #include "mcs.hh"
24 using namespace mcs;
25 
26 #if ENABLE_MYSQL
27 
28 
29 //--------------------------------------------------------------------
31 {
32  MCS_DEBUG_SETUP(0, "DBConn");
33 
34  lconnInitialized = false;
35  lconnOpened = false;
36 }
37 
38 
40 {
41  close();
42 }
43 
44 void mcs::DBConn::connect(string user, string pass, string db, string host)
45 {
46  MYSQL* ret;
47 
48  close();
49 
50  luser = user;
51  lpass = pass;
52  ldb = db ;
53  lhost = host;
54 
55  lconn = mysql_init(lconn);
56  if (! lconn)
57  throw MCS_ERROR(MSG_CANT_ALLOCATE_MYSQL);
58 
59  lconnInitialized = true;
60  mysql_options(lconn, MYSQL_OPT_CONNECT_TIMEOUT, "5");
61 
62  ret = mysql_real_connect(lconn, lhost.c_str(), luser.c_str(), lpass.c_str(),
63  ldb.c_str(), 0, MYSQL_SOCK, 0);
64  if (ret)
65  lconnOpened = true;
66  else
67  throw MCS_ERROR(MSG_CANT_OPEN_MYSQL_CONNECTION, mysql_error(lconn));
68 }
69 
70 
72 {
73  if (lconnInitialized) {
74 
75  //To prevent SIGSEGV in mysql_close()
76  //unsigned int n, f;
77  //MYSQL_RES* res = mysql_list_processes(lconn);
78  //vector<string> v = Query::printResultSet(res, n, f);
79  //mysql_free_result(res);
80  //------------------------------------
81 
82  mysql_close(lconn);
83  lconnInitialized = false;
84  lconnOpened = false;
85  }
86  lconn = NULL;
87 }
88 
89 
90 
92 {
93  return lconnOpened;
94 }
95 
96 
97 unsigned long mcs::DBConn::id()
98 {
99  unsigned long lid = mysql_thread_id(lconn);
100  return lid;
101 }
102 
104 {
105  DBConn* dbc = NULL;
106  try {
107  dbc = new DBConn();
108  dbc->connect(luser, lpass, ldb, lhost);
109 
110  if (mysql_errno(dbc->lconn))
111  throw MCS_ERROR(MSG_CANT_OPEN_MYSQL_CONNECTION, mysql_error(dbc->lconn));
112  return dbc;
113  }
114  catch (Event& e) {
115  if (dbc) delete dbc;
116  throw;
117  }
118 }
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 //--------------------------------------------------------------------
132 mcs::Query::Query(DBConn* conn, bool handleNewDBConn) : RecordSet()
133 {
134  MCS_DEBUG_SETUP(0, "Query");
135 
136  lhandleNewDBConn = handleNewDBConn;
137  if (lhandleNewDBConn) {
138  try {
139  ldbc = conn->newDBConn();
140  }
141  catch (Event& e) {
142  delete this;
143  throw;
144  }
145  }
146  else
147  ldbc = conn;
148 
149  lconn = ldbc->lconn; //Friendness of Query to DBConn class
150  ldbc->id();
151 
152  gotStmtInitialized = false;
153  gotResult = false;
154 
155  nlparam = 0;
156  lbparam = NULL;
157  lbrec = NULL;
158 
159  laffectedRows = 0;
160 
161  readTableList();
162 }
163 
164 
166 {
167  close();
168  if (lhandleNewDBConn) delete ldbc;
169 }
170 
171 
172 
173 
174 
175 //Implementation of RecorSet's virtual methods
176 Record* mcs::Query::newRecord()
177 {
178  return myrec;
179 }
180 
181 
182 bool mcs::Query::fetch(unsigned int newpos, bool random)
183 {
184  if (random)
185  mysql_stmt_data_seek(lstmt, newpos);
186 
187  int ret = mysql_stmt_fetch(lstmt);
188 
189  if (ret == 1)
190  throw MCS_ERROR(MSG_MYSQL_ERROR, mysql_stmt_error(lstmt));
191 
192  return ! (ret == MYSQL_NO_DATA);
193 }
194 
195 
196 
197 
198 
200 {
201  return laffectedRows;
202 }
203 
204 
206 {
207  return lparam;
208 }
209 
210 
211 bool mcs::Query::gotRecordSet()
212 {
213  return gotResult;
214 }
215 
216 
217 
218 
219 
220 
221 void mcs::Query::prepare(string SQL)
222 {
223  string s;
224  int i, n, numfields;
225  MYSQL_RES* res = NULL;
226  MYSQL_FIELD* fields;
227  Types type;
228 
229  string s2 = SQL;
230 
231  this->SQL = s2;
232 
233  if (SQL.empty())
234  throw MCS_ERROR(MSG_EMPTY_STRING);
235 
236  close();
237 
238  lstmt = mysql_stmt_init(lconn);
239  if (!lstmt)
240  throw MCS_ERROR(MSG_OUT_OF_MEMORY);
241  gotStmtInitialized = true;
242 
243  if (mysql_stmt_prepare(lstmt, SQL.c_str(), SQL.length()))
244  throw MCS_ERROR(MSG_MYSQL_ERROR, mysql_stmt_error(lstmt));
245 
246 
247  //Allocate binding structures for parameters
248  nlparam = mysql_stmt_param_count(lstmt);
249  if (nlparam > 0) {
250  lbparam = (MYSQL_BIND*) malloc(sizeof(MYSQL_BIND) * nlparam);
251 
252  /* ****PARAM_METADATA****
253  res = mysql_stmt_param_metadata(lstmt);
254 
255  if (res) {
256 
257  }
258  */
259 
260  }
261 
262 
263  //Allocate binding structures for records in the result
264  n = mysql_stmt_field_count(lstmt);
265  if (n > 0) {
266  res = mysql_stmt_result_metadata(lstmt);
267  if (res) {
268 
269  gotResult = true;
270  lbrec = (MYSQL_BIND*) malloc(sizeof(MYSQL_BIND) * n);
271 
272  //Will be destroyed by the underlying RecordSet object
273  myrec = new Record(false);
274 
275  fields = mysql_fetch_fields(res);
276  numfields = mysql_num_fields(res);
277 
278  for (i=0; i<numfields; i++) {
279  if (! MYSQL2Types(fields[i].type, type))
280  throw MCS_ERROR(MSG_TYPE_NOT_HANDLED, i, fields[i].type);
281 
282  Data* d = new Data(&(lbrec[i]),
283  type,
284  fields[i].name,
285  (VarLenType(type) ? fields[i].length : 1),
286  ((bool) (fields[i].flags & UNSIGNED_FLAG)),
287  fields[i].flags
288  );
289 
290  myrec->addField(d);
291  }
292  mysql_free_result(res);
293 
295  }
296  }
297 }
298 
299 
300 
302 {
303  if (mysql_stmt_bind_param(lstmt, lbparam))
304  throw MCS_ERROR(MSG_BIND_FAILED, mysql_stmt_error(lstmt));
305 }
306 
307 
308 
309 
310 
311 Data& mcs::Query::lookup(string field, string table, string where)
312 {
313  SQL = string("SELECT ") + field + string(" FROM ") + table;
314 
315  if (! where.empty())
316  SQL += string(" WHERE ") + where ;
317 
318  SQL += string(" LIMIT 1");
319 
320  query(SQL, true);
321 
322  if (nRows() != 1)
323  throw MCS_ERROR(MSG_NO_RESULT);
324 
325  return rec()[0];
326 }
327 
328 
329 
330 
331 
332 void mcs::Query::execute(bool StoreResult)
333 {
334  string s;
335 
336  if (! lstmt)
337  throw MCS_ERROR(MSG_STMT_NOT_YET_PREPARED);
338 
339  if (mysql_stmt_execute(lstmt))
340  throw MCS_ERROR(MSG_MYSQL_ERROR, mysql_stmt_error(lstmt));
341 
342  if (gotResult) {
343  if (mysql_stmt_bind_result(lstmt, lbrec))
344  throw MCS_ERROR(MSG_BIND_FAILED, mysql_stmt_error(lstmt));
345 
346  if (StoreResult) {
347  if (mysql_stmt_store_result(lstmt))
348  throw MCS_ERROR(MSG_MYSQL_ERROR, mysql_stmt_error(lstmt));
349 
351  mysql_stmt_num_rows(lstmt), myrec);
352  }
353  else
355  0, myrec);
356 
357  myrec->emptyName();
358  startFetch();
359  }
360  else {
361  lastid = mysql_insert_id(lconn);
362  laffectedRows = mysql_stmt_affected_rows(lstmt);
363  }
364 }
365 
366 
367 void mcs::Query::query(string SQL, bool StoreResult)
368 {
369  string scmp;
370 
371  SQL = trim(SQL);
372  scmp = SQL.substr(0, 6);
373 
374  if ((strcasecmp(scmp.c_str(), "SELECT") == 0) ||
375  (strcasecmp(scmp.c_str(), "INSERT") == 0) ||
376  (strcasecmp(scmp.c_str(), "REPLAC") == 0) ||
377  (strcasecmp(scmp.c_str(), "UPDATE") == 0) ||
378  (strcasecmp(scmp.c_str(), "DELETE") == 0)
379  ) {
380  prepare(SQL);
381  execute(StoreResult);
382  }
383  else {
384  simpleQuery(SQL);
385  }
386 }
387 
388 
389 
390 
392 {
393  if (lbparam) {
394  free(lbparam) ;
395  nlparam = 0;
396  lbparam = NULL;
397  lparam.clear();
398  }
399 
400 
401  if (gotResult) {
402  mysql_stmt_free_result(lstmt);
403  free(lbrec);
404  lbrec = NULL;
405  gotResult = false;
406  RecordSet::init(0);
407  }
408 
409 
410  if (gotStmtInitialized) {
411  mysql_stmt_close(lstmt);
412  lstmt = NULL;
413  gotStmtInitialized = false;
414  }
415 
416  laffectedRows = 0;
417 }
418 
419 
420 
422 {
423  MYSQL_RES* res;
424  MYSQL_ROW record;
425  unsigned int ntbl, i;
426 
427  tableList.clear();
428 
429  res = mysql_list_tables(lconn, "%");
430  if (res) {
431  ntbl = mysql_num_rows(res);
432  for (i=0; i<ntbl; i++) {
433  record = mysql_fetch_row(res);
434  tableList.push_back(record[0]);
435  }
436 
437  mysql_free_result(res);
438  }
439 }
440 
441 
442 vector<string> mcs::Query::tableInfo(string tbl)
443 {
444  unsigned int i, j;
445  string s = "SHOW COLUMNS FROM " + tbl;
446  try {
447  return simpleQuery(s, i, j);
448  }
449  catch (...) {
450  throw MCS_ERROR(MSG_CANT_GET_INFO_TABLE, tbl.csz);
451  }
452 }
453 
454 
455 vector<string> mcs::Query::printResultSet(unsigned int& nrows,
456  unsigned int& nfields,
457  MYSQL_RES* res)
458 {
459  static string tab = "\t";
460  static string null = "NULL";
461  string s;
462  unsigned int i, j, f;
463  vector<string> v;
464 
465  if (res) { //Result coming from simpleQuery
466  MYSQL_FIELD* fields;
467  MYSQL_ROW record;
468 
469  nrows = 0;
470  if (res) {
471  nrows = mysql_num_rows(res);
472  f = mysql_num_fields(res); nfields = f;
473  fields = mysql_fetch_fields(res);
474  s = "#";
475  for (j=0; j<f; j++)
476  s += fields[j].name + tab;
477  v.push_back(s);
478 
479  for (i=0; i<nrows; i++) {
480  record = mysql_fetch_row(res);
481  s = "";
482  for (j=0; j<f; j++)
483  if (record[j])
484  s+=string(record[j]) + tab;
485  else
486  s+=null + tab;
487 
488  v.push_back(s);
489  }
490  }
491  }
492 
493 
494  else { //Result coming from prepare, execute
495  if (! gotResult)
496  throw MCS_ERROR(MSG_NO_RESULT);
497 
498  nfields = metarec().count();
499 
500  s = "#";
501  for (i=0; i<nfields; i++)
502  s += metarec()[i].name() + tab;
503  v.push_back(s);
504 
505  setFirst();
506  do {
507  s = "";
508  for (int i=0; i<rec().count(); i++)
509  if (rec()[i].isNull())
510  s += null + tab;
511  else
512  s += rec()[i].sval() + tab;
513 
514  v.push_back(s);
515  }
516  while (setNext());
517 
518  nrows = v.size();
519  }
520 
521  return v;
522 
523 }
524 
525 
526 vector<string> mcs::Query::simpleQuery(string SQL)
527 {
528  unsigned int i, j;
529  return simpleQuery(SQL, i, j);
530 }
531 
532 
533 vector<string> mcs::Query::simpleQuery(string SQL,
534  unsigned int& nrows,
535  unsigned int& nfields)
536 {
537  MYSQL_RES* res;
538  vector<string> v;
539 
540  this->SQL = SQL;
541  close();
542  if (mysql_query(lconn, SQL.c_str()))
543  throw MCS_ERROR(MSG_MYSQL_ERROR, mysql_error(lconn), mysql_errno(lconn));
544 
545  res = mysql_store_result(lconn);
546  if (res) {
547  v = printResultSet(nrows, nfields, res);
548 //MYSQL_ROW record;
549 //mysql_data_seek(res, 0);
550 //record = mysql_fetch_row(res);
551 //v.push_back(record[0]);
552 
553  mysql_free_result(res);
554  }
555  return v;
556 }
557 
558 
559 //#if ENABLE_CFITSIO
560 //void mcs::Query::Result2Fits(string fn, string HDUName, bool compressed)
561 //{
562 // fitsfile *fptr;
563 // bool fitsfileOpened = false;
564 // bool memAllocated = false;
565 // int i;
566 // int status = 0;
567 // int j, fitstype;
568 // string s;
569 //
570 // char** ttype = NULL;
571 // char** tform = NULL;
572 // char* buf = NULL;
573 // char* p1;
574 // char* p2;
575 //
576 // try {
577 // if (! gotResult)
578 // throw MCS_ERROR(MSG_NO_RESULT);
579 //
580 // if (rec().count() == 0)
581 // throw MCS_ERROR(MSG_NO_FIELDS);
582 //
583 // if (HDUName.empty())
584 // HDUName = "QUERY";
585 //
586 // fn = "!" + fn;
587 // if (compressed) fn += ".gz";
588 //
589 // fits_create_file(&fptr, fn.c_str(), &status);
590 // CHECK_FITS_ERROR;
591 //
592 // fitsfileOpened = true;
593 //
594 //#define FIELD_NAME_LEN 50
595 //#define FIELD_TYPE_LEN 10
596 // ttype = (char**) malloc(sizeof(char*) * rec().count());
597 // tform = (char**) malloc(sizeof(char*) * rec().count());
598 // buf = (char*) malloc((FIELD_NAME_LEN + FIELD_TYPE_LEN + 2) *
599 // rec().count());
600 // memset(buf, 0, (FIELD_NAME_LEN + FIELD_TYPE_LEN + 2) * rec().count());
601 //
602 // p1 = buf;
603 // p2 = buf + FIELD_NAME_LEN * rec().count();
604 // memAllocated = true;
605 //
606 // for (i=0; i<rec().count(); i++) {
607 // ttype[i] = p1;
608 // p1 = stpcpy(p1, rec()[i].name().c_str());
609 // p1++;
610 //
611 // if (! Types2S_FITS(rec()[i].type(), rec()[i].maxLength(),
612 // rec()[i].isUnsigned(), s))
613 // throw MCS_ERROR(MSG_TYPE_NOT_HANDLED, i, rec()[i].type());
614 //
615 // tform[i] = p2;
616 // p2 = stpcpy(p2, s.c_str());
617 // p2++;
618 // }
619 //
620 // fits_create_tbl(fptr, BINARY_TBL, 0, rec().count(),
621 // ttype, tform,
622 // NULL, (char*) HDUName.c_str(), &status);
623 // CHECK_FITS_ERROR;
624 //
625 // i = 0;
626 // while (! eof()) {
627 // unsigned char lluc;
628 // short int llsi;
629 // int lli;
630 // long long int llli;
631 // char* llp;
632 // char* aux;
633 //
634 // for (j=0; j<rec().count(); j++) {
635 // Types2FITS(rec()[j].type(), rec()[j].isUnsigned(), fitstype);
636 //
637 // switch (fitstype) {
638 // case TBYTE:
639 // lluc = (unsigned char) rec()[j].lval();
640 // llp = (char*) &lluc; break;
641 // case TSHORT:
642 // llsi = (short int) rec()[j].lval();
643 // llp = (char*) &llsi; break;
644 // case TLONG:
645 // lli = (int) rec()[j].lval();
646 // llp = (char*) &lli; break;
647 // case TLONGLONG:
648 // llli= rec()[j].lval();
649 // llp = (char*) &llli; break;
650 // case TSTRING:
651 // aux = (char*) rec()[j].buffer();
652 // llp = (char*) &aux;
653 // break;
654 // default:
655 // llp = (char*) rec()[j].buffer();
656 // }
657 //
658 // fits_write_col(fptr, fitstype, j+1, i+1, 1, 1, llp, &status);
659 // CHECK_FITS_ERROR;
660 // }
661 // setNext();
662 // i++;
663 // }
664 //
665 // free(ttype);
666 // free(tform);
667 // free(buf);
668 // memAllocated = false;
669 // fits_close_file(fptr, &status);
670 // CHECK_FITS_ERROR;
671 //
672 // fitsfileOpened = false;
673 // }
674 // catch (Event& e) {
675 // if (memAllocated) {
676 // free(ttype);
677 // free(tform);
678 // free(buf);
679 // }
680 // if (fitsfileOpened) fits_close_file(fptr, &status);
681 // }
682 //}
683 //#endif
684 
685 
686 vector<string> mcs::Query::ExecutionDetails(string pre)
687 {
688  vector<string> buf;
689  int i;
690  string nl = "\n";
691 
692  buf.push_back( pre + "Prepared query: " + SQL );
693  buf.push_back( pre + "Number of parameters: " + itos(param().count()) );
694 
695  for (i=0; i<param().count(); i++)
696  buf.push_back( "Param #" + itos(i) + string(" value: ") + lparam[i].sval() );
697 
698  if (gotResult) {
699  buf.push_back( pre + "SELECT-LIKE query: " + SQL );
700  buf.push_back( pre + "Number of records: " + itos(nRows()) );
701  buf.push_back( pre + "Number of fields: " + itos(nFields()) );
702  buf.push_back( pre + "Fields detail follows:" );
703 
704  for (i=0; i<nFields(); i++) {
705  buf.push_back( pre + "Field #" + itos(i) + ":" );
706  buf.push_back( pre + " Name : " + metarec()[i].name() );
707  buf.push_back( pre + " Type : " + Types2Str(rec()[i].type(), false) );
708  buf.push_back( pre + " Unsigned : " + btos(rec()[i].isUnsigned()) );
709  buf.push_back( pre + " Max length: " + itos(rec()[i].maxLength()) );
710  buf.push_back( pre + " Length : " + itos(rec()[i].length()) );
711  }
712  }
713  else {
714  buf.push_back( pre + "INSERT-LIKE query" );
715  buf.push_back( pre + "Number of affected rows: " + itos(nAffectedRows()) );
716  }
717 
718  return buf;
719 }
720 
721 
722 
723 void mcs::Query::customFillBuffer(char* buf, unsigned int& chunksize, bool firstTime)
724 {
725  int i;
726  string det = "";
727  string data, s;
728  string null = "NULL";
729  string tab = "\t";
730  string nl = "\n";
731 
732  MCS_DEBUG(chunksize << " " << firstTime);
733 
734  if (firstTime) {
735  if (! gotResult)
736  throw MCS_ERROR(MSG_NO_RESULT);
737 
738  det = vtos(ExecutionDetails());
739  if (det.length() > chunksize)
740  throw MCS_ERROR(MSG_NOT_ENOUGH_SPACE, det.length(), chunksize);
741 
742  memcpy(buf, det.c_str(), det.length());
743  chunksize = det.length();
744  return;
745  }
746 
747  else {
748  if (eof()) {
749  chunksize = 0;
750  return;
751  }
752 
753  data = "";
754  while (! eof()) {
755  s = "";
756  for (i=0; i<nFields(); i++) {
757  if (rec()[i].isNull())
758  s += null;
759  else
760  s += rec()[i].sval();
761  s += tab;
762  }
763  s += nl;
764 
765  if (data.length() + s.length() < chunksize) {
766  data += s;
767  setNext();
768  }
769  else
770  break;
771  }
772 
773  memcpy(buf, data.c_str(), data.length());
774  chunksize = data.length();
775  return;
776  }
777 }
778 
779 
780 
782 {
783  unsigned int chunk = MCS_DEFAULTCHUNKSIZE;
784  ofstream of(fn.c_str());
785  bool firstTime = true;
786 
787  if (! of.is_open())
788  throw MCS_ERROR(MSG_CANT_OPEN_FILE, fn.csz);
789 
790  char* p = (char*) malloc(chunk);
791  while (chunk) {
792  customFillBuffer(p, chunk, firstTime);
793  of.write(p, chunk);
794  firstTime = false;
795  }
796  free(p);
797 
798  of.close();
799 }
800 
801 
802 
803 void mcs::Query::prepare_with_parameters(int op, char** fields, int nfields,
804  string table, string where, int nrec)
805 {
806  int i;
807  string s = "";
808  for (i=0; i<nfields; i++) {
809  if (i>0) s += " " ;
810  s += fields[i];
811  }
812  prepare_with_parameters(op, s, table, where, nrec);
813 }
814 
815 
816 void mcs::Query::parseFieldList(int op, string& fields, string& values,
817  int& autoIncr)
818 {
819  int i;
820  bool first = true;
821  autoIncr = -1;
822 
823  fields = "";
824  values = "";
825 
826  for (i=0; i<nFields(); i++) {
827  if (metarec()[i].isAutoIncrement())
828  autoIncr = i;
829 
830  if (! first) {
831  fields += ", ";
832  values += ", ";
833  }
834  first = false;
835 
836  fields += "`"+ metarec()[i].name() +"`";
837  values += "?";
838 
839  if (op == MCS_PAB_UPDATE)
840  fields += " = ?";
841  }
842 }
843 
844 
845 
846 void mcs::Query::prepare_with_parameters(int op, string fields, string table, string where, int nrec)
847 {
848  int i, autoIncr;
849  string sql, comma_fields, marks = "";
850  string tab_quoted = table;
851  Record tmprec(false);
852 
853  if (tab_quoted.find("`") == std::string::npos)
854  tab_quoted = "`"+ table +"`";
855 
856  fields = trim(fields);
857 
858  comma_fields = "*";
859  if (fields != "*")
860  comma_fields = subst(fields, " +", ", ");
861 
862  sql = "SELECT " + comma_fields + " FROM " + tab_quoted;
863  if (! where.empty())
864  sql += " WHERE " + where;
865  sql += " LIMIT 1";
866 
867  query(sql);
868 
869 
870  if (eof())
871  tmprec = metarec();
872  else
873  tmprec = rec();
874 
875  parseFieldList(op, fields, marks, autoIncr);
876 
877  switch(op) {
878  case MCS_PAB_INSERT:
879  sql = "INSERT INTO " + tab_quoted + "(" + fields + ") VALUES ";
880  marks = "(" + marks + ")";
881  for (int irec=0; irec<nrec; irec++) {
882  sql += marks;
883  if (irec == 0) {marks = ", " + marks;}
884  }
885  break;
886  case MCS_PAB_REPLACE:
887  sql = "REPLACE INTO " + tab_quoted + "(" + fields + ") VALUES (" + marks + ")";
888  break;
889  case MCS_PAB_UPDATE:
890  sql = "UPDATE " + tab_quoted + " SET " + fields + " WHERE " + where;
891  break;
892  default:
893  throw MCS_ERROR(MSG_UNEXPECTED);
894  }
895 
896  prepare(sql);
897 
898  for (int irec=0; irec<nrec; irec++) {
899  for (i=0; i<tmprec.count(); i++) {
900  Data* d = new Data(&(lbparam[i + irec*tmprec.count()]),
901  tmprec[i].type(),
902  (char*) tmprec[i].name().c_str(),
903  tmprec[i].maxLength(),
904  tmprec[i].isUnsigned());
905 
906  lparam.addField(d);
907 
908  memcpy(lparam[i].buffer(), tmprec[i].buffer(), lparam[i].maxLength());
909  }
910  }
911  bind();
912 }
913 
914 
915 
916 long long int mcs::Query::last_id()
917 {
918  return lastid;
919 }
920 
921 
922 
923 
924 
925 
926 
927 
928 
929 
930 //--------------------------------------------------------
931 mcs::Table::Table(DBConn* db, string table, string fieldkey) :
932  Query(db, true), newrec(false)
933 {
934  MCS_DEBUG_SETUP(0, "Table");
935 
936  ltable = trim(table);
937  lfieldkey = trim(fieldkey);
938 
939  loadTable();
940 }
941 
942 
944 {}
945 
946 
948 {
949  query("SELECT * FROM " + ltable, true);
950 
951  //Check for lfieldkey
952  posfieldkey = metarec().posWhoseNameIs(lfieldkey);
953 
954  newrec = rec();
955  newrec.setNull();
956 }
957 
958 
960 {
961  return newrec;
962 }
963 
964 
965 
967 {
968  insert_or_update(MCS_PAB_INSERT);
969 }
970 
971 
972 
974 {
975  insert_or_update(MCS_PAB_UPDATE);
976 }
977 
978 
980 {
981  insert_or_update(MCS_PAB_REPLACE);
982 }
983 
984 
985 void mcs::Table::insert_or_update(int op)
986 {
987  string where = "";
988  int i;
989 
990  //Dynamic_Array<int> origmap(false);
991  //origmap = rec().getFieldMap();
992  //rec().setFieldMap();
993 
994  if (op == MCS_PAB_UPDATE) { //Data are written in current record
995  newrec = rec();
996  where = lfieldkey + " = " + rec()[posfieldkey].sval();
997  }
998 
999  prepare_with_parameters(op, "*", ltable, where);
1000 
1001  //Copy values from newrec in the parameters
1002  for (i=0; i<param().count(); i++) {
1003  if ( param()[i].isAutoIncrement() ||
1004  newrec[i].isNull()
1005  )
1006  param()[i].setNull();
1007  else
1008  memcpy(param()[i].buffer(), newrec[i].buffer(), param()[i].maxLength());
1009  }
1010 
1011  execute();
1012  loadTable();
1013 
1014  //rec().setFieldMap(origmap);
1015 }
1016 
1017 
1018 
1019 #endif
bool isOpen()
Tell if a connection to the server is opened.
Definition: Db.cc:91
string btos(bool b)
Convert a boolean to a string containing "true" or "false".
Definition: Utils.cc:113
string itos(int i)
Convert an integer to a string.
Definition: Utils.cc:77
int posWhoseNameIs(string name, enum ThrowExceptions throwexc=THROW)
Return the index of the first Data objects whose name is "name".
Definition: Record.cc:457
Record & param()
Returns a reference to a Record object containing all the input parameters.
Definition: Db.cc:205
#define MCS_RS_USEMETAREC
Flag for RecordSet::init().
Definition: mcs.hh:4449
MYSQL_STMT * lstmt
Mysql statement structure.
Definition: mcs.hh:5602
vector< string > tableInfo(string tbl)
Retrieve information about a table.
Definition: Db.cc:442
unsigned int laffectedRows
Rows affected by the last INSERT-LIKE query.
Definition: mcs.hh:5565
Query(const Query &)
Declared to avoid using of default copy constructor.
vector< string > tableList
A vector<string> containing the table list.
Definition: mcs.hh:5914
Execute queries on the database.
Definition: mcs.hh:5544
Record & newRec()
Return a reference to a Record object for insert.
Definition: Db.cc:959
string ltable
Table name.
Definition: mcs.hh:6005
Data & lookup(string field, string table, string where="")
Returns the current record set.
Definition: Db.cc:311
vector< string > ExecutionDetails(string pre="")
Returns a vector of strings containing details of query execution.
Definition: Db.cc:686
void prepare_with_parameters(int op, string fields, string table, string where="", int nrec=1)
Prepare a query with input parameters.
Definition: Db.cc:846
long long int lastid
Last generated id on an AUTO_INCREMENT column.
Definition: mcs.hh:5568
Table(const Table &)
Declared to avoid using of default copy constructor.
unsigned long id()
Returns the same value as mysql_thread_id.
Definition: Db.cc:97
vector< string > simpleQuery(string SQL, unsigned int &nrows, unsigned int &nfields)
Execute a query and return result in a vector of strings.
Definition: Db.cc:533
void bind()
Bind parameters.
Definition: Db.cc:301
Hold informations about an event.
Definition: mcs.hh:814
A dynamic array of Data objects.
Definition: mcs.hh:4170
DBConn * newDBConn()
Creates a new DB connection with the same parameters.
Definition: Db.cc:103
void Result2Ascii(string fn)
Writes a table into an ASCII file using the customFillBuffer() method.
Definition: Db.cc:781
bool setFirst()
Set the record pointer to the first position.
Definition: Record.cc:829
void query(string SQL, bool StoreResult=false)
Wrapper aropund prepare() and execute().
Definition: Db.cc:367
void customFillBuffer(char *buf, unsigned int &chunksize, bool firstTime)
Fills a buffer with a result-set.
Definition: Db.cc:723
void replace()
Insert (or replace) a new record.
Definition: Db.cc:979
unsigned int nAffectedRows()
Returns number of affected records by the last execute() call.
Definition: Db.cc:199
#define MCS_DEFAULTCHUNKSIZE
File chunk size.
Definition: mcs.hh:198
~Table()
Destructor.
Definition: Db.cc:943
void setNull()
Set all Data object&#39;s name to null values.
Definition: Record.cc:516
MYSQL * lconn
Mysql connection to use.
Definition: mcs.hh:5556
void close()
Closes a db connection.
Definition: Db.cc:71
The base class that implement the data abstraction layer.
Definition: mcs.hh:4510
#define MCS_ERROR(A, rest...)
Facility to easily pass all necessary parameter to an Event constructor.
Definition: mcs.hh:964
void update()
Update the current record.
Definition: Db.cc:973
long long int last_id()
Returns the last value generated for an AUTO_INCREMENT column.
Definition: Db.cc:916
void connect(string user, string pass, string db, string host="")
Connect to a databae server.
Definition: Db.cc:44
string Types2Str(Types type, bool isunsigned)
Return the name of the type given in "type" and "isunsigned".
Definition: Data.cc:313
unsigned int posfieldkey
Position of the index field.
Definition: mcs.hh:6011
void readTableList()
Reads the list of tables in the current database.
Definition: Db.cc:421
~DBConn()
Destructor, calls close().
Definition: Db.cc:39
void loadTable()
Reload the table.
Definition: Db.cc:947
string vtos(vector< string > vec)
Join a vector of strings in a single string using newlines.
Definition: Utils.cc:122
unsigned int size()
If knowSize() is true, return the size of the entire block of data.
int nFields()
Returns number of fields.
Definition: Record.cc:765
void insert()
Insert a new record.
Definition: Db.cc:966
vector< string > printResultSet(unsigned int &nrows, unsigned int &nfields, MYSQL_RES *res=NULL)
Prints all the result set in a vector of string.
Definition: Db.cc:455
void startFetch()
Must be called when record fetching is possible.
Definition: Record.cc:693
MYSQL_BIND * lbrec
Record of binding structure for output.
Definition: mcs.hh:5614
void close()
Close the statement and frees anything has been allocated.
Definition: Db.cc:391
DBConn()
Constructor.
Definition: Db.cc:30
Handle database connection.
Definition: mcs.hh:5432
Main include file for all MCS based applications.
void addField(Data *d)
Wrapper around Dynamic_Array.push.
Definition: Record.cc:364
#define MCS_RS_KNOW_NROWS
Flag for RecordSet::init().
Definition: mcs.hh:4457
void emptyName()
Set all Data object&#39;s name to an empty string.
Definition: Record.cc:508
bool VarLenType(Types type)
Tell if "type" is a variable length type.
Definition: Data.cc:349
MYSQL * lconn
MYSQL connection structure.
Definition: mcs.hh:5438
void init(unsigned char code, unsigned int nrows=0, Record *meta=NULL, short int id=0)
Initailize the Record set.
Definition: Record.cc:638
A general purpose data type.
Definition: mcs.hh:3092
void prepare(string SQL="")
Prepare the SQL statement.
Definition: Db.cc:221
#define MCS_RS_RANDOM
Flag for RecordSet::init().
Definition: mcs.hh:4466
~Query()
Definition: Db.cc:165
bool MYSQL2Types(enum_field_types mtype, Types &type)
Convert a MySQL type into a MCS type.
Definition: Data.cc:436
string subst(string s, string what, string with, int op=0)
Perform substitutions on a string.
Definition: Utils.cc:135
Record newrec
Array of values for insert.
Definition: mcs.hh:6014
string trim(string s)
Remove any leading or trailing blanks.
Definition: Utils.cc:160
void execute(bool StoreResult=false)
Execute the prepared statement.
Definition: Db.cc:332
int count()
Wrapper around Dynamic_Array.count.
Definition: Record.cc:359
bool lhandleNewDBConn
Flag to indicate that a new DBConn object has been created.
Definition: mcs.hh:5553
bool gotResult
True if we got a result from the last query.
Definition: mcs.hh:5562
bool setNext()
Set the record pointer to the next position.
Definition: Record.cc:809
string lfieldkey
Name of the index field.
Definition: mcs.hh:6008
bool gotStmtInitialized
True if the statement has been initialized.
Definition: mcs.hh:5559
DBConn * ldbc
Internal reference to the DBConn object used to connect to db.
Definition: mcs.hh:5550
Namespace for MCS library.
MYSQL_BIND * lbparam
Record of binding structure for input (parameters).
Definition: mcs.hh:5608
Types
Enumeration of base type for Data.
Definition: mcs.hh:54
Record lparam
Record of binded Data objects for input (parameters).
Definition: mcs.hh:5574

mcslogo

MCS (My Customizable Server) ver. 0.3.3-alpha7
Documentation generated on Mon May 28 07:39:41 UTC 2018