AUP3: Several fixes

These mainly address the bugs that Steve reported and a couple
more I found along the way.

Corrected ProjectFileIO::GetMinMaxRMS() - It was still using the
original method of keep all block data in memory.  I missed it
when I redid everything.  Fixes his Amplify crash.

Temporary filenames should no longer be shown to the user.

Resaves will no longer present a Save As dialog.

Cleaned up duplicate pathname handling in ProjectFileIO.

Returned proper errors when loading a project
This commit is contained in:
Leland Lucius 2020-07-01 13:26:20 -05:00
parent 299710f0a9
commit 8ea07572c1
6 changed files with 324 additions and 173 deletions

View File

@ -53,6 +53,7 @@ static const char *ProjectFileSchema =
// One instance only.
"CREATE TABLE IF NOT EXISTS project"
"("
" id INTEGER PRIMARY KEY,"
" doc TEXT"
");"
""
@ -203,22 +204,25 @@ ProjectFileIO::~ProjectFileIO()
{
if (mDB)
{
// Save the filename since CloseDB() will clear it
wxString filename = mFileName;
// Not much we can do if this fails. The user will simply get
// the recovery dialog upon next restart.
if (CloseDB())
{
// Always remove the journal now that the DB is closed
wxRemoveFile(mDBPath + wxT("-journal"));
wxRemoveFile(filename + wxT("-journal"));
// At this point, we are shutting down cleanly and if the project file is
// still in the temp directory it means that the user has chosen not to
// save it. So, delete it.
if (mTemporary && !mDBPath.empty())
if (mTemporary)
{
wxFileName temp(FileNames::TempDir());
if (temp == wxPathOnly(mDBPath))
if (temp == wxPathOnly(filename))
{
wxRemoveFile(mDBPath);
wxRemoveFile(filename);
}
}
}
@ -238,6 +242,7 @@ sqlite3 *ProjectFileIO::DB()
sqlite3 *ProjectFileIO::OpenDB(FilePath fileName)
{
wxASSERT(mDB == nullptr);
bool temp = false;
if (fileName.empty())
{
@ -245,33 +250,30 @@ sqlite3 *ProjectFileIO::OpenDB(FilePath fileName)
if (fileName.empty())
{
fileName = FileNames::UnsavedProjectFileName();
mTemporary = true;
temp = true;
}
else
{
mTemporary = false;
temp = false;
}
}
int rc = sqlite3_open(fileName, &mDB);
if (rc != SQLITE_OK)
{
// AUD3 TODO COMPLAIN AND THROW - crash is inevitable otherwise
SetDBError(XO("Failed to open project file"));
return nullptr;
}
// AUD3 TODO get rid of the mDBPath?!?!?!?!
mDBPath = fileName;
mFileName = mDBPath;
if (!CheckVersion())
{
CloseDB();
// AUD3 TODO COMPLAIN AND THROW - crash is inevitable otherwise
return nullptr;
}
mTemporary = temp;
SetFileName(fileName);
return mDB;
}
@ -284,14 +286,15 @@ bool ProjectFileIO::CloseDB()
rc = sqlite3_close(mDB);
if (rc != SQLITE_OK)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mDB));
SetDBError(XO("Failed to close the project file"));
}
else
{
wxRemoveFile(mDBPath + wxT("-journal"));
wxRemoveFile(mFileName + wxT("-journal"));
}
mDB = nullptr;
SetFileName({});
}
return true;
@ -299,17 +302,21 @@ bool ProjectFileIO::CloseDB()
bool ProjectFileIO::DeleteDB()
{
if (!mDBPath.empty() && IsTemporary())
wxASSERT(mDB == nullptr);
if (mTemporary && !mFileName.empty())
{
wxFileName temp(FileNames::TempDir());
if (temp == wxPathOnly(mDBPath))
if (temp == wxPathOnly(mFileName))
{
if (!wxRemoveFile(mDBPath))
if (!wxRemoveFile(mFileName))
{
SetError(XO("Failed to close the project file"));
return false;
}
wxRemoveFile(mDBPath + wxT("-journal"));
wxRemoveFile(mFileName + wxT("-journal"));
}
}
@ -323,19 +330,19 @@ bool ProjectFileIO::CleanDB()
AutoSave();
wxString destpath = wxFileName::CreateTempFileName(mDBPath + ".xxxxx");
wxString destpath = wxFileName::CreateTempFileName(mFileName + ".xxxxx");
if (CopyTo(destpath))
{
if (CloseDB())
{
// This can be removed even if we fail below since the DB is closed
wxRemoveFile(mDBPath + wxT("-journal"));
wxRemoveFile(mFileName + wxT("-journal"));
wxString tmppath = wxFileName::CreateTempFileName(mDBPath + ".xxxxx");
if (wxRename(mDBPath, tmppath) == 0)
wxString tmppath = wxFileName::CreateTempFileName(mFileName + ".xxxxx");
if (wxRename(mFileName, tmppath) == 0)
{
if (wxRename(destpath, mDBPath) == 0)
if (wxRename(destpath, mFileName) == 0)
{
wxRemoveFile(tmppath);
@ -343,10 +350,18 @@ bool ProjectFileIO::CleanDB()
return true;
}
if (wxRename(tmppath, mDBPath) == 0)
if (wxRename(tmppath, mFileName) == 0)
{
wxRemoveFile(destpath);
}
else
{
SetError(XO("Could not rename %s back to %s during cleaning").Format(tmppath, mFileName));
}
}
else
{
SetError(XO("Could not rename %s during cleaning").Format(mFileName));
}
}
}
@ -371,7 +386,10 @@ int ProjectFileIO::Exec(const char *query, ExecCB callback, wxString *result)
if (errmsg)
{
mLastError.Format(XO("SQLite Error: %s"), wxString(errmsg));
SetDBError(
XO("Failed to execute a project file command:\n\n%s").Format(query)
);
mLibraryError = Verbatim(errmsg);
sqlite3_free(errmsg);
}
@ -396,8 +414,7 @@ wxString ProjectFileIO::GetValue(const char *sql)
int rc = Exec(sql, getresult, &value);
if (rc != SQLITE_OK)
{
wxLogDebug(wxT("%s"), mLastError.Debug());
// AUD TODO Handle error.
// Message already captured
}
return value;
@ -420,15 +437,18 @@ bool ProjectFileIO::GetBlob(const char *sql, wxMemoryBuffer &buffer)
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
if (rc != SQLITE_OK)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
// AUD TODO handle error
SetDBError(
XO("Unable to prepare project file command:\n\n%s").Format(sql)
);
return false;
}
rc = sqlite3_step(stmt);
if (rc != SQLITE_ROW)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
SetDBError(
XO("Failed to retrieve data from the project file.\nThe following command failed:\n\n%s").Format(sql)
);
// AUD TODO handle error
return false;
}
@ -449,30 +469,48 @@ bool ProjectFileIO::CheckVersion()
// Install our schema if this is an empty DB
long count = -1;
GetValue("SELECT Count(*) FROM sqlite_master WHERE type='table';").ToLong(&count);
if (count == -1)
{
return false;
}
// If the return count is zero, then there are no tables defined, so this
// must be a new project file.
if (count == 0)
{
return InstallSchema();
}
// Check for our application ID
long appid = 0;
long appid = -1;
GetValue("PRAGMA application_ID;").ToLong(&appid);
if (appid == -1)
{
return false;
}
// It's a database that SQLite recognizes, but it's not one of ours
if (appid != ProjectFileID)
{
mLastError = XO("This is not an Audacity AUP3 file");
SetError(XO("This is not an Audacity project file"));
return false;
}
// Get the project file version
long version;
long version = -1;
GetValue("PRAGMA user_version;").ToLong(&version);
if (version == -1)
{
return false;
}
// Project file version is higher than ours. We will refuse
// to process it since we can't trust anything about it.
// Project file version is higher than ours. We will refuse to
// process it since we can't trust anything about it.
if (version > ProjectFileVersion)
{
// AUD3 - complain about too new schema
// can't handle it!
SetError(
XO("This project was created with a newer version of Audacity:\n\nYou will need to upgrade to process it")
);
return false;
}
@ -502,7 +540,9 @@ bool ProjectFileIO::InstallSchema()
rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
if (rc != SQLITE_OK)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
SetDBError(
XO("Unable to initialize the project file")
);
return false;
}
@ -538,10 +578,12 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath)
{
int remaining = sqlite3_backup_remaining(backup);
int total = sqlite3_backup_pagecount(backup);
wxLogDebug(wxT("remaining %d total %d"), remaining, total);
if (progress.Update(total - remaining, total) != ProgressResult::Success)
{
SetError(
XO("Copy processs cancelled.")
);
success = false;
break;
}
@ -553,14 +595,26 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath)
rc = sqlite3_backup_finish(backup);
if (rc != SQLITE_OK)
{
SetDBError(
XO("The copy process failed for:\n\n%s").Format(destpath)
);
success = false;
}
}
else
{
SetDBError(
XO("Unable to initiate the backup process.")
);
}
// Close the DB
rc = sqlite3_close(destdb);
if (rc != SQLITE_OK)
{
SetDBError(
XO("Failed to successfully close the destination project file:\n\n%s")
);
success = false;
}
@ -574,6 +628,9 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath)
}
else
{
SetDBError(
XO("Unable to open the destination project file:\n\n%s").Format(destpath)
);
success = false;
}
@ -630,14 +687,14 @@ void ProjectFileIO::SetProjectTitle(int number)
const FilePath &ProjectFileIO::GetFileName() const
{
wxASSERT(mFileName == mDBPath);
return mFileName;
}
void ProjectFileIO::SetFileName(const FilePath &fileName)
{
mFileName = fileName;
if (mFileName.empty())
if (mTemporary)
{
mProject.SetProjectName({});
}
@ -649,34 +706,6 @@ void ProjectFileIO::SetFileName(const FilePath &fileName)
SetProjectTitle();
}
// Most of this string was duplicated 3 places. Made the warning consistent in this global.
// The %s is to be filled with the version string.
// PRL: Do not statically allocate a string in _() !
static TranslatableString gsLegacyFileWarning() { return
XO("This file was saved by Audacity version %s. The format has changed. \
\n\nAudacity can try to open and save this file, but saving it in this \
\nversion will then prevent any 1.2 or earlier version opening it. \
\n\nAudacity might corrupt the file in opening it, so you should \
back it up first. \
\n\nOpen this file now?");
}
bool ProjectFileIO::WarnOfLegacyFile( )
{
auto &project = mProject;
auto &window = GetProjectFrame( project );
auto msg = gsLegacyFileWarning().Format( XO("1.0 or earlier") );
// Stop icon, and choose 'NO' by default.
int action =
AudacityMessageBox(
msg,
XO("Warning - Opening Old Project File"),
wxYES_NO | wxICON_STOP | wxNO_DEFAULT | wxCENTRE,
&window);
return (action != wxNO);
}
bool ProjectFileIO::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
{
auto &project = mProject;
@ -798,12 +827,8 @@ bool ProjectFileIO::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
return false;
}
if (wxStrcmp(tag, wxT("audacityproject")) &&
wxStrcmp(tag, wxT("project")))
if (wxStrcmp(tag, wxT("project")))
{
// If the tag name is not one of these two (the NEW name is
// "project" with an Audacity namespace, but we don't detect
// the namespace yet), then we don't know what the error is
return false;
}
@ -924,8 +949,9 @@ bool ProjectFileIO::AutoSave(const AutoSaveFile &autosave)
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
if (rc != SQLITE_OK)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
// handle error
SetDBError(
XO("Unable to prepare project file command:\n\n%s").Format(sql)
);
return false;
}
@ -939,8 +965,9 @@ bool ProjectFileIO::AutoSave(const AutoSaveFile &autosave)
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
// handle error
SetDBError(
XO("Failed to update the project file.\nThe following command failed:\n\n%s").Format(sql)
);
return false;
}
@ -955,8 +982,9 @@ bool ProjectFileIO::AutoSaveDelete()
rc = sqlite3_exec(db, "DELETE FROM autosave;", nullptr, nullptr, nullptr);
if (rc != SQLITE_OK)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
// handle error
SetDBError(
XO("Failed to remove the autosave information from the project file.")
);
return false;
}
@ -965,8 +993,26 @@ bool ProjectFileIO::AutoSaveDelete()
bool ProjectFileIO::LoadProject(const FilePath &fileName)
{
bool success = false;
// OpenDB() will change mFileName if the file opens/verifies successfully,
// so we must set it back to what it was if any errors are encountered here.
wxString oldFilename = mFileName;
auto cleanup = finally([&]
{
if (!success)
{
CloseDB();
SetFileName(oldFilename);
}
});
// Open the project file
OpenDB(fileName);
if (!OpenDB(fileName))
{
return false;
}
// Get the XML document...either from the project or autosave
wxString doc;
@ -979,44 +1025,108 @@ bool ProjectFileIO::LoadProject(const FilePath &fileName)
doc = AutoSaveFile::Decode(buffer);
wasAutosave = true;
}
// Otherwise, get the project doc
else
{
// Get the project doc
doc = GetValue("SELECT doc FROM project;");
}
if (doc.empty())
{
// AUD3 fixme
wxLogDebug(wxT("%s"), mLastError.Translation());
// handle error
return false;
}
XMLFileReader xmlFile;
bool success = xmlFile.ParseString(this, doc);
success = xmlFile.ParseString(this, doc);
if (!success)
{
mLastError = xmlFile.GetErrorStr();
}
else
{
mRecovered = wasAutosave;
SetFileName(fileName);
SetProjectTitle();
SetError(
XO("Unable to parse project information.")
);
mLibraryError = xmlFile.GetErrorStr();
return false;
}
// Remember if it was recovered or not
mRecovered = wasAutosave;
if (mRecovered)
{
mModified = true;
}
return success;
// A previously saved project will have a document in the project table, so
// we use that knowledge to determine if this file is an unsaved/temporary
// file or not
long count = 0;
GetValue("SELECT Count(*) FROM project;").ToLong(&count);
mTemporary = (count != 1);
SetFileName(fileName);
return true;
}
bool ProjectFileIO::SaveProject(const FilePath &fileName)
{
wxString origName;
bool wasTemp = false;
bool success = false;
// Should probably simply all of the by using renames. But, one benefit
// of using CopyTo() for new file saves, is that it will be VACUUMED at
// the same time.
auto restore = finally([&]
{
if (!origName.empty())
{
if (success)
{
// The Save was successful, so remove the original file if
// it was a temporary file
if (wasTemp)
{
wxRemoveFile(origName);
}
}
else
{
// Close the new database
CloseDB();
// Reopen the original database
if (OpenDB(origName))
{
// And delete the new database
wxRemoveFile(fileName);
}
}
}
});
// If we're saving to a different file than the current one, then copy the
// current to the new file and make it the active file.
if (mFileName != fileName)
{
if (!CopyTo(fileName))
{
return false;
}
// Remember the original project filename and temporary status. Only do
// this after a successful copy so the "finally" block above doesn't monkey
// with the files.
origName = mFileName;
wasTemp = mTemporary;
// Close the original project file and open the new one
if (!CloseDB() || !OpenDB(fileName))
{
return false;
}
}
auto db = DB();
int rc;
@ -1024,68 +1134,51 @@ bool ProjectFileIO::SaveProject(const FilePath &fileName)
WriteXMLHeader(doc);
WriteXML(doc);
// Always use an ID of 1. This will replace any existing row.
char sql[256];
sqlite3_snprintf(sizeof(sql),
sql,
"REPLACE INTO project (doc) VALUES(?);");
"INSERT INTO project(id, doc) VALUES(1, ?1)"
" ON CONFLICT(id) DO UPDATE SET doc = ?1;");
sqlite3_stmt *stmt = nullptr;
auto cleanup = finally([&]
{
if (stmt)
{
sqlite3_finalize(stmt);
}
});
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
if (rc != SQLITE_OK)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
// handle error
SetDBError(
XO("Unable to prepare project file command:\n\n%s").Format(sql)
);
return false;
}
// BIND SQL project
sqlite3_bind_text(stmt, 1, doc, -1, SQLITE_STATIC);
rc = sqlite3_bind_text(stmt, 1, doc, -1, SQLITE_STATIC);
if (rc != SQLITE_OK)
{
SetDBError(
XO("Unable to bind to project file document.")
);
return false;
}
rc = sqlite3_step(stmt);
// This will free the statement
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
// handle error
SetDBError(
XO("Failed to save project file information.")
);
return false;
}
sqlite3_finalize(stmt);
stmt = nullptr;
if (mDBPath != fileName)
{
if (!CopyTo(fileName))
{
return false;
}
// Remember the original project filename
wxString origname = mDBPath;
// Close the original project file
CloseDB();
// Set the new filename
SetFileName(fileName);
// And open the new one
OpenDB(fileName);
// If the original project was temporary, then delete it now
if (mTemporary)
{
wxRemoveFile(origname);
}
}
// We need to remove the autosave info from the file since it is now
// clean and unmodified. Otherwise, it would be considered "recovered"
// when next opened.
AutoSaveDelete();
// No longer modified
@ -1100,6 +1193,9 @@ bool ProjectFileIO::SaveProject(const FilePath &fileName)
// Adjust the title
SetProjectTitle();
// Tell the finally block to behave
success = true;
return true;
}
@ -1126,7 +1222,6 @@ void ProjectFileIO::Reset()
mRecovered = false;
SetFileName({});
SetProjectTitle();
}
wxLongLong ProjectFileIO::GetFreeDiskSpace()
@ -1135,7 +1230,7 @@ wxLongLong ProjectFileIO::GetFreeDiskSpace()
auto db = DB();
wxLongLong freeSpace;
if (wxGetDiskSpace(wxPathOnly(mDBPath), NULL, &freeSpace))
if (wxGetDiskSpace(wxPathOnly(mFileName), NULL, &freeSpace))
{
return freeSpace;
}
@ -1148,3 +1243,22 @@ const TranslatableString & ProjectFileIO::GetLastError() const
return mLastError;
}
const TranslatableString & ProjectFileIO::GetLibraryError() const
{
return mLastError;
}
void ProjectFileIO::SetError(const TranslatableString & msg)
{
mLastError = msg;
mLibraryError = {};
}
void ProjectFileIO::SetDBError(const TranslatableString & msg)
{
mLastError = msg;
if (mDB)
{
mLibraryError = Verbatim(sqlite3_errmsg(mDB));
}
}

View File

@ -71,6 +71,7 @@ public:
wxLongLong GetFreeDiskSpace();
const TranslatableString & GetLastError() const;
const TranslatableString & GetLibraryError() const;
private:
// XMLTagHandler callback methods
@ -103,6 +104,9 @@ private:
bool CopyTo(const FilePath &destpath);
void SetError(const TranslatableString & msg);
void SetDBError(const TranslatableString & msg);
private:
// non-static data members
AudacityProject &mProject;
@ -122,6 +126,7 @@ private:
sqlite3 *mDB;
FilePath mDBPath;
TranslatableString mLastError;
TranslatableString mLibraryError;
friend SampleBlock;
};

View File

@ -144,6 +144,16 @@ auto ProjectFileManager::ReadProjectFile( const FilePath &fileName )
if (bParseSuccess)
{
if (projectFileIO.IsRecovered())
{
AudacityMessageBox(
XO("This project was not saved properly the last time Audacity ran.\n\n"
"It has been recovered to the last snapshot."),
XO("Project Recovered"),
wxICON_WARNING,
&window);
}
// By making a duplicate set of pointers to the existing blocks
// on disk, we add one to their reference count, guaranteeing
// that their reference counts will never reach zero and thus
@ -168,10 +178,12 @@ auto ProjectFileManager::ReadProjectFile( const FilePath &fileName )
}
}
// AUD3 - FIXME - error messages - needed?????
return {
false, bParseSuccess, err, projectFileIO.GetLastError(),
FindHelpUrl( projectFileIO.GetLastError() )
return
{
bParseSuccess,
err,
projectFileIO.GetLastError(),
FindHelpUrl(projectFileIO.GetLibraryError())
};
}
@ -180,7 +192,7 @@ bool ProjectFileManager::Save()
auto &projectFileIO = ProjectFileIO::Get(mProject);
// Prompt for file name?
if (projectFileIO.IsModified())
if (projectFileIO.IsTemporary())
{
return SaveAs();
}
@ -229,8 +241,6 @@ bool ProjectFileManager::DoSave(const FilePath & fileName, const bool fromSaveAs
auto &projectFileIO = ProjectFileIO::Get( proj );
const auto &settings = ProjectSettings::Get( proj );
wxASSERT_MSG(fromSaveAs, "Copy Project SHOULD only be available from SaveAs");
// Some confirmation dialogs
{
auto &tracks = TrackList::Get( proj );
@ -363,11 +373,13 @@ bool ProjectFileManager::SaveAs()
auto &window = GetProjectFrame( project );
TitleRestorer Restorer( window, project ); // RAII
bool bHasPath = true;
wxFileName filename{ projectFileIO.GetFileName() };
wxString name = project.GetProjectName();
if (!name.empty()) {
filename.SetName(name);
wxFileName filename;
if (projectFileIO.IsTemporary()) {
filename = FileNames::DefaultToDocumentsFolder(wxT("/SaveAs/Path"));
}
else {
filename = projectFileIO.GetFileName();
}
// Bug 1304: Set a default file path if none was given. For Save/SaveAs
@ -789,10 +801,7 @@ void ProjectFileManager::OpenFile(const FilePath &fileNameArg, bool addtohistory
}
auto results = ReadProjectFile( fileName );
if ( results.decodeError )
return;
const bool bParseSuccess = results.parseSuccess;
const auto &errorStr = results.errorString;
const bool err = results.trackError;

View File

@ -43,7 +43,6 @@ public:
struct ReadProjectResults
{
bool decodeError;
bool parseSuccess;
bool trackError;
const TranslatableString errorString;

View File

@ -295,18 +295,32 @@ double SampleBlock::GetSumRms() const
///
/// @param start The offset in this block where the region should begin
/// @param len The number of samples to include in the region
MinMaxRMS SampleBlock::GetMinMaxRMS(size_t start, size_t len) const
MinMaxRMS SampleBlock::GetMinMaxRMS(size_t start, size_t len)
{
float min = FLT_MAX;
float max = -FLT_MAX;
float sumsq = 0;
if (mValid && start < mSampleCount)
if (!mValid && mBlockID)
{
Load(mBlockID);
}
if (start < mSampleCount)
{
float *samples = &((float *) mSamples.get())[start];
len = std::min(len, mSampleCount - start);
for (int i = 0; i < len; ++i, ++samples)
// TODO: actually use summaries
SampleBuffer blockData(len, floatSample);
float *samples = (float *) blockData.ptr();
size_t copied = GetBlob(samples,
floatSample,
"samples",
mSampleFormat,
start * SAMPLE_SIZE(mSampleFormat),
len * SAMPLE_SIZE(mSampleFormat)) / SAMPLE_SIZE(mSampleFormat);
for (size_t i = 0; i < copied; ++i, ++samples)
{
float sample = *samples;
@ -347,6 +361,8 @@ size_t SampleBlock::GetBlob(void *dest,
size_t srcoffset,
size_t srcbytes)
{
auto db = mIO.DB();
wxASSERT(mBlockID > 0);
if (!mValid && mBlockID)
@ -373,17 +389,17 @@ size_t SampleBlock::GetBlob(void *dest,
}
});
rc = sqlite3_prepare_v2(mIO.DB(), sql, -1, &stmt, 0);
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
if (rc != SQLITE_OK)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
}
else
{
rc = sqlite3_step(stmt);
if (rc != SQLITE_ROW)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
}
else
{
@ -417,6 +433,8 @@ size_t SampleBlock::GetBlob(void *dest,
bool SampleBlock::Load(SampleBlockID sbid)
{
auto db = mIO.DB();
wxASSERT(sbid > 0);
int rc;
@ -426,6 +444,9 @@ bool SampleBlock::Load(SampleBlockID sbid)
mSummary64kBytes = 0;
mSampleCount = 0;
mSampleBytes = 0;
mSumMin = FLT_MAX;
mSumMax = -FLT_MAX;
mSumMin = 0.0;
char sql[256];
sqlite3_snprintf(sizeof(sql),
@ -444,10 +465,10 @@ bool SampleBlock::Load(SampleBlockID sbid)
}
});
rc = sqlite3_prepare_v2(mIO.DB(), sql, -1, &stmt, 0);
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
if (rc != SQLITE_OK)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
// handle error
return false;
}
@ -455,7 +476,7 @@ bool SampleBlock::Load(SampleBlockID sbid)
rc = sqlite3_step(stmt);
if (rc != SQLITE_ROW)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
// handle error
return false;
}
@ -477,6 +498,7 @@ bool SampleBlock::Load(SampleBlockID sbid)
bool SampleBlock::Commit()
{
auto db = mIO.DB();
int rc;
char sql[256];
@ -494,10 +516,10 @@ bool SampleBlock::Commit()
}
});
rc = sqlite3_prepare_v2(mIO.DB(), sql, -1, &stmt, 0);
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
if (rc != SQLITE_OK)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
// handle error
return false;
}
@ -514,12 +536,12 @@ bool SampleBlock::Commit()
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
// handle error
return false;
}
mBlockID = sqlite3_last_insert_rowid(mIO.DB());
mBlockID = sqlite3_last_insert_rowid(db);
mSamples.reset();
mSummary256.reset();
@ -532,6 +554,8 @@ bool SampleBlock::Commit()
void SampleBlock::Delete()
{
auto db = mIO.DB();
if (mBlockID)
{
int rc;
@ -542,10 +566,10 @@ void SampleBlock::Delete()
"DELETE FROM sampleblocks WHERE blockid = %lld;",
mBlockID);
rc = sqlite3_exec(mIO.DB(), sql, nullptr, nullptr, nullptr);
rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
if (rc != SQLITE_OK)
{
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
// handle error
return;
}

View File

@ -79,7 +79,7 @@ public:
double GetSumRms() const;
/// Gets extreme values for the specified region
MinMaxRMS GetMinMaxRMS(size_t start, size_t len) const;
MinMaxRMS GetMinMaxRMS(size_t start, size_t len);
/// Gets extreme values for the entire block
MinMaxRMS GetMinMaxRMS() const;