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