From 13de5a6ed0f919fa49875a2f5d098d9da8bc2c91 Mon Sep 17 00:00:00 2001 From: Paul Walker Date: Tue, 10 Aug 2021 19:55:40 -0400 Subject: [PATCH] Change a few patch db things 1. Don't initialize the DB on startup; rather init it when you first open the patch browser 2. End my 'throw in destructor' bad habit since that worked horribly. Catch everything properly etc... This closes #4822 but there's still lots to do in #2359 including a nasty locked handler fail when you start two surges against a fresh db --- src/common/PatchDB.cpp | 69 ++++++++++++++++++-- src/common/SurgeStorage.cpp | 3 + src/gui/overlays/PatchDBViewer.cpp | 1 + src/surge_synth_juce/SurgeSynthProcessor.cpp | 5 +- 4 files changed, 71 insertions(+), 7 deletions(-) diff --git a/src/common/PatchDB.cpp b/src/common/PatchDB.cpp index 50bb3e4f114..6192412a653 100644 --- a/src/common/PatchDB.cpp +++ b/src/common/PatchDB.cpp @@ -20,6 +20,7 @@ #include #include #include "vt_dsp_endian.h" +#include "DebugHelpers.h" namespace Surge { @@ -32,6 +33,7 @@ struct Exception : public std::runtime_error { explicit Exception(sqlite3 *h) : std::runtime_error(sqlite3_errmsg(h)), rc(sqlite3_errcode(h)) { + Surge::Debug::stackTraceToStdout(); } Exception(int rc, const std::string &msg) : std::runtime_error(msg), rc(rc) {} const char *what() const noexcept override @@ -60,17 +62,27 @@ void Exec(sqlite3 *h, const std::string &statement) */ struct Statement { + bool prepared{false}; Statement(sqlite3 *h, const std::string &statement) : h(h) { auto rc = sqlite3_prepare_v2(h, statement.c_str(), -1, &s, nullptr); if (rc != SQLITE_OK) throw Exception(h); + prepared = true; } - ~Statement() noexcept(false) + ~Statement() + { + if (prepared) + { + std::cout << "ERROR: Prepared Statement never Finalized" << std::endl; + } + } + void finalize() { if (s) if (sqlite3_finalize(s) != SQLITE_OK) throw Exception(h); + prepared = false; } int col_int(int c) const { return sqlite3_column_int(s, c); } @@ -153,6 +165,7 @@ struct Statement */ struct TxnGuard { + bool open{false}; explicit TxnGuard(sqlite3 *e) : d(e) { auto rc = sqlite3_exec(d, "BEGIN TRANSACTION", nullptr, nullptr, nullptr); @@ -160,14 +173,24 @@ struct TxnGuard { throw Exception(d); } + open = true; } - ~TxnGuard() noexcept(false) + + void end() { auto rc = sqlite3_exec(d, "END TRANSACTION", nullptr, nullptr, nullptr); if (rc != SQLITE_OK) { throw Exception(d); } + open = false; + } + ~TxnGuard() + { + if (open) + { + auto rc = sqlite3_exec(d, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr); + } } sqlite3 *d; }; @@ -302,6 +325,8 @@ CREATE TABLE Category ( rebuild = false; } } + + st.finalize(); } catch (const SQL::Exception &e) { @@ -419,12 +444,21 @@ CREATE TABLE Category ( } } { - SQL::TxnGuard tg(dbh); + try + { + SQL::TxnGuard tg(dbh); + + for (auto *p : doThis) + { + p->go(*this); + delete p; + } - for (auto *p : doThis) + tg.end(); + } + catch (SQL::Exception &e) { - p->go(*this); - delete p; + storage->reportError(e.what(), "Patch DB"); } } } @@ -465,6 +499,8 @@ CREATE TABLE Category ( patchLoaded = true; } + exists.finalize(); + if (!dropIds.empty()) { auto drop = SQL::Statement( @@ -478,6 +514,8 @@ CREATE TABLE Category ( drop.clearBindings(); drop.reset(); } + + drop.finalize(); } } catch (const SQL::Exception &e) @@ -507,6 +545,8 @@ CREATE TABLE Category ( // No real need to encapsulate this patchid = sqlite3_last_insert_rowid(dbh); + + ins.finalize(); } catch (const SQL::Exception &e) { @@ -579,6 +619,8 @@ CREATE TABLE Category ( ins.clearBindings(); ins.reset(); } + + ins.finalize(); } catch (const SQL::Exception &e) { @@ -601,6 +643,8 @@ CREATE TABLE Category ( auto count = there.col_int(0); if (count > 0) return; + + there.finalize(); } catch (const SQL::Exception &e) { @@ -615,6 +659,8 @@ CREATE TABLE Category ( add.bind(1, name); add.bind(2, (int)type); add.step(); + + add.finalize(); } catch (const SQL::Exception &e) { @@ -634,6 +680,9 @@ CREATE TABLE Category ( there.bind(2, (int)type); there.step(); auto count = there.col_int(0); + + there.finalize(); + if (count > 0) return; } @@ -660,6 +709,8 @@ CREATE TABLE Category ( add.bind(3, (int)type); add.bind(4, parentId); add.step(); + + add.finalize(); } catch (const SQL::Exception &e) { @@ -736,6 +787,8 @@ std::vector PatchDB::rawQueryForNameLike(const std::string auto auth = q.col_str(4); res.emplace_back(id, path, cat, name, auth); } + + q.finalize(); } catch (SQL::Exception &e) { @@ -782,6 +835,8 @@ std::vector PatchDB::internalCategories(int t, const std::st res.push_back(cr); } + q.finalize(); + auto par = SQL::Statement(worker->dbh, "select COUNT(id) from category where category.parent_id = ?"); for (auto &cr : res) @@ -794,6 +849,8 @@ std::vector PatchDB::internalCategories(int t, const std::st par.clearBindings(); par.reset(); } + + par.finalize(); } catch (SQL::Exception &e) { diff --git a/src/common/SurgeStorage.cpp b/src/common/SurgeStorage.cpp index c3baf8ab534..8b488dbe4c2 100644 --- a/src/common/SurgeStorage.cpp +++ b/src/common/SurgeStorage.cpp @@ -691,6 +691,9 @@ void SurgeStorage::createUserDirectory() void SurgeStorage::initializePatchDb() { + if (patchDB) + return; + patchDB = std::make_unique(this); auto catToType = [this](int q) { diff --git a/src/gui/overlays/PatchDBViewer.cpp b/src/gui/overlays/PatchDBViewer.cpp index a7637f01ee9..08e60b82755 100644 --- a/src/gui/overlays/PatchDBViewer.cpp +++ b/src/gui/overlays/PatchDBViewer.cpp @@ -270,6 +270,7 @@ class PatchDBSQLTableModel : public juce::TableListBoxModel PatchDBViewer::PatchDBViewer(SurgeGUIEditor *e, SurgeStorage *s) : editor(e), storage(s), juce::Component("PatchDB Viewer") { + storage->initializePatchDb(); createElements(); } PatchDBViewer::~PatchDBViewer() { treeView->setRootItem(nullptr); }; diff --git a/src/surge_synth_juce/SurgeSynthProcessor.cpp b/src/surge_synth_juce/SurgeSynthProcessor.cpp index 2eae84a632e..035d92d07df 100644 --- a/src/surge_synth_juce/SurgeSynthProcessor.cpp +++ b/src/surge_synth_juce/SurgeSynthProcessor.cpp @@ -41,7 +41,6 @@ SurgeSynthProcessor::SurgeSynthProcessor() << " - CPU : " << Surge::CPUFeatures::cpuBrand() << std::endl; surge = std::make_unique(this); - surge->storage.initializePatchDb(); // In the UI branch we want the patch DB running auto parent = std::make_unique("Root", "Root", "|"); auto macroG = std::make_unique("macros", "Macros", "|"); @@ -147,6 +146,7 @@ void SurgeSynthProcessor::setCurrentProgram(int index) const String SurgeSynthProcessor::getProgramName(int index) { +#ifdef SURGE_JUCE_PRESETS if (index == 0) return "INIT OR DROPPED"; index--; @@ -157,6 +157,9 @@ const String SurgeSynthProcessor::getProgramName(int index) auto patch = surge->storage.patch_list[presetOrderToPatchList[index]]; auto res = surge->storage.patch_category[patch.category].name + " / " + patch.name; return res; +#else + return ""; +#endif } void SurgeSynthProcessor::changeProgramName(int index, const String &newName) {}