00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <kexidb/utils.h>
00021 #include <kexidb/cursor.h>
00022 #include <kexidb/drivermanager.h>
00023
00024 #include <qmap.h>
00025 #include <qthread.h>
00026
00027 #include <kdebug.h>
00028 #include <klocale.h>
00029 #include <kstaticdeleter.h>
00030 #include <kmessagebox.h>
00031
00032 #include "utils_p.h"
00033
00034 using namespace KexiDB;
00035
00037 struct TypeCache
00038 {
00039 QMap< uint, TypeGroupList > tlist;
00040 QMap< uint, QStringList > nlist;
00041 QMap< uint, QStringList > slist;
00042 QMap< uint, Field::Type > def_tlist;
00043 };
00044
00045 static KStaticDeleter<TypeCache> KexiDB_typeCacheDeleter;
00046 TypeCache *KexiDB_typeCache = 0;
00047
00048 static void initList()
00049 {
00050 KexiDB_typeCacheDeleter.setObject( KexiDB_typeCache, new TypeCache() );
00051
00052 for (uint t=0; t<=KexiDB::Field::LastType; t++) {
00053 const uint tg = KexiDB::Field::typeGroup( t );
00054 TypeGroupList list;
00055 QStringList name_list, str_list;
00056 if (KexiDB_typeCache->tlist.find( tg )!=KexiDB_typeCache->tlist.end()) {
00057 list = KexiDB_typeCache->tlist[ tg ];
00058 name_list = KexiDB_typeCache->nlist[ tg ];
00059 str_list = KexiDB_typeCache->slist[ tg ];
00060 }
00061 list+= t;
00062 name_list += KexiDB::Field::typeName( t );
00063 str_list += KexiDB::Field::typeString( t );
00064 KexiDB_typeCache->tlist[ tg ] = list;
00065 KexiDB_typeCache->nlist[ tg ] = name_list;
00066 KexiDB_typeCache->slist[ tg ] = str_list;
00067 }
00068
00069 KexiDB_typeCache->def_tlist[ Field::InvalidGroup ] = Field::InvalidType;
00070 KexiDB_typeCache->def_tlist[ Field::TextGroup ] = Field::Text;
00071 KexiDB_typeCache->def_tlist[ Field::IntegerGroup ] = Field::Integer;
00072 KexiDB_typeCache->def_tlist[ Field::FloatGroup ] = Field::Float;
00073 KexiDB_typeCache->def_tlist[ Field::BooleanGroup ] = Field::Boolean;
00074 KexiDB_typeCache->def_tlist[ Field::DateTimeGroup ] = Field::Date;
00075 KexiDB_typeCache->def_tlist[ Field::BLOBGroup ] = Field::BLOB;
00076 }
00077
00078 const TypeGroupList KexiDB::typesForGroup(KexiDB::Field::TypeGroup typeGroup)
00079 {
00080 if (!KexiDB_typeCache)
00081 initList();
00082 return KexiDB_typeCache->tlist[ typeGroup ];
00083 }
00084
00085 QStringList KexiDB::typeNamesForGroup(KexiDB::Field::TypeGroup typeGroup)
00086 {
00087 if (!KexiDB_typeCache)
00088 initList();
00089 return KexiDB_typeCache->nlist[ typeGroup ];
00090 }
00091
00092 QStringList KexiDB::typeStringsForGroup(KexiDB::Field::TypeGroup typeGroup)
00093 {
00094 if (!KexiDB_typeCache)
00095 initList();
00096 return KexiDB_typeCache->slist[ typeGroup ];
00097 }
00098
00099 KexiDB::Field::Type KexiDB::defaultTypeForGroup(KexiDB::Field::TypeGroup typeGroup)
00100 {
00101 if (!KexiDB_typeCache)
00102 initList();
00103 return (typeGroup <= Field::LastTypeGroup) ? KexiDB_typeCache->def_tlist[ typeGroup ] : Field::InvalidType;
00104 }
00105
00106 void KexiDB::getHTMLErrorMesage(Object* obj, QString& msg, QString &details)
00107 {
00108 Connection *conn = 0;
00109 if (!obj || !obj->error()) {
00110 if (dynamic_cast<Cursor*>(obj)) {
00111 conn = dynamic_cast<Cursor*>(obj)->connection();
00112 obj = conn;
00113 }
00114 else {
00115 return;
00116 }
00117 }
00118
00119
00120
00121 if (!obj || !obj->error())
00122 return;
00123
00124 if (!obj->msgTitle().isEmpty())
00125 msg += "<p>" + obj->msgTitle();
00126
00127 if (msg.isEmpty())
00128 msg = "<p>" + obj->errorMsg();
00129 else
00130 details += "<p>" + obj->errorMsg();
00131
00132 if (!obj->serverErrorMsg().isEmpty())
00133 details += "<p><b><nobr>" +i18n("Message from server:") + "</nobr></b><br>" + obj->serverErrorMsg();
00134 if (!obj->recentSQLString().isEmpty())
00135 details += "<p><b><nobr>" +i18n("SQL statement:") + QString("</nobr></b><br><tt>%1</tt>").arg(obj->recentSQLString());
00136 int serverResult;
00137 QString serverResultName;
00138 if (obj->serverResult()!=0) {
00139 serverResult = obj->serverResult();
00140 serverResultName = obj->serverResultName();
00141 }
00142 else {
00143 serverResult = obj->previousServerResult();
00144 serverResultName = obj->previousServerResultName();
00145 }
00146 if (!serverResultName.isEmpty())
00147 details += (QString("<p><b><nobr>")+i18n("Server result name:")+"</nobr></b><br>"+serverResultName);
00148 if (!details.isEmpty()
00149 && (!obj->serverErrorMsg().isEmpty() || !obj->recentSQLString().isEmpty() || !serverResultName.isEmpty() || serverResult!=0) )
00150 {
00151 details += (QString("<p><b><nobr>")+i18n("Server result number:")+"</nobr></b><br>"+QString::number(serverResult));
00152 }
00153
00154 if (!details.isEmpty() && !details.startsWith("<qt>")) {
00155 if (details.startsWith("<p>"))
00156 details = QString::fromLatin1("<qt>")+details;
00157 else
00158 details = QString::fromLatin1("<qt><p>")+details;
00159 }
00160 }
00161
00162 void KexiDB::getHTMLErrorMesage(Object* obj, QString& msg)
00163 {
00164 getHTMLErrorMesage(obj, msg, msg);
00165 }
00166
00167 void KexiDB::getHTMLErrorMesage(Object* obj, ResultInfo *result)
00168 {
00169 getHTMLErrorMesage(obj, result->msg, result->desc);
00170 }
00171
00172 int KexiDB::idForObjectName( Connection &conn, const QString& objName, int objType )
00173 {
00174 RowData data;
00175 if (true!=conn.querySingleRecord(QString("select o_id from kexi__objects where lower(o_name)='%1' and o_type=%2")
00176 .arg(objName.lower()).arg(objType), data))
00177 return 0;
00178 bool ok;
00179 int id = data[0].toInt(&ok);
00180 return ok ? id : 0;
00181 }
00182
00183
00184
00185 TableOrQuerySchema::TableOrQuerySchema(Connection *conn, const QCString& name, bool table)
00186 : m_name(name)
00187 , m_table(table ? conn->tableSchema(QString(name)) : 0)
00188 , m_query(table ? 0 : conn->querySchema(QString(name)))
00189 {
00190 if (table && !m_table)
00191 kdWarning() << "TableOrQuery(Connection *conn, const QCString& name, bool table) : "
00192 "no table specified!" << endl;
00193 if (!table && !m_query)
00194 kdWarning() << "TableOrQuery(Connection *conn, const QCString& name, bool table) : "
00195 "no query specified!" << endl;
00196 }
00197
00198 TableOrQuerySchema::TableOrQuerySchema(FieldList &tableOrQuery)
00199 : m_table(dynamic_cast<TableSchema*>(&tableOrQuery))
00200 , m_query(dynamic_cast<QuerySchema*>(&tableOrQuery))
00201 {
00202 if (!m_table && !m_query)
00203 kdWarning() << "TableOrQuery(FieldList &tableOrQuery) : "
00204 " tableOrQuery is nether table nor query!" << endl;
00205 }
00206
00207 TableOrQuerySchema::TableOrQuerySchema(Connection *conn, int id)
00208 {
00209 m_table = conn->tableSchema(id);
00210 m_query = m_table ? 0 : conn->querySchema(id);
00211 if (!m_table && !m_query)
00212 kdWarning() << "TableOrQuery(Connection *conn, int id) : no table or query found for id=="
00213 << id << "!" << endl;
00214 }
00215
00216 TableOrQuerySchema::TableOrQuerySchema(TableSchema* table)
00217 : m_table(table)
00218 , m_query(0)
00219 {
00220 if (!m_table)
00221 kdWarning() << "TableOrQuery(TableSchema* table) : no table specified!" << endl;
00222 }
00223
00224 TableOrQuerySchema::TableOrQuerySchema(QuerySchema* query)
00225 : m_table(0)
00226 , m_query(query)
00227 {
00228 if (!m_query)
00229 kdWarning() << "TableOrQuery(QuerySchema* query) : no query specified!" << endl;
00230 }
00231
00232 const QueryColumnInfo::Vector TableOrQuerySchema::columns(bool unique)
00233 {
00234 if (m_table)
00235 return m_table->query()->fieldsExpanded();
00236
00237 if (m_query)
00238 return m_query->fieldsExpanded(unique);
00239
00240 kdWarning() << "TableOrQuery::fields() : no query or table specified!" << endl;
00241 return QueryColumnInfo::Vector();
00242 }
00243
00244 QCString TableOrQuerySchema::name() const
00245 {
00246 if (m_table)
00247 return m_table->name().latin1();
00248 if (m_query)
00249 return m_query->name().latin1();
00250 return m_name;
00251 }
00252
00253 QString TableOrQuerySchema::captionOrName() const
00254 {
00255 SchemaData *sdata = m_table ? static_cast<SchemaData *>(m_table) : static_cast<SchemaData *>(m_query);
00256 if (!sdata)
00257 return m_name;
00258 return sdata->caption().isEmpty() ? sdata->name() : sdata->caption();
00259 }
00260
00261 Field* TableOrQuerySchema::field(const QString& name)
00262 {
00263 if (m_table)
00264 return m_table->field(name);
00265 if (m_query)
00266 return m_query->field(name);
00267
00268 return 0;
00269 }
00270
00271 QueryColumnInfo* TableOrQuerySchema::columnInfo(const QString& name)
00272 {
00273 if (m_table)
00274 return m_table->query()->columnInfo(name);
00275
00276 if (m_query)
00277 return m_query->columnInfo(name);
00278
00279 return 0;
00280 }
00281
00282 QString TableOrQuerySchema::debugString()
00283 {
00284 if (m_table)
00285 return m_table->debugString();
00286 else if (m_query)
00287 return m_query->debugString();
00288 return QString::null;
00289 }
00290
00291 void TableOrQuerySchema::debug()
00292 {
00293 if (m_table)
00294 return m_table->debug();
00295 else if (m_query)
00296 return m_query->debug();
00297 }
00298
00299 Connection* TableOrQuerySchema::connection() const
00300 {
00301 if (m_table)
00302 return m_table->connection();
00303 else if (m_query)
00304 return m_query->connection();
00305 return 0;
00306 }
00307
00308
00309
00310
00311 class ConnectionTestThread : public QThread {
00312 public:
00313 ConnectionTestThread(ConnectionTestDialog *dlg, const KexiDB::ConnectionData& connData);
00314 virtual void run();
00315 protected:
00316 ConnectionTestDialog* m_dlg;
00317 KexiDB::ConnectionData m_connData;
00318 };
00319
00320 ConnectionTestThread::ConnectionTestThread(ConnectionTestDialog* dlg, const KexiDB::ConnectionData& connData)
00321 : m_dlg(dlg), m_connData(connData)
00322 {
00323 }
00324
00325 void ConnectionTestThread::run()
00326 {
00327 KexiDB::DriverManager manager;
00328 KexiDB::Driver* drv = manager.driver(m_connData.driverName);
00329
00330 if (!drv || manager.error()) {
00331
00332 m_dlg->error(&manager);
00333 return;
00334 }
00335 KexiDB::Connection * conn = drv->createConnection(m_connData);
00336 if (!conn || drv->error()) {
00337
00338 delete conn;
00339 m_dlg->error(drv);
00340 return;
00341 }
00342 if (!conn->connect() || conn->error()) {
00343
00344 m_dlg->error(conn);
00345 delete conn;
00346 return;
00347 }
00348
00349
00350 QString tmpDbName;
00351 if (!conn->useTemporaryDatabaseIfNeeded( tmpDbName )) {
00352 m_dlg->error(conn);
00353 delete conn;
00354 return;
00355 }
00356 delete conn;
00357 m_dlg->error(0);
00358 }
00359
00360 ConnectionTestDialog::ConnectionTestDialog(QWidget* parent,
00361 const KexiDB::ConnectionData& data,
00362 KexiDB::MessageHandler& msgHandler)
00363 : KProgressDialog(parent, "testconn_dlg",
00364 i18n("Test Connection"), i18n("<qt>Testing connection to <b>%1</b> database server...</qt>")
00365 .arg(data.serverInfoString(true)), true )
00366 , m_thread(new ConnectionTestThread(this, data))
00367 , m_connData(data)
00368 , m_msgHandler(&msgHandler)
00369 , m_elapsedTime(0)
00370 , m_errorObj(0)
00371 , m_stopWaiting(false)
00372 {
00373 showCancelButton(true);
00374 progressBar()->setPercentageVisible(false);
00375 progressBar()->setTotalSteps(0);
00376 connect(&m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
00377 adjustSize();
00378 resize(250, height());
00379 }
00380
00381 ConnectionTestDialog::~ConnectionTestDialog()
00382 {
00383 m_wait.wakeAll();
00384 m_thread->terminate();
00385 delete m_thread;
00386 }
00387
00388 int ConnectionTestDialog::exec()
00389 {
00390 m_timer.start(20);
00391 m_thread->start();
00392 const int res = KProgressDialog::exec();
00393 m_thread->wait();
00394 m_timer.stop();
00395 return res;
00396 }
00397
00398 void ConnectionTestDialog::slotTimeout()
00399 {
00400
00401 bool notResponding = false;
00402 if (m_elapsedTime >= 1000*5) {
00403 m_stopWaiting = true;
00404 notResponding = true;
00405 }
00406 if (m_stopWaiting) {
00407 m_timer.disconnect(this);
00408 m_timer.stop();
00409 slotCancel();
00410
00411
00412 if (m_errorObj) {
00413 m_msgHandler->showErrorMessage(m_errorObj);
00414 m_errorObj = 0;
00415 }
00416 else if (notResponding) {
00417 KMessageBox::sorry(0,
00418 i18n("<qt>Test connection to <b>%1</b> database server failed. The server is not responding.</qt>")
00419 .arg(m_connData.serverInfoString(true)),
00420 i18n("Test Connection"));
00421 }
00422 else {
00423 KMessageBox::information(0,
00424 i18n("<qt>Test connection to <b>%1</b> database server established successfully.</qt>")
00425 .arg(m_connData.serverInfoString(true)),
00426 i18n("Test Connection"));
00427 }
00428
00429
00430 m_wait.wakeAll();
00431 return;
00432 }
00433 m_elapsedTime += 20;
00434 progressBar()->setProgress( m_elapsedTime );
00435 }
00436
00437 void ConnectionTestDialog::error(KexiDB::Object *obj)
00438 {
00439 KexiDBDbg << "ConnectionTestDialog::error()" << endl;
00440 m_stopWaiting = true;
00441 m_errorObj = obj;
00442
00443
00444
00445
00446
00447
00448
00449 m_wait.wait();
00450 }
00451
00452 void ConnectionTestDialog::slotCancel()
00453 {
00454
00455 m_thread->terminate();
00456 m_timer.disconnect(this);
00457 m_timer.stop();
00458 KProgressDialog::slotCancel();
00459 }
00460
00461 void KexiDB::connectionTestDialog(QWidget* parent, const KexiDB::ConnectionData& data,
00462 KexiDB::MessageHandler& msgHandler)
00463 {
00464 ConnectionTestDialog dlg(parent, data, msgHandler);
00465 dlg.exec();
00466 }
00467
00468 int KexiDB::rowCount(const KexiDB::TableSchema& tableSchema)
00469 {
00471 if (!tableSchema.connection()) {
00472 KexiDBWarn << "KexiDB::rowsCount(const KexiDB::TableSchema&): no tableSchema.connection() !" << endl;
00473 return -1;
00474 }
00475 int count = -1;
00476 tableSchema.connection()->querySingleNumber(
00477 QString::fromLatin1("SELECT COUNT() FROM ")
00478 + tableSchema.connection()->driver()->escapeIdentifier(tableSchema.name()),
00479 count
00480 );
00481 return count;
00482 }
00483
00484 int KexiDB::rowCount(KexiDB::QuerySchema& querySchema)
00485 {
00487 if (!querySchema.connection()) {
00488 KexiDBWarn << "KexiDB::rowsCount(const KexiDB::QuerySchema&): no querySchema.connection() !" << endl;
00489 return -1;
00490 }
00491 int count = -1;
00492 querySchema.connection()->querySingleNumber(
00493 QString::fromLatin1("SELECT COUNT() FROM (")
00494 + querySchema.connection()->selectStatement(querySchema) + ")",
00495 count
00496 );
00497 return count;
00498 }
00499
00500 int KexiDB::rowCount(KexiDB::TableOrQuerySchema& tableOrQuery)
00501 {
00502 if (tableOrQuery.table())
00503 return rowCount( *tableOrQuery.table() );
00504 if (tableOrQuery.query())
00505 return rowCount( *tableOrQuery.query() );
00506 return -1;
00507 }
00508
00509 int KexiDB::fieldCount(KexiDB::TableOrQuerySchema& tableOrQuery)
00510 {
00511 if (tableOrQuery.table())
00512 return tableOrQuery.table()->fieldCount();
00513 if (tableOrQuery.query())
00514 return tableOrQuery.query()->fieldsExpanded().count();
00515 return -1;
00516 }
00517
00518 QMap<QString,QString> KexiDB::toMap( const ConnectionData& data )
00519 {
00520 QMap<QString,QString> m;
00521 m["caption"] = data.caption;
00522 m["description"] = data.description;
00523 m["driverName"] = data.driverName;
00524 m["hostName"] = data.hostName;
00525 m["port"] = QString::number(data.port);
00526 m["useLocalSocketFile"] = QString::number((int)data.useLocalSocketFile);
00527 m["localSocketFileName"] = data.localSocketFileName;
00528 m["password"] = data.password;
00529 m["savePassword"] = QString::number((int)data.savePassword);
00530 m["userName"] = data.userName;
00531 m["fileName"] = data.fileName();
00532 return m;
00533 }
00534
00535 void KexiDB::fromMap( const QMap<QString,QString>& map, ConnectionData& data )
00536 {
00537 data.caption = map["caption"];
00538 data.description = map["description"];
00539 data.driverName = map["driverName"];
00540 data.hostName = map["hostName"];
00541 data.port = map["port"].toInt();
00542 data.useLocalSocketFile = map["useLocalSocketFile"].toInt()==1;
00543 data.localSocketFileName = map["localSocketFileName"];
00544 data.password = map["password"];
00545 data.savePassword = map["savePassword"].toInt()==1;
00546 data.userName = map["userName"];
00547 data.setFileName(map["fileName"]);
00548 }
00549
00550 bool KexiDB::splitToTableAndFieldParts(const QString& string,
00551 QString& tableName, QString& fieldName,
00552 SetFieldNameIfNoTableNameOptions option)
00553 {
00554 const int id = string.find('.');
00555 if (option & SetFieldNameIfNoTableName && id==-1) {
00556 tableName = QString::null;
00557 fieldName = string;
00558 return true;
00559 }
00560 if (id<=0 || id==int(string.length()-1))
00561 return false;
00562 tableName = string.left(id);
00563 fieldName = string.mid(id+1);
00564 return true;
00565 }
00566
00567 #include "utils_p.moc"