mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-20 19:11:39 -06:00
Make strings translatable, remove some more debug code, fix tests, reduce size of patch slightly, remove weird tooltip, don't crash when closing database, simplify code, fix filters, don't link agains pthread on Windows.
224 lines
8.7 KiB
C++
224 lines
8.7 KiB
C++
#ifndef SQLITEDB_H
|
|
#define SQLITEDB_H
|
|
|
|
#include "sqlitetypes.h"
|
|
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <condition_variable>
|
|
|
|
#include <QStringList>
|
|
#include <QMultiMap>
|
|
#include <QByteArray>
|
|
|
|
struct sqlite3;
|
|
class CipherDialog;
|
|
|
|
enum
|
|
{
|
|
kLogMsg_User,
|
|
kLogMsg_App
|
|
};
|
|
|
|
typedef QMultiMap<QString, sqlb::ObjectPtr> objectMap; // Maps from object type (table, index, view, trigger) to a pointer to the object representation
|
|
typedef QMap<QString, objectMap> schemaMap; // Maps from the schema name (main, temp, attached schemas) to the object map for that schema
|
|
|
|
int collCompare(void* pArg, int sizeA, const void* sA, int sizeB, const void* sB);
|
|
|
|
/// represents a single SQLite database. except when noted otherwise,
|
|
/// all member functions are to be called from the main UI thread
|
|
/// only.
|
|
class DBBrowserDB : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private:
|
|
/// custom unique_ptr deleter releases database for further use by others
|
|
struct DatabaseReleaser
|
|
{
|
|
DatabaseReleaser(DBBrowserDB * pParent_ = nullptr) : pParent(pParent_) {}
|
|
|
|
DBBrowserDB * pParent;
|
|
|
|
void operator() (sqlite3 * db) const
|
|
{
|
|
if(!db || !pParent)
|
|
return;
|
|
|
|
std::unique_lock<std::mutex> lk(pParent->m);
|
|
pParent->db_used = false;
|
|
lk.unlock();
|
|
pParent->cv.notify_one();
|
|
}
|
|
};
|
|
|
|
public:
|
|
explicit DBBrowserDB () : _db(nullptr), db_used(false), isEncrypted(false), isReadOnly(false), dontCheckForStructureUpdates(false) {}
|
|
virtual ~DBBrowserDB (){}
|
|
|
|
bool open(const QString& db, bool readOnly = false);
|
|
bool attach(const QString& filename, QString attach_as = "");
|
|
bool create ( const QString & db);
|
|
bool close();
|
|
|
|
typedef std::unique_ptr<sqlite3, DatabaseReleaser> db_pointer_type;
|
|
|
|
/**
|
|
borrow exclusive address to the currently open database, until
|
|
releasing the returned unique_ptr.
|
|
|
|
the intended use case is that the main UI thread can call this
|
|
any time, and then optionally pass the obtained pointer to a
|
|
background worker, or release it after doing work immediately.
|
|
|
|
if database is currently used by somebody else, opens a dialog
|
|
box and gives user the opportunity to sqlite3_interrupt() the
|
|
operation of the current owner, then tries again.
|
|
|
|
\param user a string that identifies the new user, and which
|
|
can be displayed in the dialog box.
|
|
|
|
\returns a unique_ptr containing the SQLite database handle, or
|
|
nullptr in case no database is open.
|
|
**/
|
|
db_pointer_type get (QString user);
|
|
|
|
bool setSavepoint(const QString& pointname = "RESTOREPOINT");
|
|
bool releaseSavepoint(const QString& pointname = "RESTOREPOINT");
|
|
bool revertToSavepoint(const QString& pointname = "RESTOREPOINT");
|
|
bool releaseAllSavepoints();
|
|
bool revertAll();
|
|
bool dump(const QString& filename, const QStringList& tablesToDump, bool insertColNames, bool insertNew, bool exportSchema, bool exportData, bool keepOldSchema);
|
|
bool executeSQL(QString statement, bool dirtyDB = true, bool logsql = true);
|
|
bool executeMultiSQL(const QString& statement, bool dirty = true, bool log = false);
|
|
const QString& lastError() const { return lastErrorMessage; }
|
|
|
|
/**
|
|
* @brief getRow Executes a sqlite statement to get the rowdata(columns)
|
|
* for the given rowid.
|
|
* @param schemaName Name of the database schema.
|
|
* @param sTableName Table to query.
|
|
* @param rowid The rowid to fetch.
|
|
* @param rowdata A list of QByteArray containing the row data.
|
|
* @return true if statement execution was ok, else false.
|
|
*/
|
|
bool getRow(const sqlb::ObjectIdentifier& table, const QString& rowid, QVector<QByteArray>& rowdata);
|
|
|
|
private:
|
|
/**
|
|
* @brief max Queries the table t for the max value of field.
|
|
* @param tableName Table to query
|
|
* @param field Field to get the max value
|
|
* @return the max value of the field or 0 on error
|
|
*/
|
|
QString max(const sqlb::ObjectIdentifier& tableName, sqlb::FieldPtr field) const;
|
|
|
|
public:
|
|
void updateSchema();
|
|
|
|
private:
|
|
/**
|
|
* @brief Creates an empty insert statement.
|
|
* @param schemaName The name of the database schema in which to find the table
|
|
* @param pk_value This optional parameter can be used to manually set a specific value for the primary key column
|
|
* @return An sqlite conform INSERT INTO statement with empty values. (NULL,'',0)
|
|
*/
|
|
QString emptyInsertStmt(const QString& schemaName, const sqlb::Table& t, const QString& pk_value = QString()) const;
|
|
|
|
public:
|
|
QString addRecord(const sqlb::ObjectIdentifier& tablename);
|
|
bool deleteRecords(const sqlb::ObjectIdentifier& table, const QStringList& rowids, const QString& pseudo_pk = QString());
|
|
bool updateRecord(const sqlb::ObjectIdentifier& table, const QString& column, const QString& rowid, const QByteArray& value, bool itsBlob, const QString& pseudo_pk = QString());
|
|
|
|
bool createTable(const sqlb::ObjectIdentifier& name, const sqlb::FieldVector& structure);
|
|
bool renameTable(const QString& schema, const QString& from_table, const QString& to_table);
|
|
bool addColumn(const sqlb::ObjectIdentifier& tablename, const sqlb::FieldPtr& field);
|
|
|
|
/**
|
|
* @brief alterTable Can be used to rename, modify or drop an existing column of a given table
|
|
* @param schema Specifies the name of the schema, i.e. the database name, of the table
|
|
* @param tablename Specifies the name of the table to edit
|
|
* @param table Specifies the table to edit. The table constraints are used from this but not the columns
|
|
* @param name Name of the column to edit
|
|
* @param to The new field definition with changed name, type or the like. If Null-Pointer is given the column is dropped.
|
|
* @param move Set this to a value != 0 to move the new column to a different position
|
|
* @param newSchema Set this to a non-empty string to move the table to a new schema
|
|
* @return true if renaming was successful, false if not. In the latter case also lastErrorMessage is set
|
|
*/
|
|
bool alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb::Table& table, const QString& name, sqlb::FieldPtr to, int move = 0, QString newSchemaName = QString());
|
|
|
|
objectMap getBrowsableObjects(const QString& schema) const;
|
|
const sqlb::ObjectPtr getObjectByName(const sqlb::ObjectIdentifier& name) const;
|
|
bool isOpen() const;
|
|
bool encrypted() const { return isEncrypted; }
|
|
bool readOnly() const { return isReadOnly; }
|
|
bool getDirty() const;
|
|
QString currentFile() const { return curDBFilename; }
|
|
|
|
/// log an SQL statement [thread-safe]
|
|
void logSQL(QString statement, int msgtype);
|
|
|
|
QString getPragma(const QString& pragma);
|
|
bool setPragma(const QString& pragma, const QString& value);
|
|
bool setPragma(const QString& pragma, const QString& value, QString& originalvalue);
|
|
bool setPragma(const QString& pragma, int value, int& originalvalue);
|
|
|
|
bool loadExtension(const QString& filename);
|
|
|
|
private:
|
|
QVector<QPair<QString, QString>> queryColumnInformation(const QString& schema_name, const QString& object_name);
|
|
|
|
public:
|
|
QString generateSavepointName(const QString& identifier = QString()) const;
|
|
|
|
// This function generates the name for a temporary table. It guarantees that there is no table with this name yet
|
|
QString generateTemporaryTableName(const QString& schema) const;
|
|
|
|
schemaMap schemata;
|
|
|
|
signals:
|
|
void sqlExecuted(QString sql, int msgtype);
|
|
void dbChanged(bool dirty);
|
|
void structureUpdated();
|
|
void requestCollation(QString name, int eTextRep);
|
|
|
|
private:
|
|
/// external code needs to go through get() to obtain access to the database
|
|
sqlite3 * _db;
|
|
std::mutex m;
|
|
std::condition_variable cv;
|
|
bool db_used;
|
|
QString db_user;
|
|
|
|
/// wait for release of the DB locked through a previous get(),
|
|
/// giving users the option to discard running task through a
|
|
/// message box.
|
|
void waitForDbRelease();
|
|
|
|
QString curDBFilename;
|
|
QString lastErrorMessage;
|
|
QStringList savepointList;
|
|
bool isEncrypted;
|
|
bool isReadOnly;
|
|
|
|
QString primaryKeyForEditing(const sqlb::ObjectIdentifier& table, const QString& pseudo_pk) const;
|
|
|
|
void collationNeeded(void* pData, sqlite3* db, int eTextRep, const char* sCollationName);
|
|
|
|
bool tryEncryptionSettings(const QString& filename, bool* encrypted, CipherDialog*& cipherSettings);
|
|
|
|
bool dontCheckForStructureUpdates;
|
|
|
|
class NoStructureUpdateChecks
|
|
{
|
|
public:
|
|
explicit NoStructureUpdateChecks(DBBrowserDB& db) : m_db(db) { m_db.dontCheckForStructureUpdates = true; }
|
|
~NoStructureUpdateChecks() { m_db.dontCheckForStructureUpdates = false; }
|
|
|
|
private:
|
|
DBBrowserDB& m_db;
|
|
};
|
|
};
|
|
|
|
#endif
|