keximigrate.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2004 Adam Pigg <adam@piggz.co.uk>
3 Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
4 Copyright (C) 2005 Martin Ellis <martin.ellis@kdemail.net>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this program; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20*/
21
22#include "keximigrate.h"
23
24#include <kdebug.h>
25#include <kinputdialog.h>
26#include <tdeapplication.h>
27
28#include <kexiutils/identifier.h>
29#include <core/kexi.h>
30#include <core/kexiproject.h>
31#include <kexidb/drivermanager.h>
32
33using namespace KexiDB;
34using namespace KexiMigration;
35
36KexiMigrate::KexiMigrate(TQObject *parent, const char *name,
37 const TQStringList&)
38 : TQObject( parent, name )
39 , m_migrateData(0)
40 , m_destPrj(0)
41{
42 m_kexiDBCompatibleTableSchemasToRemoveFromMemoryAfterImport.setAutoDelete(true);
43}
44
47#define NUM_OF_ROWS_PER_CREATE_TABLE 20
48
49
50//=============================================================================
51// Migration parameters
52void KexiMigrate::setData(KexiMigration::Data* migrateData)
53{
54 m_migrateData = migrateData;
55}
56
57//=============================================================================
58// Destructor
59KexiMigrate::~KexiMigrate()
60{
61 delete m_destPrj;
62}
63
65 bool& acceptingNeeded)
66{
67 acceptingNeeded = false;
68 if (result)
69 result->clearStatus();
70
71 KexiDB::DriverManager drvManager;
72 KexiDB::Driver *destDriver = drvManager.driver(
73 m_migrateData->destination->connectionData()->driverName);
74 if (!destDriver) {
75 result->setStatus(&drvManager,
76 i18n("Could not create database \"%1\".")
77 .arg(m_migrateData->destination->databaseName()));
78 return false;
79 }
80
81 // For file-based dest. projects, we've already asked about overwriting
82 // existing project but for server-based projects we need to ask now.
83 if (destDriver->isFileDriver())
84 return true; //nothing to check
85 KexiDB::Connection *tmpConn
86 = destDriver->createConnection( *m_migrateData->destination->connectionData() );
87 if (!tmpConn || destDriver->error() || !tmpConn->connect()) {
88 delete tmpConn;
89 return true;
90 }
91 if (tmpConn->databaseExists( m_migrateData->destination->databaseName() )) {
92 acceptingNeeded = true;
93 }
94 tmpConn->disconnect();
95 delete tmpConn;
96 return true;
97}
98
100{
101 KexiDB::ConnectionData* sourcedata = m_migrateData->source;
102 KexiDB::ConnectionData* destinationdata = m_migrateData->destination->connectionData();
103 return (
104 sourcedata && destinationdata &&
105 m_migrateData->sourceName == m_migrateData->destination->databaseName() && // same database name
106 sourcedata->driverName == destinationdata->driverName && // same driver
107 sourcedata->hostName == destinationdata->hostName && // same host
108 sourcedata->fileName() == destinationdata->fileName() && // same filename
109 sourcedata->dbPath() == destinationdata->dbPath() && // same database path
110 sourcedata->dbFileName() == destinationdata->dbFileName() // same database filename
111 );
112}
113
114//=============================================================================
115// Perform Import operation
117{
118 if (result)
119 result->clearStatus();
120
121 KexiDB::DriverManager drvManager;
122 KexiDB::Driver *destDriver = drvManager.driver(
123 m_migrateData->destination->connectionData()->driverName);
124 if (!destDriver) {
125 result->setStatus(&drvManager,
126 i18n("Could not create database \"%1\".")
127 .arg(m_migrateData->destination->databaseName()));
128 return false;
129 }
130
131 TQStringList tables;
132
133 // Step 1 - connect
134 kdDebug() << "KexiMigrate::performImport() CONNECTING..." << endl;
135 if (!drv_connect()) {
136 kdDebug() << "Couldnt connect to database server" << endl;
137 if (result)
138 result->setStatus(i18n("Could not connect to data source \"%1\".")
139 .arg(m_migrateData->source->serverInfoString()), "");
140 return false;
141 }
142
143 // Step 2 - get table names
144 kdDebug() << "KexiMigrate::performImport() GETTING TABLENAMES..." << endl;
145 if (!tableNames(tables)) {
146 kdDebug() << "Couldnt get list of tables" << endl;
147 if (result)
148 result->setStatus(
149 i18n("Could not get a list of table names for data source \"%1\".")
150 .arg(m_migrateData->source->serverInfoString()), "");
151 return false;
152 }
153
154 // Check if there are any tables
155 if (tables.isEmpty()) {
156 kdDebug() << "There were no tables to import" << endl;
157 if (result)
158 result->setStatus(
159 i18n("No tables to import found in data source \"%1\".")
160 .arg(m_migrateData->source->serverInfoString()), "");
161 return false;
162 }
163
164 // Step 3 - Read table schemas
165 tables.sort();
166 m_tableSchemas.clear();
167 if (!destDriver) {
168 result->setStatus(&drvManager);
169 return false;
170 }
171 const bool kexi__objects_exists = tables.find("kexi__objects")!=tables.end();
172 TQStringList kexiDBTables;
173 if (kexi__objects_exists) {
175 TQString::fromLatin1("SELECT o_name FROM kexi__objects WHERE o_type=%1")
176 .arg((int)KexiDB::TableObjectType), 0, kexiDBTables, -1);
177 if (res == true) {
178 // prepend KexiDB-compatible tables to 'tables' list, so we'll copy KexiDB-compatible tables first,
179 // to make sure existing IDs will not be in conflict with IDs newly generated for non-KexiDB tables
180 kexiDBTables.sort();
181 foreach(TQStringList::ConstIterator, it, kexiDBTables)
182 tables.remove( *it );
183//kdDebug() << "KexiDB-compat tables: " << kexiDBTables << endl;
184//kdDebug() << "non-KexiDB tables: " << tables << endl;
185 }
186 }
187
188// uint i=0;
189 // -- read table schemas and create them in memory (only for non-KexiDB-compat tables)
190 foreach (TQStringList::ConstIterator, it, tables) {
191 if (destDriver->isSystemObjectName( *it ) //"kexi__objects", etc.
192 || (*it).lower().startsWith("kexi__")) //tables at KexiProject level, e.g. "kexi__blobs"
193 continue;
194 // this is a non-KexiDB table: generate schema from native data source
195 const TQString tableName( KexiUtils::string2Identifier(*it) );
196 KexiDB::TableSchema *tableSchema = new KexiDB::TableSchema(tableName);
197 tableSchema->setCaption( *it ); //caption is equal to the original name
198
199 if (!drv_readTableSchema(*it, *tableSchema)) {
200 delete tableSchema;
201 if (result)
202 result->setStatus(
203 i18n("Could not import project from data source \"%1\". Error reading table \"%2\".")
204 .arg(m_migrateData->source->serverInfoString()).arg(tableName), "");
205 return false;
206 }
207 //yeah, got a table
208 //Add it to list of tables which we will create if all goes well
209 m_tableSchemas.append(tableSchema);
210 }
211
212 // Step 4 - Create a new database as we have all required info
213 // - create copies of KexiDB-compat tables
214 // - create copies of non-KexiDB tables
215 delete m_destPrj;
216 m_destPrj = new KexiProject(m_migrateData->destination,
217 result ? (KexiDB::MessageHandler*)*result : 0);
218 bool ok = true == m_destPrj->create(true /*forceOverwrite*/);
219
220 KexiDB::Connection *destConn = 0;
221
222 if (ok)
223 ok = (destConn = m_destPrj->dbConnection());
224
226 if (ok) {
227 trans = destConn->beginTransaction();
228 if (trans.isNull()) {
229 ok = false;
230 if (result)
231 result->setStatus(destConn,
232 i18n("Could not create database \"%1\".")
233 .arg(m_migrateData->destination->databaseName()));
234 //later destConn->dropDatabase(m_migrateData->destination->databaseName());
235 //don't delete prj, otherwise eror message will be deleted delete prj;
236 //later return m_destPrj;
237 }
238 }
239
240 if (ok) {
241 if (drv_progressSupported())
242 progressInitialise();
243
244 // Step 5 - Create the copies of KexiDB-compat tables in memory (to maintain the same IDs)
245 m_kexiDBCompatibleTableSchemasToRemoveFromMemoryAfterImport.clear();
246 foreach (TQStringList::ConstIterator, it, kexiDBTables) {
247 //load the schema from kexi__objects and kexi__fields
248 TableSchema *t = new TableSchema();
250 bool firstRecord = true;
251 if (true == drv_fetchRecordFromSQL(
252 TQString("SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects "
253 "WHERE o_name='%1' AND o_type=%1").arg(*it).arg((int)KexiDB::TableObjectType),
254 data, firstRecord)
255 && destConn->setupObjectSchemaData( data, *t ))
256 {
258 //load schema for every field and add it
259 firstRecord = true;
260 TQString sql(
261 TQString::fromLatin1("SELECT t_id, f_type, f_name, f_length, f_precision, f_constraints, "
262 "f_options, f_default, f_order, f_caption, f_help"
263 " FROM kexi__fields WHERE t_id=%1 ORDER BY f_order").arg(t->id()) );
264 while (ok) {
265 tristate res = drv_fetchRecordFromSQL(sql, data, firstRecord);
266 if (res != true) {
267 if (false == res)
268 ok = false;
269 break;
270 }
271 KexiDB::Field* f = destConn->setupField( data );
272 if (f)
273 t->addField(f);
274 else
275 ok = false;
276 }
277 if (ok)
278 ok = destConn->drv_createTable(*t);
279 if (ok)
280 m_kexiDBCompatibleTableSchemasToRemoveFromMemoryAfterImport.append(t);
281 }
282 if (!ok)
283 delete t;
284 }
285 }
286
287 // Step 6 - Copy kexi__objects NOW because we'll soon create new objects with new IDs (3.)...
288 if (ok) {
289 if (kexi__objects_exists)
290 ok = drv_copyTable("kexi__objects", destConn, destConn->tableSchema("kexi__objects"));
291 }
292
293 // Step 7 - Create the non-KexiDB-compatible tables: new IDs will be assigned to them
294 if (ok) {
296 for (TQPtrListIterator<TableSchema> it (m_tableSchemas); (ts = it.current()); ++it) {
297 ok = destConn->createTable( ts );
298 if (!ok) {
299 kdDebug() << "Failed to create a table " << ts->name() << endl;
300 destConn->debugError();
301 if (result)
302 result->setStatus(destConn,
303 i18n("Could not create database \"%1\".")
304 .arg(m_migrateData->destination->databaseName()));
305 m_tableSchemas.remove(ts);
306 break;
307 }
308 updateProgress((TQ_ULLONG)NUM_OF_ROWS_PER_CREATE_TABLE);
309 }
310 }
311
312 if (ok)
313 ok = destConn->commitTransaction(trans);
314
315 if (ok) {
316 //add compatible tables to the list, so data will be copied, if needed
317 if (m_migrateData->keepData) {
318 for(TQPtrListIterator<TableSchema> it (m_kexiDBCompatibleTableSchemasToRemoveFromMemoryAfterImport);
319 it.current(); ++it)
320 {
321 m_tableSchemas.append(it.current());
322 }
323 }
324 else
325 m_tableSchemas.clear();
326 }
327
328 if (ok) {
329 if (m_destPrj->error()) {
330 ok = false;
331 if (result)
332 result->setStatus(m_destPrj,
333 i18n("Could not import project from data source \"%1\".")
334 .arg(m_migrateData->source->serverInfoString()));
335 }
336 }
337
338 // Step 8 - Copy data if asked to
339 if (ok) {
340 trans = destConn->beginTransaction();
341 ok = !trans.isNull();
342 }
343 if (ok) {
344 if (m_migrateData->keepData) {
346 // Copy data for "kexi__objectdata" as well, if available in the source db
347 if (tables.find("kexi__objectdata")!=tables.end())
348 m_tableSchemas.append(destConn->tableSchema("kexi__objectdata"));
349 // Copy data for "kexi__blobs" as well, if available in the source db
350 if (tables.find("kexi__blobs")!=tables.end())
351 m_tableSchemas.append(destConn->tableSchema("kexi__blobs"));
352 // Copy data for "kexi__fields" as well, if available in the source db
353 if (tables.find("kexi__fields")!=tables.end())
354 m_tableSchemas.append(destConn->tableSchema("kexi__fields"));
355 }
356
357 for(TQPtrListIterator<TableSchema> ts(m_tableSchemas); ok && ts.current() != 0 ; ++ts)
358 {
359 const TQString tname( ts.current()->name().lower() );
360 if (destConn->driver()->isSystemObjectName( tname )
363 && tname!="kexi__objectdata" //copy this too
364 && tname!="kexi__blobs" //copy this too
365 && tname!="kexi__fields" //copy this too
366 )
367 {
368 kdDebug() << "Do not copy data for system table: " << tname << endl;
370 continue;
371 }
372 kdDebug() << "Copying data for table: " << tname << endl;
373 TQString originalTableName;
374 if (kexiDBTables.find(tname)==kexiDBTables.end())
375 //caption is equal to the original name
376 originalTableName = ts.current()->caption().isEmpty() ? tname : ts.current()->caption();
377 else
378 originalTableName = tname;
379 ok = drv_copyTable(originalTableName, destConn, ts.current());
380 if (!ok) {
381 kdDebug() << "Failed to copy table " << tname << endl;
382 if (result)
383 result->setStatus(destConn,
384 i18n("Could not copy table \"%1\" to destination database.").arg(tname));
385 break;
386 }
387 }//for
388 }
389
390 // Done.
391 if (ok)
392 ok = destConn->commitTransaction(trans);
393
394 if (ok)
395 ok = drv_disconnect();
396
397 m_kexiDBCompatibleTableSchemasToRemoveFromMemoryAfterImport.clear();
398
399 if (ok) {
400 if (destConn)
401 ok = destConn->disconnect();
402 return ok;
403 }
404
405 // Finally: error handling
406 if (result && result->error())
407 result->setStatus(destConn,
408 i18n("Could not import data from data source \"%1\".")
409 .arg(m_migrateData->source->serverInfoString()));
410 if (destConn) {
411 destConn->debugError();
412 destConn->rollbackTransaction(trans);
413 }
415 if (destConn) {
416 destConn->disconnect();
417 destConn->dropDatabase(m_migrateData->destination->databaseName());
418 }
419 return false;
420}
421//=============================================================================
422
424{
425 if (result)
426 result->clearStatus();
427
429
430 return false;
431}
432
433//=============================================================================
434// Functions for getting table data
435bool KexiMigrate::tableNames(TQStringList & tn)
436{
438 kdDebug() << "Reading list of tables..." << endl;
439 return drv_tableNames(tn);
440}
441
442//=============================================================================
443// Progress functions
444bool KexiMigrate::progressInitialise() {
445 TQ_ULLONG sum = 0, size;
446 emit progressPercent(0);
447
449 TQStringList tables;
450 if(!tableNames(tables))
451 return false;
452
453 // 1) Get the number of rows/bytes to import
454 int tableNumber = 1;
455 for(TQStringList::Iterator it = tables.begin();
456 it != tables.end(); ++it, tableNumber++)
457 {
458 if(drv_getTableSize(*it, size)) {
459 kdDebug() << "KexiMigrate::progressInitialise() - table: " << *it
460 << "size: " << (ulong)size << endl;
461 sum += size;
462 emit progressPercent(tableNumber * 5 /* 5% */ / tables.count());
463 } else {
464 return false;
465 }
466 }
467
468 kdDebug() << "KexiMigrate::progressInitialise() - job size: " << (ulong)sum << endl;
469 m_progressTotal = sum;
470 m_progressTotal += tables.count() * NUM_OF_ROWS_PER_CREATE_TABLE;
471 m_progressTotal = m_progressTotal * 105 / 100; //add 5 percent for above task 1)
472 m_progressNextReport = sum / 100;
473 m_progressDone = m_progressTotal * 5 / 100; //5 perecent already done in task 1)
474 return true;
475}
476
477
478void KexiMigrate::updateProgress(TQ_ULLONG step) {
479 m_progressDone += step;
480 if (m_progressDone >= m_progressNextReport) {
481 int percent = (m_progressDone+1) * 100 / m_progressTotal;
482 m_progressNextReport = ((percent + 1) * m_progressTotal) / 100;
483 kdDebug() << "KexiMigrate::updateProgress(): " << (ulong)m_progressDone << "/"
484 << (ulong)m_progressTotal << " (" << percent << "%) next report at "
485 << (ulong)m_progressNextReport << endl;
486 emit progressPercent(percent);
487 }
488}
489
490//=============================================================================
491// Prompt the user to choose a field type
493{
494 TQStringList types;
495 TQString res;
496
497 types << "Byte";
498 types << "Short Integer";
499 types << "Integer";
500 types << "Big Integer";
501 types << "Boolean";
502 types << "Date";
503 types << "Date Time";
504 types << "Time";
505 types << "Float";
506 types << "Double";
507 types << "Text";
508 types << "Long Text";
509 types << "Binary Large Object";
510
511 res = KInputDialog::getItem( i18n("Field Type"),
512 i18n("The data type for %1 could not be determined. "
513 "Please select one of the following data "
514 "types").arg(fname),
515 types, 0, false);
516
518 if (res == *types.at(0))
519 return KexiDB::Field::Byte;
520 else if (res == *types.at(1))
522 else if (res == *types.at(2))
524 else if (res == *types.at(3))
526 else if (res == *types.at(4))
528 else if (res == *types.at(5))
529 return KexiDB::Field::Date;
530 else if (res == *types.at(6))
531 return KexiDB::Field::DateTime;
532 else if (res == *types.at(7))
533 return KexiDB::Field::Time;
534 else if (res == *types.at(8))
536 else if (res == *types.at(9))
538 else if (res == *types.at(10))
539 return KexiDB::Field::Text;
540 else if (res == *types.at(11))
542 else if (res == *types.at(12))
543 return KexiDB::Field::BLOB;
544 else
545 return KexiDB::Field::Text;
546}
547
548TQVariant KexiMigrate::propertyValue( const TQCString& propName )
549{
550 return m_properties[propName.lower()];
551}
552
553TQString KexiMigrate::propertyCaption( const TQCString& propName ) const
554{
555 return m_propertyCaptions[propName.lower()];
556}
557
558void KexiMigrate::setPropertyValue( const TQCString& propName, const TQVariant& value )
559{
560 m_properties[propName.lower()] = value;
561}
562
563TQValueList<TQCString> KexiMigrate::propertyNames() const
564{
565 TQValueList<TQCString> names = m_properties.keys();
566 qHeapSort(names);
567 return names;
568}
569
571{
572 if (KexiMigration::versionMajor() != versionMajor()
573 || KexiMigration::versionMinor() != versionMinor())
574 {
575 setError(ERR_INCOMPAT_DRIVER_VERSION,
576 i18n("Incompatible migration driver's \"%1\" version: found version %2, expected version %3.")
577 .arg(name())
578 .arg(TQString("%1.%2").arg(versionMajor()).arg(versionMinor()))
579 .arg(TQString("%1.%2").arg(KexiMigration::versionMajor()).arg(KexiMigration::versionMinor())));
580 return false;
581 }
582 return true;
583}
584
585bool KexiMigrate::drv_queryMaxNumber(const TQString& tableName,
586 const TQString& columnName, int& result)
587{
588 TQString string;
590 TQString::fromLatin1("SELECT MAX(%1) FROM %2").arg(drv_escapeIdentifier(columnName))
591 .arg(drv_escapeIdentifier(tableName)), 0, string);
592 if (r == false)
593 return false;
594 if (~r) {
595 result = 0;
596 return true;
597 }
598 bool ok;
599 int tmpResult = string.toInt(&ok);
600 if (ok)
601 result = tmpResult;
602 return ok;
603}
604
606 const TQString& sqlStatement, uint columnNumber, TQString& string)
607{
608 TQStringList stringList;
609 const tristate res = drv_queryStringListFromSQL(sqlStatement, columnNumber, stringList, 1);
610 if (true == res)
611 string = stringList.first();
612 return res;
613}
614
615#include "keximigrate.moc"
TQString driverName
the name of the driver that should be used to create a connection
TQString hostName
Host name used for the remote connection.
Database specific connection data, e.g. host, port.
TQString fileName() const
Get the filename used by the connection.
TQString dbFileName() const
The file name (without path) of the database file.
TQString dbPath() const
The directory the database file is in.
Provides database connection, allowing queries and data modification.
Definition connection.h:62
bool commitTransaction(Transaction trans=Transaction::null, bool ignore_inactive=false)
TableSchema * tableSchema(int tableId)
bool rollbackTransaction(Transaction trans=Transaction::null, bool ignore_inactive=false)
virtual bool drv_createTable(const TableSchema &tableSchema)
bool createTable(TableSchema *tableSchema, bool replaceExisting=false)
Creates a table according to the given schema.
bool dropDatabase(const TQString &dbName=TQString())
Drops database with name dbName.
bool disconnect()
Disconnects from driver with given parameters.
bool databaseExists(const TQString &dbName, bool ignoreErrors=true)
bool setupObjectSchemaData(const RowData &data, SchemaData &sdata)
Driver * driver() const
Definition connection.h:78
Transaction beginTransaction()
Creates new transaction handle and starts a new transaction.
KexiDB::Field * setupField(const RowData &data)
bool connect()
Connects to driver with given parameters.
Database driver management, e.g. finding and loading drivers.
Driver * driver(const TQString &name)
Generic database abstraction.
Definition driver.h:67
bool isFileDriver() const
Definition driver.cpp:149
Connection * createConnection(ConnectionData &conn_data, int options=0)
Definition driver.cpp:178
virtual bool isSystemObjectName(const TQString &n) const
Definition driver.cpp:230
FieldList & addField(Field *field)
Meta-data for a field.
Definition field.h:73
@ ShortInteger
Definition field.h:86
bool error() const
Definition object.h:38
virtual void setError(int code=ERR_OTHER, const TQString &msg=TQString())
Definition object.cpp:53
void debugError()
Definition object.cpp:159
This class encapsulates transaction handle.
Definition transaction.h:60
bool performExport(Kexi::ObjectStatus *result=0)
Perform an export operation.
bool performImport(Kexi::ObjectStatus *result=0)
Perform an import operation.
virtual tristate drv_fetchRecordFromSQL(const TQString &sqlStatement, KexiDB::RowData &data, bool &firstRecord)
KexiMigrate(TQObject *parent, const char *name, const TQStringList &args=TQStringList())
Used by MigrateManager.
virtual bool drv_tableNames(TQStringList &tablenames)=0
Get table names in source database (driver specific)
virtual bool drv_readTableSchema(const TQString &originalName, KexiDB::TableSchema &tableSchema)=0
Read schema for a given table (driver specific)
virtual TQVariant propertyValue(const TQCString &propName)
bool isSourceAndDestinationDataSourceTheSame() const
bool checkIfDestinationDatabaseOverwritingNeedsAccepting(Kexi::ObjectStatus *result, bool &acceptingNeeded)
virtual bool drv_connect()=0
Connect to source database (driver specific)
void setData(KexiMigration::Data *migrateData)
Data Setup. Requires two connection objects, a name and a bool.
virtual bool drv_queryMaxNumber(const TQString &tableName, const TQString &columnName, int &result)
virtual tristate drv_queryStringListFromSQL(const TQString &sqlStatement, uint columnNumber, TQStringList &stringList, int numRecords=-1)
virtual bool drv_getTableSize(const TQString &, TQ_ULLONG &)
TQString propertyCaption(const TQCString &propName) const
void setPropertyValue(const TQCString &propName, const TQVariant &value)
KexiMigration::Data * data() const
Definition keximigrate.h:87
KexiDB::Field::Type userType(const TQString &fname)
Prompt user to select a field type for unrecognized fields.
TQMap< TQCString, TQString > m_propertyCaptions
virtual bool drv_copyTable(const TQString &srcTable, KexiDB::Connection *destConn, KexiDB::TableSchema *dstTable)=0
Copy a table from source DB to target DB (driver specific)
TQValueList< TQCString > propertyNames() const
TQMap< TQCString, TQVariant > m_properties
virtual bool drv_disconnect()=0
Disconnect from source database (driver specific)
KexiMigration::Data * m_migrateData
Migrate Options.
virtual tristate drv_querySingleStringFromSQL(const TQString &sqlStatement, uint columnNumber, TQString &string)
A project's main controller.
Definition kexiproject.h:68
bool error() const
KexiDB::Connection * dbConnection() const
tristate create(bool forceOverwrite=false)
3-state logical type with three values: true, false and cancelled and convenient operators.
Definition tristate.h:100
High-level database connectivity library with database backend drivers.
TQValueVector< TQVariant > RowData
structure for storing single record with type information
Definition connection.h:47
Framework for importing databases into native KexiDB databases.
KEXIMIGR_EXPORT int versionMajor()
KEXIMIGR_EXPORT int versionMinor()
KEXIUTILS_EXPORT TQString string2Identifier(const TQString &s)