2 #include "servertreeitem.h"
3 #include "mainwindow.h"
6 #include <qfpixmapcache.h>
7 #include <qfexception.h>
8 #include <qfdlgexception.h>
10 #include <qfsqlquery.h>
11 #include <qfsqlcatalog.h>
16 #include <QSqlDatabase>
20 //#define QF_NO_TRASH_OUTPUT
21 #include <qflogcust.h>
23 //=============================================================
25 //=============================================================
26 ServerTreeItem::ServerTreeItem(QObject
*parent
, const QString
& name
)
29 //qfTrash() << QF_FUNC_NAME << this << name;
33 ServerTreeItem::~ServerTreeItem()
35 //qfTrash() << QF_FUNC_NAME << this << objectName();
38 MainWindow
* ServerTreeItem::mainWindow() throw( QFException
)
40 MainWindow
*ret
= qfFindParent
<MainWindow
*>(model());
44 QFObjectItemModel
* ServerTreeItem::model()
46 //qfTrash() << QF_FUNC_NAME;
49 QFObjectItemModelRoot
*r
= qobject_cast
<QFObjectItemModelRoot
*>(o
);
51 //qfTrash() << "\tmodel:" << r->model();
52 //r->model()->dumpObjectInfo();
61 Database
* ServerTreeItem::database()
66 d
= qobject_cast
<Database
*>(o
);
73 void ServerTreeItem::driverDestroyed(QObject
*o
)
75 qfTrash() << QF_FUNC_NAME
<< "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
76 qfTrash() << "\tdestroyed driver:" << o
;
79 //===================================================
81 //===================================================
82 Connection::~Connection()
84 //qDebug() << "destructor:" << this;
87 Connection::Connection(const QFDomElement
& _params
, QObject
*parent
, const QString
& name
)
88 : ServerTreeItem(parent
, name
), params(_params
)
90 setObjectName(param("description"));
91 //qfInfo() << params.toString();
94 bool Connection::isOpen()
96 return children().count() > 0;
99 void Connection::close()
101 qfTrash() << QF_FUNC_NAME
;
102 QModelIndex ix
= model()->object2index(this);
103 model()->deleteChildren(ix
);
105 QModelIndex ix = model()->object2index(this);
106 while(model()->rowCount(ix)) {
107 QObject *o = model()->take(model()->index(0, 0, ix));
108 qfTrash() << o->objectName();
112 //foreach(QObject *o, children()) delete o;
115 Database
* Connection::open() throw(QFException
)
118 QList
<QObject
*> olst
;
121 QFObjectItemModel
*m
= model();
122 QModelIndex ix
= m
->object2index(this);
123 d
= new Database(this, param("database"));
126 QStringList sl
= d
->connection().databases();
127 foreach(QString s
, sl
) {
128 if(s
== param("database")) continue;
129 olst
<< new Database(this, s
);
133 catch(QFException
&e
) {
134 QFDlgException dlg
; dlg
.exec(e
);
142 QVariant
Connection::icon(int col
)
145 static bool first_scan
= true;
148 ico
.addFile(":/images/server_on.png", QSize(), QIcon::Normal
, QIcon::On
);
149 ico
.addFile(":/images/server_off.png", QSize(), QIcon::Normal
, QIcon::Off
);
151 if(col
== 0) return qVariantFromValue(ico
);
155 QVariant
Connection::text(int col
)
159 case 0: ret
= param("description"); break;
160 case 1: ret
= param("user") + "@" + param("host"); break;
161 case 2: ret
= param("database"); break;
162 case 3: ret
= param("driver"); break;
167 QString
Connection::param(const QString
& name
)
169 //qfInfo() << QFLog::stackTrace();
170 QString default_value
= "";
171 if(name
== "description") default_value
= "New_Connection";
172 else if(name
== "host") default_value
= "localhost";
173 //qfInfo() << "default_value:" << default_value;
174 QFString s
= params
.cd(name
, !Qf::ThrowExc
).value(default_value
).toString();
175 if(name
== "password") {
176 s
= QFCrypt().decrypt(s
.toAscii());
177 //qfInfo() << "password:" << s;
182 void Connection::setParam(const QString
& name
, const QString
& value
)
184 Q_ASSERT(params
.isElement());
186 if(name
== "password") {
187 //qfTrash() << "password:" << s;
188 s
= QString::fromAscii(QFCrypt().crypt(s
));
190 params
.setValue(name
, s
);
192 //===================================================
195 //===================================================
197 //===================================================
198 Database::Database(QObject
*parent
, const QString
& name
)
199 : ServerTreeItem(parent
, name
)
201 QObject
*o
= Qf::findParentOfType(this, "MainWindow");
202 if(o
) connect(this, SIGNAL(connectionInfo(const QString
&)), o
, SLOT(appendInfo(const QString
&)));
205 Database::~Database()
207 //qfTrash() << QF_FUNC_NAME << "############";
209 //qDebug() << "destructor:" << this;
212 QVariant
Database::icon(int col
)
214 static QIcon ico_open
;
215 static QIcon ico_closed
;
216 static bool first_scan
= true;
219 ico_open
.addFile(":/images/database_on.png", QSize(), QIcon::Normal
);//, QIcon::On);
220 ico_closed
.addFile(":/images/database_off.png", QSize(), QIcon::Normal
);//, QIcon::Off);
223 if(isOpen()) return qVariantFromValue(ico_open
);
224 return qVariantFromValue(ico_closed
);
229 QVariant
Database::text(int col
)
232 if(col
== 0) ret
= objectName();
236 QString
Database::getConnectionId()
239 Connection
*c
= qobject_cast
<Connection
*>(parent());
241 s
= objectName() + "[" + c
->param("driver") + "]" + c
->param("user") + "@" + c
->param("host") + ":" + c
->param("port");
246 void Database::open() throw(QFException
)
248 qfTrash() << QF_FUNC_NAME
;
249 Connection
*c
= qobject_cast
<Connection
*>(parent());
252 sqlConnection = QFSqlConnection(QSqlDatabase::database(getConnectionId()));
253 if(!sqlConnection.isValid()) {
254 sqlConnection = QFSqlConnection(QSqlDatabase::addDatabase(c->param("driver"), getConnectionId()));
256 if(!sqlConnection.isValid()) {
257 QString s = tr("Error creating SQL connection %1").arg(getConnectionId())
259 + sqlConnection.lastError().text();
260 throw QFException(s);
263 sqlConnection
.close();
264 sqlConnection
= QFSqlConnection(c
->param("driver"));
265 //QObject::connect(sqlConnection.driver(), SIGNAL(destroyed(QObject*)), this->parent(), SLOT(driverDestroyed(QObject*)));
266 sqlConnection
.setHostName(c
->param("host"));
267 sqlConnection
.setPort(c
->param("port").toInt());
268 sqlConnection
.setUserName(c
->param("user"));
269 sqlConnection
.setPassword(c
->param("password"));
270 //qDebug() << sqlConnection.password();
271 sqlConnection
.setDatabaseName(objectName());
272 qfTrash() << "\t" << sqlConnection
.info();
273 QFSqlConnection::ConnectionOptions opts
;
274 //opts["QF_CODEC_NAME"] = theApp()->config()->value("/i18n/dbtextcodec", "UTF-8").toString();
275 QString codec_name
= c
->param("textcodec");
276 if(!codec_name
.isEmpty()) opts
["QF_CODEC_NAME"] = codec_name
;
277 sqlConnection
.setJournal(theApp()->sqlJournal());
278 sqlConnection
.open(opts
);
279 if(c
->param("driver").endsWith("MYSQL")) {
280 QString set_names
= c
->param("mysqlSetNames");
281 if(!set_names
.isEmpty() && set_names
[0] != '<') {
282 QFSqlQuery
q(sqlConnection
);
283 q
.exec("SET NAMES "SARG(set_names
));
286 else if(c
->param("driver").endsWith("SQLITE")) {
288 QString s
= c
->param("sqlite_pragma_full_column_names");
289 if(s
!= "1") s
= "0";
290 QFSqlQuery
q(sqlConnection
);
291 //qfTrash() << "\texecuting:" << "PRAGMA full_column_names = 1";
292 q
.exec("PRAGMA full_column_names = " + s
);
295 QString s
= c
->param("sqlite_pragma_short_column_names");
296 if(s
!= "1") s
= "0";
297 QFSqlQuery
q(sqlConnection
);
298 q
.exec("PRAGMA short_column_names = " + s
);
301 qfTrash() << "\tdriver:" << sqlConnection
.driver();
302 qfTrash() << "\tcodec:" << opts
["QF_CODEC_NAME"];
303 qfTrash() << "\tis open:" << sqlConnection
.isOpen();
304 QString s
= sqlConnection
.driver()->property("connectionInfo").toString();
305 qfTrash() << "\tinfo:" << s
;
306 emit
connectionInfo(s
);
308 QFObjectItemModel
*m
= model();
309 QModelIndex ix
= m
->object2index(this);
310 QList
<QObject
*> olst
;
311 if(sqlConnection
.driverName().endsWith("IBASE")) {
314 sl
= sqlConnection
.tables("cokoli", QSql::Tables
);
316 foreach(QString s
, sl
) olst
<< new Table(this, s
, QFSql::TableRelation
);
317 sl
= sqlConnection
.tables("cokoli", QSql::Views
);
319 foreach(QString s
, sl
) olst
<< new Table(this, s
, QFSql::ViewRelation
);
322 foreach(QString s
, sqlConnection
.schemas()) {
323 Schema
*sch
= new Schema(NULL
, s
);
325 connect(sch
, SIGNAL(progressValue(double, const QString
&)), mainWindow(), SLOT(setProgressValue(double, const QString
&)));
330 //QFObjectItemModel *m = model();
331 //int n = sl.count();
333 // m->emitRowsInserted(m->object2index(this), 0, n-1);
336 void Database::close()
338 qfTrash() << this << "Database::close(): " << sqlConnection
.info();
339 sqlConnection
.close();
340 sqlConnection
= QSqlDatabase(); // zrus referenci na databasi
343 QModelIndex ix
= model()->object2index(this);
344 model()->deleteChildren(ix
);
345 //QSqlDatabase::removeDatabase(getConnectionId());
348 QObjectList chld_lst = children();
349 while(!chld_lst.isEmpty())
350 delete chld_lst.takeFirst();
352 //QFObjectItemModel *m = model();
354 int n = children().count();
356 //m->emitRowsAboutToBeRemoved(m->object2index(this), 0, n-1);
357 // objekt se v destruktoru sam vyjme ze seznamu
358 foreach(QObject *o, children()) {
359 delete o; // nevim, jestli se to nebude sekat, nemelo by
360 //o->deleteLater(); // tohle je tutovka
366 //===================================================
368 //=============================================================
370 //=============================================================
371 QVariant
Schema::icon(int col
)
374 static bool first_scan
= true;
377 ico
.addFile(":/images/schema.png");
379 if(col
== 0) return qVariantFromValue(ico
);
383 QVariant
Schema::text(int col
)
386 if(col
== 0) ret
= objectName();
390 QString
Schema::createScript(int flags
) throw(QFException
)
392 qfTrash() << QF_FUNC_NAME
;
395 if(!isOpen()) open();
397 // find parent database
398 Database
*d
= database();
399 if(!d
) return "cann't find database";
400 QFSqlConnection c
= d
->connection();
401 if(c
.driverName().endsWith("SQLITE")) {
403 q
.exec("SELECT sql FROM main.sqlite_master WHERE NAME NOT LIKE 'sqlite_%'");
406 sl
<< q
.value(0).toString() + ';';
411 QFSqlCatalog
&cat
= c
.catalog();
412 if(c
.driverName().endsWith("MYSQL")) {
413 cat
.setCurrentSchema(objectName());
415 QFSqlDbInfo di
= cat
.database(objectName());
416 QStringList sl
= di
.tables();
417 QStringList sl_tables
;
418 QStringList sl_views
;
419 foreach(QString s
, sl
) {
420 QFSqlTableInfo ti
= di
.table(s
);
421 if(ti
.relationKind() == QFSql::ViewRelation
) sl_views
<< s
;
424 foreach(QString s
, sl_tables
) {
425 QFSqlTableInfo ti
= di
.table(s
);
426 new Table(this, s
, ti
.relationKind());
428 foreach(QString s
, sl_views
) {
429 new Table(this, s
, QFSql::ViewRelation
);
431 qfTrash() << "\t tables count:" << sl
.count();
432 double cnt
= sl
.count();
434 foreach(QString s
, sl_tables
) {
435 QFSqlTableInfo ti
= di
.table(s
);
436 QString tbl_name
= ti
.fullName();
437 emit
progressValue(no
++/cnt
, ti
.tableName());
438 qfTrash() << "\t table name:" << tbl_name
;
439 if(flags
& CreateTableSql
) {
440 ret
+= c
.createTableSqlCommand(tbl_name
);
443 if(flags
& DumpTableSql
) {
444 ret
+= c
.dumpTableSqlCommand(tbl_name
);
448 if(flags
& IncludeViews
) foreach(QString s
, sl_views
) {
449 QFSqlTableInfo ti
= di
.table(s
);
450 QString tbl_name
= ti
.fullName();
451 emit
progressValue(no
++/cnt
, ti
.tableName());
452 qfTrash() << "\t table name:" << tbl_name
;
453 if(flags
& CreateTableSql
) {
454 ret
+= c
.createTableSqlCommand(tbl_name
);
459 emit
progressValue(-1);
463 void Schema::open() throw(QFException
)
467 /// find parent database
468 Database
*d
= database();
470 QFSqlConnection c
= d
->connection();
471 QFSqlCatalog
&cat
= c
.catalog();
472 if(c
.driverName().endsWith("MYSQL")) {
473 cat
.setCurrentSchema(objectName());
475 QFSqlDbInfo di
= cat
.database(objectName());
476 QStringList sl_tables
= di
.tables(QFSql::AllRelations
& ~QFSql::ViewRelation
);
477 QStringList sl_views
= di
.tables(QFSql::ViewRelation
);
479 QFObjectItemModel
*m
= model();
480 QModelIndex ix
= m
->object2index(this);
481 QList
<QObject
*> olst
;
482 foreach(QString s
, sl_tables
) {
483 qfTrash() << "\t adding table" << s
;
484 olst
<< new Table(NULL
, s
, QFSql::TableRelation
);
487 foreach(QString s
, sl_views
) {
488 qfTrash() << "\t adding view" << s
;
489 olst
<< new Table(NULL
, s
, QFSql::ViewRelation
);
493 if(c.driverType() == QFSqlConnection::PSQL) {
494 QString s = "SELECT n.nspname, c.relname,"
495 " CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' END AS type,"
497 " pg_catalog.obj_description(c.oid, 'pg_class') AS descr"
498 " FROM pg_catalog.pg_class c"
499 " LEFT JOIN pg_catalog.pg_user u ON u.usesysid = c.relowner"
500 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
501 " WHERE c.relkind IN ('r','v')"
502 " AND n.nspname = '%1'"
505 q.exec(s.arg(objectName()));
506 foreach(QFSqlQuery::Row row, q.rows()) {
507 QString kind = row.value(2).toString();
508 if(kind == "view") new Table(this, row.value(1).toString(), Table::KindView);
509 if(kind == "table") new Table(this, row.value(1).toString(), Table::KindTable);
519 //qfTrash() << QF_FUNC_NAME;
520 QModelIndex ix
= model()->object2index(this);
521 model()->deleteChildren(ix
);
523 Database
*d
= database();
525 QFSqlConnection c
= d
->connection();
526 QFSqlCatalog
&cat
= c
.catalog();
527 cat
.forgetDatabase(objectName());
529 //===================================================
531 //===================================================
533 //===================================================
536 //qDebug() << "destructor:" << this;
539 QVariant
Table::icon(int col
)
542 if(kind
== QFSql::TableRelation
) return qVariantFromValue(QFPixmapCache::icon("icon.table", ":/images/table.png"));
543 else if(kind
== QFSql::ViewRelation
) return qVariantFromValue(QFPixmapCache::icon("icon.view", ":/images/view.png"));
544 else if(kind
== QFSql::SystemTableRelation
) return qVariantFromValue(QFPixmapCache::icon("icon.systemTable", ":/images/systemtable.png"));
549 QVariant
Table::text(int col
)
552 if(col
== 0) ret
= objectName();
556 QString
Table::schema() const
558 const QObject
*o
= this;
559 const Schema
*d
= NULL
;
561 d
= qobject_cast
<const Schema
*>(o
);
562 if(d
) return d
->objectName();
567 //===================================================