~ubuntu-branches/ubuntu/vivid/kate/vivid-proposed

« back to all changes in this revision

Viewing changes to addons/katesql/sqlmanager.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2014-12-04 16:49:41 UTC
  • mfrom: (1.6.6)
  • Revision ID: package-import@ubuntu.com-20141204164941-l3qbvsly83hhlw2v
Tags: 4:14.11.97-0ubuntu1
* New upstream release
* Update build-deps and use pkg-kde v3 for Qt 5 build
* kate-data now kate5-data for co-installability

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Copyright (C) 2010  Marco Mentasti  <marcomentasti@gmail.com>
 
3
 
 
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.
 
7
 
 
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.
 
12
 
 
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.
 
17
*/
 
18
 
 
19
#include "sqlmanager.h"
 
20
#include "connectionmodel.h"
 
21
 
 
22
#include <klocalizedstring.h>
 
23
#include <kconfig.h>
 
24
#include <kconfiggroup.h>
 
25
 
 
26
#include <QDebug>
 
27
#include <qsqldatabase.h>
 
28
#include <qsqlquery.h>
 
29
#include <qsqlerror.h>
 
30
#include <qsqldriver.h>
 
31
 
 
32
using KWallet::Wallet;
 
33
 
 
34
SQLManager::SQLManager(QObject *parent)
 
35
: QObject(parent)
 
36
, m_model(new ConnectionModel(this))
 
37
, m_wallet(0)
 
38
{
 
39
}
 
40
 
 
41
 
 
42
SQLManager::~SQLManager()
 
43
{
 
44
  for(int i = 0; i < m_model->rowCount(); i++)
 
45
  {
 
46
    QString connection =m_model->data(m_model->index(i), Qt::DisplayRole).toString();
 
47
    QSqlDatabase::removeDatabase(connection);
 
48
  }
 
49
 
 
50
  delete m_model;
 
51
  delete m_wallet;
 
52
}
 
53
 
 
54
 
 
55
void SQLManager::createConnection(const Connection &conn)
 
56
{
 
57
  if (QSqlDatabase::contains(conn.name))
 
58
  {
 
59
    qDebug() << "connection" << conn.name << "already exist";
 
60
    QSqlDatabase::removeDatabase(conn.name);
 
61
  }
 
62
 
 
63
  QSqlDatabase db = QSqlDatabase::addDatabase(conn.driver, conn.name);
 
64
 
 
65
  if (!db.isValid())
 
66
  {
 
67
    emit error(db.lastError().text());
 
68
    QSqlDatabase::removeDatabase(conn.name);
 
69
    return;
 
70
  }
 
71
 
 
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);
 
77
 
 
78
  if (conn.port > 0)
 
79
    db.setPort(conn.port);
 
80
 
 
81
  m_model->addConnection(conn);
 
82
 
 
83
  // try to open connection, with or without password
 
84
  if (db.open())
 
85
    m_model->setStatus(conn.name, Connection::ONLINE);
 
86
  else
 
87
  {
 
88
    if (conn.status != Connection::REQUIRE_PASSWORD)
 
89
    {
 
90
      m_model->setStatus(conn.name, Connection::OFFLINE);
 
91
      emit error(db.lastError().text());
 
92
    }
 
93
  }
 
94
 
 
95
  emit connectionCreated(conn.name);
 
96
}
 
97
 
 
98
 
 
99
bool SQLManager::testConnection(const Connection &conn, QSqlError &error)
 
100
{
 
101
  QString connectionName = (conn.name.isEmpty()) ? QString::fromLatin1 ("katesql-test") : conn.name;
 
102
 
 
103
  QSqlDatabase db = QSqlDatabase::addDatabase(conn.driver, connectionName);
 
104
 
 
105
  if (!db.isValid())
 
106
  {
 
107
    error = db.lastError();
 
108
    QSqlDatabase::removeDatabase(connectionName);
 
109
    return false;
 
110
  }
 
111
 
 
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);
 
117
 
 
118
  if (conn.port > 0)
 
119
    db.setPort(conn.port);
 
120
 
 
121
  if (!db.open())
 
122
  {
 
123
    error = db.lastError();
 
124
    QSqlDatabase::removeDatabase(connectionName);
 
125
    return false;
 
126
  }
 
127
 
 
128
  QSqlDatabase::removeDatabase(connectionName);
 
129
  return true;
 
130
}
 
131
 
 
132
bool SQLManager::isValidAndOpen(const QString &connection)
 
133
{
 
134
  QSqlDatabase db = QSqlDatabase::database(connection);
 
135
 
 
136
  if (!db.isValid())
 
137
  {
 
138
    m_model->setStatus(connection, Connection::OFFLINE);
 
139
    emit error(db.lastError().text());
 
140
    return false;
 
141
  }
 
142
 
 
143
  if (!db.isOpen())
 
144
  {
 
145
    qDebug() << "database connection is not open. trying to open it...";
 
146
 
 
147
    if (m_model->status(connection) == Connection::REQUIRE_PASSWORD)
 
148
    {
 
149
      QString password;
 
150
      int ret = readCredentials(connection, password);
 
151
 
 
152
      if (ret != 0)
 
153
        qDebug() << "Can't retrieve password from kwallet. returned code" << ret;
 
154
      else
 
155
      {
 
156
        db.setPassword(password);
 
157
        m_model->setPassword(connection, password);
 
158
      }
 
159
    }
 
160
 
 
161
    if (!db.open())
 
162
    {
 
163
      m_model->setStatus(connection, Connection::OFFLINE);
 
164
      emit error(db.lastError().text());
 
165
      return false;
 
166
    }
 
167
  }
 
168
 
 
169
  m_model->setStatus(connection, Connection::ONLINE);
 
170
 
 
171
  return true;
 
172
}
 
173
 
 
174
 
 
175
void SQLManager::reopenConnection (const QString& name)
 
176
{
 
177
  emit connectionAboutToBeClosed(name);
 
178
 
 
179
  QSqlDatabase db = QSqlDatabase::database(name);
 
180
 
 
181
  db.close();
 
182
  isValidAndOpen(name);
 
183
}
 
184
 
 
185
 
 
186
Wallet *SQLManager::openWallet()
 
187
{
 
188
  if (!m_wallet)
 
189
    /// FIXME get kate window id...
 
190
    m_wallet = Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0);
 
191
 
 
192
  if (!m_wallet)
 
193
    return 0;
 
194
 
 
195
  QString folder (QLatin1String ("SQL Connections"));
 
196
 
 
197
  if (!m_wallet->hasFolder(folder))
 
198
    m_wallet->createFolder(folder);
 
199
 
 
200
  m_wallet->setFolder(folder);
 
201
 
 
202
  return m_wallet;
 
203
}
 
204
 
 
205
 
 
206
// return 0 on success, -1 on error, -2 on user reject
 
207
int SQLManager::storeCredentials(const Connection &conn)
 
208
{
 
209
  // Sqlite is without password, avoid to open wallet
 
210
  if (conn.driver.contains(QLatin1String ("QSQLITE")))
 
211
    return 0;
 
212
 
 
213
  Wallet *wallet = openWallet();
 
214
 
 
215
  if (!wallet) // user reject
 
216
    return -2;
 
217
 
 
218
  QMap<QString, QString> map;
 
219
 
 
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;
 
226
 
 
227
  return (wallet->writeMap(conn.name, map) == 0) ? 0 : -1;
 
228
}
 
229
 
 
230
 
 
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)
 
234
{
 
235
  Wallet *wallet = openWallet();
 
236
 
 
237
  if (!wallet) // user reject
 
238
    return -2;
 
239
 
 
240
  QMap<QString, QString> map;
 
241
 
 
242
  if (wallet->readMap(name, map) == 0)
 
243
  {
 
244
    if (!map.isEmpty())
 
245
    {
 
246
      password = map.value(QLatin1String("password"));
 
247
      return 0;
 
248
    }
 
249
  }
 
250
 
 
251
  return -1;
 
252
}
 
253
 
 
254
 
 
255
ConnectionModel* SQLManager::connectionModel()
 
256
{
 
257
  return m_model;
 
258
}
 
259
 
 
260
 
 
261
void SQLManager::removeConnection(const QString &name)
 
262
{
 
263
  emit connectionAboutToBeClosed(name);
 
264
 
 
265
  m_model->removeConnection(name);
 
266
 
 
267
  QSqlDatabase::removeDatabase(name);
 
268
 
 
269
  emit connectionRemoved(name);
 
270
}
 
271
 
 
272
/// TODO: read KUrl instead of QString for sqlite paths
 
273
void SQLManager::loadConnections(KConfigGroup *connectionsGroup)
 
274
{
 
275
  Connection c;
 
276
 
 
277
  foreach ( const QString& groupName, connectionsGroup->groupList() )
 
278
  {
 
279
    qDebug() << "reading group:" << groupName;
 
280
 
 
281
    KConfigGroup group = connectionsGroup->group(groupName);
 
282
 
 
283
    c.name     = groupName;
 
284
    c.driver   = group.readEntry("driver");
 
285
    c.database = group.readEntry("database");
 
286
    c.options  = group.readEntry("options");
 
287
 
 
288
    if (!c.driver.contains(QLatin1String("QSQLITE")))
 
289
    {
 
290
      c.hostname = group.readEntry("hostname");
 
291
      c.username = group.readEntry("username");
 
292
      c.port     = group.readEntry("port", 0);
 
293
 
 
294
      // for compatibility with version 0.2, when passwords
 
295
      // were stored in config file instead of kwallet
 
296
      c.password = group.readEntry("password");
 
297
 
 
298
      if (!c.password.isEmpty())
 
299
        c.status = Connection::ONLINE;
 
300
      else
 
301
        c.status = Connection::REQUIRE_PASSWORD;
 
302
    }
 
303
    createConnection(c);
 
304
  }
 
305
}
 
306
 
 
307
void SQLManager::saveConnections(KConfigGroup *connectionsGroup)
 
308
{
 
309
  for(int i = 0; i < m_model->rowCount(); i++)
 
310
    saveConnection(connectionsGroup, m_model->data(m_model->index(i), Qt::UserRole).value<Connection>());
 
311
}
 
312
 
 
313
/// TODO: write KUrl instead of QString for sqlite paths
 
314
void SQLManager::saveConnection(KConfigGroup *connectionsGroup, const Connection &conn)
 
315
{
 
316
  qDebug() << "saving connection" << conn.name;
 
317
 
 
318
  KConfigGroup group = connectionsGroup->group(conn.name);
 
319
 
 
320
  group.writeEntry("driver"  , conn.driver);
 
321
  group.writeEntry("database", conn.database);
 
322
  group.writeEntry("options" , conn.options);
 
323
 
 
324
  if (!conn.driver.contains(QLatin1String("QSQLITE")))
 
325
  {
 
326
    group.writeEntry("hostname", conn.hostname);
 
327
    group.writeEntry("username", conn.username);
 
328
    group.writeEntry("port"    , conn.port);
 
329
  }
 
330
}
 
331
 
 
332
 
 
333
void SQLManager::runQuery(const QString &text, const QString &connection)
 
334
{
 
335
  qDebug() << "connection:" << connection;
 
336
  qDebug() << "text:"       << text;
 
337
 
 
338
  if (text.isEmpty())
 
339
    return;
 
340
 
 
341
  if (!isValidAndOpen(connection))
 
342
    return;
 
343
 
 
344
  QSqlDatabase db = QSqlDatabase::database(connection);
 
345
  QSqlQuery query(db);
 
346
 
 
347
  if (!query.prepare(text))
 
348
  {
 
349
    QSqlError err = query.lastError();
 
350
 
 
351
    if (err.type() == QSqlError::ConnectionError)
 
352
      m_model->setStatus(connection, Connection::OFFLINE);
 
353
 
 
354
    emit error(err.text());
 
355
    return;
 
356
  }
 
357
 
 
358
  if (!query.exec())
 
359
  {
 
360
    QSqlError err = query.lastError();
 
361
 
 
362
    if (err.type() == QSqlError::ConnectionError)
 
363
      m_model->setStatus(connection, Connection::OFFLINE);
 
364
 
 
365
    emit error(err.text());
 
366
    return;
 
367
  }
 
368
 
 
369
  QString message;
 
370
 
 
371
  /// TODO: improve messages
 
372
  if (query.isSelect())
 
373
  {
 
374
    if (!query.driver()->hasFeature(QSqlDriver::QuerySize))
 
375
      message = i18nc("@info", "Query completed successfully");
 
376
    else
 
377
    {
 
378
      int nRowsSelected = query.size();
 
379
      message = i18ncp("@info", "%1 record selected", "%1 records selected", nRowsSelected);
 
380
    }
 
381
  }
 
382
  else
 
383
  {
 
384
    int nRowsAffected = query.numRowsAffected();
 
385
    message = i18ncp("@info", "%1 row affected", "%1 rows affected", nRowsAffected);
 
386
  }
 
387
 
 
388
  emit success(message);
 
389
  emit queryActivated(query, connection);
 
390
}
 
391