aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/db/db.h
blob: 7d10a05de0dc2444568ca7c3c35e7bba47a8f802 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
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