3 #if wxUSE_DATABASE_CONFIG 5 #include <wx/filename.h> 6 #include <wx/sstream.h> 7 #include <wx/stdpaths.h> 13 #define viewname_default "dbconf" 15 #define viewname (m_viewName) 16 #define tablename_path (m_viewName+"path") 17 #define tablename_entry (m_viewName+"entry") 19 #define triggername_insertviewpath ("insert_"+m_viewName) 20 #define triggername_updateviewpath ("update_"+m_viewName) 21 #define triggername_deleteviewpath ("delete_"+m_viewName) 27 const wxString& appName,
28 const wxString& vendorName,
29 const wxString& viewName,
30 const wxString& settingsConf,
32 const wxMBConv& WXUNUSED(conv)
34 : wxConfigBase(appName, vendorName),
39 wxStringInputStream inStream(settingsConf);
41 if (!LoadStream(inStream, &err))
43 wxLogWarning(wxString::Format(
"%s in configuration settings '%s'", err, settingsConf));
50 wxInputStream& inStream,
51 const wxString& viewName,
52 const wxMBConv& WXUNUSED(conv)
59 wxString warning(
" configuration stream");
61 if (!LoadStream(inStream, &err))
63 wxLogWarning(wxString::Format(
"%s in configuration stream", err));
85 if (strPath.empty() || strPath.IsSameAs(wxCONFIG_PATH_SEPARATOR))
92 wxString path = strPath;
97 if (path[0] != wxCONFIG_PATH_SEPARATOR)
99 path =
m_entry.
path + wxCONFIG_PATH_SEPARATOR + path;
101 wxArrayString paths(wxSplit(path, wxCONFIG_PATH_SEPARATOR));
103 for (
size_t n = 0; n < paths.Count(); n++)
105 if (paths[n].IsSameAs(wxEmptyString))
continue;
106 path += wxCONFIG_PATH_SEPARATOR+paths[n];
132 if ((
long)
m_groups.size() <= lIndex)
return false;
147 if ((
long)
m_entries.size() <= lIndex)
return false;
157 for (dbentries::iterator it = wild.begin(); it != wild.end(); ++it)
159 wxString localpath(it->path.Right(it->path.Length()-parent.path.Length()-1));
160 if (!recursive && wxStrchr(localpath, wxCONFIG_PATH_SEPARATOR))
continue;
163 if (groups == NULL)
continue;
164 groups->push_back(*it);
168 if (entries == NULL)
continue;
169 entries->push_back(*it);
178 return entries.size();
185 return groups.size();
190 if (strName.empty())
return false;
193 return entries[0].isgroup;
198 if (strName.empty())
return false;
201 return !entries[0].isgroup;
212 if (nameORpath.empty())
return false;
213 wxString path = nameORpath;
214 if (path[0] != wxCONFIG_PATH_SEPARATOR)
216 path =
m_entry.
path + wxCONFIG_PATH_SEPARATOR + path;
218 if (path.Contains(
"..") || path.Contains(
"."))
220 wxArrayString in(wxSplit(path, wxCONFIG_PATH_SEPARATOR));
222 size_t count = in.GetCount();
223 for (
size_t n = 0; n < count; n++)
225 wxString name = in[n];
226 if (name.IsSameAs(wxEmptyString))
continue;
227 if (name ==
".")
continue;
228 if (name ==
".." && !out.empty())
235 path = wxCONFIG_PATH_SEPARATOR+wxJoin(out, wxCONFIG_PATH_SEPARATOR);
237 if (path.IsSameAs(wxCONFIG_PATH_SEPARATOR))
241 entries.push_back(root);
245 return (entries.size() > 0);
250 if (name.empty())
return false;
251 wxASSERT_MSG(!wxStrchr(name, wxCONFIG_PATH_SEPARATOR), wxT(
"AddEntry(): paths are not supported"));
261 wxString strValue(*value);
270 if (name.empty())
return false;
271 wxASSERT_MSG(!wxStrchr(name, wxCONFIG_PATH_SEPARATOR), wxT(
"WriteEntry(): paths are not supported"));
282 wxASSERT_MSG(!wxStrchr(oldName, wxCONFIG_PATH_SEPARATOR), wxT(
"RenameEntry(): paths are not supported"));
289 return WriteEntry(entries[0], newName, entries[0].value);
294 wxASSERT_MSG(!wxStrchr(oldName, wxCONFIG_PATH_SEPARATOR), wxT(
"RenameGroup(): paths are not supported"));
300 wxString path = this->RemoveTrailingSeparator(key);
303 dbentry entry = entries[0];
305 path = this->RemoveTrailingSeparator(key)+wxCONFIG_PATH_SEPARATOR+
"..";
308 dbentry parent = entries[0];
321 if (bGroupIfEmptyAlso && entries.size() == 0)
331 wxString path = this->RemoveTrailingSeparator(key);
334 dbentry group = entries[0];
336 path = this->RemoveTrailingSeparator(key)+wxCONFIG_PATH_SEPARATOR+
"..";
339 dbentry parent = entries[0];
363 *pStr = entries[0].value;
370 if (!Read(key, &str))
return false;
372 return str.ToLong(pl);
377 wxString name = key.AfterLast(wxCONFIG_PATH_SEPARATOR);
378 if (name.StartsWith(wxCONFIG_IMMUTABLE_PREFIX))
380 wxLogError(
"Immutable entries cannot be changed");
387 wxConfigPathChanger path(
this, key);
391 else if (entries[0].isgroup)
393 wxLogError(
"Can't set value of a group!.");
405 return Write(key, wxString::Format(_T(
"%ld"), lValue));
408 #if wxCHECK_VERSION(2,9,0) && wxUSE_BASE64 409 bool wxDatabaseConfig::DoReadBinary(
const wxString& key, wxMemoryBuffer* buf)
const 411 wxCHECK_MSG(buf,
false, wxT(
"NULL buffer"));
414 if (!Read(key, &str))
return false;
415 *buf = wxBase64Decode(str);
419 bool wxDatabaseConfig::DoWriteBinary(
const wxString& key,
const wxMemoryBuffer& buf)
421 return Write(key, wxBase64Encode(buf));
437 bool wxDatabaseConfig::LoadStream(wxInputStream& inStream, wxString* err)
449 m_viewName.Replace(wxCONFIG_PATH_SEPARATOR, wxEmptyString);
451 if (!inStream.CanRead())
453 if (err) err->Append(
"can't read");
457 wxFileConfig config(inStream);
470 wxString sqlCreateTablePath;
471 wxString sqlCreateTableEntry;
472 wxString sqlCreateViewPath;
474 wxString sqlCreateTriggerInsteadOfInsertViewPath;
475 wxString sqlCreateTriggerInsteadOfUpdateViewPath;
476 wxString sqlCreateTriggerInsteadOfDeleteViewPath;
478 wxString sqlAddEntry;
479 wxString sqlDelEntry;
480 wxString sqlEditEntry;
481 wxString sqlFindEntries;
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 <<
493 "PRIMARY KEY (pid, id)," 494 "FOREIGN KEY (pid) REFERENCES " << tablename_entry <<
"(id)," 495 "FOREIGN KEY (id) REFERENCES " << tablename_entry <<
"(id)" 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 <<
504 "id INT IDENTITY PRIMARY KEY," 505 "name VARCHAR(255) NOT NULL," 506 "value VARCHAR(255) NULL" 511 "INSERT INTO " << viewname <<
" (id, name, value) VALUES (?, ?, ?)" 514 "DELETE FROM " << viewname <<
" WHERE id = ?" 517 "UPDATE " << viewname <<
" SET name = ?, value = ? WHERE id = ?" 520 "SELECT id, name, value, path, isgroup FROM " << viewname <<
" WHERE path LIKE ?" 523 "DROP VIEW " << viewname <<
"\n" 524 "DROP TABLE " << tablename_path <<
"\n" 525 "DROP TABLE " << tablename_entry <<
"\n" 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" 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" 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" 539 "\tSELECT MAX(id), MAX(id) FROM " << tablename_entry <<
"\n" 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" 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" 555 "\t\t" << tablename_entry <<
".id = i.id\n" 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" 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" 572 "\t\t" << tablename_entry <<
" e\n" 574 "\t\te.id NOT IN (SELECT id FROM " << tablename_path <<
")\n" 582 if (err) err->Append(
"cannot establish database connection from");
590 wxGetEnv(
"PATH", &path);
597 wxSetEnv(
"PATH", path);
601 #if wxUSE_DATABASE_SQLITE 606 "IF NOT EXISTS (SELECT * FROM sys.views WHERE name = '" << viewname <<
"') EXECUTE('" 607 "CREATE VIEW [" << viewname <<
"]\n" 613 "\tCONVERT(VARCHAR(255), (\n" 615 "\t\t\t''/''+dbo.GROUP_CONCAT_D(ie.name, ''/'')\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" 621 "\t\t\tic.id = ic.pid\n" 623 "\t\t\tic.id = c.id\n" 627 "\tCASE WHEN e.value IS NULL THEN 1 ELSE 0 END AS [isgroup]\n" 629 "\t" << tablename_path <<
" c\n" 630 "\tJOIN " << tablename_entry <<
" e ON e.id = c.id\n" 637 #if wxUSE_DATABASE_POSTGRESQL 643 #if wxUSE_DATABASE_MYSQL 649 #if wxUSE_DATABASE_ODBC 655 #if wxUSE_DATABASE_TDS 660 "IF NOT EXISTS (SELECT * FROM sys.views WHERE name = '" << viewname <<
"') EXECUTE('" 661 "CREATE VIEW [" << viewname <<
"]\n" 667 "\tCONVERT(VARCHAR(255), (\n" 669 "\t\t\t''/''+e.name AS [text()]\n" 671 "\t\t\t" << tablename_path <<
" p\n" 672 "\t\t\tJOIN " << tablename_entry <<
" e ON e.id = p.pid\n" 674 "\t\t\tp.id = c.pid\n" 675 "\t\tFOR XML PATH('''')\n" 677 "\tCASE WHEN e.value IS NULL THEN 1 ELSE 0 END AS [isgroup]\n" 679 "\t" << tablename_path <<
" c\n" 680 "\tJOIN " << tablename_entry <<
" e ON e.id = c.id\n" 714 wxASSERT(pStatement);
717 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS 721 if (pEntries == NULL)
733 while (pResultSet->
Next())
742 pEntries->push_back(entry);
748 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS 750 catch (wxDatabaseException& e)
767 wxString message = wxString::Format(
"Error (%d): %s", e.GetErrorCode(), e.GetErrorMessage());
774 wxLogWarning(message);
778 #endif // wxUSE_MLBASE virtual bool RenameGroup(const wxString &oldName, const wxString &newName)
wxPreparedStatement * m_pStatementSqlDelEntry
const wxString & GetTypeName()
Get a descriptive name for the type of database.
virtual bool DoReadString(const wxString &key, wxString *pStr) const
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
static wxDatabase * GetDatabase(wxConfigBase &config, wxString *err=NULL, const wxString &path="/")
Get an instance of the first valid database specified in config.
virtual void SetPath(const wxString &strPath)
wxPreparedStatement * m_pStatementSqlEditEntry
void GetChildren(dbentry &parent, dbentries *groups=NULL, dbentries *entries=NULL, bool recursive=false)
const wxString & GetErrorMessage()
wxPreparedStatement * ExecuteStatement(wxPreparedStatement *pStatement, dbentries *pEntries=NULL)
virtual bool HasGroup(const wxString &strName) const
virtual bool CloseStatement(wxPreparedStatement *pStatement)
Close a prepared statement previously prepared by the database.
virtual bool RenameEntry(const wxString &oldName, const wxString &newName)
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
std::vector< dbentry > dbentries
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
const wxString & GetLibraryPath()
Get the library path required by the database.
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.
void SetRootPath(dbentry &entry)
wxPreparedStatement * m_pStatementSqlFindEntries
virtual void SetParamString(int nPosition, const wxString &strValue)=0
Set the parameter at the 1-based position to a wxString value.