Xmipp  v3.23.11-Nereus
metadata_sql.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es)
4  *
5  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6  *
7  * This program 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  * This program 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 this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  *
22  * All comments concerning this program package may be sent to the
23  * e-mail address 'xmipp@cnb.csic.es'
24  ***************************************************************************/
25 
26 #include <regex.h>
27 #include <algorithm>
28 #include <sstream>
29 #include "metadata_sql.h"
30 #include "xmipp_threads.h"
31 #include "xmipp_filename.h"
32 #include "metadata_db.h"
33 
34 //#define DEBUG
35 
36 //This is needed for static memory allocation
37 int MDSql::table_counter = 0;
38 sqlite3 *MDSql::db;
39 MDSqlStaticInit MDSql::initialization;
40 char *MDSql::errmsg;
41 const char *MDSql::zLeftover;
42 int MDSql::rc;
43 Mutex sqlMutex; //Mutex to syncronize db access
44 
45 std::stringstream MDSql::preparedStream; // Stream.
46 sqlite3_stmt * MDSql::preparedStmt;
47 
48 void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
49  int ret;
50  regex_t regex;
51  char* reg = (char*)sqlite3_value_text(values[0]);
52  char* text = (char*)sqlite3_value_text(values[1]);
53 
54  if ( argc != 2 || reg == 0 || text == 0) {
55  sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
56  return;
57  }
58 
59  ret = regcomp(&regex, reg, REG_EXTENDED | REG_NOSUB);
60  if ( ret != 0 ) {
61  sqlite3_result_error(context, "error compiling regular expression", -1);
62  return;
63  }
64 
65  ret = regexec(&regex, text , 0, NULL, 0);
66  regfree(&regex);
67 
68  sqlite3_result_int(context, (ret != REG_NOMATCH));
69 }
70 
71 int getBlocksInMetaDataFileDB(const FileName &inFile, StringVector& blockList)
72 {
73  char **results;
74  int rows;
75  int columns;
76  int rc;
77 
78  sqlite3 *db1;
79  String sql = (String)"SELECT name FROM sqlite_master\
80  WHERE type='table';";
81  if ((rc=sqlite3_open(inFile.c_str(), &db1)))
82  REPORT_ERROR(ERR_MD_SQL,formatString("Error opening database code: %d message: %s",rc,sqlite3_errmsg(db1)));
83  if ((rc=sqlite3_get_table (db1, sql.c_str(), &results, &rows, &columns, NULL)) != SQLITE_OK)
84  REPORT_ERROR(ERR_MD_SQL,formatString("Error accessing table code: %d message: %s. SQL command %s",rc,sqlite3_errmsg(db1),sql.c_str()));
85  //For tables, the type field will always be 'table' and the name field will
86  //be the name of the table. So to get a list of all tables in the database,
87 
88  if (rows < 1)
89  {
90  std::cerr << "Empty Metadata" <<std::endl;
91  return 0;
92  }
93  else
94  {
95  for (int i = 1; i <= rows; i++)
96  {
97  blockList.push_back((String)results[i]);
98  }
99  }
100  sqlite3_free_table (results);
101  sqlite3_close(db1);
102 
103  return rows;
104 }
105 
106 int MDSql::getUniqueId()
107 {
108  // if (table_counter == 0)
109  // sqlBegin();
110  return ++table_counter;
111 }
112 
113 MDSql::MDSql(MetaDataDb *md)
114 {
115  sqlMutex.lock();
116  tableId = getUniqueId();
117  //std::cerr << ">>>> creating md with table id: " << tableId << std::endl;
118  sqlMutex.unlock();
119  myMd = md;
120  myCache = new MDCache();
121  beThreadSafe = false;
122 
123 }
124 
125 MDSql::~MDSql()
126 {
127  delete myCache;
128 }
129 
130 bool MDSql::createMd()
131 {
132  sqlMutex.lock();
133  //std::cerr << "creating md" <<std::endl;
134  bool result = createTable(&(myMd->_activeLabels));
135  //std::cerr << "leave creating md" <<std::endl;
136  sqlMutex.unlock();
137 
138  return result;
139 }
140 
141 bool MDSql::clearMd()
142 {
143  sqlMutex.lock();
144  //std::cerr << "clearing md" <<std::endl;
145  myCache->clear();
146  bool result = dropTable();
147  //std::cerr << "leave clearing md" <<std::endl;
148  sqlMutex.unlock();
149 
150  return result;
151 }
152 
153 size_t MDSql::getObjId()
154 {
155  size_t id; // Return value.
156 
157  // Get last inserted row id.
158  id = sqlite3_last_insert_rowid(db);
159 
160  return(id);
161 }
162 
163 size_t MDSql::addRow()
164 {
165  //Fixme: this can be done in the constructor of MDCache only once
166  sqlite3_stmt * &stmt = myCache->addRowStmt;
167  //sqlite3_stmt * stmt = NULL;
168 
169  if (stmt == NULL)
170  {
171  std::stringstream ss;
172  ss << "INSERT INTO " << tableName(tableId) << " DEFAULT VALUES;";
173  sqlite3_prepare_v2(db, ss.str().c_str(), -1, &stmt, &zLeftover);
174 //#define DEBUG
175 #ifdef DEBUG
176  std::cerr << "DEBUG_JM: addRow: " << ss.str() <<std::endl;
177 #endif
178 #undef DEBUG
179  }
180  sqlite3_reset(stmt);
181  size_t id = BAD_OBJID;
182  if (execSingleStmt(stmt))
183  id = sqlite3_last_insert_rowid(db);
184 
185 
186  //sqlite3_finalize(stmt);
187  return id;
188 }
189 
190 bool MDSql::addColumn(MDLabel column)
191 {
192  std::stringstream ss;
193  ss << "ALTER TABLE " << tableName(tableId)
194  << " ADD COLUMN " << MDL::label2SqlColumn(column) <<";";
195  return execSingleStmt(ss);
196 }
197 
199 {
200  const char* lib = "libXmippCore.so";
201  sqlite3_enable_load_extension(db, 1);
202  if( sqlite3_load_extension(db, lib, 0, 0)!= SQLITE_OK)
203  REPORT_ERROR(ERR_MD_SQL,"Cannot activate sqlite extensions");
204  else
205  return true;
206 }
207 
209 {
210  if( sqlite3_create_function(db, "regexp", 2, SQLITE_ANY,0, &sqlite_regexp,0,0)!= SQLITE_OK)
211  REPORT_ERROR(ERR_MD_SQL,"Cannot activate sqlite extensions");
212  else
213  return true;
214 }
215 
217 {
218  beThreadSafe = false;
219  return ( sqlite3_config(SQLITE_CONFIG_MULTITHREAD) == SQLITE_OK);
220 }
222 {
223  beThreadSafe = true;
224  return ( sqlite3_config(SQLITE_CONFIG_SERIALIZED) == SQLITE_OK);
225 }
226 
227 
228 bool MDSql::renameColumn(const std::vector<MDLabel> &oldLabel, const std::vector<MDLabel> &newlabel)
229 {
230  //1 Create an new table that matches your original table,
231  // but with the changed columns.
232  bool result;
233  std::vector<MDLabel> v1(myMd->_activeLabels);
234  std::vector<MDLabel>::const_iterator itOld;
235  std::vector<MDLabel>::const_iterator itNew;
236  for( itOld = oldLabel.begin(), itNew = newlabel.begin();
237  itOld < oldLabel.end();
238  ++itOld, ++itNew )
239  std::replace(v1.begin(), v1.end(), *itOld, *itNew);
240 
241  int oldTableId = tableId;
242  sqlMutex.lock();
243  tableId = getUniqueId();
244  createTable(&v1);
245  sqlMutex.unlock();
246  //2 Now we can copy the original data to the new table:
247  String oldLabelString=" objID";
248  String newLabelString=" objID";
249  for(std::vector<MDLabel>::const_iterator it = (myMd->_activeLabels)
250  .begin();
251  it != (myMd->_activeLabels).end();
252  ++it)
253  oldLabelString += ", " + MDL::label2StrSql(*it);
254  for(std::vector<MDLabel>
255  ::const_iterator it = v1.begin();
256  it != v1.end();
257  ++it)
258  newLabelString += ", " + MDL::label2StrSql(*it);
259  std::stringstream sqlCommand;
260  sqlCommand << " INSERT INTO " + tableName(tableId)
261  << " ("+ newLabelString +") "
262  << " SELECT " + oldLabelString
263  << " FROM " + tableName(oldTableId) ;
264  execSingleStmt(sqlCommand);
265  //drop old table
266  sqlCommand.str(std::string());
267  sqlCommand << "DROP TABLE " << tableName(oldTableId);
268  execSingleStmt(sqlCommand);
269  //rename new table
270  sqlCommand.str(std::string());
271  sqlCommand << " ALTER TABLE " << tableName(tableId)
272  << " RENAME TO " << tableName(oldTableId);
273  result = execSingleStmt(sqlCommand);
274  tableId=oldTableId;
275  myMd->_activeLabels=v1;
276  return result;
277 }
278 
279 size_t MDSql::size(void)
280 {
281  std::stringstream ss;
282  ss << "SELECT COUNT(*) FROM "<< tableName(tableId) << ";";
283  return execSingleIntStmt(ss);
284 }
285 
286 template bool MDSql::setObjectValues(int id, const std::vector<MDObject*> &columnValues, const std::vector<MDLabel> *desiredLabels);
287 template bool MDSql::setObjectValues(int id, const std::vector<const MDObject*> &columnValues, const std::vector<MDLabel> *desiredLabels);
288 
289 template <typename T>
290 bool MDSql::setObjectValues(int id, const std::vector<T> &columnValues, const std::vector<MDLabel> *desiredLabels)
291 {
292  bool r = true; // Return value.
293  int rc;
294  size_t columnCount = 0;
295 
296  // Add values.
297  if (desiredLabels == nullptr)
298  {
299  bindValue(this->preparedStmt, 1, *(columnValues[0]));
300  for (size_t i=1; i<columnValues.size() ;i++)
301  bindValue(this->preparedStmt, i+1, *(columnValues[i]));
302  columnCount = columnValues.size();
303  }
304  // Add only desired columns.
305  else
306  {
307  for (size_t i=0; i<desiredLabels->size() ;i++)
308  {
309  for (size_t j=0; j<columnValues.size() ;j++)
310  {
311  if (columnValues[j]->label == (*desiredLabels)[i])
312  {
313  bindValue(this->preparedStmt, i+1, *(columnValues[j]));
314  break;
315  }
316  }
317  }
318  columnCount = desiredLabels->size();
319  }
320 
321  // id != -1 means there is a WHERE clause in the query sentence and id must be added.
322  if (id != -1)
323  sqlite3_bind_int(this->preparedStmt, columnCount, id);
324 
325  // Execute statement.
326  rc = sqlite3_step( this->preparedStmt);
327  if (rc != SQLITE_OK && rc != SQLITE_ROW && rc != SQLITE_DONE)
328  {
329  std::cerr << "MDSql::setObjectValue(MDObject): " << std::endl
330  << " " << this->preparedStream.str() << std::endl
331  <<" code: " << rc << " error: " << sqlite3_errmsg(db) << std::endl;
332  r = false;
333  }
334 
335  // Reset statement and bindings.
336  sqlite3_clear_bindings(this->preparedStmt);
337  sqlite3_reset(this->preparedStmt);
338 
339  return r;
340 }
341 
342 void MDSql::finalizePreparedStmt(void)
343 {
344  if (this->preparedStmt != NULL)
345  {
346  sqlite3_finalize( this->preparedStmt);
347  this->preparedStmt = NULL;
348  }
349 }
350 
351 //set column with a given value
352 bool MDSql::setObjectValue(const MDObject &value)
353 {
354  bool r = true;
355  int rc;
356  MDLabel column = value.label;
357  std::stringstream ss;
358  sqlite3_stmt * stmt;
359  ss << "UPDATE " << tableName(tableId)
360  << " SET " << MDL::label2StrSql(column) << "=?;";
361  rc = sqlite3_prepare_v2(db, ss.str().c_str(), -1, &stmt, &zLeftover);
362  bindValue(stmt, 1, value);
363  rc = sqlite3_step(stmt);
364  if (rc != SQLITE_OK && rc != SQLITE_ROW && rc != SQLITE_DONE)
365  {
366  std::cerr << "MDSql::setObjectValue(MDObject): " << std::endl
367  << " " << ss.str() << std::endl
368  <<" code: " << rc << " error: " << sqlite3_errmsg(db) << std::endl;
369  r = false;
370  }
371  sqlite3_finalize(stmt);
372  return r;
373 }
374 
375 bool MDSql::setObjectValue(const int objId, const MDObject &value)
376 {
377  bool r = true;
378  int rc;
379  MDLabel column = value.label;
380  std::stringstream ss;
381  //Check cached statements for setObjectValue
382  sqlite3_stmt * &stmt = myCache->setValueCache[column];
383  //sqlite3_stmt * stmt = NULL;
384  if (stmt == NULL)//if not exists create the stmt
385  {
386  std::string sep = (MDL::isString(column) || MDL::isVector(column)) ? "'" : "";
387  ss << "UPDATE " << tableName(tableId)
388  << " SET " << MDL::label2StrSql(column) << "=? WHERE objID=?;";
389 //#define DEBUG
390 #ifdef DEBUG
391  std::cerr << "DEBUG_JM: setObjectValue: " << ss.str() << std::endl;
392 
393 #endif
394 
395  sqlite3_prepare_v2(db, ss.str().c_str(), -1, &stmt, &zLeftover);
396  }
397  sqlite3_reset(stmt);
398  bindValue(stmt, 1, value);
399  sqlite3_bind_int(stmt, 2, objId);
400  rc = sqlite3_step(stmt);
401  if (rc != SQLITE_OK && rc != SQLITE_ROW && rc != SQLITE_DONE)
402  {
403  std::cerr << "MDSql::setObjectValue: " << std::endl
404  << " " << ss.str() << std::endl
405  <<" code: " << rc << " error: " << sqlite3_errmsg(db) << std::endl;
406  r = false;
407  }
408 
409  return r;
410 }
411 
412 bool MDSql::initializeSelect( bool addWhereObjId, const std::vector<MDLabel> &labels)
413 {
414  bool createdOK=true; // Return value.
415  std::stringstream ss; // Sentence string.
416 
417  // Initialize SELECT sentence.
418  ss << "SELECT ";
419 
420  // Add columns names.
421  if (labels.size() > 0)
422  {
423  // Add columns names.
424  ss << MDL::label2StrSql(labels[0]);
425  for (size_t i=1; i<labels.size() ;i++)
426  {
427  if (labels[i] != MDL_STAR_COMMENT)
428  {
429  ss << "," << MDL::label2StrSql(labels[i]);
430  }
431  }
432  }
433  // Select all columns.
434  else
435  {
436  ss << " * ";
437  }
438 
439  // Add table.
440  ss << " FROM " << tableName(tableId);
441 
442  // Check if add WHERE clause to select by id.
443  if (addWhereObjId)
444  {
445  ss << " WHERE objID=?";
446  }
447 
448  if (sqlite3_prepare_v2(db, ss.str().c_str(), -1, &this->preparedStmt, &zLeftover) != SQLITE_OK)
449  {
450  createdOK = false;
451  printf( "could not prepare statement: %s\n", sqlite3_errmsg(db) );
452  this->preparedStmt = NULL;
453  }
454 
455  return(createdOK);
456 }
457 
458 bool MDSql::initializeInsert(const std::vector<MDLabel> *labels, const std::vector<MDObject*> &values)
459 {
460  int i=0; // Loop counter.
461  int length=0; // # labels.
462  bool createdOK=true; // Return value.
463 
464  // Clear preparedStream.
465  this->preparedStream.str(std::string());
466 
467  // Initialize SQL sentence.
468  this->preparedStream << "INSERT INTO " << tableName(tableId);
469 
470  // Add columns.
471  this->preparedStream << " (";
472 
473  // Execute branch if "labels" size is not zero.
474  if (labels != NULL)
475  {
476  length = labels->size();
477  this->preparedStream << MDL::label2StrSql((*labels)[0]);
478  for (i=1; i<length ;i++)
479  {
480  this->preparedStream << "," << MDL::label2StrSql((*labels)[i]);
481  }
482  }
483  // Execute branch if "values" size is not zero.
484  else if ((length = values.size()) > 0)
485  {
486  this->preparedStream << MDL::label2StrSql((*values[0]).label);
487  for (i=1; i<length ;i++)
488  {
489  this->preparedStream << "," << MDL::label2StrSql((*values[i]).label);
490  }
491  }
492 
493  // Add one '?' character for each label.
494  this->preparedStream << ") VALUES (?";
495  for (i=1; i<length ;i++)
496  {
497  this->preparedStream << ",?";
498  }
499  this->preparedStream << ");";
500 
501  // Prepare statement.
502  if (sqlite3_prepare_v2(db, this->preparedStream.str().c_str(), -1, &this->preparedStmt, &zLeftover) != SQLITE_OK)
503  {
504  printf( "initializeInsert: could not prepare statement: %s\n", sqlite3_errmsg(db) );
505  this->preparedStmt = NULL;
506  createdOK = false;
507  }
508 
509  return(createdOK);
510 }
511 
512 bool MDSql::getObjectsValues(const std::vector<MDLabel> &labels, std::vector<MDObject> &values)
513 {
514  bool ret=true; // Return value.
515 
516  // Execute statement.
517  if (sqlite3_step(this->preparedStmt) == SQLITE_ROW)
518  {
519  const auto noOfLabels = labels.size();
520  for (size_t i=0; i < noOfLabels; i++)
521  {
522  if (labels[i] != MDL_STAR_COMMENT)
523  {
524  values.emplace_back(labels[i]);
525  auto &value = values.back();
526  extractValue(this->preparedStmt, i, value);
527  }
528  }
529  }
530  // If no row retrieved then return false.
531  else
532  {
533  ret = false;
534  }
535 
536  return(ret);
537 }
538 
539 bool MDSql::getObjectValue(const int objId, MDObject &value)
540 {
541  if (beThreadSafe) { sqlMutex.lock(); }
542  std::stringstream ss;
543  MDLabel column = value.label;
544  sqlite3_stmt * &stmt = myCache->getValueCache[column];
545 
546  if (stmt == NULL)//prepare stmt if not exists
547  {
548  //std::cerr << "Creating cache " << ++count <<std::endl;
549  ss << "SELECT " << MDL::label2StrSql(column)
550  << " FROM " << tableName(tableId)
551  << " WHERE objID=?";// << objId << ";";
552  sqlite3_prepare_v2(db, ss.str().c_str(), -1, &stmt, &zLeftover);
553  }
554 
555 //#define DEBUG
556 #ifdef DEBUG
557 
558  std::cerr << "getObjectValue: " << ss.str() <<std::endl;
559 #endif
560 
561  sqlite3_reset(stmt);
562  sqlite3_bind_int(stmt, 1, objId);
563 
564  bool wasSuccess = (sqlite3_step(stmt) == SQLITE_ROW);
565 
566  if (wasSuccess)
567  {
568  extractValue(stmt, 0, value);
569  sqlite3_step(stmt);
570  }
571  if (beThreadSafe) { sqlMutex.unlock(); }
572 
573  return wasSuccess;
574 }
575 
576 void MDSql::selectObjects(std::vector<size_t> &objectsOut, const MDQuery *queryPtr)
577 {
578  std::stringstream ss;
579  sqlite3_stmt *stmt;
580  objectsOut.clear();
581 
582  ss << "SELECT objID FROM " << tableName(tableId);
583  if (queryPtr != NULL)
584  {
585  ss << queryPtr->whereString();
586  ss << queryPtr->orderByString();
587  ss << queryPtr->limitString();
588  }
589  sqlite3_prepare_v2(db, ss.str().c_str(), -1, &stmt, &zLeftover);
590 #ifdef DEBUG
591 
592  std::cerr << "selectObjects: " << ss.str() <<std::endl;
593 #endif
594 
595  while (sqlite3_step(stmt) == SQLITE_ROW)
596  {
597  objectsOut.emplace_back(sqlite3_column_int(stmt, 0));
598  }
599  sqlite3_finalize(stmt);
600 }
601 
602 size_t MDSql::deleteObjects(const MDQuery *queryPtr)
603 {
604  std::stringstream ss;
605  ss << "DELETE FROM " << tableName(tableId);
606  if (queryPtr != NULL)
607  ss << queryPtr->whereString();
608 
609  if (execSingleStmt(ss))
610  {
611  return sqlite3_changes(db);
612  }
613  return 0;
614 
615 }
616 
617 size_t MDSql::copyObjects(MetaDataDb *mdPtrOut, const MDQuery *queryPtr) const
618 {
619  return copyObjects(mdPtrOut->myMDSql, queryPtr);
620 }
621 
622 size_t MDSql::copyObjects(MDSql * sqlOut, const MDQuery *queryPtr) const
623 {
624  //NOTE: Is assumed that the destiny table has
625  // the same columns that the source table, if not
626  // the INSERT will fail
627  std::stringstream ss, ss2;
628  ss << "INSERT INTO " << tableName(sqlOut->tableId);
629  //Add columns names to the insert and also to select
630  //* couldn't be used because maybe are duplicated objID's
631  std::string sep = " ";
632  int size = myMd->_activeLabels.size();
633 
634  for (int i = 0; i < size; i++)
635  {
636  ss2 << sep << MDL::label2StrSql( myMd->_activeLabels[i]);
637  sep = ", ";
638  }
639  ss << "(" << ss2.str() << ") SELECT " << ss2.str();
640  ss << " FROM " << tableName(tableId);
641  if (queryPtr != NULL)
642  {
643  ss << queryPtr->whereString();
644  ss << queryPtr->orderByString();
645  ss << queryPtr->limitString();
646  }
647  if (sqlOut->execSingleStmt(ss))
648  {
649  return sqlite3_changes(db);
650  }
651  return 0;
652 }
653 
654 void MDSql::aggregateMd(MetaDataDb *mdPtrOut,
655  const std::vector<AggregateOperation> &operations,
656  const std::vector<MDLabel> &operateLabel)
657 {
658  std::stringstream ss;
659  std::stringstream ss2;
660  std::string aggregateStr = MDL::label2StrSql(mdPtrOut->_activeLabels[0]);
661  ss << "INSERT INTO " << tableName(mdPtrOut->myMDSql->tableId)
662  << "(" << aggregateStr;
663  ss2 << aggregateStr;
664  //Start iterating on second label, first is the
665  //aggregating one
666  for (size_t i = 0; i < operations.size(); i++)
667  {
668  ss << ", " << MDL::label2StrSql(mdPtrOut->_activeLabels[i+1]);
669  ss2 << ", " ;
670  switch (operations[i])
671  {
672  case AGGR_COUNT:
673  ss2 << "COUNT";
674  break;
675  case AGGR_MAX:
676  ss2 << "MAX";
677  break;
678  case AGGR_MIN:
679  ss2 << "MIN";
680  break;
681  case AGGR_SUM:
682  ss2 << "SUM";
683  break;
684  case AGGR_AVG:
685  ss2 << "AVG";
686  break;
687  default:
688  REPORT_ERROR(ERR_MD_SQL, "Invalid aggregate operation.");
689  }
690  ss2 << "(" << MDL::label2StrSql(operateLabel[i])
691  << ") AS " << MDL::label2StrSql(mdPtrOut->_activeLabels[i+1]);
692  }
693  ss << ") SELECT " << ss2.str();
694  ss << " FROM " << tableName(tableId);
695  ss << " GROUP BY " << aggregateStr;
696  ss << " ORDER BY " << aggregateStr << ";";
697  //std::cerr << "ss " << ss.str() <<std::endl;
698  execSingleStmt(ss);
699 }
700 
701 
702 void MDSql::aggregateMdGroupBy(MetaDataDb *mdPtrOut,
703  AggregateOperation operation,
704  const std::vector<MDLabel> &groupByLabels ,
705  MDLabel operateLabel,
706  MDLabel resultLabel)
707 {
708  std::stringstream ss;
709  std::stringstream ss2;
710  std::stringstream groupByStr;
711 
712  groupByStr << MDL::label2StrSql(groupByLabels[0]);
713  for (size_t i = 1; i < groupByLabels.size(); i++)
714  groupByStr << ", " << MDL::label2StrSql(groupByLabels[i]);
715 
716  ss << "INSERT INTO " << tableName(mdPtrOut->myMDSql->tableId) << "("
717  << groupByStr.str() << ", " << MDL::label2StrSql(resultLabel) << ")";
718 
719  ss2 << groupByStr.str() << ", ";
720  switch (operation)
721  {
722  case AGGR_COUNT:
723  ss2 << "COUNT";
724  break;
725  case AGGR_MAX:
726  ss2 << "MAX";
727  break;
728  case AGGR_MIN:
729  ss2 << "MIN";
730  break;
731  case AGGR_SUM:
732  ss2 << "SUM";
733  break;
734  case AGGR_AVG:
735  ss2 << "AVG";
736  break;
737  default:
738  REPORT_ERROR(ERR_MD_SQL, "Invalid aggregate operation.");
739  }
740  ss2 << "(" << MDL::label2StrSql(operateLabel);
741  ss2 << ") AS " << MDL::label2StrSql(resultLabel);
742 
743  ss << " SELECT " << ss2.str();
744  ss << " FROM " << tableName(tableId);
745  ss << " GROUP BY " << groupByStr.str();
746  ss << " ORDER BY " << groupByStr.str() << ";";
747 
748  //std::cerr << "ss " << ss.str() <<std::endl;
749  execSingleStmt(ss);
750 }
751 
752 
753 double MDSql::aggregateSingleDouble(const AggregateOperation operation,
754  MDLabel operateLabel)
755 {
756  std::stringstream ss;
757  ss << "SELECT ";
758  //Start iterating on second label, first is the
759  //aggregating one
760  switch (operation)
761  {
762  case AGGR_COUNT:
763  ss << "COUNT";
764  break;
765  case AGGR_MAX:
766  ss << "MAX";
767  break;
768  case AGGR_MIN:
769  ss << "MIN";
770  break;
771  case AGGR_SUM:
772  ss << "SUM";
773  break;
774  case AGGR_AVG:
775  ss << "AVG";
776  break;
777  default:
778  REPORT_ERROR(ERR_MD_SQL, "Invalid aggregate operation.");
779  }
780  ss << "(" << MDL::label2StrSql(operateLabel) << ")" ;
781  ss << " FROM " << tableName(tableId);
782  return (execSingleDoubleStmt(ss));
783 }
784 
785 size_t MDSql::aggregateSingleSizeT(const AggregateOperation operation,
786  MDLabel operateLabel)
787 {
788  std::stringstream ss;
789  ss << "SELECT ";
790  //Start iterating on second label, first is the
791  //aggregating one
792  switch (operation)
793  {
794  case AGGR_COUNT:
795  ss << "COUNT";
796  break;
797  case AGGR_MAX:
798  ss << "MAX";
799  break;
800  case AGGR_MIN:
801  ss << "MIN";
802  break;
803  case AGGR_SUM:
804  ss << "SUM";
805  break;
806  case AGGR_AVG:
807  ss << "AVG";
808  break;
809  default:
810  REPORT_ERROR(ERR_MD_SQL, "Invalid aggregate operation.");
811  }
812  ss << "(" << MDL::label2StrSql(operateLabel) << ")" ;
813  ss << " FROM " << tableName(tableId);
814  return (execSingleIntStmt(ss));
815 }
816 
817 void MDSql::indexModify(const std::vector<MDLabel> &columns, bool create)
818 {
819  std::stringstream ss,index_name,index_column;
820  std::string sep1=" ";
821  std::string sep2=" ";
822  for (size_t i = 0; i < columns.size(); i++)
823  {
824  index_name << sep1 << tableName(tableId) << "_"
825  << MDL::label2Str(columns.at(i));
826  sep1 = "_";
827  index_column << sep2 << MDL::label2StrSql(columns.at(i));
828  sep2 = ", ";
829  }
830 
831  if (create)
832  {
833  ss << "CREATE INDEX IF NOT EXISTS " << index_name.str() << "_INDEX "
834  << " ON " << tableName(tableId) << " (" << index_column.str() << ")";
835  }
836  else
837  {
838  ss << "DROP INDEX IF EXISTS " << index_name.str() << "_INDEX ";
839  }
840  execSingleStmt(ss);
841 }
842 
843 size_t MDSql::firstRow()
844 {
845  std::stringstream ss;
846  ss << "SELECT COALESCE(MIN(objID), -1) AS MDSQL_FIRST_ID FROM "
847  << tableName(tableId) << ";";
848  return execSingleIntStmt(ss);
849 }
850 
851 size_t MDSql::lastRow()
852 {
853  std::stringstream ss;
854  ss << "SELECT COALESCE(MAX(objID), -1) AS MDSQL_LAST_ID FROM "
855  << tableName(tableId) << ";";
856  return execSingleIntStmt(ss);
857 }
858 
859 size_t MDSql::nextRow(size_t currentRow)
860 {
861  std::stringstream ss;
862  ss << "SELECT COALESCE(MIN(objID), -1) AS MDSQL_NEXT_ID FROM "
863  << tableName(tableId)
864  << " WHERE objID>" << currentRow << ";";
865  return execSingleIntStmt(ss);
866 }
867 
868 size_t MDSql::previousRow(size_t currentRow)
869 {
870  std::stringstream ss;
871  ss << "SELECT COALESCE(MAX(objID), -1) AS MDSQL_PREV_ID FROM "
872  << tableName(tableId)
873  << " WHERE objID<" << currentRow << ";";
874  return execSingleIntStmt(ss);
875 }
876 
877 int MDSql::columnMaxLength(MDLabel column)
878 {
879  std::stringstream ss;
880  ss << "SELECT MAX(COALESCE(LENGTH("<< MDL::label2StrSql(column)
881  <<"), -1)) AS MDSQL_STRING_LENGTH FROM "
882  << tableName(tableId) << ";";
883  return execSingleIntStmt(ss);
884 }
885 
886 void MDSql::setOperate(MetaDataDb *mdPtrOut, const std::vector<MDLabel> &columns, SetOperation operation)
887 {
888  std::stringstream ss, ss2;
889  bool execStmt = true;
890  int size;
891  std::string sep = " ";
892  std::vector<MDLabel> * labelVector;
893 
894  switch (operation)
895  {
896  case UNION:
897  copyObjects(mdPtrOut->myMDSql);
898  execStmt = false;
899  break;
900 
901  case UNION_DISTINCT: //unionDistinct
902  //Create string with columns list
903  size = mdPtrOut->_activeLabels.size();
904  //std::cerr << "LABEL" << MDL::label2StrSql(column) <<std::endl;
905  for (int i = 0; i < size; i++)
906  {
907  ss2 << sep << MDL::label2StrSql( myMd->_activeLabels[i]);
908  sep = ", ";
909  }
910  ss << "INSERT INTO " << tableName(mdPtrOut->myMDSql->tableId)
911  << " (" << ss2.str() << ")"
912  << " SELECT " << ss2.str()
913  << " FROM " << tableName(tableId)
914  << " WHERE ";
915  for (size_t j=0; j<columns.size(); ++j)
916  {
917  if (j>0)
918  ss << " AND ";
919  ss << MDL::label2StrSql(columns[j])
920  << " NOT IN (SELECT " << MDL::label2StrSql(columns[j])
921  << " FROM " << tableName(mdPtrOut->myMDSql->tableId) << ") ";
922  }
923  ss << ";";
924  break;
925 
926  case DISTINCT:
927  case REMOVE_DUPLICATE:
928  //Create string with columns list
929  size = mdPtrOut->_activeLabels.size();
930  sep = ' ';
931  labelVector = &(mdPtrOut->_activeLabels);
932  for (int i = 0; i < size; i++)
933  {
934  ss2 << sep << MDL::label2StrSql( labelVector->at(i));
935  sep = ", ";
936  }
937  if (operation == DISTINCT || columns[0] == MDL_UNDEFINED)
938  {
939  ss << "INSERT INTO " << tableName(mdPtrOut->myMDSql->tableId)
940  << " (" << ss2.str() << ")"
941  << " SELECT DISTINCT " << ss2.str()
942  << " FROM " << tableName(tableId) << ";";
943  }
944  else {
945  // We need this special case for the REMOVE_DUPLICATE because when using a subset
946  // of labels as key, the rest of values are taken randomly.
947  // The following query ensures that the first ocurrence of the first group of rows
948  // is used to take the remaining values
949  ss << "INSERT INTO " << tableName(mdPtrOut->myMDSql->tableId)
950  << " (ObjId," << ss2.str() << ")"
951  << " SELECT M.* FROM (SELECT " << MDL::label2StrSql(columns[0]) << ", MIN(ObjId) AS first "
952  << " FROM " << tableName(tableId) << " GROUP BY " << MDL::label2StrSql(columns[0])
953  << " ) foo JOIN " << tableName(tableId) << " M ON foo.first = M.ObjId;";
954  }
955  break;
956 
957  case INTERSECTION:
958  case SUBSTRACTION:
959  ss << "DELETE FROM " << tableName(mdPtrOut->myMDSql->tableId)
960  << " WHERE ";
961  for (size_t j=0; j<columns.size(); ++j)
962  {
963  if (j>0)
964  ss << " AND ";
965  ss << MDL::label2StrSql(columns[j]);
966  if (operation == INTERSECTION)
967  ss << " NOT";
968  ss << " IN (SELECT " << MDL::label2StrSql(columns[j])
969  << " FROM " << tableName(tableId) << ") ";
970  }
971  ss << ";";
972  break;
973  default:
974  REPORT_ERROR(ERR_ARG_INCORRECT,"Cannot use this operation for a set operation");
975  }
976  //std::cerr << "ss " << ss.str() <<std::endl;
977  if (execStmt)
978  execSingleStmt(ss);
979 }
980 
981 bool MDSql::equals(const MDSql &op)
982 {
983  std::vector<MDLabel> v1(myMd->_activeLabels),v2(op.myMd->_activeLabels);
984  std::sort(v1.begin(),v1.end());
985  std::sort(v2.begin(),v2.end());
986 
987  if(v1 != v2)
988  return (false);
989  int size = myMd->_activeLabels.size();
990  std::stringstream sqlQuery,ss2,ss2Group;
991 
993  ss2Group << MDL::label2StrSql(MDL_OBJID);
994  int precision = myMd->_precision;
995  for (int i = 0; i < size; i++)
996  {
997  //when metadata is double compare
998  if(MDL::isDouble(myMd->_activeLabels[i]))
999  {
1000  ss2 << ", CAST (" << MDL::label2StrSql( myMd->_activeLabels[i])
1001  << "*" << precision
1002  << " as INTEGER) as " << MDL::label2StrSql( myMd->_activeLabels[i]);
1003 
1004  }
1005  else
1006  {
1007  ss2 << ", " << MDL::label2StrSql( myMd->_activeLabels[i]);
1008  }
1009  ss2Group<< ", " << MDL::label2StrSql( myMd->_activeLabels[i]);
1010  }
1011  sqlQuery
1012  << "SELECT count(*) FROM ("
1013  << "SELECT count(*) as result\
1014  FROM\
1015  (\
1016  SELECT " << ss2.str() << "\
1017  FROM " << tableName(tableId)
1018  << " UNION ALL \
1019  SELECT " << ss2.str() << "\
1020  FROM " << tableName(op.tableId)
1021  << ") tmp"
1022  << " GROUP BY " << ss2Group.str()
1023  << " HAVING COUNT(*) <> 2"
1024  << ") tmp1";
1025  return (execSingleIntStmt(sqlQuery)==0);
1026 }
1027 
1028 void MDSql::setOperate(const MetaDataDb *mdInLeft,
1029  const MetaDataDb *mdInRight,
1030  const std::vector<MDLabel> &columnsLeft,
1031  const std::vector<MDLabel> &columnsRight,
1032  SetOperation operation)
1033 {
1034  std::stringstream ss, ss2, ss3;
1035  size_t size;
1036  std::string join_type = "", sep = "";
1037  switch (operation)
1038  {
1039  case INNER_JOIN:
1040  join_type = " INNER ";
1041  break;
1042  case LEFT_JOIN:
1043  join_type = " LEFT OUTER ";
1044  break;
1045  case OUTER_JOIN:
1046  join_type = " OUTER ";
1047  break;
1048  case NATURAL_JOIN:
1049  /* We do not want natural join but natural join except for the obj-ID column */
1050  join_type = " INNER ";
1051  break;
1052  default:
1053  REPORT_ERROR(ERR_ARG_INCORRECT,"Cannot use this operation for a set operation");
1054  }
1055  if(operation==NATURAL_JOIN)
1056  {
1057  std::vector<MDLabel> intersectLabels;
1058  std::vector<MDLabel>::const_iterator left, right;
1059  for (right=(mdInRight->_activeLabels).begin();
1060  right!=(mdInRight->_activeLabels).end();
1061  ++right)
1062  for (left=(mdInLeft->_activeLabels).begin();
1063  left!=(mdInLeft->_activeLabels).end();
1064  ++left)
1065  {
1066  if (*left == *right)
1067  {
1068  String labelStr = MDL::label2StrSql(*left);
1069  intersectLabels.push_back(*left);
1070  }
1071  }
1072  if (0 == intersectLabels.size()) {
1073  REPORT_ERROR(ERR_MD_SQL, "No matching columns in the tables");
1074  }
1075  mdInRight->addIndex(intersectLabels);
1076  mdInLeft->addIndex(intersectLabels);
1077  }
1078  else
1079  {
1080  if (columnsRight.size()==1)
1081  {
1082  mdInRight->addIndex(columnsRight[0]);
1083  mdInLeft->addIndex(columnsLeft[0]);
1084  }
1085  }
1086  size = myMd->_activeLabels.size();
1087  size_t sizeLeft = mdInLeft->_activeLabels.size();
1088 
1089  for (size_t i = 0; i < size; i++)
1090  {
1091  ss2 << sep << MDL::label2StrSql( myMd->_activeLabels[i]);
1092  ss3 << sep;
1093  if (i < sizeLeft && mdInLeft->_activeLabels[i] == myMd->_activeLabels[i])
1094  ss3 << tableName(mdInLeft->myMDSql->tableId) << ".";
1095  else
1096  ss3 << tableName(mdInRight->myMDSql->tableId) << ".";
1097  ss3 << MDL::label2StrSql( myMd->_activeLabels[i]);
1098  sep = ", ";
1099  }
1100  ss << "INSERT INTO " << tableName(tableId)
1101  << " (" << ss2.str() << ")"
1102  << " SELECT " << ss3.str()
1103  << " FROM " << tableName(mdInLeft->myMDSql->tableId)
1104  << join_type << " JOIN " << tableName(mdInRight->myMDSql->tableId);
1105 
1106  if (operation != NATURAL_JOIN)
1107  {
1108  ss << " ON (";
1109  for (size_t j=0; j<columnsLeft.size(); ++j)
1110  {
1111  if (j>0)
1112  ss << " AND ";
1113  ss << tableName(mdInLeft->myMDSql->tableId) << "." << MDL::label2StrSql(columnsLeft[j])
1114  << "=" << tableName(mdInRight->myMDSql->tableId) << "." << MDL::label2StrSql(columnsRight[j]);
1115  }
1116  ss << ") ";
1117  }
1118  else
1119  {
1120  sep = " ";
1121  ss << " WHERE ";
1122  for (size_t i = 0; i < mdInRight->_activeLabels.size(); i++)
1123  for (size_t j = 0; j < sizeLeft; j++)
1124  {
1125  if(mdInRight->_activeLabels[i] == mdInLeft->_activeLabels[j])
1126  {
1127  ss << sep
1128  << tableName(mdInRight->myMDSql->tableId) << "."
1129  << MDL::label2StrSql(mdInRight->_activeLabels[i])
1130  << " = "
1131  << tableName(mdInLeft->myMDSql->tableId) << "."
1132  << MDL::label2StrSql(mdInLeft->_activeLabels[j]);
1133  sep = " AND ";
1134  }
1135  }
1136  }
1137  ss << ";";
1138  // std::cerr << "ss:" << ss.str() << std::endl;
1139  // for (int j = 0; j < sizeLeft; j++)
1140  // std::cerr << "mdInRight->activeLabels:" << mdInRight->activeLabels[0] << std::endl;
1141  // for (int j = 0; j < sizeLeft; j++)
1142  // std::cerr << "mdInLeft->activeLabels:" << mdInLeft->activeLabels[1] << std::endl;
1143  execSingleStmt(ss);
1144  //std::cerr << "ss:" << ss.str() << std::endl;
1145  //dumpToFile("kk.sqlite");
1146  //exit(0);
1147 }
1148 
1149 bool MDSql::operate(const String &expression)
1150 {
1151  std::stringstream ss;
1152  ss << "UPDATE " << tableName(tableId) << " SET " << expression;
1153 
1154  return execSingleStmt(ss);
1155 }
1156 
1157 void MDSql::dumpToFile(const FileName &fileName)
1158 {
1159  sqlite3 *pTo;
1160  sqlite3_backup *pBackup;
1161 
1162  sqlCommitTrans();
1163  rc = sqlite3_open(fileName.c_str(), &pTo);
1164  if( rc==SQLITE_OK )
1165  {
1166  pBackup = sqlite3_backup_init(pTo, "main", db, "main");
1167  if( pBackup )
1168  {
1169  sqlite3_backup_step(pBackup, -1);
1170  sqlite3_backup_finish(pBackup);
1171  }
1172  rc = sqlite3_errcode(pTo);
1173  }
1174  else
1175  REPORT_ERROR(ERR_MD_SQL, "dumpToFile: error opening db file");
1176  sqlite3_close(pTo);
1177  sqlBeginTrans();
1178 }
1179 
1180 void MDSql::copyTableFromFileDB(const FileName blockname,
1181  const FileName filename,
1182  const std::vector<MDLabel> *desiredLabels,
1183  const size_t maxRows
1184  )
1185 {
1186  char **results;
1187  int rows;
1188  int columns;
1189  char *Labels;
1190  int rc;
1191 
1192  sqlite3 *db1;
1193  if (sqlite3_open(filename.c_str(), &db1))
1194  REPORT_ERROR(ERR_MD_SQL,formatString("Error opening database code: %d message: %s",rc,sqlite3_errmsg(db1)));
1195  String _blockname;
1196  String sql;
1197  if(blockname.empty())
1198  {
1199  sql = (String)"SELECT name FROM sqlite_master\
1200  WHERE type='table' LIMIT 1;";
1201  if ((rc=sqlite3_get_table (db1, sql.c_str(), &results, &rows, &columns, NULL)) != SQLITE_OK)
1202  REPORT_ERROR(ERR_MD_SQL,formatString("Error accessing table code: %d message: %s. SQL command %s",rc,sqlite3_errmsg(db1),sql.c_str()));
1203  else
1204  _blockname=(String)results[1];
1205  }
1206  else
1207  _blockname=blockname;
1208  sql = (String)"PRAGMA table_info(" + _blockname +")";
1209  if (sqlite3_get_table (db1, sql.c_str(), &results, &rows, &columns, NULL) != SQLITE_OK)
1210  REPORT_ERROR(ERR_MD_SQL,formatString("Error accessing table code: %d message: %s. SQL command %s",rc,sqlite3_errmsg(db1),sql.c_str()));
1211  //This pragma returns one row for each column in the named table.
1212  //Columns in the result set include the column name,
1213  //data type, whether or not the column can be NULL, and the default value for the column.
1214 
1215  String activeLabel;
1216  MDLabel label;
1217  if (rows < 1)
1218  std::cerr << "Empty Metadata" <<std::endl;
1219  else if (desiredLabels != NULL)
1220  {
1221 
1222  myMd->_activeLabels = *desiredLabels;
1223  for(std::vector<MDLabel>::const_iterator it = desiredLabels->
1224  begin();
1225  it != desiredLabels->end();
1226  ++it)
1227  {
1228  activeLabel += *it + " ,";
1229  }
1230  }
1231  else
1232  {
1233 
1234  activeLabel="*";
1235  for (int i = 1; i <= rows; i++)
1236  {
1237  Labels = results[(i * columns) + 1];
1238  label = MDL::str2Label(Labels);
1239 
1240  if (label == MDL_UNDEFINED)
1241  {
1242  if(strcmp(Labels,"objID"))
1243  std::cerr << (String)"WARNING: Ignoring unknown column: " + Labels << std::endl;
1244  }
1245  else
1246  {
1247  myMd->_activeLabels.push_back(label);
1248  }
1249  }
1250  }
1251  sqlite3_free_table (results);
1252  sqlite3_close(db1);
1253 
1254  //Copy table to memory
1255  //tableName(tableId);
1256  sqlCommitTrans();
1257  dropTable();
1258  createMd();
1259 
1260  String sqlCommand = formatString("ATTACH database '%s' AS load;", filename.c_str());
1261 
1262  if (sqlite3_exec(db, sqlCommand.c_str(), NULL, NULL, &errmsg) != SQLITE_OK)
1263  {
1264  std::cerr << "Couldn't attach or create table: " << errmsg << std::endl;
1265  return;
1266  }
1267  String selectCmd = formatString("SELECT %s FROM load.%s", activeLabel.c_str(), _blockname.c_str());
1268  sqlCommand = formatString("INSERT INTO %s %s", tableName(tableId).c_str(), selectCmd.c_str());
1269 
1270  if (maxRows)
1271  {
1272  std::stringstream ss;
1273  ss << "SELECT COUNT(objId) FROM load." << _blockname;
1274  myMd->_parsedLines = execSingleIntStmt(ss);
1275  //std::cerr << ss.str() << " = " << myMd->_parsedLines << std::endl;
1276 
1277  sqlCommand += formatString(" LIMIT %lu", maxRows);
1278  }
1279 
1280  if (sqlite3_exec(db, sqlCommand.c_str(),NULL,NULL,&errmsg) != SQLITE_OK)
1281  {
1282  std::cerr << (String)"Couldn't write table: " << tableName(tableId)
1283  << " " << errmsg << std::endl
1284  << "sqlcommand " << sqlCommand << std::endl;
1285  return;
1286  }
1287  sqlite3_exec(db, "DETACH load",NULL,NULL,&errmsg);
1288  sqlBeginTrans();
1289 }
1290 
1291 void MDSql::copyTableToFileDB(const FileName blockname, const FileName &fileName)
1292 {
1293  sqlCommitTrans();
1294  String _blockname;
1295  if(blockname.empty())
1296  _blockname=DEFAULT_BLOCK_NAME;
1297  else
1298  _blockname=blockname;
1299  String sqlCommand = (String)"ATTACH database '" + fileName+"' as save";
1300  sqlCommand += (String)";drop table if exists save." + blockname;
1301  if (sqlite3_exec(db, sqlCommand.c_str(),NULL,NULL,&errmsg) != SQLITE_OK)
1302  {
1303  std::cerr << "Couldn't attach or create table: " << errmsg << std::endl;
1304  return;
1305  }
1306 
1307  sqlCommand = (String)"create table save." +blockname
1308  +" as select * from main."+tableName(tableId);
1309  //do not know how to create indexes in attached table
1310  // sqlCommand += (String)";CREATE INDEX IF NOT EXISTS save.obj_Id_INDEX ON "
1311  // + "save." +blockname +"(objID)";
1312  if (sqlite3_exec(db, sqlCommand.c_str(),NULL,NULL,&errmsg) != SQLITE_OK)
1313  {
1314  std::cerr << (String)"Couldn't write table: " << blockname
1315  << " " << errmsg << std::endl;
1316  return;
1317  }
1318  sqlite3_exec(db, "DETACH save",NULL,NULL,&errmsg);
1319  sqlBeginTrans();
1320 }
1321 
1322 bool MDSql::sqlBegin()
1323 {
1324  if (table_counter > 0)
1325  return true;
1326  //std::cerr << "entering sqlBegin" <<std::endl;
1327  rc = sqlite3_open("", &db);
1328 
1329  sqlite3_exec(db, "PRAGMA temp_store=MEMORY",NULL, NULL, &errmsg);
1330  sqlite3_exec(db, "PRAGMA synchronous=OFF",NULL, NULL, &errmsg);
1331  sqlite3_exec(db, "PRAGMA count_changes=OFF",NULL, NULL, &errmsg);
1332  sqlite3_exec(db, "PRAGMA page_size=4092",NULL, NULL, &errmsg);
1333 
1334  return sqlBeginTrans();
1335 }
1336 
1337 void MDSql::sqlTimeOut(int miliseconds)
1338 {
1339  if (sqlite3_busy_timeout(db, miliseconds) != SQLITE_OK)
1340  {
1341  std::cerr << "Couldn't not set timeOut: " << std::endl;
1342  exit(0);
1343 
1344  }
1345 
1346 }
1347 
1348 void MDSql::sqlEnd()
1349 {
1350  sqlCommitTrans();
1351  sqlite3_close(db);
1352  //std::cerr << "Database sucessfully closed." <<std::endl;
1353 }
1354 
1355 bool MDSql::sqlBeginTrans()
1356 {
1357  if (sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &errmsg) != SQLITE_OK)
1358  {
1359  std::cerr << "Couldn't begin transaction: " << errmsg << std::endl;
1360  return false;
1361  }
1362  return true;
1363 }
1364 
1365 bool MDSql::sqlCommitTrans()
1366 {
1367  char *errmsg;
1368 
1369  if (sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, &errmsg) != SQLITE_OK)
1370  {
1371  std::cerr << "Couldn't commit transaction: " << errmsg << std::endl;
1372  return false;
1373  }
1374  return true;
1375 }
1376 
1377 bool MDSql::dropTable()
1378 {
1379  std::stringstream ss;
1380  ss << "DROP TABLE IF EXISTS " << tableName(tableId) << ";";
1381  return execSingleStmt(ss);
1382 }
1383 
1384 bool MDSql::createTable(const std::vector<MDLabel> * labelsVector, bool withObjID)
1385 {
1386  std::stringstream ss;
1387  ss << "CREATE TABLE " << tableName(tableId) << "(";
1388  std::string sep = "";
1389  if (withObjID)
1390  {
1391  ss << "objID INTEGER PRIMARY KEY ASC AUTOINCREMENT";
1392  sep = ", ";
1393  }
1394  if (labelsVector != NULL)
1395  {
1396  for (size_t i = 0; i < labelsVector->size(); i++)
1397  {
1398  ss << sep << MDL::label2SqlColumn(labelsVector->at(i));
1399  sep = ", ";
1400  }
1401  }
1402  ss << ");";
1403  return execSingleStmt(ss);
1404 }
1405 
1406 void MDSql::prepareStmt(const std::stringstream &ss, sqlite3_stmt *stmt)
1407 {
1408  const char * zLeftover;
1409  sqlite3_prepare_v2(db, ss.str().c_str(), -1, &stmt, &zLeftover);
1410 }
1411 
1412 bool MDSql::execSingleStmt(const std::stringstream &ss)
1413 {
1414 
1415  sqlite3_stmt * stmt;
1416  sqlite3_prepare_v2(db, ss.str().c_str(), -1, &stmt, &zLeftover);
1417 
1418 //#define DEBUG
1419 #ifdef DEBUG
1420 
1421  std::cerr << "execSingleStmt, stmt: '" << ss.str() << "'" <<std::endl;
1422 #endif
1423 #undef DEBUG
1424 
1425  bool r = execSingleStmt(stmt, &ss);
1426  sqlite3_finalize(stmt);
1427  return r;
1428 }
1429 
1430 bool MDSql::execSingleStmt(sqlite3_stmt * &stmt, const std::stringstream *ss)
1431 {
1432  int rc;
1433  rc = sqlite3_step(stmt);
1434  if (rc != SQLITE_OK && rc != SQLITE_ROW && rc != SQLITE_DONE)
1435  REPORT_ERROR(ERR_MD_SQL,formatString("Error code: %d message: %s\n Sqlite query: %s",rc,sqlite3_errmsg(db), ss->str().c_str()));
1436  return true;
1437 }
1438 
1439 size_t MDSql::execSingleIntStmt(const std::stringstream &ss)
1440 {
1441  int rc;
1442  sqlite3_stmt * stmt;
1443  sqlite3_prepare_v2(db, ss.str().c_str(), -1, &stmt, &zLeftover);
1444  rc = sqlite3_step(stmt);
1445  size_t result = sqlite3_column_int(stmt, 0);
1446 
1447  if (rc != SQLITE_OK && rc != SQLITE_ROW && rc != SQLITE_DONE)
1448  {
1449  std::cerr << "MDSql::execSingleIntStmt: error executing statement, code " << rc <<std::endl;
1450  result = -1;
1451  }
1452  sqlite3_finalize(stmt);
1453  return result;
1454 }
1455 
1456 double MDSql::execSingleDoubleStmt(const std::stringstream &ss)
1457 {
1458  int rc;
1459  sqlite3_stmt * stmt;
1460  sqlite3_prepare_v2(db, ss.str().c_str(), -1, &stmt, &zLeftover);
1461  rc = sqlite3_step(stmt);
1462  double result = sqlite3_column_double(stmt, 0);
1463 
1464  if (rc != SQLITE_OK && rc != SQLITE_ROW && rc != SQLITE_DONE)
1465  {
1466  std::cerr << "MDSql::execSingleDoubleStmt: error executing statement, code " << rc <<std::endl;
1467  result = -1;
1468  }
1469  sqlite3_finalize(stmt);
1470  return result;
1471 }
1472 std::string MDSql::tableName(const int tableId) const
1473 {
1474  std::stringstream ss;
1475  ss << "MDTable_" << tableId;
1476  return ss.str();
1477 }
1478 
1479 bool MDSql::bindStatement( size_t id)
1480 {
1481  bool success=true; // Return value.
1482 
1483  // Clear current statement.
1484  sqlite3_clear_bindings(this->preparedStmt);
1485  sqlite3_reset(this->preparedStmt);
1486 
1487  // Bind object id.
1488  if (sqlite3_bind_int(this->preparedStmt, 1, id) != SQLITE_OK)
1489  {
1490  success = false;
1491  }
1492 
1493  return(success);
1494 }
1495 
1496 int MDSql::bindValue(sqlite3_stmt *stmt, const int position, const MDObject &valueIn)
1497 {
1498  //First reset the statement
1499  //rc = sqlite3_reset(stmt);
1500  //std::cerr << "rc after reset: " << rc <<std::endl;
1501  if (valueIn.failed)
1502  {
1503  // If a value was wronly parsed, set NULL in their sqlite entry
1504  std::cerr << "WARNING!!! valueIn.failed = True, binding NULL" << std::endl;
1505 
1506  return sqlite3_bind_null(stmt, position);
1507  }
1508  else
1509  {
1510  switch (valueIn.type)
1511  {
1512  case LABEL_BOOL: //bools are int in sqlite3
1513  return sqlite3_bind_int(stmt, position, valueIn.data.boolValue ? 1 : 0);
1514  case LABEL_INT:
1515  return sqlite3_bind_int(stmt, position, valueIn.data.intValue);
1516  case LABEL_SIZET:
1517  return sqlite3_bind_int(stmt, position, valueIn.data.longintValue);
1518  case LABEL_DOUBLE:
1519  return sqlite3_bind_double(stmt, position, valueIn.data.doubleValue);
1520  case LABEL_STRING:
1521  return sqlite3_bind_text(stmt, position, valueIn.data.stringValue->c_str(), -1, SQLITE_TRANSIENT);
1522  case LABEL_VECTOR_DOUBLE:
1523  case LABEL_VECTOR_SIZET:
1524  return sqlite3_bind_text(stmt, position, valueIn.toString(false, true).c_str(), -1, SQLITE_TRANSIENT);
1525  default:
1526  REPORT_ERROR(ERR_ARG_INCORRECT,"Do not know how to handle this type");
1527  }
1528  }
1529 }
1530 
1531 void MDSql::extractValue(sqlite3_stmt *stmt, const int position, MDObject &valueOut)
1532 {
1533  switch (valueOut.type)
1534  {
1535  case LABEL_BOOL: //bools are int in sqlite3
1536  valueOut.data.boolValue = sqlite3_column_int(stmt, position) == 1;
1537  break;
1538  case LABEL_INT:
1539  valueOut.data.intValue = sqlite3_column_int(stmt, position);
1540  break;
1541  case LABEL_SIZET:
1542  valueOut.data.longintValue = sqlite3_column_int(stmt, position);
1543  break;
1544  case LABEL_DOUBLE:
1545  valueOut.data.doubleValue = sqlite3_column_double(stmt, position);
1546  break;
1547  case LABEL_STRING:
1548  {
1549  std::stringstream ss;
1550  ss << sqlite3_column_text(stmt, position);
1551  valueOut.data.stringValue->assign(ss.str());
1552 
1553  break;
1554  }
1555  case LABEL_VECTOR_DOUBLE:
1556  case LABEL_VECTOR_SIZET:
1557  {
1558  std::stringstream ss;
1559  ss << sqlite3_column_text(stmt, position);
1560  valueOut.fromStream(ss);
1561  break;
1562  }
1563  default:
1564  REPORT_ERROR(ERR_ARG_INCORRECT,"Do not know how to extract a value of type " + valueOut.type);
1565  }
1566 }
1567 
1569 {
1570  this->addRowStmt = NULL;
1571  this->iterStmt = NULL;
1572 }
1573 
1575 {
1576  clear();
1577 }
1578 
1580 {
1581  //Clear cached statements
1582  std::map<MDLabel, sqlite3_stmt*>::iterator it;
1583  //FIXME: This is a bit dirty here...should be moved to MDSQl
1584  for (it = setValueCache.begin(); it != setValueCache.end(); it++)
1585  sqlite3_finalize(it->second);
1586  setValueCache.clear();
1587 
1588  for (it = getValueCache.begin(); it != getValueCache.end(); it++)
1589  sqlite3_finalize(it->second);
1590  getValueCache.clear();
1591 
1592  if (iterStmt != NULL)
1593  {
1594  sqlite3_finalize(iterStmt);
1595  iterStmt = NULL;
1596  }
1597 
1598  if (addRowStmt != NULL)
1599  {
1600  sqlite3_finalize(addRowStmt);
1601  addRowStmt = NULL;
1602  }
1603 }
object id (int), NOTE: This label is special and shouldn&#39;t be used
std::map< MDLabel, sqlite3_stmt * > getValueCache
Definition: metadata_sql.h:317
String whereString() const
static MDLabel str2Label(const String &labelName)
iterator begin() override
Definition: metadata_vec.h:501
iterator end() override
Definition: metadata_vec.h:504
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
static bool activateMathExtensions(void)
size_t _parsedLines
void sqlite_regexp(sqlite3_context *context, int argc, sqlite3_value **values)
sqlite3_stmt * addRowStmt
Definition: metadata_sql.h:319
bool deactivateThreadMuting(void)
rowIterator< true > const_iterator
static bool isVector(const MDLabel label)
MDSql * myMDSql
Definition: metadata_db.h:62
int getBlocksInMetaDataFileDB(const FileName &inFile, StringVector &blockList)
static String label2StrSql(const MDLabel label)
void clear()
MDLabelType type
std::vector< String > StringVector
Definition: xmipp_strings.h:35
size_t size() const override
#define i
static bool activateRegExtensions(void)
Error in SQL of MetaData operations.
Definition: xmipp_error.h:159
bool fromStream(std::istream &is, bool fromString=false)
void clear() override
MDLabel label
size_t longintValue
double v1
String orderByString() const
static void sqlTimeOut(int miliSeconds)
Incorrect argument received.
Definition: xmipp_error.h:113
ObjectData data
static void dumpToFile(const FileName &fileName)
__host__ __device__ float length(float2 v)
void sort(struct DCEL_T *dcel)
Definition: sorting.cpp:18
void addIndex(MDLabel label) const
String limitString() const
String toString(bool withFormat=false, bool isSql=false) const
bool activateThreadMuting(void)
#define j
std::vector< MDLabel > _activeLabels
Definition: metadata_db.h:68
static bool isString(const MDLabel label)
double precision() const
static String label2SqlColumn(const MDLabel label)
std::string String
Definition: xmipp_strings.h:34
static bool isDouble(const MDLabel label)
String formatString(const char *format,...)
double doubleValue
virtual void unlock()
static String label2Str(const MDLabel &label)
Mutex sqlMutex
String * stringValue
#define DEFAULT_BLOCK_NAME
Definition: metadata_base.h:60
MDLabel
int _precision
std::map< MDLabel, sqlite3_stmt * > setValueCache
Definition: metadata_sql.h:318
virtual void lock()
#define BAD_OBJID
Definition: metadata_base.h:55
A comment for this object /*** NOTE THIS IS A SPECIAL CASE AND SO IS TREATED ***/.