Version: 1.0.0
sqlite_database.cpp
Go to the documentation of this file.
1 #include "wx/database/wxprec.h"
2 
3 #if wxUSE_DATABASE_SQLITE
4 
5 #include <wx/tokenzr.h>
6 #include <wx/filename.h>
7 
8 // ctor()
10  : wxDatabase()
11 {
12  m_pDatabase = NULL; //&m_Database; //new sqlite3;
13  wxCSConv conv(_("UTF-8"));
14  SetEncoding(&conv);
15 }
16 
17 wxSqliteDatabase::wxSqliteDatabase(const wxString& strDatabase, bool mustExist /*= false*/)
18  : wxDatabase()
19 {
20  m_pDatabase = NULL; //new sqlite3;
21  wxCSConv conv(_("UTF-8"));
22  SetEncoding(&conv);
23  Open(strDatabase, mustExist);
24 }
25 
26 // dtor()
28 {
29  //wxPrintf(_("~wxSqliteDatabase()\n"));
30  Close();
31  //wxDELETE(m_pDatabase);
32 }
33 
34 // open database
35 bool wxSqliteDatabase::Open(const wxString& strDatabase, bool mustExist)
36 {
37  if (strDatabase!= _(":memory:") && // :memory: is a special SQLite in-memory database
38  mustExist && !(wxFileName::FileExists(strDatabase)))
39  {
41  SetErrorMessage(_("The specified database file '") + strDatabase + _("' does not exist."));
43  return false;
44  }
45  return Open(strDatabase);
46 }
47 
48 bool wxSqliteDatabase::Open(const wxString& strDatabase)
49 {
51 
52  //if (m_pDatabase == NULL)
53  // m_pDatabase = new sqlite3;
54 
55  wxCharBuffer databaseNameBuffer = ConvertToUnicodeStream(strDatabase);
56  sqlite3* pDbPtr = (sqlite3*)m_pDatabase;
57  int nReturn = sqlite3_open(databaseNameBuffer, &pDbPtr);
58  m_pDatabase = pDbPtr;
59  if (nReturn != SQLITE_OK)
60  {
62  SetErrorMessage(ConvertFromUnicodeStream(sqlite3_errmsg((sqlite3*)m_pDatabase)));
64  return false;
65  }
66  return true;
67 }
68 
69 // close database
71 {
73 
76 
77  if (m_pDatabase != NULL)
78  {
79  int nReturn = sqlite3_close((sqlite3*)m_pDatabase);
80  if (nReturn != SQLITE_OK)
81  {
83  SetErrorMessage(ConvertFromUnicodeStream(sqlite3_errmsg((sqlite3*)m_pDatabase)));
85  return false;
86  }
87  m_pDatabase = NULL;
88  }
89 
90  return true;
91 }
92 
94 {
95  return (m_pDatabase != NULL);
96 }
97 
99 {
100  wxLogDebug(_("Beginning transaction"));
101  RunQuery(_("begin transaction;"), false);
102 }
103 
105 {
106  wxLogDebug(_("Commiting transaction"));
107  RunQuery(_("commit transaction;"), false);
108 }
109 
111 {
112  wxLogDebug(_("Rolling back transaction"));
113  RunQuery(_("rollback transaction;"), false);
114 }
115 
116 // query database
117 int wxSqliteDatabase::RunQuery(const wxString& strQuery, bool bParseQuery)
118 {
119  ResetErrorCodes();
120 
121  if (m_pDatabase == NULL)
122  return false;
123 
124  wxArrayString QueryArray;
125  if (bParseQuery)
126  QueryArray = ParseQueries(strQuery);
127  else
128  QueryArray.push_back(strQuery);
129 
130  wxArrayString::iterator start = QueryArray.begin();
131  wxArrayString::iterator stop = QueryArray.end();
132 
133  while (start != stop)
134  {
135  char* szErrorMessage = NULL;
136  wxString strErrorMessage = wxT("");
137  wxCharBuffer sqlBuffer = ConvertToUnicodeStream(*start);
138  int nReturn = sqlite3_exec((sqlite3*)m_pDatabase, sqlBuffer, 0, 0, &szErrorMessage);
139 
140  if (szErrorMessage != NULL)
141  {
142  strErrorMessage = ConvertFromUnicodeStream(szErrorMessage);
143  sqlite3_free(szErrorMessage);
144  }
145 
146  if (nReturn != SQLITE_OK)
147  {
149  SetErrorMessage(strErrorMessage);
152  }
153 
154  start++;
155  }
156  return (sqlite3_changes((sqlite3*)m_pDatabase));
157 }
158 
160 {
161  ResetErrorCodes();
162 
163  if (m_pDatabase != NULL)
164  {
165  wxArrayString QueryArray = ParseQueries(strQuery);
166 
167  for (unsigned int i=0; i<(QueryArray.size()-1); i++)
168  {
169  char* szErrorMessage = NULL;
170  wxString strErrorMessage = wxT("");
171  wxCharBuffer sqlBuffer = ConvertToUnicodeStream(QueryArray[i]);
172  int nReturn = sqlite3_exec((sqlite3*)m_pDatabase, sqlBuffer, 0, 0, &szErrorMessage);
173 
174  if (szErrorMessage != NULL)
175  {
177  strErrorMessage = ConvertFromUnicodeStream(szErrorMessage);
178  sqlite3_free(szErrorMessage);
179  return NULL;
180  }
181 
182  if (nReturn != SQLITE_OK)
183  {
185  SetErrorMessage(strErrorMessage);
187  return NULL;
188  }
189  }
190 
191  // Create a Prepared statement for the last SQL statement and get a result set from it
192  wxSqlitePreparedStatement* pStatement = (wxSqlitePreparedStatement*)PrepareStatement(QueryArray[QueryArray.size()-1], false);
193  wxSqliteResultSet* pResultSet = new wxSqliteResultSet(pStatement, true);
194  if (pResultSet)
195  pResultSet->SetEncoding(GetEncoding());
196 
197  LogResultSetForCleanup(pResultSet);
198  return pResultSet;
199  }
200  else
201  {
202  return NULL;
203  }
204 }
205 
207 {
208  return PrepareStatement(strQuery, true);
209 }
210 
211 wxPreparedStatement* wxSqliteDatabase::PrepareStatement(const wxString& strQuery, bool bLogForCleanup)
212 {
213  ResetErrorCodes();
214 
215  if (m_pDatabase != NULL)
216  {
217  wxSqlitePreparedStatement* pReturnStatement = new wxSqlitePreparedStatement((sqlite3*)m_pDatabase);
218  if (pReturnStatement)
219  pReturnStatement->SetEncoding(GetEncoding());
220 
221  wxArrayString QueryArray = ParseQueries(strQuery);
222 
223  wxArrayString::iterator start = QueryArray.begin();
224  wxArrayString::iterator stop = QueryArray.end();
225 
226  while (start != stop)
227  {
228  const char* szTail=0;
229  wxCharBuffer sqlBuffer;
230  do
231  {
232  sqlite3_stmt* pStatement;
233  wxString strSQL;
234  if (szTail != 0)
235  {
236  strSQL = (wxChar*)szTail;
237  }
238  else
239  {
240  strSQL = (*start);
241  }
242  sqlBuffer = ConvertToUnicodeStream(strSQL);
243 #if SQLITE_VERSION_NUMBER>=3003009
244  int nReturn = sqlite3_prepare_v2((sqlite3*)m_pDatabase, sqlBuffer, -1, &pStatement, &szTail);
245 #else
246  int nReturn = sqlite3_prepare((sqlite3*)m_pDatabase, sqlBuffer, -1, &pStatement, &szTail);
247 #endif
248 
249  if (nReturn != SQLITE_OK)
250  {
252  SetErrorMessage(ConvertFromUnicodeStream(sqlite3_errmsg((sqlite3*)m_pDatabase)));
253  wxDELETE(pReturnStatement);
255  return NULL;
256  }
257  pReturnStatement->AddPreparedStatement(pStatement);
258 
259 #if wxUSE_UNICODE
260  } while (strlen(szTail) > 0);
261 #else
262  } while (wxStrlen(szTail) > 0);
263 #endif
264 
265  start++;
266  }
267 
268  if (bLogForCleanup)
269  LogStatementForCleanup(pReturnStatement);
270  return pReturnStatement;
271  }
272  else
273  {
274  return NULL;
275  }
276 }
277 
278 bool wxSqliteDatabase::TableExists(const wxString& table)
279 {
280  // Initialize variables
281  bool bReturn = false;
282  // Keep these variables outside of scope so that we can clean them up
283  // in case of an error
284  wxPreparedStatement* pStatement = NULL;
285  wxDatabaseResultSet* pResult = NULL;
286 
287 #if wxUSE_DATABASE_EXCEPTIONS
288  try
289  {
290 #endif
291  wxString query = _("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=?;");
292  pStatement = PrepareStatement(query);
293  if (pStatement)
294  {
295  pStatement->SetParamString(1, table);
296  pResult = pStatement->ExecuteQuery();
297  if (pResult)
298  {
299  if (pResult->Next())
300  {
301  if(pResult->GetResultInt(1) != 0)
302  {
303  bReturn = true;
304  }
305  }
306  }
307  }
308 #if wxUSE_DATABASE_EXCEPTIONS
309  }
310  catch (wxDatabaseException& e)
311  {
312  if (pResult != NULL)
313  {
314  CloseResultSet(pResult);
315  pResult = NULL;
316  }
317 
318  if (pStatement != NULL)
319  {
320  CloseStatement(pStatement);
321  pStatement = NULL;
322  }
323 
324  throw e;
325  }
326 #endif
327 
328  if (pResult != NULL)
329  {
330  CloseResultSet(pResult);
331  pResult = NULL;
332  }
333 
334  if (pStatement != NULL)
335  {
336  CloseStatement(pStatement);
337  pStatement = NULL;
338  }
339 
340  return bReturn;
341 }
342 
343 bool wxSqliteDatabase::ViewExists(const wxString& view)
344 {
345  // Initialize variables
346  bool bReturn = false;
347  // Keep these variables outside of scope so that we can clean them up
348  // in case of an error
349  wxPreparedStatement* pStatement = NULL;
350  wxDatabaseResultSet* pResult = NULL;
351 
352 #if wxUSE_DATABASE_EXCEPTIONS
353  try
354  {
355 #endif
356  wxString query = _("SELECT COUNT(*) FROM sqlite_master WHERE type='view' AND name=?;");
357  pStatement = PrepareStatement(query);
358  if (pStatement)
359  {
360  pStatement->SetParamString(1, view);
361  pResult = pStatement->ExecuteQuery();
362  if (pResult)
363  {
364  if (pResult->Next())
365  {
366  if(pResult->GetResultInt(1) != 0)
367  {
368  bReturn = true;
369  }
370  }
371  }
372  }
373 #if wxUSE_DATABASE_EXCEPTIONS
374  }
375  catch (wxDatabaseException& e)
376  {
377  if (pResult != NULL)
378  {
379  CloseResultSet(pResult);
380  pResult = NULL;
381  }
382 
383  if (pStatement != NULL)
384  {
385  CloseStatement(pStatement);
386  pStatement = NULL;
387  }
388 
389  throw e;
390  }
391 #endif
392 
393  if (pResult != NULL)
394  {
395  CloseResultSet(pResult);
396  pResult = NULL;
397  }
398 
399  if (pStatement != NULL)
400  {
401  CloseStatement(pStatement);
402  pStatement = NULL;
403  }
404 
405  return bReturn;
406 }
407 
408 wxArrayString wxSqliteDatabase::GetTables()
409 {
410  wxArrayString returnArray;
411 
412  wxDatabaseResultSet* pResult = NULL;
413 #if wxUSE_DATABASE_EXCEPTIONS
414  try
415  {
416 #endif
417  wxString query = _("SELECT name FROM sqlite_master WHERE type='table';");
418  pResult = ExecuteQuery(query);
419 
420  while (pResult->Next())
421  {
422  returnArray.Add(pResult->GetResultString(1));
423  }
424 #if wxUSE_DATABASE_EXCEPTIONS
425  }
426  catch (wxDatabaseException& e)
427  {
428  if (pResult != NULL)
429  {
430  CloseResultSet(pResult);
431  pResult = NULL;
432  }
433 
434  throw e;
435  }
436 #endif
437 
438  if (pResult != NULL)
439  {
440  CloseResultSet(pResult);
441  pResult = NULL;
442  }
443 
444  return returnArray;
445 }
446 
447 wxArrayString wxSqliteDatabase::GetViews()
448 {
449  wxArrayString returnArray;
450 
451  wxDatabaseResultSet* pResult = NULL;
452 #if wxUSE_DATABASE_EXCEPTIONS
453  try
454  {
455 #endif
456  wxString query = _("SELECT name FROM sqlite_master WHERE type='view';");
457  pResult = ExecuteQuery(query);
458 
459  while (pResult->Next())
460  {
461  returnArray.Add(pResult->GetResultString(1));
462  }
463 #if wxUSE_DATABASE_EXCEPTIONS
464  }
465  catch (wxDatabaseException& e)
466  {
467  if (pResult != NULL)
468  {
469  CloseResultSet(pResult);
470  pResult = NULL;
471  }
472 
473  throw e;
474  }
475 #endif
476 
477  if (pResult != NULL)
478  {
479  CloseResultSet(pResult);
480  pResult = NULL;
481  }
482 
483  return returnArray;
484 }
485 
486 wxArrayString wxSqliteDatabase::GetColumns(const wxString& table)
487 {
488  wxArrayString returnArray;
489 
490  // Keep these variables outside of scope so that we can clean them up
491  // in case of an error
492  wxDatabaseResultSet* pResult = NULL;
493  wxResultSetMetaData* pMetaData = NULL;
494 
495 #if wxUSE_DATABASE_EXCEPTIONS
496  try
497  {
498 #endif
499  wxCharBuffer tableNameBuffer = ConvertToUnicodeStream(table);
500  wxString query = wxString::Format(_("SELECT * FROM '%s' LIMIT 0;"), table.c_str());
501  pResult = ExecuteQuery(query);
502  pResult->Next();
503  pMetaData = pResult->GetMetaData();
504 
505  // 1-based
506  for(int i=1; i<=pMetaData->GetColumnCount(); i++)
507  {
508  returnArray.Add(pMetaData->GetColumnName(i));
509  }
510 
511 #if wxUSE_DATABASE_EXCEPTIONS
512  }
513  catch (wxDatabaseException& e)
514  {
515  if (pMetaData != NULL)
516  {
517  pResult->CloseMetaData(pMetaData);
518  pMetaData = NULL;
519  }
520 
521  if (pResult != NULL)
522  {
523  CloseResultSet(pResult);
524  pResult = NULL;
525  }
526 
527  throw e;
528  }
529 #endif
530 
531  if (pMetaData != NULL)
532  {
533  pResult->CloseMetaData(pMetaData);
534  pMetaData = NULL;
535  }
536 
537  if (pResult != NULL)
538  {
539  CloseResultSet(pResult);
540  pResult = NULL;
541  }
542 
543  return returnArray;
544 }
545 
546 
547 wxArrayString wxSqliteDatabase::GetPKColumns(const wxString& table)
548 {
549  wxArrayString returnArray;
550 
551  // Keep these variables outside of scope so that we can clean them up
552  // in case of an error
553  wxDatabaseResultSet* pResult = NULL;
554  wxResultSetMetaData* pMetaData = NULL;
555 
556 #if wxUSE_DATABASE_EXCEPTIONS
557  try
558  {
559 #endif
560  wxCharBuffer tableNameBuffer = ConvertToUnicodeStream(table);
561  wxString query = wxString::Format(_("PRAGMA table_info('%s') ;"), table.c_str());
562  pResult = ExecuteQuery(query);
563  while(pResult->Next())
564  {
565  if(pResult->GetResultInt(wxT("pk"))==1)//its primary key
566  {
567  returnArray.Add(pResult->GetResultString(wxT("pk")));
568  }
569  }
570 
571 #if wxUSE_DATABASE_EXCEPTIONS
572  }
573  catch (wxDatabaseException& e)
574  {
575  if (pMetaData != NULL)
576  {
577  pResult->CloseMetaData(pMetaData);
578  pMetaData = NULL;
579  }
580 
581  if (pResult != NULL)
582  {
583  CloseResultSet(pResult);
584  pResult = NULL;
585  }
586 
587  throw e;
588  }
589 #endif
590 
591  if (pMetaData != NULL)
592  {
593  pResult->CloseMetaData(pMetaData);
594  pMetaData = NULL;
595  }
596 
597  if (pResult != NULL)
598  {
599  CloseResultSet(pResult);
600  pResult = NULL;
601  }
602 
603  return returnArray;
604 }
605 
606 
608 {
609  // Ultimately, this will probably be a map of SQLite database error code values to wxDatabase values
610  // For now though, we'll just return error
611  int nReturn = nCode;
612  /*
613  switch (nCode)
614  {
615  case SQLITE_ERROR:
616  nReturn = wxDATABASE_SQL_SYNTAX_ERROR;
617  break;
618  case SQLITE_INTERNAL:
619  nReturn = wxDATABASE_ERROR;
620  break;
621  case SQLITE_PERM:
622  nReturn = wxDATABASE_ERROR;
623  break;
624  case SQLITE_ABORT:
625  nReturn = wxDATABASE_ERROR;
626  break;
627  case SQLITE_BUSY:
628  nReturn = wxDATABASE_ERROR;
629  break;
630  case SQLITE_LOCKED:
631  nReturn = wxDATABASE_ERROR;
632  break;
633  case SQLITE_NOMEM:
634  nReturn = wxDATABASE_ALLOCATION_ERROR;
635  break;
636  case SQLITE_READONLY:
637  nReturn = wxDATABASE_ERROR;
638  break;
639  case SQLITE_INTERRUPT:
640  nReturn = wxDATABASE_ERROR;
641  break;
642  case SQLITE_IOERR:
643  nReturn = wxDATABASE_ERROR;
644  break;
645  case SQLITE_CORRUPT:
646  nReturn = wxDATABASE_ERROR;
647  break;
648  case SQLITE_NOTFOUND:
649  nReturn = wxDATABASE_ERROR;
650  break;
651  case SQLITE_FULL:
652  nReturn = wxDATABASE_ERROR;
653  break;
654  case SQLITE_CANTOPEN:
655  nReturn = wxDATABASE_ERROR;
656  break;
657  case SQLITE_PROTOCOL:
658  nReturn = wxDATABASE_ERROR;
659  break;
660  case SQLITE_SCHEMA:
661  nReturn = wxDATABASE_ERROR;
662  break;
663  case SQLITE_TOOBIG:
664  nReturn = wxDATABASE_ERROR;
665  break;
666  case SQLITE_CONSTRAINT:
667  nReturn = wxDATABASE_CONSTRAINT_VIOLATION;
668  break;
669  case SQLITE_MISMATCH:
670  nReturn = wxDATABASE_INCOMPATIBLE_FIELD_TYPE;
671  break;
672  case SQLITE_MISUSE:
673  nReturn = wxDATABASE_ERROR;
674  break;
675  case SQLITE_NOLFS:
676  nReturn = wxDATABASE_ERROR;
677  break;
678  case SQLITE_AUTH:
679  nReturn = wxDATABASE_ERROR;
680  break;
681  default:
682  nReturn = wxDATABASE_ERROR;
683  break;
684  }
685  */
686  return nReturn;
687 }
688 
689 #endif//wxUSE_DATABASE_SQLITE
virtual wxArrayString GetColumns(const wxString &table)
Retrieve all column names for a table.
virtual bool TableExists(const wxString &table)
Check for the existence of a table by name.
virtual void RollBack()
Rollback the current transaction.
virtual ~wxSqliteDatabase()
virtual wxString GetResultString(int nField)=0
Retrieve a wxString from the result set by the 1-based field index.
wxDatabaseResultSet * ExecuteQuery(const wxString &strQuery)
See RunQueryWithResults.
Definition: database.h:64
virtual int GetColumnCount()=0
Retrieve the number of columns in the result set.
virtual wxPreparedStatement * PrepareStatement(const wxString &strQuery)
Prepare a SQL statement which can be reused with different parameters.
virtual void Commit()
Commit the current transaction.
virtual wxArrayString GetPKColumns(const wxString &table)
get Primary keys column names
virtual bool Close()
close database
virtual bool IsOpen()
Is the connection to the database open?
virtual int GetResultInt(int nField)=0
Retrieve an integer from the result set by the 1-based field index.
virtual bool CloseStatement(wxPreparedStatement *pStatement)
Close a prepared statement previously prepared by the database.
Definition: database.cpp:95
virtual wxDatabaseResultSet * RunQueryWithResults(const wxString &strQuery)
Run a select query on the database.
#define wxDATABASE_ERROR
Definition: errorcodes.h:5
void SetErrorMessage(const wxString &strErrorMessage)
wxDatabaseResultSet * ExecuteQuery()
See RunQueryWithResults.
virtual bool Next()=0
Move to the next record in the result set.
wxArrayString ParseQueries(const wxString &strQuery)
void LogStatementForCleanup(wxPreparedStatement *pStatement)
Add prepared statement object pointer to the list for "garbage collection".
Definition: database.h:183
void SetEncoding(wxFontEncoding encoding)
void LogResultSetForCleanup(wxDatabaseResultSet *pResultSet)
Add result set object pointer to the list for "garbage collection".
Definition: database.h:181
#define wxDATABASE_QUERY_RESULT_ERROR
Definition: errorcodes.h:21
virtual bool Open(const wxString &strDatabase)
virtual int RunQuery(const wxString &strQuery, bool bParseQuery)
Run an insert, update, or delete query on the database.
virtual void BeginTransaction()
Begin a transaction.
virtual wxArrayString GetTables()
Retrieve all table names.
void SetErrorCode(int nErrorCode)
static int TranslateErrorCode(int nCode)
void CloseStatements()
Close all prepared statement objects that have been generated but not yet closed.
Definition: database.cpp:38
void AddPreparedStatement(sqlite3_stmt *pStatement)
virtual wxString ConvertFromUnicodeStream(const char *inputBuffer)
const wxCSConv * GetEncoding()
virtual bool ViewExists(const wxString &view)
Check for the existence of a view by name.
virtual const wxCharBuffer ConvertToUnicodeStream(const wxString &inputString)
virtual wxString GetColumnName(int i)=0
Retrieve a column's name.
void CloseResultSets()
Close all result set objects that have been generated but not yet closed.
Definition: database.cpp:24
virtual bool CloseResultSet(wxDatabaseResultSet *pResultSet)
Close a result set returned by the database or a prepared statement previously.
Definition: database.cpp:52
virtual void SetParamString(int nPosition, const wxString &strValue)=0
Set the parameter at the 1-based position to a wxString value.
virtual wxArrayString GetViews()
Retrieve all view names.