From a16121aeb0605a0a6d210842c9bf40aff8f09e5f Mon Sep 17 00:00:00 2001 From: Mill J Date: Wed, 19 May 2021 23:38:35 +0000 Subject: [PATCH] Sqlite3 optimizations --- meson.build | 2 +- src/Database.cpp | 127 ++++++++++++++++----------------- src/Database.hpp | 15 ++-- src/MainFrame.cpp | 178 +++++++++++++++++++++++++++------------------- src/MainFrame.hpp | 3 +- src/Sample.cpp | 84 ++++++++++++++++++++++ src/Sample.hpp | 76 ++++++++++++++++++++ 7 files changed, 337 insertions(+), 148 deletions(-) create mode 100644 src/Sample.cpp create mode 100644 src/Sample.hpp diff --git a/meson.build b/meson.build index edca4eb..d7624f2 100755 --- a/meson.build +++ b/meson.build @@ -14,7 +14,7 @@ src = [ 'src/Serialize.cpp', 'src/TreeItemDialog.cpp', 'src/Tags.cpp', - + 'src/Sample.cpp', ] wxconfig = find_program (['wx-config-gtk3', 'wx-config']) diff --git a/src/Database.cpp b/src/Database.cpp index 4162351..4ac7548 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -73,13 +73,9 @@ void Database::CreateDatabase() } } -void Database::InsertSample(int favorite, std::string filename, - std::string fileExtension, std::string samplePack, - std::string type, int channels, int length, - int sampleRate, int bitrate, std::string path, - int trashed) -{ - try +///Loops through a Sample array and adds them to the database +void Database::InsertSamples(std::vector samples) { + try { if (sqlite3_open("sample.hive", &m_Database) != SQLITE_OK) { @@ -97,36 +93,53 @@ void Database::InsertSample(int favorite, std::string filename, VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; rc = sqlite3_prepare_v2(m_Database, insert.c_str(), insert.size(), &m_Stmt, NULL); + + rc = sqlite3_exec(m_Database, "BEGIN TRANSACTION", NULL, NULL, &m_ErrMsg); + if (rc != SQLITE_OK) wxLogDebug("Cannot prepare sql statement.."); - - rc = sqlite3_bind_int(m_Stmt, 1, favorite); - rc = sqlite3_bind_text(m_Stmt, 2, filename.c_str(), filename.size(), SQLITE_STATIC); - rc = sqlite3_bind_text(m_Stmt, 3, fileExtension.c_str(), fileExtension.size(), SQLITE_STATIC); - rc = sqlite3_bind_text(m_Stmt, 4, samplePack.c_str(), samplePack.size(), SQLITE_STATIC); - rc = sqlite3_bind_text(m_Stmt, 5, type.c_str(), type.size(), SQLITE_STATIC); - rc = sqlite3_bind_int(m_Stmt, 6, channels); - rc = sqlite3_bind_int(m_Stmt, 7, length); - rc = sqlite3_bind_int(m_Stmt, 8, sampleRate); - rc = sqlite3_bind_int(m_Stmt, 9, bitrate); - rc = sqlite3_bind_text(m_Stmt, 10, path.c_str(), path.size(), SQLITE_STATIC); - rc = sqlite3_bind_int(m_Stmt, 11, trashed); - rc = sqlite3_step(m_Stmt); - - if (rc != SQLITE_DONE) + Sample sample_object; + + std::string filename; + std::string file_extension; + std::string sample_pack; + std::string type; + std::string path; + + for(unsigned int i = 0; i < samples.size(); i++) { - wxLogDebug("No data inserted. Error code: %d: Msg: %s", rc , sqlite3_errmsg(m_Database)); + sample_object = samples[i]; + + filename = sample_object.GetFilename(); + file_extension = sample_object.GetFileExtension(); + sample_pack = sample_object.GetSamplePack(); + type = sample_object.GetType(); + path = sample_object.GetPath(); + + rc = sqlite3_bind_int(m_Stmt, 1, sample_object.GetFavorite()); + rc = sqlite3_bind_text(m_Stmt, 2, filename.c_str(), filename.size(), SQLITE_STATIC); + rc = sqlite3_bind_text(m_Stmt, 3, file_extension.c_str(), file_extension.size(), SQLITE_STATIC); + rc = sqlite3_bind_text(m_Stmt, 4, sample_pack.c_str(), sample_pack.size(), SQLITE_STATIC); + rc = sqlite3_bind_text(m_Stmt, 5, type.c_str(), type.size(), SQLITE_STATIC); + rc = sqlite3_bind_int(m_Stmt, 6, sample_object.GetChannels()); + rc = sqlite3_bind_int(m_Stmt, 7, sample_object.GetLength()); + rc = sqlite3_bind_int(m_Stmt, 8, sample_object.GetSampleRate()); + rc = sqlite3_bind_int(m_Stmt, 9, sample_object.GetBitrate()); + rc = sqlite3_bind_text(m_Stmt, 10, path.c_str(),path.size(), SQLITE_STATIC); + rc = sqlite3_bind_int(m_Stmt, 11, sample_object.GetTrashed()); + + rc = sqlite3_step(m_Stmt); + rc = sqlite3_clear_bindings(m_Stmt); + rc = sqlite3_reset(m_Stmt); } + rc = sqlite3_exec(m_Database, "END TRANSACTION", NULL, NULL, &m_ErrMsg); + rc = sqlite3_finalize(m_Stmt); if (rc != SQLITE_OK) { - // wxMessageDialog msgDialog(NULL, - // "Error! Cannot insert data into table.", - // "Error", wxOK | wxICON_ERROR); - // msgDialog.ShowModal(); wxLogDebug("Error! Cannot insert data into table. Error code: %d: Msg: %s", rc , sqlite3_errmsg(m_Database)); } else @@ -155,13 +168,7 @@ void Database::InsertSample(int favorite, std::string filename, if (rc == SQLITE_INTERNAL) wxLogDebug("SQLITE_INTERNAL"); - rc = sqlite3_close(m_Database); - - if (rc == SQLITE_OK) - wxLogDebug("DB Closed.."); - else - wxLogDebug("Error! Cannot close DB, Error code: %d, Error message: %s", rc, m_ErrMsg); - + sqlite3_close(m_Database); } catch (const std::exception &exception) { @@ -751,51 +758,43 @@ Database::FilterDatabaseBySampleName(wxVector>& sampleVec, c return sampleVec; } -bool Database::HasSample(const std::string& filename) +//Compares the input array with the database and removes duplicates. +wxArrayString Database::CheckDuplicates(wxArrayString files) { + wxArrayString sorted_files; + + std::string filename; std::string sample; - bool haveSample = false; try { rc = sqlite3_open("sample.hive", &m_Database); std::string select = "SELECT * FROM SAMPLES WHERE FILENAME = ?;"; - rc = sqlite3_prepare_v2(m_Database, select.c_str(), select.size(), &m_Stmt, NULL); - - rc = sqlite3_bind_text(m_Stmt, 1, filename.c_str(), filename.size(), SQLITE_STATIC); - - if (sqlite3_step(m_Stmt) == SQLITE_ROW) - { - wxLogInfo("Record found, fetching.."); - sample = std::string(reinterpret_cast(sqlite3_column_text(m_Stmt, 0))); - haveSample = true; - } - - rc = sqlite3_finalize(m_Stmt); - - if (rc != SQLITE_OK) - { - wxMessageDialog msgDialog(NULL, "Error! Cannot find data in table.", - "Error", wxOK | wxICON_ERROR); - msgDialog.ShowModal(); - sqlite3_free(m_ErrMsg); - } - else - { - wxLogInfo("Selected data from table successfully."); - } - - sqlite3_close(m_Database); - return haveSample; + for(unsigned int i = 0; i < files.size(); i++) + { + filename = files[i].AfterLast('/').BeforeLast('.').ToStdString(); + rc = sqlite3_bind_text(m_Stmt, 1, filename.c_str(), filename.size(), SQLITE_STATIC); + + if (sqlite3_step(m_Stmt) != SQLITE_ROW) + { + sorted_files.push_back(files[i]); + } + + rc = sqlite3_clear_bindings(m_Stmt); + rc = sqlite3_reset(m_Stmt); + } + + sqlite3_finalize(m_Stmt); + sqlite3_close(m_Database); } catch (const std::exception &exception) { wxLogDebug(exception.what()); } - return false; + return sorted_files; } bool Database::IsTrashed(const std::string& filename) diff --git a/src/Database.hpp b/src/Database.hpp index ce306be..39d8034 100644 --- a/src/Database.hpp +++ b/src/Database.hpp @@ -1,5 +1,6 @@ -#include #include +#include +#include #include #include @@ -9,6 +10,8 @@ #include +#include "Sample.hpp" + class Database { public: @@ -32,12 +35,8 @@ class Database // ------------------------------------------------------------------- // Insert into database - void InsertSample(int favorite, std::string filename, - std::string fileExtension, std::string samplePack, - std::string type, int channels, int length, - int sampleRate, int bitrate, std::string path, - int trashed); - + void InsertSamples(std::vector); + // ------------------------------------------------------------------- // Update database void UpdateFavoriteColumn(const std::string& filename, int value); @@ -57,8 +56,8 @@ class Database // ------------------------------------------------------------------- // Check database - bool HasSample(const std::string& filename); bool IsTrashed(const std::string& filename); + wxArrayString CheckDuplicates(wxArrayString files); // ------------------------------------------------------------------- // Remove from database diff --git a/src/MainFrame.cpp b/src/MainFrame.cpp index 42daa79..0fdbfe4 100644 --- a/src/MainFrame.cpp +++ b/src/MainFrame.cpp @@ -29,6 +29,7 @@ #include "Tags.hpp" // #include "TreeItemDialog.hpp" #include "Serialize.hpp" +#include "Sample.hpp" #include @@ -348,75 +349,119 @@ wxString TagLibTowx(const TagLib::String& in) return wxString::FromUTF8(in.toCString(true)); } -void MainFrame::AddSamples(wxString file) +// Adds multiple samples to the database. +void MainFrame::AddSamples(wxArrayString files) { Settings settings(this, m_ConfigFilepath, m_DatabaseFilepath); + Database db(*m_InfoBar); + + wxBusyCursor busy_cursor; + wxWindowDisabler window_disabler; + wxProgressDialog* progressDialog = new wxProgressDialog("Adding files..", "Adding files, please wait...", + (int)files.size(), this, + wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_CAN_ABORT | + wxPD_AUTO_HIDE); + progressDialog->CenterOnParent(wxBOTH); + + std::vector sample_array; + std::string path; + std::string artist; + std::string filename_with_extension; + std::string filename_without_extension; + std::string extension; + std::string filename; + + //Check All Files At Once + wxArrayString sorted_files; + sorted_files = db.CheckDuplicates(files); + files = sorted_files; + + if(files.size() < 1) { + progressDialog->Destroy(); + return; + } - std::string path = file.ToStdString(); - - std::string filename_with_extension = file.AfterLast('/').ToStdString(); - std::string filename_without_extension = file.AfterLast('/').BeforeLast('.').ToStdString(); - std::string extension = file.AfterLast('.').ToStdString(); - - std::string filename = settings.IsShowFileExtension() ? - filename_with_extension : filename_without_extension; - - Tags tags(path); - - std::string artist = tags.GetAudioInfo().artist.ToStdString(); - - int channels = tags.GetAudioInfo().channels; - int length = tags.GetAudioInfo().length; - int sample_rate = tags.GetAudioInfo().sample_rate; - int bitrate = tags.GetAudioInfo().bitrate; - - wxVector data; - - if (tags.IsFileValid()) + progressDialog->SetRange(files.size()); + for(unsigned int i = 0; i < files.size(); i++) { - data.clear(); - data.push_back(false); - data.push_back(filename); - data.push_back(artist); - data.push_back(""); - data.push_back(wxString::Format("%d", channels)); - data.push_back(wxString::Format("%d", length)); - data.push_back(wxString::Format("%d", sample_rate)); - data.push_back(wxString::Format("%d", bitrate)); + progressDialog->Update(i, wxString::Format("Getting Data For %s", files[i].AfterLast('/'))); - wxLogDebug("Adding file: %s :: Extension: %s", filename, extension); - - if (!db.HasSample(filename_without_extension)) + if(progressDialog->WasCancelled()) { - m_SampleListView->AppendItem(data); + progressDialog->Destroy(); + return; + } - db.InsertSample(0, filename_without_extension, extension, artist, - "", channels, length, sample_rate, bitrate, - path, 0); + path = files[i].ToStdString(); + filename_with_extension = files[i].AfterLast('/').ToStdString(); + filename = files[i].AfterLast('/').BeforeLast('.').ToStdString(); + extension = files[i].AfterLast('.').ToStdString(); + + Sample sample_object; + sample_object.SetPath(path); + + sample_object.SetFilename(filename); + sample_object.SetFileExtension(extension); + + Tags tags(path); + artist = tags.GetAudioInfo().artist.ToStdString(); + + sample_object.SetSamplePack(artist); + sample_object.SetChannels(tags.GetAudioInfo().channels); + sample_object.SetLength(tags.GetAudioInfo().length); + sample_object.SetSampleRate(tags.GetAudioInfo().sample_rate); + sample_object.SetBitrate(tags.GetAudioInfo().bitrate); + + wxVector data; + + if (tags.IsFileValid()) + { + data.clear(); + data.push_back(false); + + if(settings.IsShowFileExtension()) + data.push_back(filename_with_extension); + else + data.push_back(filename); + + data.push_back(sample_object.GetSamplePack()); + data.push_back(""); + data.push_back(wxString::Format("%d", sample_object.GetChannels())); + data.push_back(wxString::Format("%d", sample_object.GetLength())); + data.push_back(wxString::Format("%d", sample_object.GetSampleRate())); + data.push_back(wxString::Format("%d", sample_object.GetBitrate())); + + wxLogDebug("Will Add file: %s :: Extension: %s", sample_object.GetFilename(), sample_object.GetFileExtension()); + + m_SampleListView->AppendItem(data); + sample_array.push_back(sample_object); } else { - wxString msg = wxString::Format("%s already exists.", file.AfterLast('/')); - m_InfoBar->ShowMessage(msg, wxICON_INFORMATION); + wxString msg = wxString::Format("Error! Cannot open %s, Invalid file type.", sample_object.GetFilename()); + m_InfoBar->ShowMessage(msg, wxICON_ERROR); } } - else - { - wxString msg = wxString::Format("Error! Cannot open %s, Invalid file type.", filename); - m_InfoBar->ShowMessage(msg, wxICON_ERROR); - } + progressDialog->Pulse("Updating Database",NULL); + db.InsertSamples(sample_array); + + progressDialog->Destroy(); } void MainFrame::OnClickDirCtrl(wxCommandEvent& event) { - wxString path = m_DirCtrl->GetFilePath(); - - MainFrame::AddSamples(path); + wxArrayString path; + path.push_back(m_DirCtrl->GetFilePath()); + + AddSamples(path); } void MainFrame::OnDragAndDropToSampleListView(wxDropFilesEvent& event) { + //Log Start + wxLogDebug("Start Inserting Samples"); + if (event.GetNumberOfFiles() > 0) { wxString* dropped = event.GetFiles(); @@ -425,15 +470,18 @@ void MainFrame::OnDragAndDropToSampleListView(wxDropFilesEvent& event) wxBusyCursor busy_cursor; wxWindowDisabler window_disabler; + wxString name; wxString filepath; wxArrayString filepath_array; - wxProgressDialog* progressDialog = new wxProgressDialog("Adding files..", "Adding files, please wait...", + wxProgressDialog* progressDialog = new wxProgressDialog("Reading files..", "Reading files, please wait...", event.GetNumberOfFiles(), this, wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_CAN_ABORT | wxPD_AUTO_HIDE); progressDialog->CenterOnParent(wxBOTH); + wxYield(); + for (int i = 0; i < event.GetNumberOfFiles(); i++) { filepath = dropped[i]; @@ -446,27 +494,20 @@ void MainFrame::OnDragAndDropToSampleListView(wxDropFilesEvent& event) { wxDir::GetAllFiles(filepath, &filepath_array); } - progressDialog->Pulse("Reading Samples",NULL); } - progressDialog->SetRange(filepath_array.size()); - - for (size_t i = 0; i < filepath_array.size(); i++) - { - MainFrame::AddSamples(filepath_array[i]); - progressDialog->Update(i, wxString::Format("Adding %s", filepath_array[i].AfterLast('/'))); - - if(progressDialog->WasCancelled()) - break; - } - progressDialog->Destroy(); + AddSamples(filepath_array); + + wxLogDebug("Done Inserting Samples:"); } } void MainFrame::OnAutoImportDir() { + wxLogDebug("Start Importing Samples:"); + Settings settings(this,m_ConfigFilepath, m_DatabaseFilepath); wxBusyCursor busy_cursor; @@ -501,19 +542,10 @@ void MainFrame::OnAutoImportDir() progressDialog->Pulse("Reading Samples",NULL); } - progressDialog->SetRange(filepath_array.size()); - - for (size_t i = 0; i < filepath_array.size(); i++) - { - MainFrame::AddSamples(filepath_array[i]); - - progressDialog->Update(i, wxString::Format("Adding %s", filepath_array[i].AfterLast('/'))); - - if(progressDialog->WasCancelled()) - break; - } - progressDialog->Destroy(); + AddSamples(filepath_array); + + wxLogDebug("Done Importing Samples:"); } void LogDragResult(wxDragResult result) diff --git a/src/MainFrame.hpp b/src/MainFrame.hpp index 29fd6bd..d60755e 100644 --- a/src/MainFrame.hpp +++ b/src/MainFrame.hpp @@ -183,9 +183,8 @@ class MainFrame : public wxFrame void UpdateElapsedTime(wxTimerEvent& event); // ------------------------------------------------------------------- - void AddSamples(wxString file); void OnAutoImportDir(); - + void AddSamples(wxArrayString files); // ------------------------------------------------------------------- void LoadDatabase(); void RefreshDatabase(); diff --git a/src/Sample.cpp b/src/Sample.cpp new file mode 100644 index 0000000..6c5d04e --- /dev/null +++ b/src/Sample.cpp @@ -0,0 +1,84 @@ +/** + * @file Sample.hpp + * @brief Defines Sample + * @author mill-j + * @date 04/28/2021 + * @copyright GNU GPL v3 + */ + +#include "Sample.hpp" + +///Default Constructor, Creates an empty sample profile +Sample::Sample(){} + +///Overloaded Constructor, Creates a sample profile with supplied data. @see Set() +Sample::Sample(int favorite, std::string filename, + std::string fileExtension, std::string samplePack, + std::string type, int channels, int length, + int sampleRate, int bitrate, std::string path, + int trashed) +{ + Set(favorite, filename, fileExtension, samplePack, type, + channels, length, sampleRate, bitrate, path, trashed); +} + + +///Clears all sample data; +void Sample::Clear() +{ + sFavorite = 0; + sFilename = ""; + sFileExtension = ""; + sSamplePack = ""; + sType = ""; + sChannels = 0; + sLength = 0; + sSampleRate = 0; + sBitrate = 0; + sPath = ""; + sTrashed = 0; +} + + +int Sample::GetFavorite(){return sFavorite;} +std::string Sample::GetFilename(){return sFilename;} +std::string Sample::GetFileExtension(){return sFileExtension;} +std::string Sample::GetSamplePack(){return sSamplePack;} +std::string Sample::GetType(){return sType;} +int Sample::GetChannels(){return sChannels;} +int Sample::GetLength(){return sLength;} +int Sample::GetSampleRate(){return sSampleRate;} +int Sample::GetBitrate(){return sBitrate;} +std::string Sample::GetPath(){return sPath;} +int Sample::GetTrashed (){return sTrashed;} + +void Sample::Set(int favorite, std::string filename, + std::string fileExtension, std::string samplePack, + std::string type, int channels, int length, + int sampleRate, int bitrate, std::string path, + int trashed) +{ + sFavorite = favorite; + sFilename = filename; + sFileExtension = fileExtension; + sSamplePack = samplePack; + sType = type; + sChannels = channels; + sLength = length; + sSampleRate = sampleRate; + sBitrate = bitrate; + sPath = path; + sTrashed = trashed; +} + +void Sample::SetFavorite(int favorite){sFavorite = favorite;} +void Sample::SetFilename(std::string filename){sFilename = filename;} +void Sample::SetFileExtension(std::string fileExtension){sFileExtension = fileExtension;} +void Sample::SetSamplePack(std::string samplePack){sSamplePack = samplePack;} +void Sample::SetType(std::string type){sType = type;} +void Sample::SetChannels(int channels){sChannels = channels;} +void Sample::SetLength(int length){sLength = length;} +void Sample::SetSampleRate(int sampleRate){sSampleRate = sampleRate;} +void Sample::SetBitrate(int bitrate){sBitrate = bitrate;} +void Sample::SetPath(std::string path){sPath = path;} +void Sample::SetTrashed (int trashed){sTrashed = trashed;} diff --git a/src/Sample.hpp b/src/Sample.hpp new file mode 100644 index 0000000..30da065 --- /dev/null +++ b/src/Sample.hpp @@ -0,0 +1,76 @@ +/** + * @file Sample.hpp + * @brief Declares Sample + * @author mill-j + * @date 04/28/2021 + * @copyright GNU GPL v3 + */ + +#ifndef _SAMPLE_HPP__ +#define _SAMPLE_HPP__ + +#include + + +/** + * @class Sample + * @brief This class holds data for one sample. + */ + +class Sample { + private: + int sFavorite = 0; + std::string sFilename = ""; + std::string sFileExtension = ""; + std::string sSamplePack = ""; + std::string sType = ""; + int sChannels = 0; + int sLength = 0; + int sSampleRate = 0; + int sBitrate = 0; + std::string sPath = ""; + int sTrashed = 0; + public: + Sample(); + + Sample(int favorite, std::string filename, + std::string fileExtension, std::string samplePack, + std::string type, int channels, int length, + int sampleRate, int bitrate, std::string path, + int trashed); + + void Clear(); + + int GetFavorite(); + std::string GetFilename(); + std::string GetFileExtension(); + std::string GetSamplePack(); + std::string GetType(); + int GetChannels(); + int GetLength(); + int GetSampleRate(); + int GetBitrate(); + std::string GetPath(); + int GetTrashed (); + + void Set(int favorite, std::string filename, + std::string fileExtension, std::string samplePack, + std::string type, int channels, int length, + int sampleRate, int bitrate, std::string path, + int trashed); + + void SetFavorite(int favorite); + void SetFilename(std::string filename); + void SetFileExtension(std::string fileExtension); + void SetSamplePack(std::string samplePack); + void SetType(std::string type); + void SetChannels(int channels); + void SetLength(int length); + void SetSampleRate(int sampleRate); + void SetBitrate(int bitrate); + void SetPath(std::string path); + void SetTrashed ( int trashed); + +}; + +#endif