2014-10-14 13:14:57 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; version 2 of the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <QDateTime>
|
|
|
|
#include <QString>
|
2014-10-14 22:51:51 +04:00
|
|
|
#include <QDebug>
|
2014-10-14 13:14:57 +04:00
|
|
|
|
|
|
|
#include "ownsql.h"
|
|
|
|
|
2014-10-14 14:18:33 +04:00
|
|
|
#define SQLITE_DO(A) if(1) { \
|
|
|
|
_errId = (A); if(_errId != SQLITE_OK) { _error= QString::fromUtf8(sqlite3_errmsg(_db)); \
|
|
|
|
} }
|
2014-10-14 13:14:57 +04:00
|
|
|
|
2014-10-14 22:51:51 +04:00
|
|
|
namespace Mirall {
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlDatabase::SqlDatabase()
|
2014-10-16 12:39:10 +04:00
|
|
|
:_db(0),
|
|
|
|
_errId(0)
|
2014-10-14 13:14:57 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SqlDatabase::isOpen()
|
|
|
|
{
|
2014-10-15 18:46:39 +04:00
|
|
|
return _db != 0;
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SqlDatabase::open( const QString& filename )
|
|
|
|
{
|
2014-10-14 14:18:33 +04:00
|
|
|
if(isOpen()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int flag = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_NOMUTEX;
|
2014-10-15 18:46:39 +04:00
|
|
|
SQLITE_DO( sqlite3_open_v2(filename.toUtf8().constData(), &_db, flag, 0) );
|
2014-10-14 13:14:57 +04:00
|
|
|
|
|
|
|
if( _errId != SQLITE_OK ) {
|
|
|
|
close(); // FIXME: Correct?
|
2014-10-15 18:46:39 +04:00
|
|
|
_db = 0;
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
|
|
|
return isOpen();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SqlDatabase::error() const
|
|
|
|
{
|
|
|
|
const QString err(_error);
|
|
|
|
// _error.clear();
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SqlDatabase::close()
|
|
|
|
{
|
|
|
|
if( _db ) {
|
|
|
|
SQLITE_DO(sqlite3_close_v2(_db) );
|
2014-10-15 18:46:39 +04:00
|
|
|
_db = 0;
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SqlDatabase::transaction()
|
|
|
|
{
|
2014-10-15 21:47:25 +04:00
|
|
|
if( ! _db ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
SQLITE_DO(sqlite3_exec(_db, "BEGIN", 0, 0, 0));
|
|
|
|
return _errId == SQLITE_OK;
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SqlDatabase::commit()
|
|
|
|
{
|
2014-10-15 21:47:25 +04:00
|
|
|
if( ! _db ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
SQLITE_DO(sqlite3_exec(_db, "COMMIT", 0, 0, 0));
|
|
|
|
return _errId == SQLITE_OK;
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
sqlite3* SqlDatabase::sqliteDb()
|
|
|
|
{
|
|
|
|
return _db;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* =========================================================================================== */
|
|
|
|
|
|
|
|
SqlQuery::SqlQuery( SqlDatabase db )
|
2014-10-14 22:51:51 +04:00
|
|
|
:_db(db.sqliteDb()),
|
|
|
|
_stmt(0)
|
2014-10-14 13:14:57 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
SqlQuery::~SqlQuery()
|
|
|
|
{
|
|
|
|
if( _stmt ) {
|
2014-10-17 15:39:48 +04:00
|
|
|
finish();
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SqlQuery::SqlQuery(const QString& sql, SqlDatabase db)
|
2014-10-14 22:51:51 +04:00
|
|
|
:_db(db.sqliteDb()),
|
|
|
|
_stmt(0)
|
2014-10-14 13:14:57 +04:00
|
|
|
{
|
|
|
|
prepare(sql);
|
|
|
|
}
|
|
|
|
|
2014-10-14 22:51:51 +04:00
|
|
|
int SqlQuery::prepare( const QString& sql)
|
2014-10-14 13:14:57 +04:00
|
|
|
{
|
2014-10-14 22:51:51 +04:00
|
|
|
QString s(sql);
|
|
|
|
_sql = s.trimmed();
|
|
|
|
if(_stmt ) {
|
|
|
|
finish();
|
|
|
|
}
|
|
|
|
if(!_sql.isEmpty() ) {
|
2014-10-15 18:46:39 +04:00
|
|
|
SQLITE_DO(sqlite3_prepare_v2(_db, _sql.toUtf8().constData(), -1, &_stmt, 0));
|
2014-10-14 22:51:51 +04:00
|
|
|
if( _errId != SQLITE_OK ) {
|
2014-10-17 13:35:06 +04:00
|
|
|
qDebug() << "Sqlite prepare statement error:" << _error << "in"<<_sql;
|
2014-10-14 22:51:51 +04:00
|
|
|
}
|
|
|
|
// Q_ASSERT(_errId == SQLITE_OK);
|
|
|
|
}
|
|
|
|
return _errId;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SqlQuery::isSelect()
|
|
|
|
{
|
|
|
|
return (!_sql.isEmpty() && _sql.startsWith("SELECT", Qt::CaseInsensitive));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SqlQuery::isPragma()
|
|
|
|
{
|
|
|
|
return (!_sql.isEmpty() && _sql.startsWith("PRAGMA", Qt::CaseInsensitive));
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SqlQuery::exec()
|
|
|
|
{
|
2014-10-14 22:51:51 +04:00
|
|
|
// Don't do anything for selects, that is how we use the lib :-|
|
|
|
|
if(_stmt && !isSelect() && !isPragma() ) {
|
|
|
|
SQLITE_DO(sqlite3_step(_stmt));
|
2014-10-15 15:29:25 +04:00
|
|
|
return (_errId == SQLITE_DONE); // either SQLITE_ROW or SQLITE_DONE
|
2014-10-14 22:51:51 +04:00
|
|
|
}
|
2014-10-14 13:14:57 +04:00
|
|
|
|
2014-10-14 22:51:51 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SqlQuery::next()
|
|
|
|
{
|
|
|
|
SQLITE_DO(sqlite3_step(_stmt));
|
|
|
|
return _errId == SQLITE_ROW;
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void SqlQuery::bindValue(int pos, const QVariant& value)
|
|
|
|
{
|
2014-10-16 13:20:21 +04:00
|
|
|
int res = -1;
|
2014-10-14 13:14:57 +04:00
|
|
|
if( _stmt ) {
|
|
|
|
switch (value.type()) {
|
|
|
|
case QVariant::Int:
|
|
|
|
case QVariant::Bool:
|
|
|
|
res = sqlite3_bind_int(_stmt, pos, value.toInt());
|
|
|
|
break;
|
|
|
|
case QVariant::Double:
|
|
|
|
res = sqlite3_bind_double(_stmt, pos, value.toDouble());
|
|
|
|
break;
|
|
|
|
case QVariant::UInt:
|
|
|
|
case QVariant::LongLong:
|
|
|
|
res = sqlite3_bind_int64(_stmt, pos, value.toLongLong());
|
|
|
|
break;
|
|
|
|
case QVariant::DateTime: {
|
|
|
|
const QDateTime dateTime = value.toDateTime();
|
|
|
|
const QString str = dateTime.toString(QLatin1String("yyyy-MM-ddThh:mm:ss.zzz"));
|
|
|
|
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
|
|
|
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QVariant::Time: {
|
|
|
|
const QTime time = value.toTime();
|
|
|
|
const QString str = time.toString(QLatin1String("hh:mm:ss.zzz"));
|
|
|
|
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
|
|
|
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QVariant::String: {
|
2014-10-16 13:20:50 +04:00
|
|
|
if( !value.toString().isNull() ) {
|
|
|
|
// lifetime of string == lifetime of its qvariant
|
|
|
|
const QString *str = static_cast<const QString*>(value.constData());
|
|
|
|
res = sqlite3_bind_text16(_stmt, pos, str->utf16(),
|
2014-10-16 17:30:50 +04:00
|
|
|
(str->size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
2014-10-16 13:20:50 +04:00
|
|
|
} else {
|
|
|
|
// unbound value create a null entry.
|
|
|
|
res = SQLITE_OK;
|
|
|
|
}
|
2014-10-14 13:14:57 +04:00
|
|
|
break; }
|
|
|
|
default: {
|
|
|
|
QString str = value.toString();
|
|
|
|
// SQLITE_TRANSIENT makes sure that sqlite buffers the data
|
|
|
|
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
|
|
|
(str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
|
|
|
break; }
|
|
|
|
}
|
|
|
|
}
|
2014-10-16 13:20:21 +04:00
|
|
|
Q_ASSERT( res == SQLITE_OK );
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
QString SqlQuery::stringValue(int index)
|
|
|
|
{
|
|
|
|
return QString::fromUtf16(static_cast<const ushort*>(sqlite3_column_text16(_stmt, index)));
|
|
|
|
}
|
|
|
|
|
|
|
|
int SqlQuery::intValue(int index)
|
|
|
|
{
|
|
|
|
return sqlite3_column_int(_stmt, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
quint64 SqlQuery::int64Value(int index)
|
|
|
|
{
|
|
|
|
return sqlite3_column_int64(_stmt, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray SqlQuery::baValue(int index)
|
|
|
|
{
|
|
|
|
return QByteArray( static_cast<const char*>(sqlite3_column_blob(_stmt, index)),
|
|
|
|
sqlite3_column_bytes(_stmt, index));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SqlQuery::error() const
|
|
|
|
{
|
2014-10-14 22:51:51 +04:00
|
|
|
return _error;
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
QString SqlQuery::lastQuery() const
|
|
|
|
{
|
2014-10-14 22:51:51 +04:00
|
|
|
return _sql;
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int SqlQuery::numRowsAffected()
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SqlQuery::finish()
|
|
|
|
{
|
|
|
|
SQLITE_DO(sqlite3_finalize(_stmt));
|
2014-10-15 18:46:39 +04:00
|
|
|
_stmt = 0;
|
2014-10-14 13:14:57 +04:00
|
|
|
}
|
2014-10-14 22:51:51 +04:00
|
|
|
|
|
|
|
void SqlQuery::reset()
|
|
|
|
{
|
|
|
|
SQLITE_DO(sqlite3_reset(_stmt));
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Mirall
|