2
Copyright (C) 2010 Marco Mentasti <marcomentasti@gmail.com>
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License version 2 as published by the Free Software Foundation.
8
This library is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
Library General Public License for more details.
13
You should have received a copy of the GNU Library General Public License
14
along with this library; see the file COPYING.LIB. If not, write to
15
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16
Boston, MA 02110-1301, USA.
19
#include "sqlmanager.h"
20
#include "connectionmodel.h"
22
#include <klocalizedstring.h>
24
#include <kconfiggroup.h>
27
#include <qsqldatabase.h>
28
#include <qsqlquery.h>
29
#include <qsqlerror.h>
30
#include <qsqldriver.h>
32
using KWallet::Wallet;
34
SQLManager::SQLManager(QObject *parent)
36
, m_model(new ConnectionModel(this))
42
SQLManager::~SQLManager()
44
for(int i = 0; i < m_model->rowCount(); i++)
46
QString connection =m_model->data(m_model->index(i), Qt::DisplayRole).toString();
47
QSqlDatabase::removeDatabase(connection);
55
void SQLManager::createConnection(const Connection &conn)
57
if (QSqlDatabase::contains(conn.name))
59
qDebug() << "connection" << conn.name << "already exist";
60
QSqlDatabase::removeDatabase(conn.name);
63
QSqlDatabase db = QSqlDatabase::addDatabase(conn.driver, conn.name);
67
emit error(db.lastError().text());
68
QSqlDatabase::removeDatabase(conn.name);
72
db.setHostName(conn.hostname);
73
db.setUserName(conn.username);
74
db.setPassword(conn.password);
75
db.setDatabaseName(conn.database);
76
db.setConnectOptions(conn.options);
79
db.setPort(conn.port);
81
m_model->addConnection(conn);
83
// try to open connection, with or without password
85
m_model->setStatus(conn.name, Connection::ONLINE);
88
if (conn.status != Connection::REQUIRE_PASSWORD)
90
m_model->setStatus(conn.name, Connection::OFFLINE);
91
emit error(db.lastError().text());
95
emit connectionCreated(conn.name);
99
bool SQLManager::testConnection(const Connection &conn, QSqlError &error)
101
QString connectionName = (conn.name.isEmpty()) ? QString::fromLatin1 ("katesql-test") : conn.name;
103
QSqlDatabase db = QSqlDatabase::addDatabase(conn.driver, connectionName);
107
error = db.lastError();
108
QSqlDatabase::removeDatabase(connectionName);
112
db.setHostName(conn.hostname);
113
db.setUserName(conn.username);
114
db.setPassword(conn.password);
115
db.setDatabaseName(conn.database);
116
db.setConnectOptions(conn.options);
119
db.setPort(conn.port);
123
error = db.lastError();
124
QSqlDatabase::removeDatabase(connectionName);
128
QSqlDatabase::removeDatabase(connectionName);
132
bool SQLManager::isValidAndOpen(const QString &connection)
134
QSqlDatabase db = QSqlDatabase::database(connection);
138
m_model->setStatus(connection, Connection::OFFLINE);
139
emit error(db.lastError().text());
145
qDebug() << "database connection is not open. trying to open it...";
147
if (m_model->status(connection) == Connection::REQUIRE_PASSWORD)
150
int ret = readCredentials(connection, password);
153
qDebug() << "Can't retrieve password from kwallet. returned code" << ret;
156
db.setPassword(password);
157
m_model->setPassword(connection, password);
163
m_model->setStatus(connection, Connection::OFFLINE);
164
emit error(db.lastError().text());
169
m_model->setStatus(connection, Connection::ONLINE);
175
void SQLManager::reopenConnection (const QString& name)
177
emit connectionAboutToBeClosed(name);
179
QSqlDatabase db = QSqlDatabase::database(name);
182
isValidAndOpen(name);
186
Wallet *SQLManager::openWallet()
189
/// FIXME get kate window id...
190
m_wallet = Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0);
195
QString folder (QLatin1String ("SQL Connections"));
197
if (!m_wallet->hasFolder(folder))
198
m_wallet->createFolder(folder);
200
m_wallet->setFolder(folder);
206
// return 0 on success, -1 on error, -2 on user reject
207
int SQLManager::storeCredentials(const Connection &conn)
209
// Sqlite is without password, avoid to open wallet
210
if (conn.driver.contains(QLatin1String ("QSQLITE")))
213
Wallet *wallet = openWallet();
215
if (!wallet) // user reject
218
QMap<QString, QString> map;
220
map[QLatin1String ("driver")] = conn.driver.toUpper();
221
map[QLatin1String ("hostname")] = conn.hostname.toUpper();
222
map[QLatin1String ("port")] = QString::number(conn.port);
223
map[QLatin1String ("database")] = conn.database.toUpper();
224
map[QLatin1String ("username")] = conn.username;
225
map[QLatin1String ("password")] = conn.password;
227
return (wallet->writeMap(conn.name, map) == 0) ? 0 : -1;
231
// return 0 on success, -1 on error or not found, -2 on user reject
232
// if success, password contain the password
233
int SQLManager::readCredentials(const QString &name, QString &password)
235
Wallet *wallet = openWallet();
237
if (!wallet) // user reject
240
QMap<QString, QString> map;
242
if (wallet->readMap(name, map) == 0)
246
password = map.value(QLatin1String("password"));
255
ConnectionModel* SQLManager::connectionModel()
261
void SQLManager::removeConnection(const QString &name)
263
emit connectionAboutToBeClosed(name);
265
m_model->removeConnection(name);
267
QSqlDatabase::removeDatabase(name);
269
emit connectionRemoved(name);
272
/// TODO: read KUrl instead of QString for sqlite paths
273
void SQLManager::loadConnections(KConfigGroup *connectionsGroup)
277
foreach ( const QString& groupName, connectionsGroup->groupList() )
279
qDebug() << "reading group:" << groupName;
281
KConfigGroup group = connectionsGroup->group(groupName);
284
c.driver = group.readEntry("driver");
285
c.database = group.readEntry("database");
286
c.options = group.readEntry("options");
288
if (!c.driver.contains(QLatin1String("QSQLITE")))
290
c.hostname = group.readEntry("hostname");
291
c.username = group.readEntry("username");
292
c.port = group.readEntry("port", 0);
294
// for compatibility with version 0.2, when passwords
295
// were stored in config file instead of kwallet
296
c.password = group.readEntry("password");
298
if (!c.password.isEmpty())
299
c.status = Connection::ONLINE;
301
c.status = Connection::REQUIRE_PASSWORD;
307
void SQLManager::saveConnections(KConfigGroup *connectionsGroup)
309
for(int i = 0; i < m_model->rowCount(); i++)
310
saveConnection(connectionsGroup, m_model->data(m_model->index(i), Qt::UserRole).value<Connection>());
313
/// TODO: write KUrl instead of QString for sqlite paths
314
void SQLManager::saveConnection(KConfigGroup *connectionsGroup, const Connection &conn)
316
qDebug() << "saving connection" << conn.name;
318
KConfigGroup group = connectionsGroup->group(conn.name);
320
group.writeEntry("driver" , conn.driver);
321
group.writeEntry("database", conn.database);
322
group.writeEntry("options" , conn.options);
324
if (!conn.driver.contains(QLatin1String("QSQLITE")))
326
group.writeEntry("hostname", conn.hostname);
327
group.writeEntry("username", conn.username);
328
group.writeEntry("port" , conn.port);
333
void SQLManager::runQuery(const QString &text, const QString &connection)
335
qDebug() << "connection:" << connection;
336
qDebug() << "text:" << text;
341
if (!isValidAndOpen(connection))
344
QSqlDatabase db = QSqlDatabase::database(connection);
347
if (!query.prepare(text))
349
QSqlError err = query.lastError();
351
if (err.type() == QSqlError::ConnectionError)
352
m_model->setStatus(connection, Connection::OFFLINE);
354
emit error(err.text());
360
QSqlError err = query.lastError();
362
if (err.type() == QSqlError::ConnectionError)
363
m_model->setStatus(connection, Connection::OFFLINE);
365
emit error(err.text());
371
/// TODO: improve messages
372
if (query.isSelect())
374
if (!query.driver()->hasFeature(QSqlDriver::QuerySize))
375
message = i18nc("@info", "Query completed successfully");
378
int nRowsSelected = query.size();
379
message = i18ncp("@info", "%1 record selected", "%1 records selected", nRowsSelected);
384
int nRowsAffected = query.numRowsAffected();
385
message = i18ncp("@info", "%1 row affected", "%1 rows affected", nRowsAffected);
388
emit success(message);
389
emit queryActivated(query, connection);