aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/db/db.h
diff options
context:
space:
mode:
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/db/db.h')
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/db/db.h831
1 files changed, 831 insertions, 0 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/db/db.h b/SQLiteStudio3/coreSQLiteStudio/db/db.h
new file mode 100644
index 0000000..7d10a05
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/db/db.h
@@ -0,0 +1,831 @@
+#ifndef DB_H
+#define DB_H
+
+#include "returncode.h"
+#include "dialect.h"
+#include "services/functionmanager.h"
+#include "common/readwritelocker.h"
+#include "coreSQLiteStudio_global.h"
+#include "db/attachguard.h"
+#include "interruptable.h"
+#include "dbobjecttype.h"
+#include <QObject>
+#include <QVariant>
+#include <QList>
+#include <QHash>
+#include <QReadWriteLock>
+#include <QRunnable>
+#include <QStringList>
+#include <QSet>
+
+/** @file */
+
+class AsyncQueryRunner;
+class Db;
+class DbManager;
+class SqlQuery;
+
+typedef QSharedPointer<SqlQuery> SqlQueryPtr;
+
+/**
+ * @brief Option to make new Db instance not install any functions or collations in the database.
+ *
+ * This connection option should be used (with boolean value = true) when creating Db instance
+ * to be used internally (not exposed to the user) and you don't want any special features
+ * (like custom SQL functions, custom collations) to be registered in that database.
+ */
+static_char* DB_PURE_INIT = "sqlitestudio_pure_db_initalization";
+
+/**
+ * @brief Option name for plugin handling the database.
+ *
+ * This is a constant naming the connection option, which tells SQLiteStudio which plugin was dedicated to handle
+ * particular database.
+ */
+static_char* DB_PLUGIN = "plugin";
+
+/**
+ * @brief Database managed by application.
+ *
+ * Everything you might want to do with SQLite databases goes through this interface in the application.
+ * It's has a common interface for common database operations, such as connecting and disconnecting,
+ * checking current status, executing queries and reading results.
+ * It keeps information about the database version, dialect (SQLite 2 vs SQLite 3), encoding (UTF-8, UTF-16, etc.),
+ * symbolic name of the database and path to the file.
+ *
+ * Regular routine with the database object would be to open it (if not open yet), execute some query
+ * and collect results. It can be done in several ways, but here's simple one:
+ * @code
+ * QList<int> queryDb(const QString& dbName, const QString& colValue1, int colValue2)
+ * {
+ * // Getting database object by its name and opening it if necessary
+ * Db* db = DBLIST->getDb(dbName);
+ * if (!db)
+ * return; // no such database
+ *
+ * if (!db->isOpen())
+ * db->open();
+ *
+ * // Executing query and getting results
+ * SqlQueryPtr results = db->exec("SELECT intCol FROM table WHERE col1 = ?, col2 = ?", colValue1, colValue2)
+ *
+ * QList<int> resultList;
+ * SqlResultsRowPtr row;
+ * while (row = results->next())
+ * {
+ * resultList << row->value("intCol").toInt();
+ * }
+ * return resultList;
+ * }
+ * @endcode
+ *
+ * The example above is very generic way to do things. You can use many methods which simplifies tasks in case
+ * you work with smaller data sets. For example:
+ * @code
+ * int getRowId(Db* db, int colVal)
+ * {
+ * // We assume that db is already open
+ * return db->exec("SELECT rowid FROM table WHERE column = ?", colVal).getSingleCell().toInt();
+ * }
+ * @endcode
+ *
+ * To write some data into database you can write as this:
+ * @code
+ * void insert(Db* db, const QString& val1, int val2)
+ * {
+ * // We assume that db is already open
+ * db->exec("INSERT INTO table (col1, col2) VALUES (?, ?)", val1, val2);
+ * }
+ * @endcode
+ *
+ * You can use named parameters:
+ * @code
+ * void insert(Db* db, const QString& val1, int val2)
+ * {
+ * QHash<QString,QVariant> params;
+ * params["c1"] = val1;
+ * params["c2"] = val2;
+ * db->exec("INSERT INTO table (col1, col2) VALUES (:c1, :c2)", params);
+ * }
+ * @endcode
+ *
+ * To check if the execution was successful, test results:
+ * @code
+ * void insert(Db* db, const QString& val1, int val2)
+ * {
+ * SqlQueryPtr results = db->exec("INSERT INTO table (col1, col2) VALUES (?, ?)", val1, val2);
+ * if (results->isError())
+ * {
+ * qWarning() << "Error while inserting:" << results->getErrorCode() << results->getErrorText();
+ * }
+ * }
+ * @endcode
+ *
+ * @see DbBase
+ * @see DbQt
+ * @see DbQt2
+ * @see DbQt3
+ */
+class API_EXPORT Db : public QObject, public Interruptable
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Flags for query execution.
+ *
+ * Those flags are used by exec() and asyncExec(). They can be used with bit-wise operators.
+ */
+ enum class Flag
+ {
+ NONE = 0x0, /**< No flags. This is default. */
+ PRELOAD = 0x1, /**< Preloads all execution results into the results object. Useful for asynchronous execution. */
+ NO_LOCK = 0x2 /**<
+ * Prevents SQLiteStudio from setting the lock for execution on this base (not the SQLite lock,
+ * just a Db internal lock for multi-threading access to the Db::exec()). This should be used
+ * only in justified circumstances. That is when the Db call has to be done from within the part
+ * of code, where the lock on Db was already set. Never (!) use this to ommit lock from different
+ * threads. Justified situation is when you implement Db::initialDbSetup() in the derived class,
+ * or when you implement SqlFunctionPlugin. Don't use it for the usual cases.
+ */
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ /**
+ * @brief Function to handle SQL query results.
+ *
+ * The function has to accept single results object and return nothing.
+ * After results are processed, they will be deleted automatically, no need to handle that.
+ */
+ typedef std::function<void(SqlQueryPtr)> QueryResultsHandler;
+
+ /**
+ * @brief Default, empty constructor.
+ */
+ Db();
+
+ /**
+ * @brief Releases resources.
+ *
+ * Detaches any attached databases and closes the database if open.
+ */
+ virtual ~Db();
+
+ /**
+ * @brief Registers Db in Qt meta subsystem.
+ *
+ * It's called at the application startup. Makes Db* supported by Qt meta subsystem.
+ */
+ static void metaInit();
+
+ /**
+ * @brief Converts flags into string representation.
+ * @param flags Flags to convert. Can be multiple flags OR'ed.
+ * @return Flags as string representation, for example: STRING_REPLACE_ARGS.
+ */
+ static QString flagsToString(Flags flags);
+
+ /**
+ * @brief Checks if database is open (connected).
+ * @return true if the database is connected, or false otherwise.
+ */
+ virtual bool isOpen() = 0;
+
+ /**
+ * @brief Gets database symbolic name.
+ * @return Database symbolic name (as it was defined in call to DbManager#addDb() or DbManager#updateDb()).
+ */
+ virtual QString getName() = 0;
+
+ /**
+ * @brief Gets database file path.
+ * @return Database file path (as it was defined in call to DbManager#addDb() or DbManager#updateDb()).
+ */
+ virtual QString getPath() = 0;
+
+ /**
+ * @brief Gets SQLite version major number for this database.
+ * @return Major version number, that is 3 for SQLite 3.x.x and 2 for SQLite 2.x.x.
+ *
+ * You don't have to open the database. This information is always available.
+ */
+ virtual quint8 getVersion() = 0;
+
+ /**
+ * @brief Gets database dialect.
+ * @return Database dialect, which is either Sqlite2 or Sqlite3.
+ *
+ * You don't have to open the database. This information is always available.
+ */
+ virtual Dialect getDialect() = 0;
+
+ /**
+ * @brief Gets database encoding.
+ * @return Database encoding as returned from SQLite query: <tt>PRAGMA encoding;</tt>
+ *
+ * If the database is not open, then this methods quickly opens it, queries the encoding and closes the database.
+ * The opening and closing of the database is not visible outside, it's just an internal operation.
+ */
+ virtual QString getEncoding() = 0;
+
+ /**
+ * @brief Gets connection options.
+ * @return Connection options, the same as were passed to DbManager#addDb() or DbManager#updateDb().
+ */
+ virtual QHash<QString,QVariant>& getConnectionOptions() = 0;
+
+ /**
+ * @brief Sets new name for the database.
+ * @param value New name.
+ *
+ * This method works only on closed databases. If the database is open, then warning is logged
+ * and function does nothing more.
+ */
+ virtual void setName(const QString& value) = 0;
+
+ /**
+ * @brief Sets new file path for the database.
+ * @param value New file path.
+ *
+ * This method works only on closed databases. If the database is open, then warning is logged
+ * and function does nothing more.
+ */
+ virtual void setPath(const QString& value) = 0;
+
+ /**
+ * @brief Sets connection options for the database.
+ * @param value Connection options. See DbManager::addDb() for details.
+ *
+ * This method works only on closed databases. If the database is open, then warning is logged
+ * and function does nothing more.
+ */
+ virtual void setConnectionOptions(const QHash<QString,QVariant>& value) = 0;
+
+ /**
+ * @brief Sets the timeout for waiting for the database to be unlocked.
+ * @param secs Number of seconds.
+ *
+ * When the database is locked by another application, then the SQLiteStudio will wait given number
+ * of seconds for the database to be released, before the execution error is reported.
+ *
+ * Set it to negative value to set infinite timeout.
+ *
+ * This doesn't involve locking done by SQLiteStudio internally (see Db::Flag::NO_LOCK), which doesn't time out.
+ */
+ virtual void setTimeout(int secs) = 0;
+
+ /**
+ * @brief Gets the current database lock waiting timeout value.
+ * @return Number of seconds to wait for the database to be released.
+ *
+ * See setTimeout() for details.
+ */
+ virtual int getTimeout() const = 0;
+
+ /**
+ * @brief Executes SQL query.
+ * @param query Query to be executed. Parameter placeholders can be either of: ?, :param, \@param, just don't mix different types in single query.
+ * @param args List of values to bind to parameter placeholders. As those are unnamed parameters, the order is important.
+ * @param flags Execution flags.
+ * @return Execution results.
+ *
+ * Executes SQL query and returns results. If there was an error, the results will tell you when you call SqlResults::isError().
+ *
+ * Queries like SELECT, INSERT, UPDATE, and DELETE accept positional parameters, but only for column values. If you would like to pass table name
+ * for SELECT, you would have to use Flags::STRING_REPLACE_ARGS and parameter placeholders in format %1, %2, %3, and so on. You cannot mix
+ * string parameters (as for Flags::STRING_REPLACE_ARGS) and regular SQLite parameters in single query. If you really need to, then you should
+ * build query string first (using QString::arg() for string parameters) and then pass it to exec(), which will accept SQLite parameters binding.
+ *
+ * If the query doesn't return any interesting results (for example it's INSERT) and you don't care about errors, you can safely ignore results object.
+ * The result object is shared pointer, therefore it will delete itself if not used.
+ *
+ * Given C++11 you can initialize list with braces, like this:
+ * @code
+ * SqlQueryPtr results = db->exec("SELECT * FROM table WHERE c1 = ? AND c2 = ? AND c3 = ? AND c4 = ?",
+ * {45, 76, "test", 3.56});
+ * @endcode
+ */
+ virtual SqlQueryPtr exec(const QString& query, const QList<QVariant> &args, Flags flags = Flag::NONE) = 0;
+
+ /**
+ * @brief Executes SQL query using named parameters.
+ * @param query Query to be executed. Parameter placeholders can be either of: :param, \@param, just don't mix different types in single query.
+ * @param args Map of parameter name and the value assigned to it.
+ * @param flags Execution flags. See exec() for setails.
+ * @return Execution results.
+ *
+ * Given C++11 you can initialize hash map with braces, like this:
+ * @code
+ * SqlQueryPtr results = db->exec("SELECT * FROM table WHERE id = :userId AND name = :firstName",
+ * {
+ * {":userId", 45},
+ * {":firstName", "John"}
+ * });
+ * @endcode
+ *
+ * @overload
+ */
+ virtual SqlQueryPtr exec(const QString& query, const QHash<QString, QVariant>& args, Flags flags = Flag::NONE) = 0;
+
+ /**
+ * @brief Executes SQL query.
+ * @overload
+ */
+ virtual SqlQueryPtr exec(const QString &query, Db::Flags flags = Flag::NONE) = 0;
+
+ /**
+ * @brief Executes SQL query.
+ * @overload
+ */
+ virtual SqlQueryPtr exec(const QString &query, const QVariant &arg) = 0;
+
+ /**
+ * @brief Executes SQL query.
+ * @overload
+ */
+ virtual SqlQueryPtr exec(const QString &query, std::initializer_list<QVariant> argList) = 0;
+
+ /**
+ * @brief Executes SQL query.
+ * @overload
+ */
+ virtual SqlQueryPtr exec(const QString &query, std::initializer_list<std::pair<QString,QVariant>> argMap) = 0;
+
+ /**
+ * @brief Executes SQL query asynchronously using list of parameters.
+ * @param query Query to be executed. Parameter placeholders can be either of: ?, :param, \@param, just don't mix different types in single query.
+ * @param args List of parameter values to bind.
+ * @param resultsHandler Function (can be lambda) to handle results. The function has to accept single SqlQueryPtr object and return nothing.
+ * @param flags Execution flags. See exec() for setails.
+ *
+ * Asynchronous execution takes place in another thread. Once the execution is finished, the results handler function is called.
+ *
+ * Example:
+ * @code
+ * db->asyncExec("SELECT * FROM table WHERE col = ?", {5}, [=](SqlQueryPtr results)
+ * {
+ * qDebug() << "Received" << results->rowCount() << "rows in results.";
+ * });
+ * @endcode
+ */
+ virtual void asyncExec(const QString& query, const QList<QVariant>& args, QueryResultsHandler resultsHandler, Flags flags = Flag::NONE) = 0;
+
+ /**
+ * @brief Executes SQL query asynchronously using named parameters.
+ * @param query Query to be executed. Parameter placeholders can be either of: :param, \@param, just don't mix different types in single query.
+ * @param args Map of parameter name and the value assigned to it.
+ * @param resultsHandler Function (can be lambda) to handle results. The function has to accept single SqlQueryPtr object and return nothing.
+ * @param flags Execution flags. See exec() for details.
+ * @return Asynchronous execution ID.
+ * @overload
+ */
+ virtual void asyncExec(const QString& query, const QHash<QString, QVariant>& args, QueryResultsHandler resultsHandler, Flags flags = Flag::NONE) = 0;
+
+ /**
+ * @brief Executes SQL query asynchronously.
+ * @param query Query to be executed. See exec() for details.
+ * @param resultsHandler Function (can be lambda) to handle results. The function has to accept single SqlQueryPtr object and return nothing.
+ * @param flags Execution flags. See exec() for details.
+ * @return Asynchronous execution ID.
+ * @overload
+ */
+ virtual void asyncExec(const QString& query, QueryResultsHandler resultsHandler, Flags flags = Flag::NONE) = 0;
+
+ /**
+ * @brief Executes SQL query asynchronously using list of parameters.
+ * @param query Query to be executed. Parameter placeholders can be either of: ?, :param, \@param, just don't mix different types in single query.
+ * @param args List of parameter values to bind.
+ * @param flags Execution flags. See exec() for setails.
+ * @return Asynchronous execution ID.
+ *
+ * Asynchronous execution takes place in another thread. Once the execution is finished, the results is provided
+ * with asyncExecFinished() signal. You should get the ID from results of this method and compare it with ID
+ * from the signal, so when it matches, it means that the results object from signal is the answer to this execution.
+ *
+ * It's recommended to use method version which takes function pointer for results handing, as it's more resiliant to errors in the code.
+ *
+ * Given C++11 you can initialize list with braces, like this:
+ * @code
+ * int asyncId = db->asyncExec("SELECT * FROM table WHERE c1 = ? AND c2 = ? AND c3 = ? AND c4 = ?",
+ * {45, 76, "test", 3.56});
+ * @endcode
+ */
+ virtual quint32 asyncExec(const QString& query, const QList<QVariant>& args, Flags flags = Flag::NONE) = 0;
+
+ /**
+ * @brief Executes SQL query asynchronously using named parameters.
+ * @param query Query to be executed. Parameter placeholders can be either of: :param, \@param, just don't mix different types in single query.
+ * @param args Map of parameter name and the value assigned to it.
+ * @param flags Execution flags. See exec() for details.
+ * @return Asynchronous execution ID.
+ * @overload
+ *
+ * It's recommended to use method version which takes function pointer for results handing, as it's more resiliant to errors in the code.
+ */
+ virtual quint32 asyncExec(const QString& query, const QHash<QString, QVariant>& args, Flags flags = Flag::NONE) = 0;
+
+ /**
+ * @brief Executes SQL query asynchronously.
+ * @param query Query to be executed. See exec() for details.
+ * @param flags Execution flags. See exec() for details.
+ * @return Asynchronous execution ID.
+ * @overload
+ *
+ * It's recommended to use method version which takes function pointer for results handing, as it's more resiliant to errors in the code.
+ */
+ virtual quint32 asyncExec(const QString& query, Flags flags = Flag::NONE) = 0;
+
+ virtual SqlQueryPtr prepare(const QString& query) = 0;
+
+ /**
+ * @brief Begins SQL transaction.
+ * @return true on success, or false on failure.
+ *
+ * This method uses basic "BEGIN" statement to begin transaction, therefore recurrent transactions are not supported.
+ * This is because SQLite2 doesn't support "SAVEPOINT" and this is the common interface for all SQLite versions.
+ */
+ virtual bool begin() = 0;
+
+ /**
+ * @brief Commits SQL transaction.
+ * @return true on success, or false otherwise.
+ */
+ virtual bool commit() = 0;
+
+ /**
+ * @brief Rolls back the transaction.
+ * @return true on success, or false otherwise (i.e. there was no transaction open, there was a connection problem, etc).
+ */
+ virtual bool rollback() = 0;
+
+ /**
+ * @brief Interrupts current execution asynchronously.
+ *
+ * It's almost the same as interrupt(), except it returns immediately, instead of waiting for the interruption to finish.
+ * In case of some heavy queries the interruption process might take a little while.
+ */
+ virtual void asyncInterrupt() = 0;
+
+ /**
+ * @brief Checks if the database is readable at the moment.
+ * @return true if the database is readable, or false otherwise.
+ *
+ * The database can be in 3 states: not locked, locked for reading or locked for writing.
+ * If it's locked for writing, than it's not readable and this method will return false.
+ * If it's locked for reading or not locked at all, then this method will return true.
+ * Database can be locked by other threads executing their queries on the database.
+ */
+ virtual bool isReadable() = 0;
+
+ /**
+ * @brief Checks if the database is writable at the moment.
+ * @return true if the database is writable, or false otherwise.
+ *
+ * The database can be in 3 states: not locked, locked for reading or locked for writing.
+ * If it's locked for writing (by other thread) or reading, than it's not writable and this method will return false.
+ * If it's not locked at all, then this method will return true.
+ * Database can be locked by other threads executing their queries on the database.
+ */
+ virtual bool isWritable() = 0;
+
+ /**
+ * @brief Tells if the database is valid for operating on it.
+ * @return true if the databse is valid, false otherwise.
+ *
+ * A valid database is the one that has valid path and driver plugin support loaded.
+ * Invalid database is the one that application failed to load. Those are marked with the exclamation icon on the UI.
+ */
+ virtual bool isValid() const = 0;
+
+ /**
+ * @brief Attaches given database to this database.
+ * @param otherDb Other registered database object.
+ * @param silent If true, no errors or warnings will be reported to the NotifyManager (they will still appear in logs).
+ * @return Name of the attached database (it's not the symbolic name of the other database, it's a name you would use in <tt>ATTACH 'name'</tt> statement).
+ *
+ * This is convinent method to attach other registered databases to this database. It generates attached database name, so it doesn't conflict
+ * with other - already attached - database names, attaches the database with that name and returns that name to you, so you can refer to it in queries.
+ */
+ virtual QString attach(Db* otherDb, bool silent = false) = 0;
+
+ /**
+ * @brief Attaches given database to this database using guarded attach.
+ * @param otherDb Other registered database object.
+ * @param silent If true, no errors or warnings will be reported to the NotifyManager (they will still appear in logs).
+ * @return Guarded attach instance with the name of the attached database inside.
+ *
+ * The guarded attach automatically detaches attached database when the attach guard is destroyed (goes out of scope).
+ * The AttachGuard is in fact a QSharedPointer, so you can pass it by value to other functions prolong attchment.
+ */
+ virtual AttachGuard guardedAttach(Db* otherDb, bool silent = false) = 0;
+
+ /**
+ * @brief Detaches given database from this database.
+ * @param otherDb Other registered database object.
+ *
+ * If the otherDb is not attached, this method does nothing. Otherwise it calls <tt>DETACH</tt> statement using the attach name generated before by attach().
+ * You don't have to provide the attach name, as Db class remembers those names internally.
+ */
+ virtual void detach(Db* otherDb) = 0;
+
+ /**
+ * @brief Detaches all attached databases.
+ *
+ * Detaches all attached databases. This includes only databases attached with attach(). Databases attached with manual <tt>ATTACH</tt> query execution
+ * will not be detached.
+ */
+ virtual void detachAll() = 0;
+
+ /**
+ * @brief Gets attached databases.
+ * @return Table of attached databases and the attach names used to attach them.
+ *
+ * This method returns only databases attached with attach() method.
+ */
+ virtual const QHash<Db*,QString>& getAttachedDatabases() = 0;
+
+ /**
+ * @brief Gets all attached databases.
+ * @return Set of attach names.
+ *
+ * This method returns all attached database names (the attach names), including both those from attach() and manual <tt>ATTACH</tt> query execution.
+ */
+ virtual QSet<QString> getAllAttaches() = 0;
+
+ /**
+ * @brief Generates unique name for object to be created in the database.
+ * @param attachedDbName Optional attach name, so the name will be in context of that database.
+ * @return Unique object name.
+ *
+ * Queries database for all existing objects and then generates name that is not on that list.
+ * The generated name is a random string of length 16.
+ */
+ virtual QString getUniqueNewObjectName(const QString& attachedDbName = QString()) = 0;
+
+ /**
+ * @brief Gets last error string from database driver.
+ * @return Last encountered error.
+ *
+ * Result of this method is determinated by DbPlugin.
+ */
+ virtual QString getErrorText() = 0;
+
+ /**
+ * @brief Gets last error code from database driver.
+ * @return Code of last encountered error.
+ *
+ * Result of this method is determinated by DbPlugin.
+ */
+ virtual int getErrorCode() = 0;
+
+ /**
+ * @brief Gets database type label.
+ * @return Database type label.
+ *
+ * The database type label is used on UI to tell user what database it is (SQLite 3, SQLite 2, Encrypted SQLite 3, etc).
+ * This is defined by DbPlugin.
+ */
+ virtual QString getTypeLabel() = 0;
+
+ /**
+ * @brief Initializes resources once the all derived Db classes are constructed.
+ * @return true on success, false on failure.
+ *
+ * It's called just after this object was created. Implementation of this method can call virtual methods, which was a bad idea
+ * to do in constructor (because of how it's works in C++, if you didn't know).
+ *
+ * It usually queries database for it's version, etc.
+ */
+ virtual bool initAfterCreated() = 0;
+
+ /**
+ * @brief Deregisters custom SQL function from this database.
+ * @param name Name of the function.
+ * @param argCount Number of arguments accepted by the function (-1 for undefined).
+ * @return true if deregistering was successful, or false otherwise.
+ *
+ * @see FunctionManager
+ */
+ virtual bool deregisterFunction(const QString& name, int argCount) = 0;
+
+ /**
+ * @brief Registers scalar custom SQL function.
+ * @param name Name of the function.
+ * @param argCount Number of arguments accepted by the function (-1 for undefined).
+ * @return true on success, false on failure.
+ *
+ * Scalar functions are evaluated for each row and their result is used in place of function invokation.
+ * Example of SQLite built-in scalar function is abs(), or length().
+ *
+ * This method is used only to let the database know, that the given function exists in FunctionManager and we want it to be visible
+ * in this database's context. When the function is called from SQL query, then the function execution is delegated to the FunctionManager.
+ *
+ * For details about usage of custom SQL functions see http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_SQL_functions
+ *
+ * @see FunctionManager
+ */
+ virtual bool registerScalarFunction(const QString& name, int argCount) = 0;
+
+ /**
+ * @brief Registers aggregate custom SQL function.
+ * @param name Name of the function.
+ * @param argCount Number of arguments accepted by the function (-1 for undefined).
+ * @return true on success, false on failure.
+ *
+ * Aggregate functions are used to aggregate many rows into single row. They are common in queries with GROUP BY statements.
+ * The aggregate function in SQLite is actually implemented by 2 functions - one for executing per each row (and which doesn't return any result yet,
+ * just collects the data) and then the second function, executed at the end. The latter one must return the result, which becomes the result
+ * of aggregate function.
+ *
+ * Aggregate functions in SQLiteStudio are almost the same as in SQLite itself, except SQLiteStudio has also a third function, which is called
+ * at the very begining, before the first "per step" function is called. It's used to initialize anything that the step function might need.
+ *
+ * This method is used only to let the database know, that the given function exists in FunctionManager and we want it to be visible
+ * in this database's context. When the function is called from SQL query, then the function execution is delegated to the FunctionManager.
+ *
+ * For details about usage of custom SQL functions see http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_SQL_functions
+ *
+ * @see FunctionManager
+ */
+ virtual bool registerAggregateFunction(const QString& name, int argCount) = 0;
+
+ /**
+ * @brief Registers a collation sequence implementation in the database.
+ * @param name Name of the collation.
+ * @return true on success, false on failure.
+ *
+ * Collations are not supported by SQLite 2, so this method will always fail for those databases.
+ *
+ * Collations are handled by CollationManager. Each collation managed by the manager has a code implemented to return -1, 0 or 1
+ * when comparing 2 values in the database in order to sort query results. The name passed to this method is a name of the collation
+ * as it is used in SQL queries and also the same name must be used when defining collation in Collations editor window.
+ *
+ * For details about usage of custom collations see http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_collations
+ *
+ * @see CollationManager
+ */
+ virtual bool registerCollation(const QString& name) = 0;
+
+ /**
+ * @brief Deregisters previously registered collation from this database.
+ * @param name Collation name.
+ * @return true on success, false on failure.
+ *
+ * See registerCollation() for details on custom collations.
+ */
+ virtual bool deregisterCollation(const QString& name) = 0;
+
+ signals:
+ /**
+ * @brief Emitted when the connection to the database was established.
+ */
+ void connected();
+
+ /**
+ * @brief Emitted after connection to the database was closed.
+ */
+ void disconnected();
+
+ /**
+ * @brief Emitted when other database was attached to this datbase.
+ * @param db Other database that was attached.
+ *
+ * This is emitted only when the database was attached with attach() call.
+ * Manual "ATTACH" query execution doesn't cause this signal to be emitted.
+ */
+ void attached(Db* db);
+
+ /**
+ * @brief Emitted when other database was detached from this datbase.
+ * @param db Other database that was detached.
+ *
+ * This is emitted only when the database was detached with detach() call.
+ * Manual "DETACH" query execution doesn't cause this signal to be emitted.
+ */
+ void detached(Db* db);
+
+ //void attached(QString db); // TODO emit when called by user's sql
+ //void detached(QString db); // TODO emit when called by user's sql
+
+ /**
+ * @brief Emitted when the asynchronous execution was finished.
+ * @param asyncId Asynchronous ID.
+ * @param results Results from query execution.
+ *
+ * This signal is emitted only when no handler function was passed to asyncExec().
+ * It's emitted, so the results can be handled.
+ * Always test \p asyncId if it's equal to ID returned from asyncExec().
+ */
+ void asyncExecFinished(quint32 asyncId, SqlQueryPtr results);
+
+ /**
+ * @brief idle Database became idle and awaits for instructions.
+ *
+ * This signal is emited after async execution has finished.
+ * It is important to re-check isWritable() or isReadable()
+ * in any slot connected to this signal, because some other slot
+ * called before currently processed slot could already order
+ * another async execution.
+ */
+ void idle();
+
+ /**
+ * @brief Emitted when any database object (table, index, trigger, or view) was just deleted from this database.
+ * @param database Database (attach) name from which the object was deleted. Usually the "main".
+ * @param name Name of the object deleted.
+ * @param type Type of the object deleted.
+ *
+ * This signal covers only deletions made by this database of course. Deletions made by any other application
+ * are not announced by this signal (as this is impossible to detect it just like that).
+ */
+ void dbObjectDeleted(const QString& database, const QString& name, DbObjectType type);
+
+ /**
+ * @brief Emitted just before disconnecting and user can deny it.
+ * @param disconnectingDenied If set to true by anybody, then disconnecting is aborted.
+ */
+ void aboutToDisconnect(bool& disconnectingDenied);
+
+ public slots:
+ /**
+ * @brief Opens connection to the database.
+ * @return true on success, false on error.
+ *
+ * Emits connected() only on success.
+ */
+ virtual bool open() = 0;
+
+ /**
+ * @brief Closes connection to the database.
+ * @return true on success, false on error.
+ *
+ * Emits disconnected() only on success (i.e. db was open before).
+ */
+ virtual bool close() = 0;
+
+ /**
+ * @brief Opens connection to the database quietly.
+ * @return true on success, false on error.
+ *
+ * Opens database, doesn't emit any signal.
+ */
+ virtual bool openQuiet() = 0;
+
+ /**
+ * @brief Opens connection to the database quietly, without applying any specific settings.
+ * @return true on success, false on error.
+ *
+ * Opens database, doesn't emit any signal. It also doesn't apply any pragmas, neither registers
+ * functions or collations. It should be used when you want to do some basic query on the database,
+ * like when you probe the database for being the correct database for this implementation (driver, etc).
+ * Actually, that's what DbPluginSqlite3 plugin (among others) use.
+ *
+ * To close database open with this method use closeQuiet().
+ */
+ virtual bool openForProbing() = 0;
+
+ /**
+ * @brief Closes connection to the database quietly.
+ * @return true on success, false on error.
+ *
+ * Closes database, doesn't emit any signal.
+ */
+ virtual bool closeQuiet() = 0;
+
+ /**
+ * @brief Deregisters all funtions registered in the database and registers new (possibly the same) functions.
+ *
+ * This slot is called from openAndSetup() and then every time user modifies custom SQL functions and commits changes to them.
+ * It deregisters all functions registered before in this database and registers new functions, currently defined for
+ * this database.
+ *
+ * @see FunctionManager
+ */
+ virtual void registerAllFunctions() = 0;
+
+ /**
+ * @brief Deregisters all collations registered in the database and registers new (possibly the same) collations.
+ *
+ * This slot is called from openAndsetup() and then every time user modifies custom collations and commits changes to them.
+ */
+ virtual void registerAllCollations() = 0;
+};
+
+QDataStream &operator<<(QDataStream &out, const Db* myObj);
+QDataStream &operator>>(QDataStream &in, Db*& myObj);
+
+Q_DECLARE_METATYPE(Db*)
+Q_DECLARE_OPERATORS_FOR_FLAGS(Db::Flags)
+
+class API_EXPORT Sqlite2ColumnDataTypeHelper
+{
+ public:
+ void setBinaryType(int columnIndex);
+ bool isBinaryColumn(int columnIndex) const;
+ void clearBinaryTypes();
+
+ private:
+ QSet<int> binaryColumns;
+};
+
+#endif // DB_H