1 /***************************************************************************
2 qgsvirtuallayersqlitehelper.cpp
3 begin : December 2015
4 copyright : (C) 2015 Hugo Mercier, Oslandia
5 email : hugo dot mercier at oslandia dot com
6 ***************************************************************************/
7
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17 #include <QString>
18 #include <QVariant>
19
20 #include <stdexcept>
21
22 #include "qgsvirtuallayersqlitehelper.h"
23 #include "qgslogger.h"
24
QgsScopedSqlite(const QString & path,bool withExtension)25 QgsScopedSqlite::QgsScopedSqlite( const QString &path, bool withExtension )
26 {
27 if ( withExtension )
28 {
29 // register a statically-linked function as extension
30 // for all future database connection
31 sqlite3_auto_extension( reinterpret_cast < void( * )() > ( qgsvlayerModuleInit ) );
32 }
33 int r;
34 r = sqlite3_open( path.toUtf8().constData(), &db_ );
35 if ( withExtension )
36 {
37 // reset the automatic extensions
38 sqlite3_reset_auto_extension();
39 }
40
41 if ( r )
42 {
43 QString err = QStringLiteral( "%1 [%2]" ).arg( sqlite3_errmsg( db_ ), path );
44 QgsDebugMsg( err );
45 throw std::runtime_error( err.toUtf8().constData() );
46 }
47 // enable extended result codes
48 sqlite3_extended_result_codes( db_, 1 );
49 }
50
QgsScopedSqlite(QgsScopedSqlite & other)51 QgsScopedSqlite::QgsScopedSqlite( QgsScopedSqlite &other )
52 {
53 db_ = other.db_;
54 other.db_ = nullptr;
55 }
56
operator =(QgsScopedSqlite & other)57 QgsScopedSqlite &QgsScopedSqlite::operator=( QgsScopedSqlite &other )
58 {
59 reset( other.release() );
60 return *this;
61 }
62
~QgsScopedSqlite()63 QgsScopedSqlite::~QgsScopedSqlite()
64 {
65 close_();
66 }
67
get() const68 sqlite3 *QgsScopedSqlite::get() const { return db_; }
69
interrupt()70 bool QgsScopedSqlite::interrupt()
71 {
72 bool rc = false;
73 if ( db_ )
74 {
75 sqlite3_interrupt( db_ );
76 rc = true;
77 }
78 return rc;
79 }
80
release()81 sqlite3 *QgsScopedSqlite::release()
82 {
83 sqlite3 *pp = db_;
84 db_ = nullptr;
85 return pp;
86 }
87
reset(sqlite3 * db)88 void QgsScopedSqlite::reset( sqlite3 *db )
89 {
90 close_();
91 db_ = db;
92 }
93
close_()94 void QgsScopedSqlite::close_()
95 {
96 if ( db_ )
97 sqlite3_close( db_ );
98 }
99
100 namespace Sqlite
101 {
Query(sqlite3 * db,const QString & q)102 Query::Query( sqlite3 *db, const QString &q )
103 : db_( db )
104 , nBind_( 1 )
105 {
106 QByteArray ba( q.toUtf8() );
107 int r = sqlite3_prepare_v2( db, ba.constData(), ba.size(), &stmt_, nullptr );
108 if ( r )
109 {
110 QString err = QStringLiteral( "Query preparation error on %1: %2" ).arg( q, sqlite3_errmsg( db ) );
111 throw std::runtime_error( err.toUtf8().constData() );
112 }
113 }
114
~Query()115 Query::~Query()
116 {
117 sqlite3_finalize( stmt_ );
118 }
119
step()120 int Query::step() { return sqlite3_step( stmt_ ); }
121
bind(const QVariant & value,int idx)122 Query &Query::bind( const QVariant &value, int idx )
123 {
124 switch ( value.type() )
125 {
126 case QVariant::String:
127 {
128 QByteArray ba( value.toString().toUtf8() );
129 int r = sqlite3_bind_text( stmt_, idx, ba.constData(), ba.size(), SQLITE_TRANSIENT );
130 if ( r )
131 {
132 throw std::runtime_error( sqlite3_errmsg( db_ ) );
133 }
134 return *this;
135 }
136
137 case QVariant::Double:
138 {
139 bool ok; // no reason to fail double conversion
140 double dbl = value.toDouble( &ok );
141 int r = sqlite3_bind_double( stmt_, idx, dbl );
142 if ( r )
143 {
144 throw std::runtime_error( sqlite3_errmsg( db_ ) );
145 }
146 return *this;
147 }
148
149 default:
150 // Unsupported type
151 Q_ASSERT( false );
152 }
153
154 return *this;
155 }
156
bind(const QVariant & value)157 Query &Query::bind( const QVariant &value )
158 {
159 return bind( value, nBind_++ );
160 }
161
exec(sqlite3 * db,const QString & sql)162 void Query::exec( sqlite3 *db, const QString &sql )
163 {
164 char *errMsg = nullptr;
165 int r = sqlite3_exec( db, sql.toUtf8().constData(), nullptr, nullptr, &errMsg );
166 if ( r )
167 {
168 QString err = QStringLiteral( "Query execution error on %1: %2 - %3" ).arg( sql ).arg( r ).arg( errMsg );
169 throw std::runtime_error( err.toUtf8().constData() );
170 }
171 }
172
reset()173 void Query::reset()
174 {
175 int r = sqlite3_reset( stmt_ );
176 if ( r )
177 {
178 throw std::runtime_error( sqlite3_errmsg( db_ ) );
179 }
180 nBind_ = 1;
181 }
182
columnCount() const183 int Query::columnCount() const
184 {
185 return sqlite3_column_count( stmt_ );
186 }
187
columnName(int i) const188 QString Query::columnName( int i ) const
189 {
190 return QString( sqlite3_column_name( stmt_, i ) );
191 }
192
columnType(int i) const193 int Query::columnType( int i ) const
194 {
195 return sqlite3_column_type( stmt_, i );
196 }
197
columnInt(int i) const198 int Query::columnInt( int i ) const
199 {
200 return sqlite3_column_int( stmt_, i );
201 }
202
columnInt64(int i) const203 qint64 Query::columnInt64( int i ) const
204 {
205 return sqlite3_column_int64( stmt_, i );
206 }
207
columnDouble(int i) const208 double Query::columnDouble( int i ) const
209 {
210 return sqlite3_column_double( stmt_, i );
211 }
212
columnText(int i) const213 QString Query::columnText( int i ) const
214 {
215 int size = sqlite3_column_bytes( stmt_, i );
216 const char *str = reinterpret_cast< const char * >( sqlite3_column_text( stmt_, i ) );
217 return QString::fromUtf8( str, size );
218 }
219
columnBlob(int i) const220 QByteArray Query::columnBlob( int i ) const
221 {
222 int size = sqlite3_column_bytes( stmt_, i );
223 const char *data = reinterpret_cast< const char * >( sqlite3_column_blob( stmt_, i ) );
224 // data is not copied. QByteArray is just here a augmented pointer
225 return QByteArray::fromRawData( data, size );
226 }
227
stmt()228 sqlite3_stmt *Query::stmt() { return stmt_; }
229
230 }
231