aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xbmc/dbwrappers/sqlitedataset.cpp217
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoHelper.cpp6
-rw-r--r--xbmc/pvr/addons/PVRClients.cpp7
3 files changed, 174 insertions, 56 deletions
diff --git a/xbmc/dbwrappers/sqlitedataset.cpp b/xbmc/dbwrappers/sqlitedataset.cpp
index f0b11d4b79..45592f320a 100644
--- a/xbmc/dbwrappers/sqlitedataset.cpp
+++ b/xbmc/dbwrappers/sqlitedataset.cpp
@@ -11,7 +11,9 @@
*/
#include <iostream>
+#include <map>
#include <string>
+#include <sstream>
#include "sqlitedataset.h"
#include "utils/log.h"
@@ -21,6 +23,137 @@
#include "platform/linux/XTimeUtils.h"
#endif
+namespace {
+#define X(VAL) std::make_pair(VAL, #VAL)
+//!@todo Remove ifdefs when sqlite version requirement has been bumped to at least 3.26.0
+const std::map<int, const char*> g_SqliteErrorStrings =
+{
+ X(SQLITE_OK),
+ X(SQLITE_ERROR),
+ X(SQLITE_INTERNAL),
+ X(SQLITE_PERM),
+ X(SQLITE_ABORT),
+ X(SQLITE_BUSY),
+ X(SQLITE_LOCKED),
+ X(SQLITE_NOMEM),
+ X(SQLITE_READONLY),
+ X(SQLITE_INTERRUPT),
+ X(SQLITE_IOERR),
+ X(SQLITE_CORRUPT),
+ X(SQLITE_NOTFOUND),
+ X(SQLITE_FULL),
+ X(SQLITE_CANTOPEN),
+ X(SQLITE_PROTOCOL),
+ X(SQLITE_EMPTY),
+ X(SQLITE_SCHEMA),
+ X(SQLITE_TOOBIG),
+ X(SQLITE_CONSTRAINT),
+ X(SQLITE_MISMATCH),
+ X(SQLITE_MISUSE),
+ X(SQLITE_NOLFS),
+ X(SQLITE_AUTH),
+ X(SQLITE_FORMAT),
+ X(SQLITE_RANGE),
+ X(SQLITE_NOTADB),
+ X(SQLITE_NOTICE),
+ X(SQLITE_WARNING),
+ X(SQLITE_ROW),
+ X(SQLITE_DONE),
+#if defined(SQLITE_ERROR_MISSING_COLLSEQ)
+ X(SQLITE_ERROR_MISSING_COLLSEQ),
+#endif
+#if defined(SQLITE_ERROR_RETRY)
+ X(SQLITE_ERROR_RETRY),
+#endif
+#if defined(SQLITE_ERROR_SNAPSHOT)
+ X(SQLITE_ERROR_SNAPSHOT),
+#endif
+ X(SQLITE_IOERR_READ),
+ X(SQLITE_IOERR_SHORT_READ),
+ X(SQLITE_IOERR_WRITE),
+ X(SQLITE_IOERR_FSYNC),
+ X(SQLITE_IOERR_DIR_FSYNC),
+ X(SQLITE_IOERR_TRUNCATE),
+ X(SQLITE_IOERR_FSTAT),
+ X(SQLITE_IOERR_UNLOCK),
+ X(SQLITE_IOERR_RDLOCK),
+ X(SQLITE_IOERR_DELETE),
+ X(SQLITE_IOERR_BLOCKED),
+ X(SQLITE_IOERR_NOMEM),
+ X(SQLITE_IOERR_ACCESS),
+ X(SQLITE_IOERR_CHECKRESERVEDLOCK),
+ X(SQLITE_IOERR_LOCK),
+ X(SQLITE_IOERR_CLOSE),
+ X(SQLITE_IOERR_DIR_CLOSE),
+ X(SQLITE_IOERR_SHMOPEN),
+ X(SQLITE_IOERR_SHMSIZE),
+ X(SQLITE_IOERR_SHMLOCK),
+ X(SQLITE_IOERR_SHMMAP),
+ X(SQLITE_IOERR_SEEK),
+ X(SQLITE_IOERR_DELETE_NOENT),
+ X(SQLITE_IOERR_MMAP),
+ X(SQLITE_IOERR_GETTEMPPATH),
+ X(SQLITE_IOERR_CONVPATH),
+ X(SQLITE_IOERR_VNODE),
+ X(SQLITE_IOERR_AUTH),
+#if defined(SQLITE_IOERR_BEGIN_ATOMIC)
+ X(SQLITE_IOERR_BEGIN_ATOMIC),
+#endif
+#if defined(SQLITE_IOERR_COMMIT_ATOMIC)
+ X(SQLITE_IOERR_COMMIT_ATOMIC),
+#endif
+#if defined(SQLITE_IOERR_ROLLBACK_ATOMIC)
+ X(SQLITE_IOERR_ROLLBACK_ATOMIC),
+#endif
+ X(SQLITE_LOCKED_SHAREDCACHE),
+#if defined(SQLITE_LOCKED_VTAB)
+ X(SQLITE_LOCKED_VTAB),
+#endif
+ X(SQLITE_BUSY_RECOVERY),
+ X(SQLITE_BUSY_SNAPSHOT),
+ X(SQLITE_CANTOPEN_NOTEMPDIR),
+ X(SQLITE_CANTOPEN_ISDIR),
+ X(SQLITE_CANTOPEN_FULLPATH),
+ X(SQLITE_CANTOPEN_CONVPATH),
+#if defined(SQLITE_CANTOPEN_DIRTYWAL)
+ X(SQLITE_CANTOPEN_DIRTYWAL),
+#endif
+ X(SQLITE_CORRUPT_VTAB),
+#if defined(SQLITE_CORRUPT_SEQUENCE)
+ X(SQLITE_CORRUPT_SEQUENCE),
+#endif
+ X(SQLITE_READONLY_RECOVERY),
+ X(SQLITE_READONLY_CANTLOCK),
+ X(SQLITE_READONLY_ROLLBACK),
+ X(SQLITE_READONLY_DBMOVED),
+#if defined(SQLITE_READONLY_CANTINIT)
+ X(SQLITE_READONLY_CANTINIT),
+#endif
+#if defined(SQLITE_READONLY_DIRECTORY)
+ X(SQLITE_READONLY_DIRECTORY),
+#endif
+ X(SQLITE_ABORT_ROLLBACK),
+ X(SQLITE_CONSTRAINT_CHECK),
+ X(SQLITE_CONSTRAINT_COMMITHOOK),
+ X(SQLITE_CONSTRAINT_FOREIGNKEY),
+ X(SQLITE_CONSTRAINT_FUNCTION),
+ X(SQLITE_CONSTRAINT_NOTNULL),
+ X(SQLITE_CONSTRAINT_PRIMARYKEY),
+ X(SQLITE_CONSTRAINT_TRIGGER),
+ X(SQLITE_CONSTRAINT_UNIQUE),
+ X(SQLITE_CONSTRAINT_VTAB),
+ X(SQLITE_CONSTRAINT_ROWID),
+ X(SQLITE_NOTICE_RECOVER_WAL),
+ X(SQLITE_NOTICE_RECOVER_ROLLBACK),
+ X(SQLITE_WARNING_AUTOINDEX),
+ X(SQLITE_AUTH_USER),
+#if defined(SQLITE_OK_LOAD_PERMANENTLY)
+ X(SQLITE_OK_LOAD_PERMANENTLY),
+#endif
+};
+#undef X
+}
+
namespace dbiplus {
//************* Callback function ***************************
@@ -129,56 +262,19 @@ int SqliteDatabase::status(void) {
return DB_CONNECTION_OK;
}
-int SqliteDatabase::setErr(int err_code, const char * qry){
- switch (err_code) {
- case SQLITE_OK: error ="Successful result";
- break;
- case SQLITE_ERROR: error = "SQL error or missing database";
- break;
- case SQLITE_INTERNAL: error = "An internal logic error in SQLite";
- break;
- case SQLITE_PERM: error ="Access permission denied";
- break;
- case SQLITE_ABORT: error = "Callback routine requested an abort";
- break;
- case SQLITE_BUSY: error = "The database file is locked";
- break;
- case SQLITE_LOCKED: error = "A table in the database is locked";
- break;
- case SQLITE_NOMEM: error = "A malloc() failed";
- break;
- case SQLITE_READONLY: error = "Attempt to write a readonly database";
- break;
- case SQLITE_INTERRUPT: error = "Operation terminated by sqlite_interrupt()";
- break;
- case SQLITE_IOERR: error = "Some kind of disk I/O error occurred";
- break;
- case SQLITE_CORRUPT: error = "The database disk image is malformed";
- break;
- case SQLITE_NOTFOUND: error = "(Internal Only) Table or record not found";
- break;
- case SQLITE_FULL: error = "Insertion failed because database is full";
- break;
- case SQLITE_CANTOPEN: error = "Unable to open the database file";
- break;
- case SQLITE_PROTOCOL: error = "Database lock protocol error";
- break;
- case SQLITE_EMPTY: error = "(Internal Only) Database table is empty";
- break;
- case SQLITE_SCHEMA: error = "The database schema changed";
- break;
- case SQLITE_TOOBIG: error = "Too much data for one row of a table";
- break;
- case SQLITE_CONSTRAINT: error = "Abort due to constraint violation";
- break;
- case SQLITE_MISMATCH: error = "Data type mismatch";
- break;
- default : error = "Undefined SQLite error";
- }
- error = "[" + db + "] " + error;
- error += "\nQuery: ";
- error += qry;
- error += "\n";
+int SqliteDatabase::setErr(int err_code, const char * qry) {
+ std::stringstream ss;
+ ss << "[" << db << "] ";
+ auto errorIt = g_SqliteErrorStrings.find(err_code);
+ if (errorIt != g_SqliteErrorStrings.end()) {
+ ss << "SQLite error " << errorIt->second;
+ } else {
+ ss << "Undefined SQLite error " << err_code;
+ }
+ if (conn)
+ ss << " (" << sqlite3_errmsg(conn) << ")";
+ ss << "\nQuery: " << qry;
+ error = ss.str();
return err_code;
}
@@ -208,11 +304,12 @@ int SqliteDatabase::connect(bool create) {
}
else if (errorCode == SQLITE_OK)
{
+ sqlite3_extended_result_codes(conn, 1);
sqlite3_busy_handler(conn, busy_callback, NULL);
char* err=NULL;
if (setErr(sqlite3_exec(getHandle(),"PRAGMA empty_result_callbacks=ON",NULL,NULL,&err),"PRAGMA empty_result_callbacks=ON") != SQLITE_OK)
{
- throw DbErrors(getErrorMsg());
+ throw DbErrors("%s", getErrorMsg());
}
else if (sqlite3_db_readonly(conn, nullptr) == 1)
{
@@ -523,7 +620,14 @@ void SqliteDataset::make_query(StringList &_sql) {
char* err=NULL;
Dataset::parse_sql(query);
if (db->setErr(sqlite3_exec(this->handle(),query.c_str(),NULL,NULL,&err),query.c_str())!=SQLITE_OK) {
- throw DbErrors(db->getErrorMsg());
+ std::string message = db->getErrorMsg();
+ if (err) {
+ message.append(" (");
+ message.append(err);
+ message.append(")");
+ sqlite3_free(err);
+ }
+ throw DbErrors("%s", message.c_str());
}
} // end of for
@@ -651,7 +755,10 @@ int SqliteDataset::exec(const std::string &sql) {
return res;
else
{
- throw DbErrors(db->getErrorMsg());
+ if (errmsg)
+ throw DbErrors("%s (%s)", db->getErrorMsg(), errmsg);
+ else
+ throw DbErrors("%s", db->getErrorMsg());
}
}
@@ -676,7 +783,7 @@ bool SqliteDataset::query(const std::string &query) {
sqlite3_stmt *stmt = NULL;
if (db->setErr(sqlite3_prepare_v2(handle(),query.c_str(),-1,&stmt, NULL),query.c_str()) != SQLITE_OK)
- throw DbErrors(db->getErrorMsg());
+ throw DbErrors("%s", db->getErrorMsg());
// column headers
const unsigned int numColumns = sqlite3_column_count(stmt);
@@ -724,7 +831,7 @@ bool SqliteDataset::query(const std::string &query) {
}
else
{
- throw DbErrors(db->getErrorMsg());
+ throw DbErrors("%s", db->getErrorMsg());
}
}
diff --git a/xbmc/guilib/guiinfo/GUIInfoHelper.cpp b/xbmc/guilib/guiinfo/GUIInfoHelper.cpp
index afd07a094f..92cca9ac44 100644
--- a/xbmc/guilib/guiinfo/GUIInfoHelper.cpp
+++ b/xbmc/guilib/guiinfo/GUIInfoHelper.cpp
@@ -163,7 +163,11 @@ CGUIListItemPtr GetCurrentListItem(int contextWindow, int containerId /* = 0 */,
{
CGUIListItemPtr item;
- if (containerId == 0 && itemOffset == 0 && !(itemFlags & INFOFLAG_LISTITEM_CONTAINER))
+ if (containerId == 0 &&
+ itemOffset == 0 &&
+ !(itemFlags & INFOFLAG_LISTITEM_CONTAINER) &&
+ !(itemFlags & INFOFLAG_LISTITEM_ABSOLUTE) &&
+ !(itemFlags & INFOFLAG_LISTITEM_POSITION))
item = GetCurrentListItemFromWindow(contextWindow);
if (!item)
diff --git a/xbmc/pvr/addons/PVRClients.cpp b/xbmc/pvr/addons/PVRClients.cpp
index 34d7f54ef5..36dd2717d8 100644
--- a/xbmc/pvr/addons/PVRClients.cpp
+++ b/xbmc/pvr/addons/PVRClients.cpp
@@ -596,6 +596,13 @@ void CPVRClients::ConnectionStateChange(
{
case PVR_CONNECTION_STATE_SERVER_UNREACHABLE:
iMsg = 35505; // Server is unreachable
+ if (client->GetPreviousConnectionState() == PVR_CONNECTION_STATE_UNKNOWN ||
+ client->GetPreviousConnectionState() == PVR_CONNECTION_STATE_CONNECTING)
+ {
+ // Make our users happy. There were so many complaints about this notification because their TV backend
+ // was not up quick enough after Kodi start. So, ignore the very first 'server not reachable' notification.
+ bNotify = false;
+ }
break;
case PVR_CONNECTION_STATE_SERVER_MISMATCH:
iMsg = 35506; // Server does not respond properly