All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DBSqLite.cpp
Go to the documentation of this file.
1 /*
2  * DBSqLite.cpp
3  *
4  * This file is part of the HausmiSEP project
5  *
6  * Copyright (C) 2012, 2013 Marco Alvarado (malvcr@gmail.com)
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
23 #include <HSEPData/DBBase.h>
24 #include <HSEP/Array.h>
25 #include <HSEP/Dictionary.h>
26 #include <iostream>
27 #include <sqlite3.h>
28 #include <stdio.h>
29 
30 using namespace HSEPData;
31 using namespace HSEP;
32 using namespace std;
33 
34 namespace HSEPDataSqLite {
35 
36 // ----------------------------------------------------------------------------------------
37 
38  string SqLiteWhatMethod(string& pMessageRef, exception* pExceptionPtr) {
39 
40  char vTemp[10240];
41 
42  //sql::SQLException& vException = (sql::SQLException&)*pException;
43 
44  sprintf(vTemp,
45  "# ERR: SQLException in %s (%s) on line %d\n# ERR: %s (SqLite error code: #d, SQLState: #s)\n",
46  __FILE__,
47  __FUNCTION__,
48  __LINE__,
49  pExceptionPtr->what()
50  //pException->getErrorCode(),
51  //vException.getSQLState().c_str()
52  );
53 
54  pMessageRef = string (vTemp);
55 
56  return pMessageRef;
57 
58  } // SqLiteWhatMethod
59 
69  class RAII_mutex {
70  sqlite3* aConnectionPtr;
71  public:
72  RAII_mutex(sqlite3* pConnectionPtr) : aConnectionPtr(pConnectionPtr) {
73  sqlite3_mutex_enter(sqlite3_db_mutex(aConnectionPtr));
74  }
76  sqlite3_mutex_leave(sqlite3_db_mutex(aConnectionPtr));
77  }
78  };
79 
80  // ----------------------------------------------------------------------------------------
81 
85  struct SQLResultValue {
86  virtual string toString() = 0;
87  virtual ~SQLResultValue() {}
88  };
89 
94  int aValue;
95 
96  string toString() {
97  return to_string(aValue);
98  }
99  };
100 
105  string aValue;
106 
107  string toString() {
108  return aValue;
109  }
110  };
111 
116 
117  struct SQLResultData {
118 
122  size_t aCurrent = 0;
123 
124  bool isFirst() {
125  return (aCurrent == 0);
126  }
127 
128  bool isLast() {
129  return (aCurrent == (count()-1));
130  }
131 
132  size_t count() {
133  return (aData.size());
134  }
135 
136  void next() {
137  aCurrent++;
138  }
139 
141  return aData.ptr(aCurrent);
142  }
143 
144  void getMetadata(DBMetadata& pMetadata) {
145  pMetadata(aMetadata);
146  }
147 
149  return aData;
150  }
151 
152  void getString(string& pNameRef,string& pResult) {
153 
154  if (aPositions.has(pNameRef)) {
155  int vPosition = aPositions.ref(pNameRef);
156  SQLResultRow* vRow = aData.ptr(aCurrent);
157  pResult = vRow->ptr(vPosition)->toString();
158  }
159 
160  } // getString
161 
162  void getString(size_t pPosition,string& pResult) {
163 
164  if (aPositions.size() > pPosition) {
165  SQLResultRow* vRow = aData.ptr(aCurrent);
166  pResult = vRow->ptr(pPosition)->toString();
167  }
168 
169  } // getString
170 
171 
172  }; // SQLResultData
173 
174 
175  SqLiteResultSet::SqLiteResultSet() : DBResultSet() {
176  aResultSet = (void*)new SQLResultData();
177  } // SqLiteResultSet constructor
178 
180  delete (SQLResultData*)aResultSet;
181  } // SqLiteResultSet destructor
182 
183 
185 
186  bool vResult = false;
187  vResult = ((SQLResultData*)aResultSet)->isLast();
188  return vResult;
189  } // SqLiteResultSet::isLast
190 
192  bool vResult = -1;
193  vResult =((SQLResultData*)aResultSet)->count();
194  return vResult;
195  } // SqLiteResultSet::size
196 
198 
199  SQLResultData* vResultData = (SQLResultData*)aResultSet;
200  vResultData->getMetadata(pMetadataRef);
201 
202  } // SqLiteResultSet::getMetadata
203 
204 
206 
207  SQLResultData* vResultData = ((SQLResultData*)aResultSet);
208 
209  int vWorked = 0;
210 
211  vResultData->table().forEach([&](SQLResultRow* vRowPtr){
212  if (pCycleRef.execute(this,vResultData->isFirst(),vResultData->isLast())) {
213  vWorked++;
214  }
215  vResultData->next();
216  });
217 
218  return vWorked;
219 
220  } // SqLiteResultSet::forEach
221 
223 
224  SQLResultData* vResultData = ((SQLResultData*)aResultSet);
225 
226  int vWorked = 0;
227 
228  vResultData->table().forEach([&](SQLResultRow* vRowPtr) {
229  if (pFunction(this,vResultData->isFirst(),vResultData->isLast())) {
230  vWorked++;
231  }
232  vResultData->next();
233  });
234 
235  return vWorked;
236 
237  } // SqLiteResultSet::forEach
238 
239  string SqLiteResultSet::getString(string& pNameRef) {
240 
241  SQLResultData* vResultData = ((SQLResultData*)aResultSet);
242  string vResult;
243  vResultData->getString(pNameRef,vResult);
244 
245  return vResult;
246 
247  } // SqLiteResultSet::getString
248 
249  string SqLiteResultSet::getString(int pPosition) {
250 
251 
252  SQLResultData* vResultData = ((SQLResultData*)aResultSet);
253  string vResult;
254  vResultData->getString(pPosition,vResult);
255 
256  return vResult;
257 
258  } // SqLiteResultSet::getString
259 
260  // ----------------------------------------------------------------------------------------
261 
263  aStatement = nullptr;
264  } // SqLiteStatement constructor
265 
267  if (aStatement) {
268  sqlite3_finalize((sqlite3_stmt*)aStatement);
269  }
270  } // SqLiteStatement destructor
271 
272  bool SqLiteStatement::createIt(void* pConnectionPtr,string& pQueryRef) {
273 
274  bool vResult = false;
275  int vSize = (int)pQueryRef.size()+1;
276 
277  try {
278  RAII_mutex((sqlite3*)pConnectionPtr);
279  int vResCode = sqlite3_prepare_v2(
280  (sqlite3*)pConnectionPtr,
281  pQueryRef.c_str(),
282  vSize,
283  (sqlite3_stmt**)&aStatement,
284  nullptr
285  );
286  if (SQLITE_OK != vResCode) {
287  setLastError(sqlite3_errmsg((sqlite3*)pConnectionPtr));
288  aStatement = nullptr;
289  }
290  else {
291  vResult = true;
292  }
293  // implicit RAII_mutex release (going out of scope)
294  }
295  catch (exception &vExc) {
296  string vMessage;
297  setLastError(SqLiteWhatMethod(vMessage,&vExc));
298  aStatement = nullptr;
299  }
300  return vResult;
301 
302  } // SqLiteStatement::createIt
303 
304  // The index 0 is not used ... we put the first DBT_Null to fill the gap ...
305  //
307 
308 
309  void feedMetadata(sqlite3_stmt* pStatement, SQLResultData* pResultData) {
310 
311  int vColumns = sqlite3_column_count(pStatement);
312 
313  for (int vIdx=0;vIdx<vColumns;vIdx++) {
314 
315  DBMetadataField* vMetadataField = new DBMetadataField();
316  vMetadataField->aColumnName = string(sqlite3_column_name(pStatement,vIdx));
317  int vSqliteType = sqlite3_column_type(pStatement,vIdx);
318  vMetadataField->aColumnType = DBT_SQL2BW[vSqliteType];
319 
320  pResultData->aMetadata.push(vMetadataField);
321  pResultData->aPositions.put(vMetadataField->aColumnName,vIdx);
322  }
323 
324  } // feedMetadata
325 
326  void feedData(sqlite3_stmt* pStatement, SQLResultData* pResultData) {
327 
328  SQLResultRow* vRow = new SQLResultRow();
329 
330  int vIdx = 0;
331 
332  pResultData->aMetadata.forEach([&](DBMetadataField* vFieldPtr){
333 
334  SQLResultValue* vValue;
335 
337  switch (vFieldPtr->aColumnType) {
338  case DBT_String:
339  const unsigned char* vValueStr;
340  vValue = new SQLResultValue_String();
341  vValueStr = sqlite3_column_text(pStatement,vIdx);
342  ((SQLResultValue_String*)vValue)->aValue = string((char*)vValueStr);
343  break;
344  case DBT_Number:
345  vValue = new SQLResultValue_Int();
346  ((SQLResultValue_Int*)vValue)->aValue = sqlite3_column_int(pStatement,vIdx);
347  break;
348  }
349 
350  vRow->push(vValue);
351 
352  vIdx++;
353 
354  });
355 
356  pResultData->aData.push(vRow);
357 
358  } // feedData
359 
360 
361  DBResultSet* SqLiteStatement::executeQueryPtr() {
362 
363  SqLiteResultSet* vResultSet = new SqLiteResultSet();
364  SQLResultData* vResultData = ((SQLResultData*)vResultSet->aResultSet);
365 
366  sqlite3_stmt* vStatement = (sqlite3_stmt*)aStatement;
367  bool vFirstLine = true;
368 
369  while (sqlite3_step(vStatement) == SQLITE_ROW) {
370 
371  if (vFirstLine) {
372  vFirstLine = false;
373  feedMetadata(vStatement,vResultData);
374  }
375  feedData(vStatement,vResultData);
376  }
377 
378  return vResultSet;
379 
380  } // SqLiteStatement::executeQuery
381 
382  void feedParameters(sqlite3_stmt* pStatement, DBParameters& pParametersRef) {
383 
384  int vIndex = 1;
385 
386  for (DBParameter vParameter : pParametersRef) {
387 
389  switch (vParameter.first) {
390  case DBT_String:
391  sqlite3_bind_text(pStatement,vIndex,vParameter.second.c_str(),(int)vParameter.second.size(),0);
392  break;
393  case DBT_Number:
394  int vValue;
395  vValue = stoi(vParameter.second);
396  sqlite3_bind_int(pStatement,vIndex,vValue);
397  break;
398  }
399  vIndex++;
400  }
401 
402  } // feedParameters
403 
404  DBResultSet* SqLiteStatement::executeQueryPtr(DBParameters& pParametersRef) {
405 
406  SqLiteResultSet* vResultSet = new SqLiteResultSet();
407  SQLResultData* vResultData = ((SQLResultData*)vResultSet->aResultSet);
408 
409  sqlite3_stmt* vStatement = (sqlite3_stmt*)aStatement;
410  bool vFirstLine = true;
411 
412  feedParameters(vStatement,pParametersRef);
413 
414  while (sqlite3_step(vStatement) == SQLITE_ROW) {
415  if (vFirstLine) {
416  vFirstLine = false;
417  feedMetadata(vStatement,vResultData);
418  }
419  feedData(vStatement,vResultData);
420  }
421  sqlite3_reset(vStatement);
422 
423  return vResultSet;
424 
425  } // SqLiteStatement::executeQueryPtr
426 
427  // ----------------------------------------------------------------------------------------
428 
429  SqLiteEnvironment::SqLiteEnvironment() : DBEnvironment() {
430  aOpened = false;
431  aConnection = nullptr;
432  } // SqLiteEnvironment constructor
433 
435 
436  try {
437  sqlite3_close((sqlite3*)aConnection);
438  } catch (exception &vExc) {
439  string vMessage;
440  setLastError(SqLiteWhatMethod(vMessage,&vExc));
441  }
442 
443  } // SqLiteEnvironment destructor
444 
445  ErrorCode SqLiteEnvironment::connect(string& pConnectionStringRef,string& pUserRef,string& pPasswordRef) {
446 
448 
449  int vSQLResult = -1;
450  int vFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX; // serialized "full threading" mode
451 
452  try {
453  if (aOpened) {
454  sqlite3_close((sqlite3*)aConnection);
455  aOpened = false;
456  }
457  vSQLResult = sqlite3_open_v2(pConnectionStringRef.c_str(), (sqlite3**)&aConnection,vFlags,nullptr);
458  RAII_mutex((sqlite3*)aConnection);
459  if (SQLITE_OK != vSQLResult) {
460  setLastError(sqlite3_errmsg((sqlite3*)aConnection));
461  }
462  else {
463  aOpened = true;
464  vResult = EC::OK;
465  }
466  // RAII mutex going out of context and releasing internal mutex
467  } catch (exception& vExc) {
468  string vMessage;
469  setLastError(SqLiteWhatMethod(vMessage,&vExc));
470  }
471 
472  return vResult;
473 
474  } // SqLiteEnvironment::connect
475 
476  ErrorCode SqLiteEnvironment::setSchema(string& pNewSchemaRef) {
477  return EC::OK;
478  } // SqLiteEnvironment::setSchema
479 
481 
482  SqLiteStatement* vResult = nullptr;
483 
484  try {
485  vResult = new SqLiteStatement();
486 
487  if (!vResult->createIt(aConnection,pQueryRef)) {
488  setLastError(vResult->lastErrorRef());
489  delete vResult;
490  vResult = nullptr;
491  }
492 
493  } catch (exception &vExc) {
494  string vMessage;
495  setLastError(SqLiteWhatMethod(vMessage,&vExc));
496  }
497 
498  return vResult;
499 
500  } // SqLiteEnvironment::getStatement
501 
502  // ----------------------------------------------------------------------------------------
503 
507 #define SQLITE_HEAP_SIZE 102400
508 
520  class SQLiteHeap {
521  void* aHeap;
522  public:
523 
525 
527  aHeap = malloc(SQLITE_HEAP_SIZE);
528 
529  // No guarantee that the heap es 100% clean. No surprises.
530  //
531  memset(aHeap,1,SQLITE_HEAP_SIZE);
532  // 8 byte - 64 bit architecture
533  //
534  sqlite3_config(SQLITE_CONFIG_HEAP, aHeap, SQLITE_HEAP_SIZE, 8);
535  }
537  // As this is "security oriented", it is important to clear the
538  // used heap before returning it to the Operating System.
539  //
540  memset(aHeap,1,SQLITE_HEAP_SIZE);
541  free(aHeap);
542  }
543  };
544 
548  SQLiteHeap SQLiteHeap::aSQLHeap; // can't be a pointer -- to be managed by the destructor accordingly
549 
550 } // HSEPDataSqLite namespace
551 
558 } // createEnvironment
559 
564 extern "C" void driverInfo(string& pInfo) {
565  pInfo = string("SqLite BW driver 1.0");
566 } // driverInfo