3
* Object representing an SQLite transaction
5
* Note that this is implemented using SQLite's
6
* [[http://sqlite.org/lang_savepoint.html|SAVEPOINT]] feature,
7
* meaning that by default it is like that of a
8
* {@link TransactionType.DEFERRED} transaction. This behaviour may
9
* be modified by first manually running a
10
* [[http://sqlite.org/lang_transaction.html|transaction]] in SQL,
11
* but remember that such transactions cannot be nested.
13
public class Transaction : GLib.Object, Queryable {
15
* Status of the transaction.
17
public TransactionStatus status { get; private set; default = TransactionStatus.UNRESOLVED; }
22
public SQLHeavy.Queryable? parent { get; construct; }
27
public SQLHeavy.Database database { owned get { return this.parent.database; } }
29
private Sqlite.Mutex? _transaction_lock = new Sqlite.Mutex (Sqlite.MUTEX_FAST);
34
public void @lock () {
35
this._transaction_lock.enter ();
41
public void @unlock () {
42
lock ( this._queue ) {
43
if ( this._queue != null && (this._queue.get_length () > 0) ) {
45
for ( GLib.SequenceIter<SQLHeavy.Query> iter = this._queue.get_begin_iter () ;
47
iter = iter.next () ) {
48
SQLHeavy.QueryResult result = new SQLHeavy.QueryResult.no_exec (iter.get ());
49
result.next_internal ();
50
this._queue.remove (iter);
52
} catch ( SQLHeavy.Error e ) {
53
GLib.critical ("Unable to execute queued query: %s", e.message);
58
this._transaction_lock.leave ();
61
private GLib.Sequence<SQLHeavy.Query>? _queue = null;
66
public void queue (SQLHeavy.Query query) throws SQLHeavy.Error {
67
lock ( this._queue ) {
68
if ( this._queue == null )
69
this._queue = new GLib.Sequence<SQLHeavy.Query> (GLib.g_object_unref);
71
this._queue.append (query);
76
* The transaction has been resolved (committed or rolled back)
78
* @param status whether the transaction was committed or rolled back
80
public signal void resolved (SQLHeavy.TransactionStatus status);
83
* Resolve the transaction
85
* @param commit whether to commit the transaction or roll it back
87
private void resolve (bool commit) throws SQLHeavy.Error {
88
if ( this.status != TransactionStatus.UNRESOLVED )
89
throw new SQLHeavy.Error.TRANSACTION ("Refusing to resolve an already resolved transaction.");
91
SQLHeavy.Query query = this.parent.prepare ("%s SAVEPOINT 'SQLHeavy-0x%x';".printf (commit ? "RELEASE" : "ROLLBACK TRANSACTION TO", (uint)this));
92
this.parent.queue (query);
94
this.status = commit ? TransactionStatus.COMMITTED : TransactionStatus.ROLLED_BACK;
95
this.parent.@unlock ();
96
this.resolved (this.status);
101
* Resolve the transaction asychronously
103
* @param commit whether to commit the transaction or roll it back
105
private async void resolve_async (bool commit) throws SQLHeavy.Error {
106
if ( this.status != TransactionStatus.UNRESOLVED )
107
throw new SQLHeavy.Error.TRANSACTION ("Refusing to resolve an already resolved transaction.");
109
SQLHeavy.Query query = this.prepare ("%s SAVEPOINT 'SQLHeavy-0x%x';".printf (commit ? "RELEASE" : "ROLLBACK TRANSACTION TO", (uint)this));
110
yield query.execute_async ();
112
this.status = commit ? TransactionStatus.COMMITTED : TransactionStatus.ROLLED_BACK;
113
this.parent.@unlock ();
114
this.resolved (this.status);
118
* Commit the transaction to the database
120
public void commit () throws SQLHeavy.Error {
125
* Commit the transaction to the database asynchronously
127
public async void commit_async () throws SQLHeavy.Error {
128
yield this.resolve_async (true);
132
* Rollback the transaction
134
public void rollback () throws SQLHeavy.Error {
135
this.resolve (false);
139
* Rollback the transaction asynchronously
141
public async void rollback_async () throws SQLHeavy.Error {
142
yield this.resolve_async (false);
146
if ( this.status == TransactionStatus.UNRESOLVED )
150
private SQLHeavy.Error? err = null;
153
this.parent.@lock ();
156
this.prepare ("SAVEPOINT 'SQLHeavy-0x%x';".printf ((uint)this)).execute ();
158
catch ( SQLHeavy.Error e ) {
160
GLib.critical ("Unable to create transaction: %s (%d)", e.message, e.code);
161
this.parent.@unlock ();
166
* Create a new transaction.
168
* @param parent The queryable to create the transaction on top of
170
public Transaction (SQLHeavy.Queryable parent) throws SQLHeavy.Error {
171
Object (parent: parent);
172
if ( this.err != null )