Sqlite3 optimizations

This commit is contained in:
Mill J 2021-05-19 23:38:35 +00:00 committed by Apoorv
parent 2c0c85e442
commit a16121aeb0
7 changed files with 337 additions and 148 deletions

View File

@ -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'])

View File

@ -73,12 +73,8 @@ 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)
{
///Loops through a Sample array and adds them to the database
void Database::InsertSamples(std::vector<Sample> 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);
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++)
{
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, 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, 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, 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_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);
if (rc != SQLITE_DONE)
{
wxLogDebug("No data inserted. Error code: %d: Msg: %s", rc , sqlite3_errmsg(m_Database));
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<wxVector<wxVariant>>& 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);
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)
if (sqlite3_step(m_Stmt) != SQLITE_ROW)
{
wxLogInfo("Record found, fetching..");
sample = std::string(reinterpret_cast<const char*>(sqlite3_column_text(m_Stmt, 0)));
haveSample = true;
sorted_files.push_back(files[i]);
}
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.");
rc = sqlite3_clear_bindings(m_Stmt);
rc = sqlite3_reset(m_Stmt);
}
sqlite3_finalize(m_Stmt);
sqlite3_close(m_Database);
return haveSample;
}
catch (const std::exception &exception)
{
wxLogDebug(exception.what());
}
return false;
return sorted_files;
}
bool Database::IsTrashed(const std::string& filename)

View File

@ -1,5 +1,6 @@
#include <mutex>
#include <string>
#include <vector>
#include <iostream>
#include <wx/infobar.h>
#include <wx/treebase.h>
@ -9,6 +10,8 @@
#include <sqlite3.h>
#include "Sample.hpp"
class Database
{
public:
@ -32,11 +35,7 @@ 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<Sample>);
// -------------------------------------------------------------------
// Update database
@ -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

View File

@ -29,6 +29,7 @@
#include "Tags.hpp"
// #include "TreeItemDialog.hpp"
#include "Serialize.hpp"
#include "Sample.hpp"
#include <wx/fswatcher.h>
@ -348,28 +349,69 @@ 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);
std::string path = file.ToStdString();
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::string filename_with_extension = file.AfterLast('/').ToStdString();
std::string filename_without_extension = file.AfterLast('/').BeforeLast('.').ToStdString();
std::string extension = file.AfterLast('.').ToStdString();
std::vector<Sample> sample_array;
std::string path;
std::string artist;
std::string filename_with_extension;
std::string filename_without_extension;
std::string extension;
std::string filename;
std::string filename = settings.IsShowFileExtension() ?
filename_with_extension : filename_without_extension;
//Check All Files At Once
wxArrayString sorted_files;
sorted_files = db.CheckDuplicates(files);
files = sorted_files;
if(files.size() < 1) {
progressDialog->Destroy();
return;
}
progressDialog->SetRange(files.size());
for(unsigned int i = 0; i < files.size(); i++)
{
progressDialog->Update(i, wxString::Format("Getting Data For %s", files[i].AfterLast('/')));
if(progressDialog->WasCancelled())
{
progressDialog->Destroy();
return;
}
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();
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;
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<wxVariant> data;
@ -377,46 +419,49 @@ void MainFrame::AddSamples(wxString file)
{
data.clear();
data.push_back(false);
if(settings.IsShowFileExtension())
data.push_back(filename_with_extension);
else
data.push_back(filename);
data.push_back(artist);
data.push_back(sample_object.GetSamplePack());
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));
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("Adding file: %s :: Extension: %s", filename, extension);
wxLogDebug("Will Add file: %s :: Extension: %s", sample_object.GetFilename(), sample_object.GetFileExtension());
if (!db.HasSample(filename_without_extension))
{
m_SampleListView->AppendItem(data);
db.InsertSample(0, filename_without_extension, extension, artist,
"", channels, length, sample_rate, bitrate,
path, 0);
sample_array.push_back(sample_object);
}
else
{
wxString msg = wxString::Format("%s already exists.", file.AfterLast('/'));
m_InfoBar->ShowMessage(msg, wxICON_INFORMATION);
}
}
else
{
wxString msg = wxString::Format("Error! Cannot open %s, Invalid file type.", filename);
wxString msg = wxString::Format("Error! Cannot open %s, Invalid file type.", sample_object.GetFilename());
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();
wxArrayString path;
path.push_back(m_DirCtrl->GetFilePath());
MainFrame::AddSamples(path);
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)

View File

@ -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();

84
src/Sample.cpp Normal file
View File

@ -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;}

76
src/Sample.hpp Normal file
View File

@ -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 <string>
/**
* @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