00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "keximigrate.h"
00023
00024 #include <kdebug.h>
00025 #include <kinputdialog.h>
00026 #include <kapplication.h>
00027
00028 #include <kexiutils/identifier.h>
00029 #include <core/kexi.h>
00030 #include <core/kexiproject.h>
00031 #include <kexidb/drivermanager.h>
00032
00033 using namespace KexiDB;
00034 using namespace KexiMigration;
00035
00036 KexiMigrate::KexiMigrate(QObject *parent, const char *name,
00037 const QStringList&)
00038 : QObject( parent, name )
00039 , m_migrateData(0)
00040 , m_destPrj(0)
00041
00042 {
00043 }
00044
00047 #define NUM_OF_ROWS_PER_CREATE_TABLE 20
00048
00049
00050
00051
00052 void KexiMigrate::setData(KexiMigration::Data* migrateData)
00053 {
00054 m_migrateData = migrateData;
00055 }
00056
00057
00058
00059 KexiMigrate::~KexiMigrate()
00060 {
00061 delete m_destPrj;
00062 }
00063
00064 bool KexiMigrate::checkIfDestinationDatabaseOverwritingNeedsAccepting(Kexi::ObjectStatus* result,
00065 bool& acceptingNeeded)
00066 {
00067 acceptingNeeded = false;
00068 if (result)
00069 result->clearStatus();
00070
00071 KexiDB::DriverManager drvManager;
00072 KexiDB::Driver *destDriver = drvManager.driver(
00073 m_migrateData->destination->connectionData()->driverName);
00074 if (!destDriver) {
00075 result->setStatus(&drvManager,
00076 i18n("Could not create database \"%1\".")
00077 .arg(m_migrateData->destination->databaseName()));
00078 return false;
00079 }
00080
00081
00082
00083 if (destDriver->isFileDriver())
00084 return true;
00085 KexiDB::Connection *tmpConn
00086 = destDriver->createConnection( *m_migrateData->destination->connectionData() );
00087 if (!tmpConn || destDriver->error() || !tmpConn->connect()) {
00088 delete tmpConn;
00089 return true;
00090 }
00091 if (tmpConn->databaseExists( m_migrateData->destination->databaseName() )) {
00092 acceptingNeeded = true;
00093 }
00094 tmpConn->disconnect();
00095 delete tmpConn;
00096 return true;
00097 }
00098
00099
00100
00101 bool KexiMigrate::performImport(Kexi::ObjectStatus* result)
00102 {
00103 if (result)
00104 result->clearStatus();
00105
00106 KexiDB::DriverManager drvManager;
00107 KexiDB::Driver *destDriver = drvManager.driver(
00108 m_migrateData->destination->connectionData()->driverName);
00109 if (!destDriver) {
00110 result->setStatus(&drvManager,
00111 i18n("Could not create database \"%1\".")
00112 .arg(m_migrateData->destination->databaseName()));
00113 return false;
00114 }
00115
00116 QStringList tables;
00117
00118
00119 kdDebug() << "KexiMigrate::performImport() CONNECTING..." << endl;
00120 if (!drv_connect()) {
00121 kdDebug() << "Couldnt connect to database server" << endl;
00122 if (result)
00123 result->setStatus(i18n("Could not connect to data source \"%1\".")
00124 .arg(m_migrateData->source->serverInfoString()), "");
00125 return false;
00126 }
00127
00128
00129 kdDebug() << "KexiMigrate::performImport() GETTING TABLENAMES..." << endl;
00130 if (!tableNames(tables)) {
00131 kdDebug() << "Couldnt get list of tables" << endl;
00132 if (result)
00133 result->setStatus(
00134 i18n("Could not get a list of table names for data source \"%1\".")
00135 .arg(m_migrateData->source->serverInfoString()), "");
00136 return false;
00137 }
00138
00139
00140
00141
00142
00143 if (tables.isEmpty()) {
00144 kdDebug() << "There were no tables to import" << endl;
00145 if (result)
00146 result->setStatus(
00147 i18n("No tables to import found in data source \"%1\".")
00148 .arg(m_migrateData->source->serverInfoString()), "");
00149 return false;
00150 }
00151
00152
00153 m_tableSchemas.clear();
00154 if (!destDriver) {
00155 result->setStatus(&drvManager);
00156 return false;
00157 }
00158 foreach(QStringList::ConstIterator, it, tables) {
00159 if (destDriver->isSystemObjectName( *it )
00160 || (*it).lower().startsWith("kexi__"))
00161 continue;
00162
00163 const QString tableName( KexiUtils::string2Identifier(*it) );
00164 KexiDB::TableSchema *tableSchema;
00165
00166
00167
00168 tableSchema = new KexiDB::TableSchema(tableName);
00169
00170 tableSchema->setCaption( *it );
00171
00172 if (drv_readTableSchema(*it, *tableSchema)) {
00173
00174
00175 m_tableSchemas.append(tableSchema);
00176 } else {
00177 delete tableSchema;
00178 if (result)
00179 result->setStatus(
00180 i18n("Could not import project from data source \"%1\". Error reading table \"%2\".")
00181 .arg(m_migrateData->source->serverInfoString()).arg(tableName), "");
00182 return false;
00183 }
00184 }
00185
00186
00187 delete m_destPrj;
00188 m_destPrj = createProject(result);
00189 if (!m_destPrj || m_destPrj->error()) {
00190 if (result)
00191 result->setStatus(m_destPrj,
00192 i18n("Could not import project from data source \"%1\".")
00193 .arg(m_migrateData->source->serverInfoString()));
00194 return false;
00195 }
00196
00197
00198 bool ok = true;
00199 KexiDB::Transaction trans;
00200 if (!m_migrateData->keepData)
00201 m_tableSchemas.clear();
00202
00203 KexiDB::Connection *destConn = m_destPrj->dbConnection();
00204 ok = destConn;
00205 if (ok) {
00206 trans = destConn->beginTransaction();
00207 ok = !trans.isNull();
00208 }
00209 if (ok) {
00210
00211 if (tables.find("kexi__objectdata")!=tables.end())
00212 m_tableSchemas.append(destConn->tableSchema("kexi__objectdata"));
00213 }
00214
00215 for(QPtrListIterator<TableSchema> ts(m_tableSchemas); ok && ts.current() != 0 ; ++ts)
00216 {
00217 const QString tname( ts.current()->name().lower() );
00218 if (destConn->driver()->isSystemObjectName( tname )
00221 && tname!="kexi__objectdata"
00222 )
00223 {
00224 kdDebug() << "Do not copy data for system table: " << tname << endl;
00226 continue;
00227 }
00228 kdDebug() << "Copying data for table: " << tname << endl;
00229 ok = drv_copyTable(
00230 ts.current()->caption().isEmpty() ? tname : ts.current()->caption(),
00231 destConn,
00232 ts.current()
00233 );
00234 if (!ok) {
00235 kdDebug() << "Failed to copy table " << tname << endl;
00236 if (result)
00237 result->setStatus(destConn,
00238 i18n("Could not copy table \"%1\" to destination database.").arg(tname));
00239 break;
00240 }
00241 }
00242
00243
00244
00245 if (ok && tables.find("kexi__objects")!=tables.end()) {
00246
00247
00248 KexiDB::TableSchema *kexi__objectsCopy =
00249 new KexiDB::TableSchema( *destConn->tableSchema("kexi__objects") );
00250 kexi__objectsCopy->setName("kexi__objects__copy");
00251 ok = destConn->createTable( kexi__objectsCopy );
00252 if (!ok) {
00253 kdDebug() << "Failed to create a table " << kexi__objectsCopy->name() << endl;
00254 delete kexi__objectsCopy;
00255 kexi__objectsCopy = 0;
00256 destConn->debugError();
00257 if (result)
00258 result->setStatus(destConn,
00259 i18n("Could not create database \"%1\".")
00260 .arg(m_migrateData->destination->databaseName()));
00261 }
00262 if (ok) {
00263 ok = drv_copyTable("kexi__objects", destConn, kexi__objectsCopy);
00264 }
00267 if (ok) {
00268 ok = destConn->executeSQL(
00269 QString::fromLatin1("INSERT INTO kexi__objects SELECT * FROM kexi__objects__copy "
00270 "WHERE o_type<>%1").arg((int)KexiDB::TableObjectType));
00271 }
00272 if (kexi__objectsCopy && !destConn->dropTable( kexi__objectsCopy )) {
00273 ok = false;
00274 }
00275 }
00276
00277
00278 if (ok) {
00279 ok = destConn->commitTransaction(trans);
00280 }
00281
00282 if (ok)
00283 ok = drv_disconnect();
00284
00285 if (!ok) {
00286 if (result && result->error())
00287 result->setStatus(destConn,
00288 i18n("Could not import data from data source \"%1\".")
00289 .arg(m_migrateData->source->serverInfoString()));
00290 if (destConn) {
00291 destConn->debugError();
00292 destConn->rollbackTransaction(trans);
00293 }
00294 drv_disconnect();
00295 if (destConn) {
00296 destConn->disconnect();
00297 destConn->dropDatabase(m_migrateData->destination->databaseName());
00298 }
00299
00300 return false;
00301 }
00302 if (destConn)
00303 ok = destConn->disconnect();
00304
00305 return ok;
00306 }
00307
00308
00309 bool KexiMigrate::performExport(Kexi::ObjectStatus* result)
00310 {
00311 if (result)
00312 result->clearStatus();
00313
00315
00316 return false;
00317 }
00318
00319
00320
00321 KexiProject *KexiMigrate::createProject(Kexi::ObjectStatus* result)
00322 {
00323 kdDebug() << "Creating database [" << m_migrateData->destination->databaseName()
00324 << "]" << endl;
00325
00326 KexiProject *prj = new KexiProject(m_migrateData->destination,
00327 (KexiDB::MessageHandler*)*result);
00328 tristate r = prj->create(true );
00329 if (r!=true) {
00330
00331 return prj;
00332 }
00333
00334 KexiDB::TransactionGuard tg(*prj->dbConnection());
00335 if (tg.transaction().isNull()) {
00336 if (result)
00337 result->setStatus(prj->dbConnection(),
00338 i18n("Could not create database \"%1\".")
00339 .arg(m_migrateData->destination->databaseName()));
00340 prj->dbConnection()->dropDatabase(m_migrateData->destination->databaseName());
00341
00342 return prj;
00343 }
00344
00345 if(drv_progressSupported()) {
00346 progressInitialise();
00347 }
00348
00349
00350 KexiDB::TableSchema *ts;
00351 for(QPtrListIterator<TableSchema> it (m_tableSchemas); (ts = it.current()) != 0;++it) {
00352 if(!prj->dbConnection()->createTable( ts )) {
00353 kdDebug() << "Failed to create a table " << ts->name() << endl;
00354 prj->dbConnection()->debugError();
00355 if (result)
00356 result->setStatus(prj->dbConnection(),
00357 i18n("Could not create database \"%1\".")
00358 .arg(m_migrateData->destination->databaseName()));
00359 m_tableSchemas.remove(ts);
00360 prj->dbConnection()->dropDatabase(m_migrateData->destination->databaseName());
00361
00362 return prj;
00363 }
00364 updateProgress((Q_ULLONG)NUM_OF_ROWS_PER_CREATE_TABLE);
00365 }
00366 if (!tg.commit()) {
00367 prj->dbConnection()->dropDatabase(m_migrateData->destination->databaseName());
00368
00369 return prj;
00370 }
00371 return prj;
00372 }
00373
00374
00375
00376 bool KexiMigrate::tableNames(QStringList & tn)
00377 {
00379 kdDebug() << "Reading list of tables..." << endl;
00380 return drv_tableNames(tn);
00381 }
00382
00383
00384
00385 bool KexiMigrate::progressInitialise() {
00386 Q_ULLONG sum = 0, size;
00387 emit progressPercent(0);
00388
00390 QStringList tables;
00391 if(!tableNames(tables))
00392 return false;
00393
00394
00395 int tableNumber = 1;
00396 for(QStringList::Iterator it = tables.begin();
00397 it != tables.end(); ++it, tableNumber++)
00398 {
00399 if(drv_getTableSize(*it, size)) {
00400 kdDebug() << "KexiMigrate::progressInitialise() - table: " << *it
00401 << "size: " << (ulong)size << endl;
00402 sum += size;
00403 emit progressPercent(tableNumber * 5 / tables.count());
00404 } else {
00405 return false;
00406 }
00407 }
00408
00409 kdDebug() << "KexiMigrate::progressInitialise() - job size: " << (ulong)sum << endl;
00410 m_progressTotal = sum;
00411 m_progressTotal += tables.count() * NUM_OF_ROWS_PER_CREATE_TABLE;
00412 m_progressTotal = m_progressTotal * 105 / 100;
00413 m_progressNextReport = sum / 100;
00414 m_progressDone = m_progressTotal * 5 / 100;
00415 return true;
00416 }
00417
00418
00419 void KexiMigrate::updateProgress(Q_ULLONG step) {
00420 m_progressDone += step;
00421 if (m_progressDone >= m_progressNextReport) {
00422 int percent = (m_progressDone+1) * 100 / m_progressTotal;
00423 m_progressNextReport = ((percent + 1) * m_progressTotal) / 100;
00424 kdDebug() << "KexiMigrate::updateProgress(): " << (ulong)m_progressDone << "/"
00425 << (ulong)m_progressTotal << " (" << percent << "%) next report at "
00426 << (ulong)m_progressNextReport << endl;
00427 emit progressPercent(percent);
00428 }
00429 }
00430
00431
00432
00433 KexiDB::Field::Type KexiMigrate::userType(const QString& fname)
00434 {
00435 KInputDialog *dlg;
00436 QStringList types;
00437 QString res;
00438
00439 types << "Byte";
00440 types << "Short Integer";
00441 types << "Integer";
00442 types << "Big Integer";
00443 types << "Boolean";
00444 types << "Date";
00445 types << "Date Time";
00446 types << "Time";
00447 types << "Float";
00448 types << "Double";
00449 types << "Text";
00450 types << "Long Text";
00451 types << "Binary Large Object";
00452
00453 res = dlg->getItem( i18n("Field Type"),
00454 i18n("The data type for %1 could not be determined. "
00455 "Please select one of the following data "
00456 "types").arg(fname),
00457 types, 0, false);
00458
00460 if (res == types[0])
00461 return KexiDB::Field::Byte;
00462 else if (res == types[1])
00463 return KexiDB::Field::ShortInteger;
00464 else if (res == types[2])
00465 return KexiDB::Field::Integer;
00466 else if (res == types[3])
00467 return KexiDB::Field::BigInteger;
00468 else if (res == types[4])
00469 return KexiDB::Field::Boolean;
00470 else if (res == types[5])
00471 return KexiDB::Field::Date;
00472 else if (res == types[6])
00473 return KexiDB::Field::DateTime;
00474 else if (res == types[7])
00475 return KexiDB::Field::Time;
00476 else if (res == types[8])
00477 return KexiDB::Field::Float;
00478 else if (res == types[9])
00479 return KexiDB::Field::Double;
00480 else if (res == types[10])
00481 return KexiDB::Field::Text;
00482 else if (res == types[11])
00483 return KexiDB::Field::LongText;
00484 else if (res == types[12])
00485 return KexiDB::Field::BLOB;
00486 else
00487 return KexiDB::Field::Text;
00488 }
00489
00490 QVariant KexiMigrate::propertyValue( const QCString& propName )
00491 {
00492 return m_properties[propName.lower()];
00493 }
00494
00495 QString KexiMigrate::propertyCaption( const QCString& propName ) const
00496 {
00497 return m_propertyCaptions[propName.lower()];
00498 }
00499
00500 void KexiMigrate::setPropertyValue( const QCString& propName, const QVariant& value )
00501 {
00502 m_properties[propName.lower()] = value;
00503 }
00504
00505 QValueList<QCString> KexiMigrate::propertyNames() const
00506 {
00507 QValueList<QCString> names = m_properties.keys();
00508 qHeapSort(names);
00509 return names;
00510 }
00511
00512 bool KexiMigrate::isValid()
00513 {
00514 if (KexiMigration::versionMajor() != versionMajor()
00515 || KexiMigration::versionMinor() != versionMinor())
00516 {
00517 setError(ERR_INCOMPAT_DRIVER_VERSION,
00518 i18n("Incompatible migration driver's \"%1\" version: found version %2, expected version %3.")
00519 .arg(name())
00520 .arg(QString("%1.%2").arg(versionMajor()).arg(versionMinor()))
00521 .arg(QString("%1.%2").arg(KexiMigration::versionMajor()).arg(KexiMigration::versionMinor())));
00522 return false;
00523 }
00524 return true;
00525 }
00526
00527 #include "keximigrate.moc"