Version: 1.0.0
dbconf.cpp
Go to the documentation of this file.
1 #include "wx/base/wxprec.h"
2 
3 #if wxUSE_DATABASE_CONFIG
4 
5 #include <wx/filename.h>
6 #include <wx/sstream.h>
7 #include <wx/stdpaths.h>
8 
9 #include <wx/log.h>
10 #include <wx/intl.h>
11 #include <wx/utils.h>
12 
13 #define viewname_default "dbconf"
14 
15 #define viewname (m_viewName)
16 #define tablename_path (m_viewName+"path")
17 #define tablename_entry (m_viewName+"entry")
18 
19 #define triggername_insertviewpath ("insert_"+m_viewName)
20 #define triggername_updateviewpath ("update_"+m_viewName)
21 #define triggername_deleteviewpath ("delete_"+m_viewName)
22 
23 wxIMPLEMENT_ABSTRACT_CLASS(wxDatabaseConfig, wxConfigBase);
24 
26 (
27  const wxString& appName,
28  const wxString& vendorName,
29  const wxString& viewName,
30  const wxString& settingsConf,
31  long WXUNUSED(style),
32  const wxMBConv& WXUNUSED(conv)
33  )
34  : wxConfigBase(appName, vendorName),
35  m_viewName(viewName),
36  m_pDatabase(NULL),
37  m_self(wx_const_cast(wxDatabaseConfig*, this))
38 {
39  wxStringInputStream inStream(settingsConf);
40  wxString err;
41  if (!LoadStream(inStream, &err))
42  {
43  wxLogWarning(wxString::Format("%s in configuration settings '%s'", err, settingsConf));
44  }
45 }
46 
47 #ifdef wxUSE_STREAMS
49 (
50  wxInputStream& inStream,
51  const wxString& viewName,
52  const wxMBConv& WXUNUSED(conv)
53  )
54  : wxConfigBase(),
55  m_viewName(viewName),
56  m_pDatabase(NULL),
57  m_self(wx_const_cast(wxDatabaseConfig*, this))
58 {
59  wxString warning(" configuration stream");
60  wxString err;
61  if (!LoadStream(inStream, &err))
62  {
63  wxLogWarning(wxString::Format("%s in configuration stream", err));
64  }
65 }
66 #endif
67 
69 {
70  Flush();
71  CleanUp();
72 }
73 
74 void wxDatabaseConfig::SetRootPath(dbentry& entry)
75 {
76  entry.id = 0;
77  entry.name = "";
78  entry.value = "";
79  entry.path = "";
80  entry.isgroup = true;
81 }
82 
83 void wxDatabaseConfig::SetPath(const wxString& strPath)
84 {
85  if (strPath.empty() || strPath.IsSameAs(wxCONFIG_PATH_SEPARATOR))
86  {
88  return;
89  }
90 
91  dbentries entries;
92  wxString path = strPath;
93 
94  // let's be optimistic, most calls should be to existing paths!
95  if (!FindEntries(path, entries))
96  {
97  if (path[0] != wxCONFIG_PATH_SEPARATOR)
98  {
99  path = m_entry.path + wxCONFIG_PATH_SEPARATOR + path;
100  }
101  wxArrayString paths(wxSplit(path, wxCONFIG_PATH_SEPARATOR));
102  path.Empty();
103  for (size_t n = 0; n < paths.Count(); n++)
104  {
105  if (paths[n].IsSameAs(wxEmptyString)) continue;
106  path += wxCONFIG_PATH_SEPARATOR+paths[n];
107  if (!FindEntries(path, entries))
108  {
109  if (!AddEntry(m_entry, paths[n])) return;
110  if (!FindEntries(path, entries)) return;
111  }
112  m_entry = entries[0];
113  entries.clear();
114  }
115  }
116  else
117  {
118  m_entry = entries[0];
119  }
120 }
121 
122 bool wxDatabaseConfig::GetFirstGroup(wxString& str, long& lIndex) const
123 {
124  m_self->m_groups.clear();
126  lIndex = 0;
127  return m_groups.size() == 0 ? false : GetNextGroup(str, lIndex);
128 }
129 
130 bool wxDatabaseConfig::GetNextGroup(wxString& str, long& lIndex) const
131 {
132  if ((long)m_groups.size() <= lIndex) return false;
133  str = m_groups[lIndex++].name;
134  return true;
135 }
136 
137 bool wxDatabaseConfig::GetFirstEntry(wxString& str, long& lIndex) const
138 {
139  m_self->m_entries.clear();
141  lIndex = 0;
142  return m_entries.size() == 0 ? false : GetNextEntry(str, lIndex);
143 }
144 
145 bool wxDatabaseConfig::GetNextEntry(wxString& str, long& lIndex) const
146 {
147  if ((long)m_entries.size() <= lIndex) return false;
148  str = m_entries[lIndex++].name;
149  return true;
150 }
151 
152 void wxDatabaseConfig::GetChildren(dbentry& parent, dbentries* groups, dbentries* entries, bool recursive)
153 {
154  dbentries wild;
155  m_self->FindEntries(parent.path+wxCONFIG_PATH_SEPARATOR+'%', wild);
156 
157  for (dbentries::iterator it = wild.begin(); it != wild.end(); ++it)
158  {
159  wxString localpath(it->path.Right(it->path.Length()-parent.path.Length()-1));
160  if (!recursive && wxStrchr(localpath, wxCONFIG_PATH_SEPARATOR)) continue;
161  if (it->isgroup)
162  {
163  if (groups == NULL) continue;
164  groups->push_back(*it);
165  }
166  else
167  {
168  if (entries == NULL) continue;
169  entries->push_back(*it);
170  }
171  }
172 }
173 
174 size_t wxDatabaseConfig::GetNumberOfEntries(bool bRecursive) const
175 {
176  dbentries entries;
177  m_self->GetChildren(m_self->m_entry, NULL, &entries, bRecursive);
178  return entries.size();
179 }
180 
181 size_t wxDatabaseConfig::GetNumberOfGroups(bool bRecursive) const
182 {
183  dbentries groups;
184  m_self->GetChildren(m_self->m_entry, &groups, NULL, bRecursive);
185  return groups.size();
186 }
187 
188 bool wxDatabaseConfig::HasGroup(const wxString& strName) const
189 {
190  if (strName.empty()) return false;
191  dbentries entries;
192  if (!m_self->FindEntries(strName, entries)) return false;
193  return entries[0].isgroup;
194 }
195 
196 bool wxDatabaseConfig::HasEntry(const wxString& strName) const
197 {
198  if (strName.empty()) return false;
199  dbentries entries;
200  if (!m_self->FindEntries(strName, entries)) return false;
201  return !entries[0].isgroup;
202 }
203 
204 bool wxDatabaseConfig::Flush(bool WXUNUSED(bCurrentOnly))
205 {
206  // should probably enclose all changes in a db transaction and commit it here!
207  return true;
208 }
209 
210 bool wxDatabaseConfig::FindEntries(const wxString& nameORpath, dbentries& entries)
211 {
212  if (nameORpath.empty()) return false;
213  wxString path = nameORpath;
214  if (path[0] != wxCONFIG_PATH_SEPARATOR)
215  {
216  path = m_entry.path + wxCONFIG_PATH_SEPARATOR + path;
217  }
218  if (path.Contains("..") || path.Contains("."))
219  {
220  wxArrayString in(wxSplit(path, wxCONFIG_PATH_SEPARATOR));
221  wxArrayString out;
222  size_t count = in.GetCount();
223  for (size_t n = 0; n < count; n++)
224  {
225  wxString name = in[n];
226  if (name.IsSameAs(wxEmptyString)) continue;
227  if (name == ".") continue;
228  if (name == ".." && !out.empty())
229  {
230  out.pop_back();
231  continue;
232  }
233  out.Add(name);
234  }
235  path = wxCONFIG_PATH_SEPARATOR+wxJoin(out, wxCONFIG_PATH_SEPARATOR);
236  }
237  if (path.IsSameAs(wxCONFIG_PATH_SEPARATOR))
238  {
239  dbentry root;
240  SetRootPath(root);
241  entries.push_back(root);
242  }
245  return (entries.size() > 0);
246 }
247 
248 bool wxDatabaseConfig::AddEntry(dbentry& parent, const wxString& name, const wxString* value)
249 {
250  if (name.empty()) return false;
251  wxASSERT_MSG(!wxStrchr(name, wxCONFIG_PATH_SEPARATOR), wxT("AddEntry(): paths are not supported"));
252 
253  m_pStatementSqlAddEntry->SetParamInt(1, parent.id);
255  if (value == NULL)
256  {
258  }
259  else
260  {
261  wxString strValue(*value);
263  }
265  return true;
266 }
267 
268 bool wxDatabaseConfig::WriteEntry(dbentry& entry, const wxString& name, const wxString& value)
269 {
270  if (name.empty()) return false;
271  wxASSERT_MSG(!wxStrchr(name, wxCONFIG_PATH_SEPARATOR), wxT("WriteEntry(): paths are not supported"));
272 
277  return true;
278 }
279 
280 bool wxDatabaseConfig::RenameEntry(const wxString& oldName, const wxString& newName)
281 {
282  wxASSERT_MSG(!wxStrchr(oldName, wxCONFIG_PATH_SEPARATOR), wxT("RenameEntry(): paths are not supported"));
283 
284  dbentries entries;
285  if ( FindEntries(newName, entries)) return false;
286  entries.clear();
287  if (!FindEntries(oldName, entries)) return false;
288 
289  return WriteEntry(entries[0], newName, entries[0].value);
290 }
291 
292 bool wxDatabaseConfig::RenameGroup(const wxString& oldName, const wxString& newName)
293 {
294  wxASSERT_MSG(!wxStrchr(oldName, wxCONFIG_PATH_SEPARATOR), wxT("RenameGroup(): paths are not supported"));
295  return RenameEntry(oldName, newName);
296 }
297 
298 bool wxDatabaseConfig::DeleteEntry(const wxString& key, bool bGroupIfEmptyAlso)
299 {
300  wxString path = this->RemoveTrailingSeparator(key);
301  dbentries entries;
302  if (!m_self->FindEntries(path, entries)) return false;
303  dbentry entry = entries[0];
304 
305  path = this->RemoveTrailingSeparator(key)+wxCONFIG_PATH_SEPARATOR+"..";
306  entries.clear();
307  if (!m_self->FindEntries(path, entries)) return false;
308  dbentry parent = entries[0];
309 
310  m_pStatementSqlDelEntry->SetParamInt(1, entry.id);
312 
313  if (!m_entry.path.IsSameAs(parent.path) && m_entry.path.StartsWith(parent.path))
314  {
315  m_entry = parent;
316  }
317 
318  entries.clear();
319  m_self->GetChildren(parent, NULL, &entries);
320 
321  if (bGroupIfEmptyAlso && entries.size() == 0)
322  {
323  m_pStatementSqlDelEntry->SetParamInt(1, parent.id);
325  }
326  return true;
327 }
328 
329 bool wxDatabaseConfig::DeleteGroup(const wxString& key)
330 {
331  wxString path = this->RemoveTrailingSeparator(key);
332  dbentries entries;
333  if (!m_self->FindEntries(path, entries)) return false;
334  dbentry group = entries[0];
335 
336  path = this->RemoveTrailingSeparator(key)+wxCONFIG_PATH_SEPARATOR+"..";
337  entries.clear();
338  if (!m_self->FindEntries(path, entries)) return false;
339  dbentry parent = entries[0];
340 
341  m_pStatementSqlDelEntry->SetParamInt(1, group.id);
343 
344  if (!m_entry.path.IsSameAs(parent.path) && m_entry.path.StartsWith(parent.path))
345  {
346  m_entry = parent;
347  }
348 
349  return true;
350 }
351 
353 {
356  return true;
357 }
358 
359 bool wxDatabaseConfig::DoReadString(const wxString& key, wxString* pStr) const
360 {
361  dbentries entries;
362  if (!m_self->FindEntries(key, entries)) return false;
363  *pStr = entries[0].value;
364  return true;
365 }
366 
367 bool wxDatabaseConfig::DoReadLong(const wxString& key, long* pl) const
368 {
369  wxString str;
370  if (!Read(key, &str)) return false;
371  str.Trim();
372  return str.ToLong(pl);
373 }
374 
375 bool wxDatabaseConfig::DoWriteString(const wxString& key, const wxString& szValue)
376 {
377  wxString name = key.AfterLast(wxCONFIG_PATH_SEPARATOR);
378  if (name.StartsWith(wxCONFIG_IMMUTABLE_PREFIX))
379  {
380  wxLogError("Immutable entries cannot be changed");
381  return false;
382  }
383 
384  dbentries entries;
385  if (!FindEntries(key, entries))
386  {
387  wxConfigPathChanger path(this, key);
388  //wxLogTrace(DBLCONF_TRACE_MASK, wxString::Format("Adding Entry '%s' = '%s' to Group '%s'", name, szValue, m_entry.path));
389  AddEntry(m_entry, name, &szValue);
390  }
391  else if (entries[0].isgroup)
392  {
393  wxLogError("Can't set value of a group!.");
394  }
395  else
396  {
397  //wxLogTrace(DBLCONF_TRACE_MASK, wxString::Format("Writing Entry '%s' = '%s' in Group '%s'", name, szValue, entries[0].path));
398  WriteEntry(entries[0], name, szValue);
399  }
400  return true;
401 }
402 
403 bool wxDatabaseConfig::DoWriteLong(const wxString& key, long lValue)
404 {
405  return Write(key, wxString::Format(_T("%ld"), lValue));
406 }
407 
408 #if wxCHECK_VERSION(2,9,0) && wxUSE_BASE64
409 bool wxDatabaseConfig::DoReadBinary(const wxString& key, wxMemoryBuffer* buf) const
410 {
411  wxCHECK_MSG(buf, false, wxT("NULL buffer"));
412 
413  wxString str;
414  if (!Read(key, &str)) return false;
415  *buf = wxBase64Decode(str);
416  return true;
417 }
418 
419 bool wxDatabaseConfig::DoWriteBinary(const wxString& key, const wxMemoryBuffer& buf)
420 {
421  return Write(key, wxBase64Encode(buf));
422 }
423 #endif
424 
426 {
431 
433 
434  wxDELETE(m_pDatabase);
435 }
436 
437 bool wxDatabaseConfig::LoadStream(wxInputStream& inStream, wxString* err)
438 {
440 
441  if (m_viewName.IsEmpty())
442  {
443  m_viewName = m_self->GetAppName();
444  if (m_viewName.IsEmpty())
445  {
446  m_viewName = viewname_default;
447  }
448  }
449  m_viewName.Replace(wxCONFIG_PATH_SEPARATOR, wxEmptyString);
450 
451  if (!inStream.CanRead())
452  {
453  if (err) err->Append("can't read");
454  return false;
455  }
456 
457  wxFileConfig config(inStream);
458 
459  /*
460  SQLite doesn't support stored procedures nor recursion.
461  The best compromise between all the flavours of databases is to store the group paths as a closure set
462  and to access the groups and entries via a view with triggers instead of accessing the underlying tables directly.
463 
464  table "tablename_entry" contains the rows for both group names and entry name/values
465  table "tablename_path" contains a closure set for the group paths
466 
467  view "viewname" (and its associated triggers) provide the interface used by this code
468  */
469 
470  wxString sqlCreateTablePath;
471  wxString sqlCreateTableEntry;
472  wxString sqlCreateViewPath;
473 
474  wxString sqlCreateTriggerInsteadOfInsertViewPath;
475  wxString sqlCreateTriggerInsteadOfUpdateViewPath;
476  wxString sqlCreateTriggerInsteadOfDeleteViewPath;
477 
478  wxString sqlAddEntry;
479  wxString sqlDelEntry;
480  wxString sqlEditEntry;
481  wxString sqlFindEntries;
482 
483  wxString sqlDropAll;
484 
485  // should work on all DBs?
486  sqlCreateTablePath <<
487  "IF NOT EXISTS (SELECT * FROM sys.views WHERE name = '" << viewname <<"') "
488  "AND NOT EXISTS (SELECT * FROM sys.objects WHERE type IN ('U') AND name = '" << tablename_path << "') EXECUTE('"
489  "CREATE TABLE " << tablename_path <<
490  "("
491  "pid INT NOT NULL,"
492  "id INT NOT NULL,"
493  "PRIMARY KEY (pid, id),"
494  "FOREIGN KEY (pid) REFERENCES " << tablename_entry << "(id),"
495  "FOREIGN KEY (id) REFERENCES " << tablename_entry << "(id)"
496  ")"
497  "')"
498  ;
499  sqlCreateTableEntry <<
500  "IF NOT EXISTS (SELECT * FROM sys.views WHERE name = '" << viewname <<"') "
501  "AND NOT EXISTS (SELECT * FROM sys.objects WHERE type IN ('U') AND name = '" << tablename_entry <<"') EXECUTE('"
502  "CREATE TABLE " << tablename_entry <<
503  "("
504  "id INT IDENTITY PRIMARY KEY,"
505  "name VARCHAR(255) NOT NULL,"
506  "value VARCHAR(255) NULL"
507  ")"
508  "')"
509  ;
510  sqlAddEntry <<
511  "INSERT INTO " << viewname <<" (id, name, value) VALUES (?, ?, ?)"
512  ;
513  sqlDelEntry <<
514  "DELETE FROM " << viewname <<" WHERE id = ?"
515  ;
516  sqlEditEntry <<
517  "UPDATE " << viewname <<" SET name = ?, value = ? WHERE id = ?"
518  ;
519  sqlFindEntries <<
520  "SELECT id, name, value, path, isgroup FROM " << viewname <<" WHERE path LIKE ?"
521  ;
522  sqlDropAll <<
523  "DROP VIEW " << viewname <<"\n"
524  "DROP TABLE " << tablename_path <<"\n"
525  "DROP TABLE " << tablename_entry <<"\n"
526  ;
527  sqlCreateTriggerInsteadOfInsertViewPath <<
528  "IF NOT EXISTS (SELECT * FROM sys.triggers WHERE name = '" << triggername_insertviewpath <<"') EXECUTE('\n"
529  "CREATE TRIGGER [" << triggername_insertviewpath <<"] ON " << viewname <<" INSTEAD OF INSERT\n"
530  "AS\n"
531  "BEGIN\n"
532  "\tINSERT INTO " << tablename_entry <<" (name, value) SELECT i.name, i.value FROM inserted i\n"
533  "\tINSERT INTO " << tablename_path <<" (pid, id)\n"
534  "\tSELECT p.pid, (SELECT MAX(id) FROM " << tablename_entry <<")\n"
535  "\tFROM\n"
536  "\t\t" << tablename_path <<" p\n"
537  "\t\tJOIN inserted i ON p.id = i.id -- treat i.id as the pid p\n"
538  "\tUNION\n"
539  "\tSELECT MAX(id), MAX(id) FROM " << tablename_entry <<"\n"
540  //"\tSELECT id, name, value FROM " << tablename_entry <<" WHERE id IN (SELECT MAX(id) FROM " << tablename_entry <<")\n"
541  "END\n"
542  "')"
543  ;
544  sqlCreateTriggerInsteadOfUpdateViewPath <<
545  "IF NOT EXISTS (SELECT * FROM sys.triggers WHERE name = '" << triggername_updateviewpath <<"') EXECUTE('\n"
546  "CREATE TRIGGER [" << triggername_updateviewpath <<"] ON " << viewname <<" INSTEAD OF UPDATE\n"
547  "AS\n"
548  "BEGIN\n"
549  "\tUPDATE " << tablename_entry <<" SET\n"
550  "\t\t" << tablename_entry <<".name = i.name,\n"
551  "\t\t" << tablename_entry <<".value = CASE WHEN " << tablename_entry <<".value IS NULL THEN NULL ELSE i.value END\n"
552  "\tFROM\n"
553  "\t\tinserted i\n"
554  "\tWHERE\n"
555  "\t\t" << tablename_entry <<".id = i.id\n"
556  //"\tSELECT e.id, e.name, e.value FROM " << tablename_entry <<" e JOIN inserted i ON i.id = e.id\n"
557  "END\n"
558  "')"
559  ;
560  sqlCreateTriggerInsteadOfDeleteViewPath <<
561  "IF NOT EXISTS (SELECT * FROM sys.triggers WHERE name = '" << triggername_deleteviewpath <<"') EXECUTE('\n"
562  "CREATE TRIGGER [" << triggername_deleteviewpath <<"] ON " << viewname <<" INSTEAD OF DELETE\n"
563  "AS\n"
564  "BEGIN\n"
565  "\tDELETE p\n"
566  "\tFROM\n"
567  "\t\t" << tablename_path <<" c\n"
568  "\t\tJOIN " << tablename_path <<" p ON p.id = c.id\n"
569  "\t\tJOIN deleted d ON c.pid = d.id -- treat d.id as the id\n"
570  "\tDELETE e\n"
571  "\tFROM\n"
572  "\t\t" << tablename_entry <<" e\n"
573  "\tWHERE\n"
574  "\t\te.id NOT IN (SELECT id FROM " << tablename_path <<")\n"
575  "END\n"
576  "')"
577  ;
578 
579  m_pDatabase = wxDatabase::GetDatabase(config, err);
580  if (m_pDatabase == NULL)
581  {
582  if (err) err->Append("cannot establish database connection from");
583  return false;
584  }
585 
586  // if necessary add the database library path to the system path
587  if (!m_pDatabase->GetLibraryPath().IsEmpty())
588  {
589  wxString path;
590  wxGetEnv("PATH", &path);
591 #ifdef WIN32
592  path.Append(";");
593 #else
594  path.Append(":");
595 #endif
596  path.Append(m_pDatabase->GetLibraryPath());
597  wxSetEnv("PATH", path);
598  }
599 
600  if (false);
601 #if wxUSE_DATABASE_SQLITE
602  else
603  if (m_pDatabase->GetTypeName().IsSameAs("SQLITE"))
604  {
605  sqlCreateViewPath <<
606  "IF NOT EXISTS (SELECT * FROM sys.views WHERE name = '" << viewname <<"') EXECUTE('"
607  "CREATE VIEW [" << viewname <<"]\n"
608  "AS\n"
609  "SELECT\n"
610  "\te.id,\n"
611  "\te.name,\n"
612  "\te.value,\n"
613  "\tCONVERT(VARCHAR(255), (\n"
614  "\t\tSELECT\n"
615  "\t\t\t''/''+dbo.GROUP_CONCAT_D(ie.name, ''/'')\n"
616  "\t\tFROM\n"
617  "\t\t\t" << tablename_path <<" ic\n"
618  "\t\t\tJOIN " << tablename_path <<" ip ON ip.id = ic.pid\n"
619  "\t\t\tJOIN " << tablename_entry <<" ie ON ie.id = ip.pid\n"
620  "\t\tWHERE\n"
621  "\t\t\tic.id = ic.pid\n"
622  "\t\t\tAND\n"
623  "\t\t\tic.id = c.id\n"
624  "\t\tGROUP BY\n"
625  "\t\t\tic.id\n"
626  "\t)) AS [path],\n"
627  "\tCASE WHEN e.value IS NULL THEN 1 ELSE 0 END AS [isgroup]\n"
628  "FROM\n"
629  "\t" << tablename_path <<" c\n"
630  "\tJOIN " << tablename_entry <<" e ON e.id = c.id\n"
631  "WHERE\n"
632  "\tc.id = c.pid\n"
633  "')"
634  ;
635  }
636 #endif
637 #if wxUSE_DATABASE_POSTGRESQL
638  else
639  if (m_pDatabase->GetTypeName().IsSameAs("POSTGRESQL"))
640  {
641  }
642 #endif
643 #if wxUSE_DATABASE_MYSQL
644  else
645  if (m_pDatabase->GetTypeName().IsSameAs("MYSQL"))
646  {
647  }
648 #endif
649 #if wxUSE_DATABASE_ODBC
650  else
651  if (m_pDatabase->GetTypeName().IsSameAs("ODBC"))
652  {
653  }
654 #endif
655 #if wxUSE_DATABASE_TDS
656  else
657  if (m_pDatabase->GetTypeName().IsSameAs("TDS"))
658  {
659  sqlCreateViewPath <<
660  "IF NOT EXISTS (SELECT * FROM sys.views WHERE name = '" << viewname <<"') EXECUTE('"
661  "CREATE VIEW [" << viewname <<"]\n"
662  "AS\n"
663  "SELECT\n"
664  "\te.id,\n"
665  "\te.name,\n"
666  "\te.value,\n"
667  "\tCONVERT(VARCHAR(255), (\n"
668  "\t\tSELECT\n"
669  "\t\t\t''/''+e.name AS [text()]\n"
670  "\t\tFROM\n"
671  "\t\t\t" << tablename_path <<" p\n"
672  "\t\t\tJOIN " << tablename_entry <<" e ON e.id = p.pid\n"
673  "\t\tWHERE\n"
674  "\t\t\tp.id = c.pid\n"
675  "\t\tFOR XML PATH('''')\n"
676  "\t)) AS [path],\n"
677  "\tCASE WHEN e.value IS NULL THEN 1 ELSE 0 END AS [isgroup]\n"
678  "FROM\n"
679  "\t" << tablename_path <<" c\n"
680  "\tJOIN " << tablename_entry <<" e ON e.id = c.id\n"
681  "WHERE\n"
682  "\tc.id = c.pid\n"
683  "')"
684  ;
685  }
686 #endif
687 
688  m_pDatabase->CloseStatement(this->ExecuteStatement(this->PrepareStatement(sqlCreateTableEntry)));
689  m_pDatabase->CloseStatement(this->ExecuteStatement(this->PrepareStatement(sqlCreateTablePath)));
690  m_pDatabase->CloseStatement(this->ExecuteStatement(this->PrepareStatement(sqlCreateViewPath)));
691  m_pDatabase->CloseStatement(this->ExecuteStatement(this->PrepareStatement(sqlCreateTriggerInsteadOfInsertViewPath)));
692  m_pDatabase->CloseStatement(this->ExecuteStatement(this->PrepareStatement(sqlCreateTriggerInsteadOfUpdateViewPath)));
693  m_pDatabase->CloseStatement(this->ExecuteStatement(this->PrepareStatement(sqlCreateTriggerInsteadOfDeleteViewPath)));
694 
695  m_pStatementSqlAddEntry = this->PrepareStatement(sqlAddEntry);
696  m_pStatementSqlDelEntry = this->PrepareStatement(sqlDelEntry);
697  m_pStatementSqlEditEntry = this->PrepareStatement(sqlEditEntry);
698  m_pStatementSqlFindEntries = this->PrepareStatement(sqlFindEntries);
699 
700  m_pStatementSqlDropAll = this->PrepareStatement(sqlDropAll);
701 
702  return true;
703 }
704 
706 {
708  DatabaseErrorCheck(pStatement);
709  return pStatement;
710 }
711 
713 {
714  wxASSERT(pStatement);
715  m_self->DatabaseErrorCheck(pStatement);
716  //m_self->DatabaseErrorCheck(m_pDatabase);
717 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
718  try
719  {
720 #endif
721  if (pEntries == NULL)
722  {
723  pStatement->RunQuery();
724  m_self->DatabaseErrorCheck(pStatement);
725  }
726  else
727  {
728  wxDatabaseResultSet* pResultSet = pStatement->RunQueryWithResults();
729  m_self->DatabaseErrorCheck(pStatement);
730  if (pResultSet)
731  {
732  DatabaseErrorCheck(pResultSet);
733  while (pResultSet->Next())
734  {
735  DatabaseErrorCheck(pResultSet);
736  dbentry entry;
737  entry.id = pResultSet->GetResultLong(1);
738  entry.name = pResultSet->GetResultString(2);
739  entry.value = pResultSet->GetResultString(3);
740  entry.path = pResultSet->GetResultString(4);
741  entry.isgroup = pResultSet->GetResultBool(5);
742  pEntries->push_back(entry);
743  }
744  m_pDatabase->CloseResultSet(pResultSet);
745  }
746  }
747  //m_self->DatabaseErrorCheck(m_pDatabase);
748 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
749  }
750  catch (wxDatabaseException& e)
751  {
753  }
754 #endif
755  return pStatement;
756 }
757 
759 {
760  if (reporter->GetErrorCode() == wxDATABASE_OK) return;
761  wxString message(wxString::Format("Error (%d): %s", reporter->GetErrorCode(), reporter->GetErrorMessage()));
762  wxLogError(message);
763 }
764 
765 void wxDatabaseConfig::ProcessException(wxDatabaseException& e, bool fail)
766 {
767  wxString message = wxString::Format("Error (%d): %s", e.GetErrorCode(), e.GetErrorMessage());
768  if (fail)
769  {
770  wxLogError(message);
771  }
772  else
773  {
774  wxLogWarning(message);
775  }
776 }
777 
778 #endif // wxUSE_MLBASE
virtual bool RenameGroup(const wxString &oldName, const wxString &newName)
wxPreparedStatement * m_pStatementSqlDelEntry
Definition: dbconf.h:92
const wxString & GetTypeName()
Get a descriptive name for the type of database.
Definition: database.h:149
virtual bool DoReadString(const wxString &key, wxString *pStr) const
dbentries m_groups
Definition: dbconf.h:117
virtual bool GetFirstGroup(wxString &str, long &lIndex) const
virtual bool GetNextEntry(wxString &str, long &lIndex) const
virtual bool DoWriteString(const wxString &key, const wxString &szValue)
bool WriteEntry(dbentry &entry, const wxString &name, const wxString &value)
virtual void SetParamInt(int nPosition, int nValue)=0
Set the parameter at the 1-based position to an int value.
virtual bool GetNextGroup(wxString &str, long &lIndex) const
virtual size_t GetNumberOfGroups(bool bRecursive=false) const
virtual bool DeleteGroup(const wxString &key)
virtual void SetParamNull(int nPosition)=0
Set the parameter at the 1-based position to a NULL value.
virtual bool HasEntry(const wxString &strName) const
wxPreparedStatement * PrepareStatement(const wxString &strQuery)
virtual wxString GetResultString(int nField)=0
Retrieve a wxString from the result set by the 1-based field index.
void DatabaseErrorCheck(wxDatabaseErrorReporter *reporter)
virtual ~wxDatabaseConfig()
virtual wxPreparedStatement * PrepareStatement(const wxString &strQuery)=0
Prepare a SQL statement which can be reused with different parameters.
virtual bool DoReadLong(const wxString &key, long *pl) const
bool FindEntries(const wxString &nameORpath, dbentries &entries)
wxPreparedStatement * m_pStatementSqlDropAll
Definition: dbconf.h:96
static wxDatabase * GetDatabase(wxConfigBase &config, wxString *err=NULL, const wxString &path="/")
Get an instance of the first valid database specified in config.
Definition: database.cpp:922
virtual void SetPath(const wxString &strPath)
wxPreparedStatement * m_pStatementSqlEditEntry
Definition: dbconf.h:93
dbentries m_entries
Definition: dbconf.h:118
void GetChildren(dbentry &parent, dbentries *groups=NULL, dbentries *entries=NULL, bool recursive=false)
const wxString & GetErrorMessage()
#define wxDATABASE_OK
Definition: errorcodes.h:4
wxPreparedStatement * ExecuteStatement(wxPreparedStatement *pStatement, dbentries *pEntries=NULL)
virtual bool HasGroup(const wxString &strName) const
wxDatabase * m_pDatabase
Definition: dbconf.h:90
virtual bool CloseStatement(wxPreparedStatement *pStatement)
Close a prepared statement previously prepared by the database.
Definition: database.cpp:95
wxString m_viewName
Definition: dbconf.h:111
virtual bool RenameEntry(const wxString &oldName, const wxString &newName)
dbentry m_entry
Definition: dbconf.h:110
virtual bool DeleteAll()
virtual bool Flush(bool bCurrentOnly=false)
virtual long GetResultLong(int nField)=0
Retrieve a long from the result set by the 1-based field index.
wxDatabaseConfig(const wxString &appName=wxEmptyString, const wxString &vendorName=wxEmptyString, const wxString &viewName=wxEmptyString, const wxString &settingsConf=wxEmptyString, long style=0, const wxMBConv &conv=wxConvAuto())
virtual bool GetFirstEntry(wxString &str, long &lIndex) const
virtual bool Next()=0
Move to the next record in the result set.
virtual int RunQuery()=0
Run an insert, update, or delete query on the database.
wxPreparedStatement * m_pStatementSqlAddEntry
Definition: dbconf.h:91
std::vector< dbentry > dbentries
Definition: dbconf.h:80
virtual wxDatabaseResultSet * RunQueryWithResults()=0
Run an insert, update, or delete query on the database.
virtual bool GetResultBool(int nField)=0
Retrieve a boolean from the result set by the 1-based field index.
virtual size_t GetNumberOfEntries(bool bRecursive=false) const
virtual bool DeleteEntry(const wxString &key, bool bGroupIfEmptyAlso=true)
wxDatabaseConfig * m_self
Definition: dbconf.h:82
const wxString & GetLibraryPath()
Get the library path required by the database.
Definition: database.h:157
bool AddEntry(dbentry &parent, const wxString &name, const wxString *value=NULL)
virtual bool DoWriteLong(const wxString &key, long lValue)
void ProcessException(wxDatabaseException &e, bool fail=true)
virtual bool CloseResultSet(wxDatabaseResultSet *pResultSet)
Close a result set returned by the database or a prepared statement previously.
Definition: database.cpp:52
void SetRootPath(dbentry &entry)
wxPreparedStatement * m_pStatementSqlFindEntries
Definition: dbconf.h:94
virtual void SetParamString(int nPosition, const wxString &strValue)=0
Set the parameter at the 1-based position to a wxString value.