MRPT  1.9.9
CSimpleDatabase.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "db-precomp.h" // Precompiled headers
11 
14 #include <mrpt/system/os.h>
15 
16 using namespace mrpt::db;
17 using namespace mrpt::system;
18 using namespace std;
19 
20 #undef _UNICODE // JLBC
21 
22 #include "xmlparser/xmlParser.h"
23 
24 #include <iostream>
25 
26 // This must be added to any CSerializable class implementation file.
29 
30 uint8_t CSimpleDatabase::serializeGetVersion() const { return 0; }
32 {
33  // Save all tables in DB:
34  auto n = (uint32_t)m_tables.size();
35  out << n;
36 
37  for (const auto& m_table : m_tables)
38  {
39  out << m_table.first; //.c_str();
40  out << *m_table.second;
41  }
42 }
45 {
46  switch (version)
47  {
48  case 0:
49  {
50  std::string aux;
51 
52  // Clear existing tables:
53  clear();
54 
55  // Load all tables in DB:
56  uint32_t n;
57  in >> n;
58 
59  for (uint32_t i = 0; i < n; i++)
60  {
61  in >> aux;
62 
64  std::make_shared<CSimpleDatabaseTable>();
65  in >> (*newTb);
66 
67  m_tables[aux] = newTb;
68  }
69  }
70  break;
71  default:
73  };
74 }
75 
78 {
79  uint32_t row, col, nRec = (uint32_t)getRecordCount(),
80  nFie = (uint32_t)fieldsCount();
81 
82  out << nRec << nFie;
83 
84  for (col = 0; col < nFie; col++) out << field_names[col]; //.c_str();
85 
86  for (row = 0; row < nRec; row++)
87  for (col = 0; col < nFie; col++) out << data[row][col]; //.c_str();
88 }
91 {
92  switch (version)
93  {
94  case 0:
95  {
96  uint32_t row, col, nRec, nFie;
97  // char str[10000];
98 
99  in >> nRec >> nFie;
100 
101  data.resize(nRec);
102  field_names.resize(nFie);
103 
104  for (col = 0; col < nFie; col++) in >> field_names[col];
105 
106  for (row = 0; row < nRec; row++)
107  {
108  data[row].resize(nFie);
109 
110  for (col = 0; col < nFie; col++) in >> data[row][col];
111  }
112  }
113  break;
114  default:
116  };
117 }
118 
119 /*---------------------------------------------------------------
120  Constructor
121  ---------------------------------------------------------------*/
123 /*---------------------------------------------------------------
124  Destructor
125  ---------------------------------------------------------------*/
127 /*---------------------------------------------------------------
128  Clear the DB
129  ---------------------------------------------------------------*/
130 void CSimpleDatabase::clear() { m_tables.clear(); }
131 /*---------------------------------------------------------------
132  getTable
133  ---------------------------------------------------------------*/
135  const std::string& tableName)
136 {
137  MRPT_START
138 
139  auto it = m_tables.find(tableName);
140  if (it != m_tables.end()) return it->second;
141 
142  THROW_EXCEPTION_FMT("Table '%s' was not found", tableName.c_str());
143 
144  MRPT_END
145 }
146 
147 /*---------------------------------------------------------------
148  getTable
149  ---------------------------------------------------------------*/
151 {
152  MRPT_START
153 
154  ASSERT_(tableIndex < tablesCount());
155  auto it = m_tables.begin();
156  std::advance(it, tableIndex);
157  return it->second;
158 
159  MRPT_END
160 }
161 
162 /*---------------------------------------------------------------
163  tablesCount
164  ---------------------------------------------------------------*/
165 size_t CSimpleDatabase::tablesCount() const { return m_tables.size(); }
166 /*---------------------------------------------------------------
167  tablesName
168  ---------------------------------------------------------------*/
169 string CSimpleDatabase::tablesName(size_t tableIndex) const
170 {
171  MRPT_START
172 
173  ASSERT_(tableIndex < tablesCount());
174  auto it = m_tables.begin();
175  std::advance(it, tableIndex);
176  return it->first;
177 
178  MRPT_END
179 }
180 
181 /*---------------------------------------------------------------
182  createTable
183  ---------------------------------------------------------------*/
185 {
186  CSimpleDatabaseTable::Ptr table = std::make_shared<CSimpleDatabaseTable>();
187  m_tables[name] = table;
188  return table;
189 }
190 
191 /*---------------------------------------------------------------
192  Constructor
193  ---------------------------------------------------------------*/
195 /*---------------------------------------------------------------
196  Destructor
197  ---------------------------------------------------------------*/
199 /*---------------------------------------------------------------
200  fieldsCount
201  ---------------------------------------------------------------*/
202 size_t CSimpleDatabaseTable::fieldsCount() const { return field_names.size(); }
203 /*---------------------------------------------------------------
204  addField
205  ---------------------------------------------------------------*/
206 void CSimpleDatabaseTable::addField(const char* fieldName)
207 {
208  field_names.emplace_back(fieldName);
209  data.clear();
210 }
211 
212 /*---------------------------------------------------------------
213  getFieldName
214  ---------------------------------------------------------------*/
215 string CSimpleDatabaseTable::getFieldName(size_t fieldIndex) const
216 {
217  MRPT_START
218 
219  ASSERT_(fieldIndex < fieldsCount());
220  return field_names[fieldIndex];
221 
222  MRPT_END
223 }
224 
225 /*---------------------------------------------------------------
226  fieldIndex
227  ---------------------------------------------------------------*/
228 size_t CSimpleDatabaseTable::fieldIndex(const char* fieldName) const
229 {
230  MRPT_START
231 
232  size_t i, n = field_names.size();
233 
234  for (i = 0; i < n; i++)
235  if (!os::_strcmpi(fieldName, field_names[i].c_str())) return (int)i;
236 
237  THROW_EXCEPTION_FMT("fieldIndex: Field '%s' not found", fieldName);
238 
239  MRPT_END
240 }
241 
242 /*---------------------------------------------------------------
243  getRecordCount
244  ---------------------------------------------------------------*/
245 size_t CSimpleDatabaseTable::getRecordCount() const { return data.size(); }
246 /*---------------------------------------------------------------
247  get
248  ---------------------------------------------------------------*/
249 string CSimpleDatabaseTable::get(size_t recordIndex, string field) const
250 {
251  MRPT_START
252  ASSERT_(recordIndex < getRecordCount());
253  return data[recordIndex][fieldIndex(field.c_str())];
254  MRPT_END
255 }
256 
257 /*---------------------------------------------------------------
258  get
259  ---------------------------------------------------------------*/
260 string CSimpleDatabaseTable::get(size_t recordIndex, size_t fieldIndex) const
261 {
262  MRPT_START
263  ASSERT_(recordIndex < getRecordCount());
264  ASSERT_(fieldIndex < fieldsCount());
265  return data[recordIndex][fieldIndex];
266  MRPT_END
267 }
268 
269 /*---------------------------------------------------------------
270  set
271  ---------------------------------------------------------------*/
272 void CSimpleDatabaseTable::set(size_t recordIndex, string field, string value)
273 {
274  MRPT_START
275 
276  ASSERT_(recordIndex < getRecordCount());
277  data[recordIndex][fieldIndex(field.c_str())] = value;
278 
279  MRPT_END
280 }
281 
282 /*---------------------------------------------------------------
283  set
284  ---------------------------------------------------------------*/
286  size_t recordIndex, size_t fieldIndex, string value)
287 {
288  MRPT_START
289 
290  ASSERT_(recordIndex < getRecordCount());
291  ASSERT_(fieldIndex < fieldsCount());
292  data[recordIndex][fieldIndex] = value;
293 
294  MRPT_END
295 }
296 
297 /*---------------------------------------------------------------
298  query
299  ---------------------------------------------------------------*/
300 int CSimpleDatabaseTable::query(string field, string value) const
301 {
302  int fieldInd, i, n = (uint32_t)getRecordCount();
303 
304  try
305  {
306  fieldInd = (uint32_t)fieldIndex(field.c_str());
307  }
308  catch (...)
309  {
310  return -1;
311  }
312 
313  for (i = 0; i < n; i++)
314  {
315  if (!os::_strcmpi(value.c_str(), data[i][fieldInd].c_str())) return i;
316  }
317 
318  // Do not found:
319  return -1;
320 }
321 
322 /*---------------------------------------------------------------
323  appendRecord
324  ---------------------------------------------------------------*/
326 {
327  std::vector<std::string> new_rec;
328 
329  new_rec.resize(fieldsCount());
330  data.push_back(new_rec);
331 
332  return data.size() - 1;
333 }
334 
335 /*---------------------------------------------------------------
336  deleteRecord
337  ---------------------------------------------------------------*/
338 void CSimpleDatabaseTable::deleteRecord(size_t recordIndex)
339 {
340  MRPT_START
341  ASSERT_(recordIndex < getRecordCount());
342  auto it = data.begin();
343  std::advance(it, recordIndex);
344  data.erase(it);
345 
346  MRPT_END
347 }
348 
349 /*---------------------------------------------------------------
350  saveAsXML
351  ---------------------------------------------------------------*/
352 bool CSimpleDatabase::saveAsXML(const string& fileName) const
353 {
354  try
355  {
356  // Root node:
357  XMLNode rootXml =
358  XMLNode::createXMLTopNode("CSimpleDatabase-MRPT-Object");
359 
360  // For each table:
361  for (const auto& m_table : m_tables)
362  {
363  CSimpleDatabaseTable::Ptr t = m_table.second;
364  XMLNode tabNod = rootXml.addChild("table");
365  tabNod.addAttribute("name", m_table.first.c_str());
366 
367  // Add field descriptions:
368  // ------------------------
369  size_t nFields = t->fieldsCount();
370  size_t nRecs = t->getRecordCount();
371 
372  XMLNode fNod = tabNod.addChild("fields");
373  for (unsigned int i = 0; i < nFields; i++)
374  fNod.addChild(t->getFieldName(i).c_str());
375 
376  // Add record contents:
377  // ------------------------
378  for (unsigned int i = 0; i < nRecs; i++)
379  {
380  XMLNode recNod = tabNod.addChild("record");
381  for (size_t j = 0; j < nFields; j++)
382  {
383  XMLNode recContent =
384  recNod.addChild(t->getFieldName(j).c_str());
385  recContent.addText(t->get(i, j).c_str());
386  }
387  }
388 
389  } // end for each table.
390 
391  rootXml.writeToFile(fileName.c_str());
392 
393  return true; // Ok
394  }
395  catch (exception& e)
396  {
397  cerr << "[CSimpleDatabase::saveAsXML] Exception ignored:" << endl
398  << e.what() << endl;
399  return false; // Errors found
400  }
401  catch (...)
402  {
403  return false; // Errors found
404  }
405 }
406 
407 /*---------------------------------------------------------------
408  loadFromXML
409  ---------------------------------------------------------------*/
410 bool CSimpleDatabase::loadFromXML(const string& fileName)
411 {
412  try
413  {
415  XMLNode root = XMLNode::parseFile(fileName.c_str(), nullptr, &results);
416 
417  if (results.error != eXMLErrorNone)
418  {
419  cerr << "[CSimpleDatabase::loadFromXML] Error loading XML file: "
420  << XMLNode::getError(results.error) << " at line "
421  << results.nLine << ":" << results.nColumn << endl;
422  return false;
423  }
424 
425  root = root.getChildNode("CSimpleDatabase-MRPT-Object");
426  if (root.isEmpty())
427  {
428  cerr << "[CSimpleDatabase::loadFromXML] Loaded XML file does not "
429  "have a 'CSimpleDatabase-MRPT-Object' tag";
430  return false;
431  }
432 
433  // Clear previous contents:
434  clear();
435 
436  // Get tables:
437  size_t i, j, nTables = root.nChildNode("table");
438  for (i = 0; i < nTables; i++)
439  {
440  XMLNode tabNod = root.getChildNode("table", (int)i);
441  ASSERT_(!tabNod.isEmpty());
442  // Create table:
444  createTable(tabNod.getAttribute("name"));
445 
446  // Create fields:
447  XMLNode fNod = tabNod.getChildNode("fields");
448  ASSERT_(!fNod.isEmpty());
449  size_t nFields = fNod.nChildNode();
450  for (j = 0; j < nFields; j++)
451  {
452  t->addField(fNod.getChildNode((int)j).getName());
453  } // end for each field
454 
455  // Add record data:
456  size_t nRecs = tabNod.nChildNode("record");
457  for (size_t k = 0; k < nRecs; k++)
458  {
459  size_t recIdx = t->appendRecord();
460 
461  XMLNode recNod = tabNod.getChildNode("record", (int)k);
462  ASSERT_(!recNod.isEmpty());
463  for (j = 0; j < nFields; j++)
464  {
465  XMLCSTR str =
466  recNod.getChildNode(t->getFieldName(j).c_str())
467  .getText();
468  t->set(recIdx, j, str != nullptr ? string(str) : string());
469  }
470 
471  } // end for each record
472 
473  } // for each table
474 
475  return true; // Ok
476  }
477  catch (exception& e)
478  {
479  cerr << "[CSimpleDatabase::loadFromXML] Exception ignored:" << endl
480  << e.what() << endl;
481  return false; // Errors found
482  }
483  catch (...)
484  {
485  return false; // Errors found
486  }
487 }
488 
489 /*---------------------------------------------------------------
490  dropTable
491  ---------------------------------------------------------------*/
493 {
494  MRPT_START
495 
496  auto it = m_tables.find(tableName);
497  if (it == m_tables.end())
498  THROW_EXCEPTION_FMT("Table '%s' was not found", tableName.c_str());
499 
500  m_tables.erase(it);
501 
502  MRPT_END
503 }
504 
505 /*---------------------------------------------------------------
506  renameTable
507  ---------------------------------------------------------------*/
509  const std::string& tableName, const std::string& newTableName)
510 {
511  MRPT_START
512 
513  if (tableName == newTableName) return; // done
514 
515  auto it = m_tables.find(tableName);
516  if (it == m_tables.end())
517  THROW_EXCEPTION_FMT("Table '%s' was not found", tableName.c_str());
518 
519  {
520  auto itNew = m_tables.find(newTableName);
521  if (itNew != m_tables.end())
523  "A table with the name '%s' already exists",
524  newTableName.c_str());
525  }
526 
527  CSimpleDatabaseTable::Ptr tb = it->second;
528 
529  m_tables.erase(it);
530  m_tables[newTableName] = tb;
531 
532  MRPT_END
533 }
CSimpleDatabaseTable()
Default constructor.
#define MRPT_START
Definition: exceptions.h:241
GLdouble GLdouble t
Definition: glext.h:3695
bool saveAsXML(const std::string &fileName) const
Saves this database as a XML file.
Main Class representing a XML node.
Definition: xmlParser.h:314
void serializeTo(mrpt::serialization::CArchive &out) const override
Pure virtual method for writing (serializing) to an abstract archive.
int query(std::string field, std::string value) const
Executes a query in the table, returning the record index which a given field has a given value...
size_t fieldsCount() const
Get the count of fields.
XMLError writeToFile(XMLCSTR filename, const char *encoding=nullptr, char nFormat=1) const
Save the content of an xmlNode inside a file.
Definition: xmlParser.cpp:807
This class impements a very simple database system.
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
To be added to all CSerializable-classes implementation files.
GLenum GLsizei n
Definition: glext.h:5136
size_t tablesCount() const
Returns the tables count in the DB.
char isEmpty() const
is this node Empty?
Definition: xmlParser.cpp:3419
std::string getFieldName(size_t fieldIndex) const
Get the name of a field by its index.
GLenum GLsizei GLenum GLenum const GLvoid * table
Definition: glext.h:3535
static XMLNode createXMLTopNode(XMLCSTR lpszName, char isDeclaration=FALSE)
Create the top node of an XMLNode structure.
Definition: xmlParser.cpp:1415
STL namespace.
CSimpleDatabaseTable::Ptr createTable(const std::string &name)
Creates a new table in the DB, initially empty.
#define XMLCSTR
Definition: xmlParser.h:225
size_t fieldIndex(const char *fieldName) const
Get the index for a given field name.
void serializeFrom(mrpt::serialization::CArchive &in, uint8_t serial_version) override
Pure virtual method for reading (deserializing) from an abstract archive.
~CSimpleDatabase() override
Destructor.
std::string tablesName(size_t tableIndex) const
Returns the tables names in the DB.
void addField(const char *fieldName)
Add a new field to the table.
unsigned char uint8_t
Definition: rptypes.h:44
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
Definition: exceptions.h:97
static XMLCSTR getError(XMLError error)
this gives you a
Definition: xmlParser.cpp:83
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:120
XMLAttribute getAttribute(int i=0) const
return ith attribute
Definition: xmlParser.cpp:3384
map< string, CVectorDouble > results
void dropTable(const std::string &tableName)
Deletes the given table.
CSimpleDatabase()
Default constructor.
void clear()
Clears the DB.
size_t appendRecord()
Append a new and empty record at the end of the table, and return the index of the newly added record...
void deleteRecord(size_t recordIndex)
Delete the record at the given index.
GLsizei const GLchar ** string
Definition: glext.h:4116
CSimpleDatabaseTable::Ptr getTable(const std::string &tableName)
Returns the table with the indicated name.
static XMLNode parseFile(XMLCSTR filename, XMLCSTR tag=nullptr, XMLResults *pResults=nullptr)
Parse an XML file and return the root of a XMLNode tree representing the file.
Definition: xmlParser.cpp:2285
XMLCSTR addText(XMLCSTR lpszValue, XMLElementPosition pos=-1)
Add a new text content.
Definition: xmlParser.cpp:3439
Virtual base class for "archives": classes abstracting I/O streams.
Definition: CArchive.h:53
std::string get(size_t recordIndex, std::string field) const
Returns the cell content of the record indicates by its index, and the field indicated in "field"...
GLenum GLenum GLvoid * row
Definition: glext.h:3580
#define MRPT_END
Definition: exceptions.h:245
void set(size_t recordIndex, std::string field, std::string value)
Sets the cell content of the record indicates by its index, and the field indicated in "field"...
GLuint in
Definition: glext.h:7391
GLuint const GLchar * name
Definition: glext.h:4068
~CSimpleDatabaseTable() override
Destructor.
XMLNode addChild(XMLCSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1)
Add a new child node.
Definition: xmlParser.cpp:3421
This class implements the tables of databases.
GLsizei const GLfloat * value
Definition: glext.h:4134
uint8_t serializeGetVersion() const override
Must return the current versioning number of the object.
void renameTable(const std::string &tableName, const std::string &newTableName)
Changes the name of a given table.
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Definition: exceptions.h:69
unsigned __int32 uint32_t
Definition: rptypes.h:50
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3550
void clear()
Clear the contents of this container.
Definition: ts_hash_map.h:182
void serializeFrom(mrpt::serialization::CArchive &in, uint8_t serial_version) override
Pure virtual method for reading (deserializing) from an abstract archive.
size_t getRecordCount() const
Get the records count in the table.
bool loadFromXML(const std::string &fileName)
Loads the content of this database from a a XML file.
int nChildNode(XMLCSTR name) const
return the number of child node with specific name
Definition: xmlParser.cpp:3099
void serializeTo(mrpt::serialization::CArchive &out) const override
Pure virtual method for writing (serializing) to an abstract archive.
Structure used to obtain error details if the parse fails.
Definition: xmlParser.h:275
XMLNode getChildNode(int i=0) const
return ith child node
Definition: xmlParser.cpp:3404
XMLAttribute * addAttribute(XMLCSTR lpszName, XMLCSTR lpszValuev)
it will be detached from it&#39;s parents before being attached to the current XMLNode ...
Definition: xmlParser.cpp:3431
int _strcmpi(const char *str1, const char *str2) noexcept
An OS-independent version of strcmpi.
Definition: os.cpp:322



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 8fe78517f Sun Jul 14 19:43:28 2019 +0200 at lun oct 28 02:10:00 CET 2019