source: trunk/src/sql/drivers/sqlite/qsql_sqlite.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 20.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtSql module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qsql_sqlite.h"
43
44#include <qcoreapplication.h>
45#include <qvariant.h>
46#include <qsqlerror.h>
47#include <qsqlfield.h>
48#include <qsqlindex.h>
49#include <qsqlquery.h>
50#include <qstringlist.h>
51#include <qvector.h>
52#include <qdebug.h>
53
54#if defined Q_OS_WIN
55# include <qt_windows.h>
56#else
57# include <unistd.h>
58#endif
59
60#include <sqlite3.h>
61
62Q_DECLARE_METATYPE(sqlite3*)
63Q_DECLARE_METATYPE(sqlite3_stmt*)
64
65QT_BEGIN_NAMESPACE
66
67static QVariant::Type qGetColumnType(const QString &tpName)
68{
69 const QString typeName = tpName.toLower();
70
71 if (typeName == QLatin1String("integer")
72 || typeName == QLatin1String("int"))
73 return QVariant::Int;
74 if (typeName == QLatin1String("double")
75 || typeName == QLatin1String("float")
76 || typeName.startsWith(QLatin1String("numeric")))
77 return QVariant::Double;
78 if (typeName == QLatin1String("blob"))
79 return QVariant::ByteArray;
80 return QVariant::String;
81}
82
83static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type,
84 int errorCode = -1)
85{
86 return QSqlError(descr,
87 QString::fromUtf16(static_cast<const ushort *>(sqlite3_errmsg16(access))),
88 type, errorCode);
89}
90
91class QSQLiteDriverPrivate
92{
93public:
94 inline QSQLiteDriverPrivate() : access(0) {}
95 sqlite3 *access;
96};
97
98
99class QSQLiteResultPrivate
100{
101public:
102 QSQLiteResultPrivate(QSQLiteResult *res);
103 void cleanup();
104 bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch);
105 // initializes the recordInfo and the cache
106 void initColumns(bool emptyResultset);
107 void finalize();
108
109 QSQLiteResult* q;
110 sqlite3 *access;
111
112 sqlite3_stmt *stmt;
113
114 uint skippedStatus: 1; // the status of the fetchNext() that's skipped
115 uint skipRow: 1; // skip the next fetchNext()?
116 uint utf8: 1;
117 QSqlRecord rInf;
118 QSql::NumericalPrecisionPolicy precisionPolicy;
119};
120
121static const uint initial_cache_size = 128;
122
123QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult* res) : q(res), access(0),
124 stmt(0), skippedStatus(false), skipRow(false), utf8(false), precisionPolicy(QSql::HighPrecision)
125{
126}
127
128void QSQLiteResultPrivate::cleanup()
129{
130 finalize();
131 rInf.clear();
132 skippedStatus = false;
133 skipRow = false;
134 q->setAt(QSql::BeforeFirstRow);
135 q->setActive(false);
136 q->cleanup();
137}
138
139void QSQLiteResultPrivate::finalize()
140{
141 if (!stmt)
142 return;
143
144 sqlite3_finalize(stmt);
145 stmt = 0;
146}
147
148void QSQLiteResultPrivate::initColumns(bool emptyResultset)
149{
150 int nCols = sqlite3_column_count(stmt);
151 if (nCols <= 0)
152 return;
153
154 q->init(nCols);
155
156 for (int i = 0; i < nCols; ++i) {
157 QString colName = QString::fromUtf16(
158 static_cast<const ushort *>(sqlite3_column_name16(stmt, i))
159 ).remove(QLatin1Char('"'));
160
161 // must use typeName for resolving the type to match QSqliteDriver::record
162 QString typeName = QString::fromUtf16(
163 static_cast<const ushort *>(sqlite3_column_decltype16(stmt, i)));
164
165 int dotIdx = colName.lastIndexOf(QLatin1Char('.'));
166 QSqlField fld(colName.mid(dotIdx == -1 ? 0 : dotIdx + 1), qGetColumnType(typeName));
167
168 // sqlite3_column_type is documented to have undefined behavior if the result set is empty
169 int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i);
170 fld.setSqlType(stp);
171 rInf.append(fld);
172 }
173}
174
175bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
176{
177 int res;
178 int i;
179
180 if (skipRow) {
181 // already fetched
182 Q_ASSERT(!initialFetch);
183 skipRow = false;
184 return skippedStatus;
185 }
186 skipRow = initialFetch;
187
188 if (!stmt) {
189 q->setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"),
190 QCoreApplication::translate("QSQLiteResult", "No query"), QSqlError::ConnectionError));
191 q->setAt(QSql::AfterLastRow);
192 return false;
193 }
194 res = sqlite3_step(stmt);
195
196 switch(res) {
197 case SQLITE_ROW:
198 // check to see if should fill out columns
199 if (rInf.isEmpty())
200 // must be first call.
201 initColumns(false);
202 if (idx < 0 && !initialFetch)
203 return true;
204 for (i = 0; i < rInf.count(); ++i) {
205 switch (sqlite3_column_type(stmt, i)) {
206 case SQLITE_BLOB:
207 values[i + idx] = QByteArray(static_cast<const char *>(
208 sqlite3_column_blob(stmt, i)),
209 sqlite3_column_bytes(stmt, i));
210 break;
211 case SQLITE_INTEGER:
212 values[i + idx] = sqlite3_column_int64(stmt, i);
213 break;
214 case SQLITE_FLOAT:
215 switch(precisionPolicy) {
216 case QSql::LowPrecisionInt32:
217 values[i + idx] = sqlite3_column_int(stmt, i);
218 break;
219 case QSql::LowPrecisionInt64:
220 values[i + idx] = sqlite3_column_int64(stmt, i);
221 break;
222 case QSql::LowPrecisionDouble:
223 values[i + idx] = sqlite3_column_double(stmt, i);
224 break;
225 case QSql::HighPrecision:
226 default:
227 values[i + idx] = QString::fromUtf16(static_cast<const ushort *>(
228 sqlite3_column_text16(stmt, i)),
229 sqlite3_column_bytes16(stmt, i) / sizeof(ushort));
230 break;
231 };
232 break;
233 case SQLITE_NULL:
234 values[i + idx] = QVariant(QVariant::String);
235 break;
236 default:
237 values[i + idx] = QString::fromUtf16(static_cast<const ushort *>(
238 sqlite3_column_text16(stmt, i)),
239 sqlite3_column_bytes16(stmt, i) / sizeof(ushort));
240 break;
241 }
242 }
243 return true;
244 case SQLITE_DONE:
245 if (rInf.isEmpty())
246 // must be first call.
247 initColumns(true);
248 q->setAt(QSql::AfterLastRow);
249 sqlite3_reset(stmt);
250 return false;
251 case SQLITE_ERROR:
252 // SQLITE_ERROR is a generic error code and we must call sqlite3_reset()
253 // to get the specific error message.
254 res = sqlite3_reset(stmt);
255 q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult",
256 "Unable to fetch row"), QSqlError::ConnectionError, res));
257 q->setAt(QSql::AfterLastRow);
258 return false;
259 case SQLITE_MISUSE:
260 case SQLITE_BUSY:
261 default:
262 // something wrong, don't get col info, but still return false
263 q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult",
264 "Unable to fetch row"), QSqlError::ConnectionError, res));
265 sqlite3_reset(stmt);
266 q->setAt(QSql::AfterLastRow);
267 return false;
268 }
269 return false;
270}
271
272QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db)
273 : QSqlCachedResult(db)
274{
275 d = new QSQLiteResultPrivate(this);
276 d->access = db->d->access;
277}
278
279QSQLiteResult::~QSQLiteResult()
280{
281 d->cleanup();
282 delete d;
283}
284
285void QSQLiteResult::virtual_hook(int id, void *data)
286{
287 switch (id) {
288 case QSqlResult::DetachFromResultSet:
289 if (d->stmt)
290 sqlite3_reset(d->stmt);
291 break;
292 case QSqlResult::SetNumericalPrecision:
293 Q_ASSERT(data);
294 d->precisionPolicy = *reinterpret_cast<QSql::NumericalPrecisionPolicy *>(data);
295 break;
296 default:
297 QSqlResult::virtual_hook(id, data);
298 }
299}
300
301bool QSQLiteResult::reset(const QString &query)
302{
303 if (!prepare(query))
304 return false;
305 return exec();
306}
307
308bool QSQLiteResult::prepare(const QString &query)
309{
310 if (!driver() || !driver()->isOpen() || driver()->isOpenError())
311 return false;
312
313 d->cleanup();
314
315 setSelect(false);
316
317#if (SQLITE_VERSION_NUMBER >= 3003011)
318 int res = sqlite3_prepare16_v2(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
319 &d->stmt, 0);
320#else
321 int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
322 &d->stmt, 0);
323#endif
324
325 if (res != SQLITE_OK) {
326 setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
327 "Unable to execute statement"), QSqlError::StatementError, res));
328 d->finalize();
329 return false;
330 }
331 return true;
332}
333
334bool QSQLiteResult::exec()
335{
336 const QVector<QVariant> values = boundValues();
337
338 d->skippedStatus = false;
339 d->skipRow = false;
340 d->rInf.clear();
341 clearValues();
342 setLastError(QSqlError());
343
344 int res = sqlite3_reset(d->stmt);
345 if (res != SQLITE_OK) {
346 setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
347 "Unable to reset statement"), QSqlError::StatementError, res));
348 d->finalize();
349 return false;
350 }
351 int paramCount = sqlite3_bind_parameter_count(d->stmt);
352 if (paramCount == values.count()) {
353 for (int i = 0; i < paramCount; ++i) {
354 res = SQLITE_OK;
355 const QVariant value = values.at(i);
356
357 if (value.isNull()) {
358 res = sqlite3_bind_null(d->stmt, i + 1);
359 } else {
360 switch (value.type()) {
361 case QVariant::ByteArray: {
362 const QByteArray *ba = static_cast<const QByteArray*>(value.constData());
363 res = sqlite3_bind_blob(d->stmt, i + 1, ba->constData(),
364 ba->size(), SQLITE_STATIC);
365 break; }
366 case QVariant::Int:
367 res = sqlite3_bind_int(d->stmt, i + 1, value.toInt());
368 break;
369 case QVariant::Double:
370 res = sqlite3_bind_double(d->stmt, i + 1, value.toDouble());
371 break;
372 case QVariant::UInt:
373 case QVariant::LongLong:
374 res = sqlite3_bind_int64(d->stmt, i + 1, value.toLongLong());
375 break;
376 case QVariant::String: {
377 // lifetime of string == lifetime of its qvariant
378 const QString *str = static_cast<const QString*>(value.constData());
379 res = sqlite3_bind_text16(d->stmt, i + 1, str->utf16(),
380 (str->size()) * sizeof(QChar), SQLITE_STATIC);
381 break; }
382 default: {
383 QString str = value.toString();
384 // SQLITE_TRANSIENT makes sure that sqlite buffers the data
385 res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
386 (str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
387 break; }
388 }
389 }
390 if (res != SQLITE_OK) {
391 setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
392 "Unable to bind parameters"), QSqlError::StatementError, res));
393 d->finalize();
394 return false;
395 }
396 }
397 } else {
398 setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult",
399 "Parameter count mismatch"), QString(), QSqlError::StatementError));
400 return false;
401 }
402 d->skippedStatus = d->fetchNext(cache(), 0, true);
403 if (lastError().isValid()) {
404 setSelect(false);
405 setActive(false);
406 return false;
407 }
408 setSelect(!d->rInf.isEmpty());
409 setActive(true);
410 return true;
411}
412
413bool QSQLiteResult::gotoNext(QSqlCachedResult::ValueCache& row, int idx)
414{
415 return d->fetchNext(row, idx, false);
416}
417
418int QSQLiteResult::size()
419{
420 return -1;
421}
422
423int QSQLiteResult::numRowsAffected()
424{
425 return sqlite3_changes(d->access);
426}
427
428QVariant QSQLiteResult::lastInsertId() const
429{
430 if (isActive()) {
431 qint64 id = sqlite3_last_insert_rowid(d->access);
432 if (id)
433 return id;
434 }
435 return QVariant();
436}
437
438QSqlRecord QSQLiteResult::record() const
439{
440 if (!isActive() || !isSelect())
441 return QSqlRecord();
442 return d->rInf;
443}
444
445QVariant QSQLiteResult::handle() const
446{
447 return qVariantFromValue(d->stmt);
448}
449
450/////////////////////////////////////////////////////////
451
452QSQLiteDriver::QSQLiteDriver(QObject * parent)
453 : QSqlDriver(parent)
454{
455 d = new QSQLiteDriverPrivate();
456}
457
458QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent)
459 : QSqlDriver(parent)
460{
461 d = new QSQLiteDriverPrivate();
462 d->access = connection;
463 setOpen(true);
464 setOpenError(false);
465}
466
467
468QSQLiteDriver::~QSQLiteDriver()
469{
470 delete d;
471}
472
473bool QSQLiteDriver::hasFeature(DriverFeature f) const
474{
475 switch (f) {
476 case BLOB:
477 case Transactions:
478 case Unicode:
479 case LastInsertId:
480 case PreparedQueries:
481 case PositionalPlaceholders:
482 case SimpleLocking:
483 case FinishQuery:
484 return true;
485 case QuerySize:
486 case NamedPlaceholders:
487 case BatchOperations:
488 case LowPrecisionNumbers:
489 case EventNotifications:
490 case MultipleResultSets:
491 return false;
492 }
493 return false;
494}
495
496static int qGetSqliteTimeout(QString opts)
497{
498 enum { DefaultTimeout = 5000 };
499
500 opts.remove(QLatin1Char(' '));
501 if (opts.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT="))) {
502 bool ok;
503 int nt = opts.mid(21).toInt(&ok);
504 if (ok)
505 return nt;
506 }
507 return DefaultTimeout;
508}
509
510/*
511 SQLite dbs have no user name, passwords, hosts or ports.
512 just file names.
513*/
514bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &conOpts)
515{
516 if (isOpen())
517 close();
518
519 if (db.isEmpty())
520 return false;
521
522 if (sqlite3_open16(db.constData(), &d->access) == SQLITE_OK) {
523 sqlite3_busy_timeout(d->access, qGetSqliteTimeout(conOpts));
524 setOpen(true);
525 setOpenError(false);
526 return true;
527 } else {
528 setLastError(qMakeError(d->access, tr("Error opening database"),
529 QSqlError::ConnectionError));
530 setOpenError(true);
531 return false;
532 }
533}
534
535void QSQLiteDriver::close()
536{
537 if (isOpen()) {
538 if (sqlite3_close(d->access) != SQLITE_OK)
539 setLastError(qMakeError(d->access, tr("Error closing database"),
540 QSqlError::ConnectionError));
541 d->access = 0;
542 setOpen(false);
543 setOpenError(false);
544 }
545}
546
547QSqlResult *QSQLiteDriver::createResult() const
548{
549 return new QSQLiteResult(this);
550}
551
552bool QSQLiteDriver::beginTransaction()
553{
554 if (!isOpen() || isOpenError())
555 return false;
556
557 QSqlQuery q(createResult());
558 if (!q.exec(QLatin1String("BEGIN"))) {
559 setLastError(QSqlError(tr("Unable to begin transaction"),
560 q.lastError().databaseText(), QSqlError::TransactionError));
561 return false;
562 }
563
564 return true;
565}
566
567bool QSQLiteDriver::commitTransaction()
568{
569 if (!isOpen() || isOpenError())
570 return false;
571
572 QSqlQuery q(createResult());
573 if (!q.exec(QLatin1String("COMMIT"))) {
574 setLastError(QSqlError(tr("Unable to commit transaction"),
575 q.lastError().databaseText(), QSqlError::TransactionError));
576 return false;
577 }
578
579 return true;
580}
581
582bool QSQLiteDriver::rollbackTransaction()
583{
584 if (!isOpen() || isOpenError())
585 return false;
586
587 QSqlQuery q(createResult());
588 if (!q.exec(QLatin1String("ROLLBACK"))) {
589 setLastError(QSqlError(tr("Unable to rollback transaction"),
590 q.lastError().databaseText(), QSqlError::TransactionError));
591 return false;
592 }
593
594 return true;
595}
596
597QStringList QSQLiteDriver::tables(QSql::TableType type) const
598{
599 QStringList res;
600 if (!isOpen())
601 return res;
602
603 QSqlQuery q(createResult());
604 q.setForwardOnly(true);
605
606 QString sql = QLatin1String("SELECT name FROM sqlite_master WHERE %1 "
607 "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1");
608 if ((type & QSql::Tables) && (type & QSql::Views))
609 sql = sql.arg(QLatin1String("type='table' OR type='view'"));
610 else if (type & QSql::Tables)
611 sql = sql.arg(QLatin1String("type='table'"));
612 else if (type & QSql::Views)
613 sql = sql.arg(QLatin1String("type='view'"));
614 else
615 sql.clear();
616
617 if (!sql.isEmpty() && q.exec(sql)) {
618 while(q.next())
619 res.append(q.value(0).toString());
620 }
621
622 if (type & QSql::SystemTables) {
623 // there are no internal tables beside this one:
624 res.append(QLatin1String("sqlite_master"));
625 }
626
627 return res;
628}
629
630static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false)
631{
632 QString schema;
633 QString table(tableName);
634 int indexOfSeparator = tableName.indexOf(QLatin1String("."));
635 if (indexOfSeparator > -1) {
636 schema = tableName.left(indexOfSeparator).append(QLatin1String("."));
637 table = tableName.mid(indexOfSeparator + 1);
638 }
639 q.exec(QLatin1String("PRAGMA ") + schema + QLatin1String("table_info ('") + table + QLatin1String("')"));
640
641 QSqlIndex ind;
642 while (q.next()) {
643 bool isPk = q.value(5).toInt();
644 if (onlyPIndex && !isPk)
645 continue;
646 QString typeName = q.value(2).toString().toLower();
647 QSqlField fld(q.value(1).toString(), qGetColumnType(typeName));
648 if (isPk && (typeName == QLatin1String("integer")))
649 // INTEGER PRIMARY KEY fields are auto-generated in sqlite
650 // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
651 fld.setAutoValue(true);
652 fld.setRequired(q.value(3).toInt() != 0);
653 fld.setDefaultValue(q.value(4));
654 ind.append(fld);
655 }
656 return ind;
657}
658
659QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
660{
661 if (!isOpen())
662 return QSqlIndex();
663
664 QSqlQuery q(createResult());
665 q.setForwardOnly(true);
666 return qGetTableInfo(q, tblname, true);
667}
668
669QSqlRecord QSQLiteDriver::record(const QString &tbl) const
670{
671 if (!isOpen())
672 return QSqlRecord();
673
674 QSqlQuery q(createResult());
675 q.setForwardOnly(true);
676 return qGetTableInfo(q, tbl);
677}
678
679QVariant QSQLiteDriver::handle() const
680{
681 return qVariantFromValue(d->access);
682}
683
684QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType /*type*/) const
685{
686 QString res = identifier;
687 if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) {
688 res.replace(QLatin1Char('"'), QLatin1String("\"\""));
689 res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
690 res.replace(QLatin1Char('.'), QLatin1String("\".\""));
691 }
692 return res;
693}
694
695QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.