summaryrefslogtreecommitdiffstats
path: root/kexi/migration
diff options
context:
space:
mode:
Diffstat (limited to 'kexi/migration')
-rw-r--r--kexi/migration/Makefile.am57
-rw-r--r--kexi/migration/configure.in.in7
-rw-r--r--kexi/migration/importoptionsdlg.cpp111
-rw-r--r--kexi/migration/importoptionsdlg.h51
-rw-r--r--kexi/migration/importwizard.cpp1031
-rw-r--r--kexi/migration/importwizard.h153
-rw-r--r--kexi/migration/keximigrate.cpp616
-rw-r--r--kexi/migration/keximigrate.h314
-rw-r--r--kexi/migration/keximigratedata.cpp34
-rw-r--r--kexi/migration/keximigratedata.h59
-rw-r--r--kexi/migration/keximigratetest.cpp49
-rw-r--r--kexi/migration/keximigration_driver.desktop59
-rw-r--r--kexi/migration/migratemanager.cpp384
-rw-r--r--kexi/migration/migratemanager.h82
-rw-r--r--kexi/migration/migratemanager_p.h85
-rw-r--r--kexi/migration/mysql/Makefile.am18
-rw-r--r--kexi/migration/mysql/keximigrate_mysql.desktop54
-rw-r--r--kexi/migration/mysql/mysqlmigrate.cpp522
-rw-r--r--kexi/migration/mysql/mysqlmigrate.h85
-rw-r--r--kexi/migration/pqxx/Makefile.am20
-rw-r--r--kexi/migration/pqxx/keximigrate_pqxx.desktop53
-rw-r--r--kexi/migration/pqxx/pg_type.h192
-rw-r--r--kexi/migration/pqxx/pqxxmigrate.cpp660
-rw-r--r--kexi/migration/pqxx/pqxxmigrate.h120
-rw-r--r--kexi/migration/txt/Makefile.am18
-rw-r--r--kexi/migration/txt/txtmigrate.cpp27
-rw-r--r--kexi/migration/txt/txtmigrate.h33
27 files changed, 4894 insertions, 0 deletions
diff --git a/kexi/migration/Makefile.am b/kexi/migration/Makefile.am
new file mode 100644
index 00000000..75806ba5
--- /dev/null
+++ b/kexi/migration/Makefile.am
@@ -0,0 +1,57 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+lib_LTLIBRARIES = libkeximigrate.la
+
+INCLUDES = \
+ -I$(top_srcdir)/kexi \
+ -I$(top_srcdir)/kexi/core \
+ -I$(top_srcdir)/kexi/widget \
+ -I$(top_builddir)/kexi/widget \
+ -I$(top_srcdir)/kexi/main/startup \
+ -I$(top_builddir)/kexi/main/startup \
+ $(all_includes)
+
+if compile_pgsql_plugin
+pgsql_dir=pqxx
+endif
+
+if compile_mysql_plugin
+mysql_dir=mysql
+endif
+
+SUBDIRS = . $(pgsql_dir) $(mysql_dir)
+
+libkeximigrate_la_METASOURCES = AUTO
+
+libkeximigrate_la_SOURCES = keximigrate.cpp importwizard.cpp migratemanager.cpp \
+ keximigratedata.cpp importoptionsdlg.cpp
+
+libkeximigrate_la_LIBADD = \
+ $(top_builddir)/kexi/core/libkexicore.la \
+ $(top_builddir)/kexi/kexidb/libkexidb.la \
+ $(top_builddir)/kexi/widget/libkexiextendedwidgets.la \
+ $(top_builddir)/kexi/main/libkeximain.la \
+ $(LIB_QT) $(LIB_KDECORE)
+
+libkeximigrate_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(VER_INFO)
+
+noinst_HEADERS = importwizard.h migratemanager_p.h
+
+keximigrateincludedir=$(includedir)/kexidb
+keximigrateinclude_HEADERS=keximigrate.h keximigratedata.h migratemanager.h
+
+kde_servicetypes_DATA = keximigration_driver.desktop
+
+KDE_OPTIONS=nofinal
+noinst_PROGRAMS = keximigratetest
+
+keximigratetest_SOURCES = keximigratetest.cpp
+keximigratetest_LDADD = libkeximigrate.la \
+ $(top_builddir)/kexi/core/libkexicore.la \
+ $(top_builddir)/kexi/kexidb/libkexidb.la \
+ $(top_builddir)/kexi/widget/libkexiextendedwidgets.la \
+ $(top_builddir)/kexi/main/libkeximain.la \
+ $(LIB_QT) $(LIB_KDECORE)
+
+keximigratetest_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+
diff --git a/kexi/migration/configure.in.in b/kexi/migration/configure.in.in
new file mode 100644
index 00000000..6744e431
--- /dev/null
+++ b/kexi/migration/configure.in.in
@@ -0,0 +1,7 @@
+# KexiMDB isn't built as part of Kexi right now.
+#AC_ARG_ENABLE(keximdb,
+# AC_HELP_STRING([--enable-keximdb],
+# [build KexiMDB (MS Access) plugin [default=no]]),
+# compile_keximdb_plugin=$enableval, compile_keximdb_plugin=no)
+#
+#AM_CONDITIONAL(compile_keximdb_plugin, test "x$compile_keximdb_plugin" != "xno")
diff --git a/kexi/migration/importoptionsdlg.cpp b/kexi/migration/importoptionsdlg.cpp
new file mode 100644
index 00000000..24ff3259
--- /dev/null
+++ b/kexi/migration/importoptionsdlg.cpp
@@ -0,0 +1,111 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "importoptionsdlg.h"
+#include <widget/kexicharencodingcombobox.h>
+
+#include <qdir.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qtextcodec.h>
+#include <qcheckbox.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcombobox.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kcharsets.h>
+#include <kiconloader.h>
+
+using namespace KexiMigration;
+
+OptionsDialog::OptionsDialog( const QString& databaseFile, const QString& selectedEncoding, QWidget* parent )
+ : KDialogBase(
+ KDialogBase::Plain,
+ i18n( "Advanced Import Options" ),
+ Ok|Cancel,
+ Ok,
+ parent,
+ "KexiMigration::OptionsDialog",
+ true,
+ false
+ )
+{
+ setIcon(DesktopIcon("configure"));
+ QGridLayout *lyr = new QGridLayout( plainPage(), 4, 3, KDialogBase::marginHint(),
+ KDialogBase::spacingHint());
+
+ m_encodingComboBox = new KexiCharacterEncodingComboBox(plainPage(), selectedEncoding);
+ m_encodingComboBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ lyr->addWidget( m_encodingComboBox, 1, 1 );
+ QLabel* lbl = new QLabel(
+ i18n("<h3>Text encoding for Microsoft Access database</h3>\n"
+ "<p>Database file \"%1\" appears to be created by a version of Microsoft Access older than 2000.</p>"
+ "<p>In order to properly import national characters, you may need to choose a proper text encoding "
+ "if the database was created on a computer with a different character set.</p>")
+ .arg(QDir::convertSeparators(databaseFile)), plainPage());
+ lbl->setAlignment( Qt::AlignAuto | Qt::WordBreak );
+ lbl->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ lyr->addMultiCellWidget( lbl, 0, 0, 0, 2 );
+
+ QLabel* lbl2 = new QLabel( m_encodingComboBox, i18n("Text encoding:"), plainPage());
+ lyr->addWidget( lbl2, 1, 0 );
+
+ m_chkAlwaysUseThisEncoding = new QCheckBox(
+ i18n("Always use this encoding in similar situations"), plainPage());
+ lyr->addMultiCellWidget( m_chkAlwaysUseThisEncoding, 2, 2, 1,2 );
+
+ lyr->addItem( new QSpacerItem( 20, 111, QSizePolicy::Minimum, QSizePolicy::Expanding ), 3, 1 );
+ lyr->addItem( new QSpacerItem( 121, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ), 1, 2 );
+
+ //read config
+ kapp->config()->setGroup("ImportExport");
+ QString defaultEncodingForMSAccessFiles = kapp->config()->readEntry("DefaultEncodingForMSAccessFiles");
+ if (!defaultEncodingForMSAccessFiles.isEmpty()) {
+ m_encodingComboBox->setSelectedEncoding(defaultEncodingForMSAccessFiles);
+ m_chkAlwaysUseThisEncoding->setChecked(true);
+ }
+
+ adjustSize();
+ m_encodingComboBox->setFocus();
+}
+
+OptionsDialog::~OptionsDialog()
+{
+}
+
+KexiCharacterEncodingComboBox* OptionsDialog::encodingComboBox() const
+{
+ return m_encodingComboBox;
+}
+
+void OptionsDialog::accept()
+{
+ kapp->config()->setGroup("ImportExport");
+ if (m_chkAlwaysUseThisEncoding->isChecked())
+ kapp->config()->writeEntry("defaultEncodingForMSAccessFiles",
+ m_encodingComboBox->selectedEncoding());
+ else
+ kapp->config()->deleteEntry("defaultEncodingForMSAccessFiles");
+
+ KDialogBase::accept();
+}
+
+#include "importoptionsdlg.moc"
diff --git a/kexi/migration/importoptionsdlg.h b/kexi/migration/importoptionsdlg.h
new file mode 100644
index 00000000..736cb174
--- /dev/null
+++ b/kexi/migration/importoptionsdlg.h
@@ -0,0 +1,51 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KEXIMIGRATIONOPTIONSDIALOG_H
+#define KEXIMIGRATIONOPTIONSDIALOG_H
+
+#include <kdialogbase.h>
+
+class QCheckBox;
+class KexiCharacterEncodingComboBox;
+
+namespace KexiMigration {
+
+//! @short Import Options dialog.
+//! It is currently used for MDB driver only
+//! @todo Hardcoded. Move such code to KexiMigrate drivers.
+class OptionsDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ OptionsDialog( const QString& databaseFile, const QString& selectedEncoding, QWidget* parent = 0 );
+ virtual ~OptionsDialog();
+
+ KexiCharacterEncodingComboBox* encodingComboBox() const;
+
+ protected slots:
+ virtual void accept();
+
+ protected:
+ KexiCharacterEncodingComboBox *m_encodingComboBox;
+ QCheckBox *m_chkAlwaysUseThisEncoding;
+};
+}
+
+#endif
diff --git a/kexi/migration/importwizard.cpp b/kexi/migration/importwizard.cpp
new file mode 100644
index 00000000..dda3d200
--- /dev/null
+++ b/kexi/migration/importwizard.cpp
@@ -0,0 +1,1031 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Adam Pigg <[email protected]>
+ Copyright (C) 2004-2006 Jaroslaw Staniek <[email protected]>
+ Copyright (C) 2005 Martin Ellis <[email protected]>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "importwizard.h"
+#include "keximigrate.h"
+#include "importoptionsdlg.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qvbuttongroup.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+
+#include <kcombobox.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kdebug.h>
+#include <klineedit.h>
+#include <kiconloader.h>
+#include <kbuttonbox.h>
+
+#include <kexidb/drivermanager.h>
+#include <kexidb/driver.h>
+#include <kexidb/connectiondata.h>
+#include <kexidb/utils.h>
+#include <core/kexidbconnectionset.h>
+#include <core/kexi.h>
+#include <KexiConnSelector.h>
+#include <KexiProjectSelector.h>
+#include <KexiOpenExistingFile.h>
+#include <KexiDBTitlePage.h>
+#include <kexiutils/utils.h>
+#include <kexidbdrivercombobox.h>
+#include <kexitextmsghandler.h>
+#include <widget/kexicharencodingcombobox.h>
+#include <widget/kexiprjtypeselector.h>
+
+
+using namespace KexiMigration;
+
+//===========================================================
+//
+ImportWizard::ImportWizard(QWidget *parent, QMap<QString,QString>* args)
+ : KWizard(parent)
+ , m_args(args)
+{
+ setCaption(i18n("Import Database"));
+ setIcon(DesktopIcon("database_import"));
+ m_prjSet = 0;
+ m_fileBasedDstWasPresented = false;
+ m_setupFileBasedSrcNeeded = true;
+ m_importExecuted = false;
+ m_srcTypeCombo = 0;
+
+ setMinimumSize(400, 400);
+ parseArguments();
+ setupIntro();
+// setupSrcType();
+ setupSrcConn();
+ setupSrcDB();
+ setupDstType();
+ setupDstTitle();
+ setupDst();
+ setupImportType();
+ setupImporting();
+ setupFinish();
+
+ connect(this, SIGNAL(selected(const QString &)), this, SLOT(pageSelected(const QString &)));
+ connect(this, SIGNAL(helpClicked()), this, SLOT(helpClicked()));
+
+ if (m_predefinedConnectionData) {
+ // setup wizard for predefined server source
+ m_srcConn->showAdvancedConn();
+ setAppropriate( m_srcConnPage, false );
+ setAppropriate( m_srcDBPage, false );
+ }
+ else if (!m_predefinedDatabaseName.isEmpty()) {
+ // setup wizard for predefined source
+ // (used when external project type was opened in Kexi, e.g. mdb file)
+// MigrateManager manager;
+// QString driverName = manager.driverForMimeType( m_predefinedMimeType );
+// m_srcTypeCombo->setCurrentText( driverName );
+
+// showPage( m_srcConnPage );
+ m_srcConn->showSimpleConn();
+ m_srcConn->setSelectedFileName(m_predefinedDatabaseName);
+
+ //disable all prev pages except "welcome" page
+ for (int i=0; i<indexOf(m_dstTypePage); i++) {
+ if (page(i)!=m_introPage)
+ setAppropriate( page(i), false );
+ }
+ }
+
+ m_sourceDBEncoding = QString::fromLatin1(KGlobal::locale()->encoding()); //default
+}
+
+//===========================================================
+//
+ImportWizard::~ImportWizard()
+{
+ delete m_prjSet;
+}
+
+//===========================================================
+//
+void ImportWizard::parseArguments()
+{
+ m_predefinedConnectionData = 0;
+ if (!m_args)
+ return;
+ if (!(*m_args)["databaseName"].isEmpty() && !(*m_args)["mimeType"].isEmpty()) {
+ m_predefinedDatabaseName = (*m_args)["databaseName"];
+ m_predefinedMimeType = (*m_args)["mimeType"];
+ if (m_args->contains("connectionData")) {
+ m_predefinedConnectionData = new KexiDB::ConnectionData();
+ KexiDB::fromMap(
+ KexiUtils::deserializeMap((*m_args)["connectionData"]), *m_predefinedConnectionData
+ );
+ }
+ }
+ m_args->clear();
+}
+
+//===========================================================
+//
+void ImportWizard::setupIntro()
+{
+ m_introPage = new QWidget(this);
+ QVBoxLayout *vbox = new QVBoxLayout(m_introPage, KDialog::marginHint());
+
+ QLabel *lblIntro = new QLabel(m_introPage);
+ lblIntro->setAlignment( Qt::AlignTop | Qt::AlignLeft | Qt::WordBreak );
+ QString msg;
+ if (m_predefinedConnectionData) { //predefined import: server source
+ msg = i18n("<qt>Database Importing wizard is about to import \"%1\" database "
+ "<nobr>(connection %2)</nobr> into a Kexi database.</qt>")
+ .arg(m_predefinedDatabaseName).arg(m_predefinedConnectionData->serverInfoString());
+ }
+ else if (!m_predefinedDatabaseName.isEmpty()) { //predefined import: file source
+//! @todo this message is currently ok for files only
+ KMimeType::Ptr mimeTypePtr = KMimeType::mimeType(m_predefinedMimeType);
+ msg = i18n("<qt>Database Importing wizard is about to import <nobr>\"%1\"</nobr> file "
+ "of type \"%2\" into a Kexi database.</qt>")
+ .arg(QDir::convertSeparators(m_predefinedDatabaseName)).arg(mimeTypePtr->comment());
+ }
+ else {
+ msg = i18n("Database Importing wizard allows you to import an existing database "
+ "into a Kexi database.");
+ }
+ lblIntro->setText(msg+"\n\n"
+ +i18n("Click \"Next\" button to continue or \"Cancel\" button to exit this wizard."));
+ vbox->addWidget( lblIntro );
+ addPage(m_introPage, i18n("Welcome to the Database Importing Wizard"));
+}
+
+//===========================================================
+//
+/*
+void ImportWizard::setupSrcType()
+{
+ m_srcTypePage = new QWidget(this);
+
+//! @todo Would be good if KexiDBDriverComboBox worked for migration drivers
+ QVBoxLayout *vbox = new QVBoxLayout(m_srcTypePage, KDialog::marginHint());
+
+ QHBoxLayout *hbox = new QHBoxLayout(vbox);
+ QLabel *lbl = new QLabel(i18n("Source database type:")+" ", m_srcTypePage);
+ hbox->addWidget(lbl);
+
+ m_srcTypeCombo = new KComboBox(m_srcTypePage);
+ hbox->addWidget(m_srcTypeCombo);
+ hbox->addStretch(1);
+ vbox->addStretch(1);
+ lbl->setBuddy(m_srcTypeCombo);
+
+ MigrateManager manager;
+ QStringList names = manager.driverNames();
+
+ m_srcTypeCombo->insertStringList(names);
+ addPage(m_srcTypePage, i18n("Select Source Database Type"));
+}
+*/
+//===========================================================
+//
+void ImportWizard::setupSrcConn()
+{
+ m_srcConnPage = new QWidget(this);
+ QVBoxLayout *vbox = new QVBoxLayout(m_srcConnPage, KDialog::marginHint());
+
+ m_srcConn = new KexiConnSelectorWidget(Kexi::connset(),
+ ":ProjectMigrationSourceDir", m_srcConnPage, "m_srcConnSelector");
+
+ m_srcConn->hideConnectonIcon();
+ m_srcConn->showSimpleConn();
+
+ QStringList excludedFilters;
+//! @todo remove when support for kexi files as source prj is added in migration
+ excludedFilters += KexiDB::Driver::defaultFileBasedDriverMimeType();
+ excludedFilters += "application/x-kexiproject-shortcut";
+ excludedFilters += "application/x-kexi-connectiondata";
+ m_srcConn->m_fileDlg->setExcludedFilters(excludedFilters);
+
+// m_srcConn->hideHelpers();
+ vbox->addWidget(m_srcConn);
+ addPage(m_srcConnPage, i18n("Select Location for Source Database"));
+}
+
+//===========================================================
+//
+void ImportWizard::setupSrcDB()
+{
+// arrivesrcdbPage creates widgets on that page
+ m_srcDBPage = new QWidget(this);
+ m_srcDBName = NULL;
+ addPage(m_srcDBPage, i18n("Select Source Database"));
+}
+
+//===========================================================
+//
+void ImportWizard::setupDstType()
+{
+ m_dstTypePage = new QWidget(this);
+
+ KexiDB::DriverManager manager;
+ KexiDB::Driver::InfoMap drvs = manager.driversInfo();
+
+ QVBoxLayout *vbox = new QVBoxLayout(m_dstTypePage, KDialog::marginHint());
+
+ QHBoxLayout *hbox = new QHBoxLayout(vbox);
+ QLabel *lbl = new QLabel(i18n("Destination database type:")+" ", m_dstTypePage);
+ lbl->setAlignment(Qt::AlignAuto|Qt::AlignTop);
+ hbox->addWidget(lbl);
+
+ m_dstPrjTypeSelector = new KexiPrjTypeSelector(m_dstTypePage);
+ hbox->addWidget(m_dstPrjTypeSelector);
+ m_dstPrjTypeSelector->option_file->setText(i18n("Database project stored in a file"));
+ m_dstPrjTypeSelector->option_server->setText(i18n("Database project stored on a server"));
+
+ QVBoxLayout *frame_server_vbox = new QVBoxLayout(m_dstPrjTypeSelector->frame_server, KDialog::spacingHint());
+ m_dstServerTypeCombo = new KexiDBDriverComboBox(m_dstPrjTypeSelector->frame_server, drvs,
+ KexiDBDriverComboBox::ShowServerDrivers);
+ frame_server_vbox->addWidget(m_dstServerTypeCombo);
+ hbox->addStretch(1);
+ vbox->addStretch(1);
+ lbl->setBuddy(m_dstServerTypeCombo);
+
+//! @todo hardcoded: find a way to preselect default engine item
+ //m_dstTypeCombo->setCurrentText("SQLite3");
+ addPage(m_dstTypePage, i18n("Select Destination Database Type"));
+}
+
+//===========================================================
+//
+void ImportWizard::setupDstTitle()
+{
+ m_dstTitlePage = new KexiDBTitlePage(i18n("Destination project's caption:"),
+ this, "KexiDBTitlePage");
+ m_dstTitlePage->layout()->setMargin( KDialog::marginHint() );
+ m_dstTitlePage->updateGeometry();
+ m_dstNewDBNameLineEdit = m_dstTitlePage->le_caption;
+ addPage(m_dstTitlePage, i18n("Select Destination Database Project's Caption"));
+}
+
+//===========================================================
+//
+void ImportWizard::setupDst()
+{
+ m_dstPage = new QWidget(this);
+ QVBoxLayout *vbox = new QVBoxLayout(m_dstPage, KDialog::marginHint());
+
+ m_dstConn = new KexiConnSelectorWidget(Kexi::connset(),
+ ":ProjectMigrationDestinationDir", m_dstPage, "m_dstConnSelector");
+ m_dstConn->hideHelpers();
+ //me: Can't connect m_dstConn->m_fileDlg here, it doesn't exist yet
+ //connect(this, SLOT(next()), m_dstConn->m_fileDlg, SIGNAL(accepted()));
+
+ vbox->addWidget( m_dstConn );
+ connect(m_dstConn,SIGNAL(connectionItemExecuted(ConnectionDataLVItem*)),
+ this,SLOT(next()));
+
+// m_dstConn->hideHelpers();
+ m_dstConn->showSimpleConn();
+ //anyway, db files will be _saved_
+ m_dstConn->m_fileDlg->setMode( KexiStartupFileDialog::SavingFileBasedDB );
+// m_dstConn->hideHelpers();
+// m_dstConn->m_file->btn_advanced->hide();
+// m_dstConn->m_file->label->hide();
+// m_dstConn->m_file->lbl->hide();
+ //m_dstConn->m_file->spacer7->hide();
+
+
+ //js dstNewDBName = new KLineEdit(dstControls);
+ // dstNewDBName->setText(i18n("Enter new database name here"));
+ addPage(m_dstPage, i18n("Select Location for Destination Database"));
+}
+
+//===========================================================
+//
+void ImportWizard::setupImportType()
+{
+ m_importTypePage = new QWidget(this);
+ QVBoxLayout *vbox = new QVBoxLayout(m_importTypePage, KDialog::marginHint());
+ m_importTypeButtonGroup = new QVButtonGroup(m_importTypePage);
+ m_importTypeButtonGroup->setLineWidth(0);
+ vbox->addWidget( m_importTypeButtonGroup );
+
+ (void)new QRadioButton(i18n("Structure and data"), m_importTypeButtonGroup);
+ (void)new QRadioButton(i18n("Structure only"), m_importTypeButtonGroup);
+
+ m_importTypeButtonGroup->setExclusive( true );
+ m_importTypeButtonGroup->setButton( 0 );
+ addPage(m_importTypePage, i18n("Select Type of Import"));
+}
+
+//===========================================================
+//
+void ImportWizard::setupImporting()
+{
+ m_importingPage = new QWidget(this);
+ m_importingPage->hide();
+ QVBoxLayout *vbox = new QVBoxLayout(m_importingPage, KDialog::marginHint());
+ m_lblImportingTxt = new QLabel(m_importingPage);
+ m_lblImportingTxt->setAlignment( Qt::AlignTop | Qt::AlignLeft | Qt::WordBreak );
+
+ m_lblImportingErrTxt = new QLabel(m_importingPage);
+ m_lblImportingErrTxt->setAlignment( Qt::AlignTop | Qt::AlignLeft | Qt::WordBreak );
+
+ m_progressBar = new KProgress(100, m_importingPage);
+ m_progressBar->hide();
+
+ vbox->addWidget( m_lblImportingTxt );
+ vbox->addWidget( m_lblImportingErrTxt );
+ vbox->addStretch(1);
+
+ KButtonBox *optionsBox = new KButtonBox(m_importingPage);
+ vbox->addWidget( optionsBox );
+ m_importOptionsButton = optionsBox->addButton(i18n("Advanced Options"), this, SLOT(slotOptionsButtonClicked()));
+ m_importOptionsButton->setIconSet(SmallIconSet("configure"));
+ optionsBox->addStretch(1);
+
+ vbox->addWidget( m_progressBar );
+
+ vbox->addStretch(2);
+
+ m_importingPage->show();
+
+ addPage(m_importingPage, i18n("Importing"));
+}
+
+//===========================================================
+//
+void ImportWizard::setupFinish()
+{
+ m_finishPage = new QWidget(this);
+ m_finishPage->hide();
+ QVBoxLayout *vbox = new QVBoxLayout(m_finishPage, KDialog::marginHint());
+ m_finishLbl = new QLabel(m_finishPage);
+ m_finishLbl->setAlignment( Qt::AlignTop | Qt::AlignLeft | Qt::WordBreak );
+
+ vbox->addWidget( m_finishLbl );
+ m_openImportedProjectCheckBox = new QCheckBox(i18n("Open imported project"),
+ m_finishPage, "openImportedProjectCheckBox");
+ m_openImportedProjectCheckBox->setChecked(true);
+ vbox->addSpacing( KDialog::spacingHint() );
+ vbox->addWidget( m_openImportedProjectCheckBox );
+ vbox->addStretch(1);
+
+ addPage(m_finishPage, i18n("Success"));
+}
+
+//===========================================================
+//
+bool ImportWizard::checkUserInput()
+{
+ QString finishtxt;
+
+ if (m_dstNewDBNameLineEdit->text().isEmpty())
+ {
+ finishtxt = finishtxt + "<br>" + i18n("No new database name was entered.");
+ }
+
+ Kexi::ObjectStatus result;
+ KexiMigrate* sourceDriver = prepareImport(result);
+ if (sourceDriver && sourceDriver->isSourceAndDestinationDataSourceTheSame())
+ {
+ finishtxt = finishtxt + "<br>" + i18n("Source database is the same as destination.");
+ }
+
+ if (! finishtxt.isNull())
+ {
+ finishtxt = "<qt>" + i18n("Following problems were found with the data you entered:") +
+ "<br>" + finishtxt + "<br><br>" +
+ i18n("Please click 'Back' button and correct these errors.");
+ m_lblImportingErrTxt->setText(finishtxt);
+ }
+
+ return finishtxt.isNull();
+}
+
+void ImportWizard::arriveSrcConnPage()
+{
+ m_srcConnPage->hide();
+
+// checkIfSrcTypeFileBased(m_srcTypeCombo->currentText());
+// if (fileBasedSrcSelected()) {
+//moved m_srcConn->showSimpleConn();
+ /*! @todo KexiStartupFileDialog needs "open file" and "open server" modes
+ in addition to just "open" */
+ if (m_setupFileBasedSrcNeeded) {
+ m_setupFileBasedSrcNeeded = false;
+ QStringList additionalMimeTypes;
+ /* moved
+ if (m_srcTypeCombo->currentText().contains("Access")) {
+ //! @todo tmp: hardcoded!
+ additionalMimeTypes << "application/x-msaccess";
+ }*/
+ m_srcConn->m_fileDlg->setMode(KexiStartupFileDialog::Opening);
+ m_srcConn->m_fileDlg->setAdditionalFilters(additionalMimeTypes);
+/*moved if (m_srcTypeCombo->currentText().contains("Access")) {
+ //! @todo tmp: hardcoded!
+ #ifdef Q_WS_WIN
+ m_srcConn->m_fileDlg->setSelectedFilter("*.mdb");
+ #else
+ m_srcConn->m_fileDlg->setFilter("*.mdb");
+ #endif
+ }*/
+ //m_srcConn->m_file->label->hide();
+ //m_srcConn->m_file->btn_advanced->hide();
+ //m_srcConn->m_file->label->parentWidget()->hide();
+ }
+// } else {
+// m_srcConn->showAdvancedConn();
+// }
+ /*! @todo Support different file extensions based on MigrationDriver */
+ m_srcConnPage->show();
+}
+
+void ImportWizard::arriveSrcDBPage()
+{
+ if (fileBasedSrcSelected()) {
+ //! @todo Back button doesn't work after selecting a file to import
+ //moved showPage(m_dstTypePage);
+ }
+ else if (!m_srcDBName) {
+ m_srcDBPage->hide();
+ kdDebug() << "Looks like we need a project selector widget!" << endl;
+
+ KexiDB::ConnectionData* condata = m_srcConn->selectedConnectionData();
+ if(condata) {
+ m_prjSet = new KexiProjectSet(*condata);
+ QVBoxLayout *vbox = new QVBoxLayout(m_srcDBPage, KDialog::marginHint());
+ m_srcDBName = new KexiProjectSelectorWidget(m_srcDBPage,
+ "KexiMigrationProjectSelector", m_prjSet);
+ vbox->addWidget( m_srcDBName );
+ m_srcDBName->label->setText(i18n("Select source database you wish to import:"));
+ }
+ m_srcDBPage->show();
+ }
+}
+
+void ImportWizard::arriveDstTitlePage()
+{
+ if(fileBasedSrcSelected()) {
+ QString suggestedDBName( QFileInfo(m_srcConn->selectedFileName()).fileName() );
+ const QFileInfo fi( suggestedDBName );
+ suggestedDBName = suggestedDBName.left(suggestedDBName.length()
+ - (fi.extension().length() ? (fi.extension().length()+1) : 0));
+ m_dstNewDBNameLineEdit->setText( suggestedDBName );
+ } else {
+ if (m_predefinedConnectionData) {
+ // server source db is predefined
+ m_dstNewDBNameLineEdit->setText( m_predefinedDatabaseName );
+ }
+ else {
+ if (!m_srcDBName || !m_srcDBName->selectedProjectData()) {
+ back(); //todo!
+ return;
+ }
+ m_dstNewDBNameLineEdit->setText( m_srcDBName->selectedProjectData()->databaseName() );
+ }
+ }
+}
+
+void ImportWizard::arriveDstPage()
+{
+ m_dstPage->hide();
+
+// checkIfDstTypeFileBased(m_dstTypeCombo->currentText());
+ if(fileBasedDstSelected()) {
+ m_dstConn->showSimpleConn();
+ m_dstConn->m_fileDlg->setMode( KexiStartupFileDialog::SavingFileBasedDB );
+ if (!m_fileBasedDstWasPresented) {
+ //without extension - it will be added automatically
+ m_dstConn->m_fileDlg->setLocationText(m_dstNewDBNameLineEdit->text());
+ }
+ m_fileBasedDstWasPresented = true;
+ } else {
+ m_dstConn->showAdvancedConn();
+ }
+ m_dstPage->show();
+}
+
+void ImportWizard::arriveImportingPage() {
+// checkIfDstTypeFileBased(m_dstTypeCombo->currentText());
+/*moved if (m_fileBasedDstWasPresented) {
+ if (!m_dstConn->m_fileDlg->checkFileName()) {
+ back();
+ return;
+ }
+ }*/
+ m_importingPage->hide();
+ if (checkUserInput()) {
+ setNextEnabled(m_importingPage, true);
+ }
+ else {
+ setNextEnabled(m_importingPage, false);
+ }
+
+ m_lblImportingTxt->setText(i18n(
+ "All required information has now "
+ "been gathered. Click \"Next\" button to start importing.\n\n"
+ "Depending on size of the database this may take some time."
+ /*"Note: You may be asked for extra "
+ "information such as field types if "
+ "the wizard could not automatically "
+ "determine this for you."*/));
+
+//todo
+
+ //temp. hack for MS Access driver only
+//! @todo for other databases we will need KexiMigration::Conenction
+//! and KexiMigration::Driver classes
+ bool showOptions = false;
+ if (fileBasedSrcSelected()) {
+ Kexi::ObjectStatus result;
+ KexiMigrate* sourceDriver = prepareImport(result);
+ if (sourceDriver) {
+ showOptions = !result.error()
+ && sourceDriver->propertyValue( "source_database_has_nonunicode_encoding" ).toBool();
+ KexiMigration::Data *data = sourceDriver->data();
+ sourceDriver->setData( 0 );
+ delete data;
+ }
+ }
+ if (showOptions)
+ m_importOptionsButton->show();
+ else
+ m_importOptionsButton->hide();
+
+ m_importingPage->show();
+}
+
+void ImportWizard::arriveFinishPage() {
+// backButton()->hide();
+// cancelButton()->setEnabled(false);
+// m_finishLbl->setText( m_successText.arg(m_dstNewDBNameLineEdit->text()) );
+}
+
+bool ImportWizard::fileBasedSrcSelected() const
+{
+ if (m_predefinedConnectionData)
+ return false;
+
+// kdDebug() << (m_srcConn->selectedConnectionType()==KexiConnSelectorWidget::FileBased) << endl;
+ return m_srcConn->selectedConnectionType()==KexiConnSelectorWidget::FileBased;
+}
+
+bool ImportWizard::fileBasedDstSelected() const
+{
+// QString dstType(m_dstServerTypeCombo->currentText());
+
+ return m_dstPrjTypeSelector->buttonGroup->selectedId() == 1;
+
+/* if ((dstType == "PostgreSQL") || (dstType == "MySQL")) {
+ return false;
+ } else {
+ return true;
+ }*/
+}
+
+
+void ImportWizard::progressUpdated(int percent) {
+ m_progressBar->setProgress(percent);
+ KApplication::kApplication()->processEvents();
+}
+
+//===========================================================
+//
+QString ImportWizard::driverNameForSelectedSource()
+{
+ if (fileBasedSrcSelected()) {
+ KMimeType::Ptr ptr = KMimeType::findByFileContent( m_srcConn->selectedFileName() );
+ if (!ptr || ptr.data()->name()=="application/octet-stream" || ptr.data()->name()=="text/plain") {
+ //try by URL:
+ ptr = KMimeType::findByURL( m_srcConn->selectedFileName() );
+ }
+ return ptr ? m_migrateManager.driverForMimeType( ptr.data()->name() ) : QString::null;
+ }
+
+ //server-based
+ if (m_predefinedConnectionData) {
+ return m_predefinedConnectionData->driverName;
+ }
+
+ return m_srcConn->selectedConnectionData()
+ ? m_srcConn->selectedConnectionData()->driverName : QString::null;
+}
+
+//===========================================================
+//
+void ImportWizard::accept()
+{
+ /*moved
+ backButton()->setEnabled(false);
+ finishButton()->setEnabled(false);
+// cancelButton()->setEnabled(false);
+ acceptImport();
+ backButton()->setEnabled(true);
+ finishButton()->setEnabled(true);
+// cancelButton()->setEnabled(true);
+*/
+ if (m_args) {
+ if ((!fileBasedDstSelected() && !m_args->contains("destinationConnectionShortcut"))
+ || !m_openImportedProjectCheckBox->isChecked())
+ {
+ //do not open dest db if used didn't want it
+ //for server connections, destinationConnectionShortcut must be defined
+ m_args->remove("destinationDatabaseName");
+ }
+ }
+ KWizard::accept();
+}
+
+KexiMigrate* ImportWizard::prepareImport(Kexi::ObjectStatus& result)
+{
+ KexiUtils::WaitCursor wait;
+
+ // Start with a driver manager
+ KexiDB::DriverManager manager;
+
+ kdDebug() << "Creating destination driver..." << endl;
+
+ // Get a driver to the destination database
+ KexiDB::Driver *destDriver = manager.driver(
+ m_dstConn->selectedConnectionData() ? m_dstConn->selectedConnectionData()->driverName //server based
+ : KexiDB::Driver::defaultFileBasedDriverName()
+ // : m_dstTypeCombo->currentText() //file based
+ );
+ if (!destDriver || manager.error())
+ {
+ result.setStatus(&manager);
+ kdDebug() << "Manager error..." << endl;
+ manager.debugError();
+// result.setStatus(&manager);
+ }
+
+ // Set up destination connection data
+ KexiDB::ConnectionData *cdata;
+ bool cdataOwned = false;
+ QString dbname;
+ if (!result.error())
+ {
+ if (m_dstConn->selectedConnectionData())
+ {
+ //server-based project
+ kdDebug() << "Server destination..." << endl;
+ cdata = m_dstConn->selectedConnectionData();
+ dbname = m_dstNewDBNameLineEdit->text();
+ }
+ else // if (m_dstTypeCombo->currentText().lower() == KexiDB::Driver::defaultFileBasedDriverName())
+ {
+ //file-based project
+ kdDebug() << "File Destination..." << endl;
+ cdata = new KexiDB::ConnectionData();
+ cdataOwned = true;
+ cdata->caption = m_dstNewDBNameLineEdit->text();
+ cdata->driverName = KexiDB::Driver::defaultFileBasedDriverName();
+ dbname = m_dstConn->selectedFileName();
+ cdata->setFileName( dbname );
+ kdDebug() << "Current file name: " << dbname << endl;
+ }
+/* else
+ {
+ //TODO This needs a better message
+ //KMessageBox::error(this,
+ result.setStatus(i18n("No connection data is available. You did not select a destination filename."),"");
+ //return false;
+ } */
+ }
+
+ // Find a source (migration) driver name
+ QString sourceDriverName;
+ if (!result.error())
+ {
+ sourceDriverName = driverNameForSelectedSource();
+ if (sourceDriverName.isEmpty())
+ result.setStatus(i18n("No appropriate migration driver found."),
+ m_migrateManager.possibleProblemsInfoMsg());
+ }
+
+ // Get a source (migration) driver
+ KexiMigrate* sourceDriver = 0;
+ if (!result.error())
+ {
+ sourceDriver = m_migrateManager.driver( sourceDriverName );
+ if(!sourceDriver || m_migrateManager.error()) {
+ kdDebug() << "Import migrate driver error..." << endl;
+ result.setStatus(&m_migrateManager);
+ }
+ }
+
+ KexiUtils::removeWaitCursor();
+
+ // Set up source (migration) data required for connection
+ if (sourceDriver && !result.error())
+ {
+ // Setup progress feedback for the GUI
+ if(sourceDriver->progressSupported()) {
+ m_progressBar->updateGeometry();
+ disconnect(sourceDriver, SIGNAL(progressPercent(int)),
+ this, SLOT(progressUpdated(int)));
+ connect(sourceDriver, SIGNAL(progressPercent(int)),
+ this, SLOT(progressUpdated(int)));
+ progressUpdated(0);
+ }
+
+ bool keepData;
+ if (m_importTypeButtonGroup->selectedId() == 0)
+ {
+ kdDebug() << "Structure and data selected" << endl;
+ keepData = true;
+ }
+ else if (m_importTypeButtonGroup->selectedId() == 1)
+ {
+ kdDebug() << "structure only selected" << endl;
+ keepData = false;
+ }
+ else
+ {
+ kdDebug() << "Neither radio button is selected (not possible?) presume keep data" << endl;
+ keepData = true;
+ }
+
+ KexiMigration::Data* md = new KexiMigration::Data();
+ // delete md->destination;
+ md->destination = new KexiProjectData(*cdata, dbname);
+ if(fileBasedSrcSelected()) {
+ KexiDB::ConnectionData* conn_data = new KexiDB::ConnectionData();
+ conn_data->setFileName(m_srcConn->selectedFileName());
+ md->source = conn_data;
+ md->sourceName = "";
+ }
+ else
+ {
+ if (m_predefinedConnectionData)
+ md->source = m_predefinedConnectionData;
+ else
+ md->source = m_srcConn->selectedConnectionData();
+
+ if (!m_predefinedDatabaseName.isEmpty())
+ md->sourceName = m_predefinedDatabaseName;
+ else
+ md->sourceName = m_srcDBName->selectedProjectData()->databaseName();
+ //! @todo Aah, this is so C-like. Move to performImport().
+ }
+ md->keepData = keepData;
+ sourceDriver->setData(md);
+ return sourceDriver;
+ }
+ return 0;
+}
+
+tristate ImportWizard::import()
+{
+ m_importExecuted = true;
+
+ Kexi::ObjectStatus result;
+ KexiMigrate* sourceDriver = prepareImport(result);
+
+ bool acceptingNeeded = false;
+
+ // Perform import
+ if (sourceDriver && !result.error())
+ {
+ if (!m_sourceDBEncoding.isEmpty()) {
+ sourceDriver->setPropertyValue( "source_database_nonunicode_encoding",
+ QVariant(m_sourceDBEncoding.upper().replace(' ',"")) // "CP1250", not "cp 1250"
+ );
+ }
+
+ if (!sourceDriver->checkIfDestinationDatabaseOverwritingNeedsAccepting(&result, acceptingNeeded)) {
+ kdDebug() << "Abort import cause checkIfDestinationDatabaseOverwritingNeedsAccepting returned false." << endl;
+ return false;
+ }
+
+ kdDebug() << sourceDriver->data()->destination->databaseName() << endl;
+ kdDebug() << "Performing import..." << endl;
+ }
+
+ if (sourceDriver && !result.error() && acceptingNeeded) { // ok, the destination-db already exists...
+ if (KMessageBox::Yes != KMessageBox::warningYesNo(this,
+ "<qt>"+i18n("Database %1 already exists."
+ "<p>Do you want to replace it with a new one?")
+ .arg(sourceDriver->data()->destination->infoString()),
+ 0, KGuiItem(i18n("&Replace")), KGuiItem(i18n("No"))))
+ {
+ return cancelled;
+ }
+ }
+
+ if (sourceDriver && !result.error() && sourceDriver->progressSupported()) {
+ m_progressBar->show();
+ }
+
+ if (sourceDriver && !result.error() && sourceDriver->performImport(&result))
+ {
+ if (m_args) {
+// if (fileBasedDstSelected()) {
+ m_args->insert("destinationDatabaseName",
+ sourceDriver->data()->destination->databaseName());
+// }
+ QString destinationConnectionShortcut(
+ Kexi::connset().fileNameForConnectionData( m_dstConn->selectedConnectionData() ) );
+ if (!destinationConnectionShortcut.isEmpty()) {
+ m_args->insert("destinationConnectionShortcut", destinationConnectionShortcut);
+ }
+ }
+ setTitle(m_finishPage, i18n("Success"));
+ return true;
+ }
+
+ if (!sourceDriver || result.error())
+ {
+ m_progressBar->setProgress(0);
+ m_progressBar->hide();
+
+ QString msg, details;
+ KexiTextMessageHandler handler(msg, details);
+ handler.showErrorMessage(&result);
+
+ kdDebug() << msg << "\n" << details << endl;
+ setTitle(m_finishPage, i18n("Failure"));
+ m_finishLbl->setText(
+ i18n("<p>Import failed.</p>%1<p>%2</p><p>You can click \"Back\" button and try again.</p>")
+ .arg(msg).arg(details));
+ return false;
+ }
+// delete kexi_conn;
+ return true;
+}
+
+void ImportWizard::reject()
+{
+ KWizard::reject();
+}
+
+//===========================================================
+//
+void ImportWizard::next()
+{
+ if (currentPage() == m_srcConnPage) {
+ if (fileBasedSrcSelected()
+ && /*! @todo use KURL? */!QFileInfo(m_srcConn->selectedFileName()).isFile()) {
+
+ KMessageBox::sorry(this,i18n("Select source database filename."));
+ return;
+ }
+
+ if ( (! fileBasedSrcSelected()) && (! m_srcConn->selectedConnectionData()) ) {
+ KMessageBox::sorry(this,i18n("Select source database."));
+ return;
+ }
+
+ KexiMigrate* import = m_migrateManager.driver( driverNameForSelectedSource() );
+ if(!import || m_migrateManager.error()) {
+ QString dbname;
+ if (fileBasedSrcSelected())
+ dbname = m_srcConn->selectedFileName();
+ else
+ dbname = m_srcConn->selectedConnectionData()
+ ? m_srcConn->selectedConnectionData()->serverInfoString() : QString::null;
+ if (!dbname.isEmpty())
+ dbname = QString(" \"%1\"").arg(dbname);
+ KMessageBox::error(this, i18n("Could not import database%1. This type is not supported.")
+ .arg(dbname));
+ return;
+ }
+ }
+ else if (currentPage() == m_dstPage) {
+ if (m_fileBasedDstWasPresented) {
+ if (fileBasedDstSelected() && !m_dstConn->m_fileDlg->checkFileName())
+ return;
+ }
+ }
+ else if (currentPage() == m_importingPage) {
+ if (!m_importExecuted) {
+ m_importOptionsButton->hide();
+ nextButton()->setEnabled(false);
+ finishButton()->setEnabled(false);
+ backButton()->setEnabled(false);
+ m_lblImportingTxt->setText(i18n("Importing in progress..."));
+ tristate res = import();
+ if (true == res) {
+ m_finishLbl->setText(
+ i18n("Database has been imported into Kexi database project \"%1\".")
+ .arg(m_dstNewDBNameLineEdit->text()) );
+ cancelButton()->setEnabled(false);
+ setBackEnabled(m_finishPage, false);
+ setFinishEnabled(m_finishPage, true);
+ m_openImportedProjectCheckBox->show();
+ next();
+ return;
+ }
+
+ m_progressBar->hide();
+ cancelButton()->setEnabled(true);
+ setBackEnabled(m_finishPage, true);
+ setFinishEnabled(m_finishPage, false);
+ m_openImportedProjectCheckBox->hide();
+ if (!res)
+ next();
+ else if (~res) {
+ arriveImportingPage();
+ // back();
+ }
+ m_importExecuted = false;
+ return;
+ }
+ }
+
+ setAppropriate( m_srcDBPage, !fileBasedSrcSelected() && !m_predefinedConnectionData ); //skip m_srcDBPage
+ KWizard::next();
+}
+
+void ImportWizard::back()
+{
+ setAppropriate( m_srcDBPage, !fileBasedSrcSelected() && !m_predefinedConnectionData ); //skip m_srcDBPage
+ KWizard::back();
+}
+
+void ImportWizard::pageSelected(const QString &)
+{
+ if (currentPage() == m_introPage) {
+ }
+// else if (currentPage() == m_srcTypePage) {
+// }
+ else if (currentPage() == m_srcConnPage) {
+ arriveSrcConnPage();
+ }
+ else if (currentPage() == m_srcDBPage) {
+ arriveSrcDBPage();
+ }
+ else if (currentPage() == m_dstTypePage) {
+ }
+ else if (currentPage() == m_dstTitlePage) {
+ arriveDstTitlePage();
+ }
+ else if (currentPage() == m_dstPage) {
+ arriveDstPage();
+ }
+ else if (currentPage() == m_importingPage) {
+ arriveImportingPage();
+ }
+ else if (currentPage() == m_finishPage) {
+ arriveFinishPage();
+ }
+}
+
+void ImportWizard::helpClicked()
+{
+ if (currentPage() == m_introPage)
+ {
+ KMessageBox::information(this, i18n("No help is available for this page."), i18n("Help"));
+ }
+/* else if (currentPage() == m_srcTypePage)
+ {
+ KMessageBox::information(this, i18n("Here you can choose the type of data to import data from."), i18n("Help"));
+ }*/
+ else if (currentPage() == m_srcConnPage)
+ {
+ KMessageBox::information(this, i18n("Here you can choose the location to import data from."), i18n("Help"));
+ }
+ else if (currentPage() == m_srcDBPage)
+ {
+ KMessageBox::information(this, i18n("Here you can choose the actual database to import data from."), i18n("Help"));
+ }
+ else if (currentPage() == m_dstTypePage)
+ {
+ KMessageBox::information(this, i18n("Here you can choose the location to save the data."), i18n("Help"));
+ }
+ else if (currentPage() == m_dstPage)
+ {
+ KMessageBox::information(this, i18n("Here you can choose the location to save the data in and the new database name."), i18n("Help"));
+ }
+ else if (currentPage() == m_finishPage || currentPage() == m_importingPage)
+ {
+ KMessageBox::information(this, i18n("No help is available for this page."), i18n("Help"));
+ }
+}
+
+void ImportWizard::slotOptionsButtonClicked()
+{
+ OptionsDialog dlg(m_srcConn->selectedFileName(), m_sourceDBEncoding, this);
+ if (QDialog::Accepted != dlg.exec())
+ return;
+
+ if (m_sourceDBEncoding != dlg.encodingComboBox()->selectedEncoding()) {
+ m_sourceDBEncoding = dlg.encodingComboBox()->selectedEncoding();
+ }
+}
+
+#include "importwizard.moc"
diff --git a/kexi/migration/importwizard.h b/kexi/migration/importwizard.h
new file mode 100644
index 00000000..7d51a934
--- /dev/null
+++ b/kexi/migration/importwizard.h
@@ -0,0 +1,153 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Adam Pigg <[email protected]>
+ Copyright (C) 2004-2006 Jaroslaw Staniek <[email protected]>
+ Copyright (C) 2005 Martin Ellis <[email protected]>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXIMIGRATIONIMPORTWIZARD_H
+#define KEXIMIGRATIONIMPORTWIZARD_H
+
+#include <kwizard.h>
+#include <kprogress.h>
+#include <kapplication.h>
+
+#include <kexiutils/tristate.h>
+#include "migratemanager.h"
+
+class QLabel;
+class QCheckBox;
+class QPushButton;
+class QHBoxLayout;
+class QVBoxLayout;
+class QVButtonGroup;
+class KComboBox;
+class KListView;
+class KLineEdit;
+class KexiConnSelectorWidget;
+class KexiProjectSelectorWidget;
+class KexiProjectSet;
+class KexiDBTitlePage;
+class KexiDBDriverComboBox;
+class KexiPrjTypeSelector;
+
+namespace Kexi
+{
+ class ObjectStatus;
+}
+
+namespace KexiDB
+{
+ class ConnectionData;
+}
+
+namespace KexiMigration {
+
+class KexiMigrate;
+
+//! GUI for importing external databases (file-based and server-based)
+class KEXIMIGR_EXPORT ImportWizard : public KWizard
+{
+Q_OBJECT
+public:
+ /*! Creates wizard's instance.
+ \a args contains arguments that can be parsed by parseArguments().
+ \a *arg will be also set to imported project's filename on success
+ and to null value on failure or cancellation. */
+ ImportWizard(QWidget *parent = 0, QMap<QString,QString>* args = 0);
+ virtual ~ImportWizard();
+
+public slots:
+ void progressUpdated(int percent);
+
+protected slots:
+ virtual void next();
+ virtual void back();
+ void pageSelected(const QString &);
+ virtual void accept();
+ virtual void reject();
+ void helpClicked();
+ void slotOptionsButtonClicked();
+
+private:
+ void parseArguments();
+ void setupIntro();
+// void setupSrcType();
+ void setupSrcConn();
+ void setupSrcDB();
+ void setupDstType();
+ void setupDstTitle();
+ void setupDst();
+ void setupFinish();
+ void setupImportType();
+ void setupImporting();
+ bool checkUserInput();
+
+ KexiMigrate* prepareImport(Kexi::ObjectStatus& result);
+
+ /*! Performs import. \return true/false on success/faulure
+ or cancelled when user cancelled importing (mainly
+ because didn't allow overwriting an existing database by a new one). */
+ tristate import();
+
+ bool fileBasedSrcSelected() const;
+ bool fileBasedDstSelected() const;
+ QString driverNameForSelectedSource();
+// void checkIfSrcTypeFileBased(const QString& srcType);
+// void checkIfDstTypeFileBased(const QString& dstType);
+
+ void arriveSrcConnPage();
+ void arriveSrcDBPage();
+ void arriveDstTitlePage();
+ void arriveDstPage();
+ void arriveFinishPage();
+ void arriveImportingPage();
+
+ QWidget *m_introPage, /* *m_srcTypePage,*/ *m_srcConnPage, *m_srcDBPage,
+ *m_dstTypePage, *m_dstPage, *m_importTypePage, *m_importingPage, *m_finishPage;
+
+ QVButtonGroup *m_importTypeButtonGroup;
+ KexiDBTitlePage* m_dstTitlePage;
+
+ KComboBox *m_srcTypeCombo;
+ KexiDBDriverComboBox *m_dstServerTypeCombo;
+ KexiPrjTypeSelector *m_dstPrjTypeSelector;
+
+ KexiConnSelectorWidget *m_srcConn, *m_dstConn;
+ KLineEdit *m_dstNewDBNameLineEdit;
+ KexiProjectSelectorWidget *m_srcDBName;
+
+ QLabel *m_lblImportingTxt, *m_lblImportingErrTxt, *m_finishLbl;
+ QCheckBox *m_openImportedProjectCheckBox;
+ bool m_fileBasedDstWasPresented, m_setupFileBasedSrcNeeded,
+ m_importExecuted; //!< used in import()
+ KexiProjectSet* m_prjSet;
+ KProgress *m_progressBar;
+ QPushButton* m_importOptionsButton;
+ QMap<QString,QString> *m_args;
+ QString m_predefinedDatabaseName, m_predefinedMimeType;
+ KexiDB::ConnectionData *m_predefinedConnectionData;
+ MigrateManager m_migrateManager; //!< object lives here, so status messages can be globally preserved
+
+ //! Encoding for source db. Currently only used for MDB driver.
+//! @todo Hardcoded. Move to KexiMigrate driver's impl.
+ QString m_sourceDBEncoding;
+};
+
+}
+
+#endif
diff --git a/kexi/migration/keximigrate.cpp b/kexi/migration/keximigrate.cpp
new file mode 100644
index 00000000..26229323
--- /dev/null
+++ b/kexi/migration/keximigrate.cpp
@@ -0,0 +1,616 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Adam Pigg <[email protected]>
+ Copyright (C) 2004-2006 Jaroslaw Staniek <[email protected]>
+ Copyright (C) 2005 Martin Ellis <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "keximigrate.h"
+
+#include <kdebug.h>
+#include <kinputdialog.h>
+#include <kapplication.h>
+
+#include <kexiutils/identifier.h>
+#include <core/kexi.h>
+#include <core/kexiproject.h>
+#include <kexidb/drivermanager.h>
+
+using namespace KexiDB;
+using namespace KexiMigration;
+
+KexiMigrate::KexiMigrate(QObject *parent, const char *name,
+ const QStringList&)
+ : QObject( parent, name )
+ , m_migrateData(0)
+ , m_destPrj(0)
+{
+ m_kexiDBCompatibleTableSchemasToRemoveFromMemoryAfterImport.setAutoDelete(true);
+}
+
+//! Used for computing progress:
+//! let's assume that each table creation costs the same as inserting 20 rows
+#define NUM_OF_ROWS_PER_CREATE_TABLE 20
+
+
+//=============================================================================
+// Migration parameters
+void KexiMigrate::setData(KexiMigration::Data* migrateData)
+{
+ m_migrateData = migrateData;
+}
+
+//=============================================================================
+// Destructor
+KexiMigrate::~KexiMigrate()
+{
+ delete m_destPrj;
+}
+
+bool KexiMigrate::checkIfDestinationDatabaseOverwritingNeedsAccepting(Kexi::ObjectStatus* result,
+ bool& acceptingNeeded)
+{
+ acceptingNeeded = false;
+ if (result)
+ result->clearStatus();
+
+ KexiDB::DriverManager drvManager;
+ KexiDB::Driver *destDriver = drvManager.driver(
+ m_migrateData->destination->connectionData()->driverName);
+ if (!destDriver) {
+ result->setStatus(&drvManager,
+ i18n("Could not create database \"%1\".")
+ .arg(m_migrateData->destination->databaseName()));
+ return false;
+ }
+
+ // For file-based dest. projects, we've already asked about overwriting
+ // existing project but for server-based projects we need to ask now.
+ if (destDriver->isFileDriver())
+ return true; //nothing to check
+ KexiDB::Connection *tmpConn
+ = destDriver->createConnection( *m_migrateData->destination->connectionData() );
+ if (!tmpConn || destDriver->error() || !tmpConn->connect()) {
+ delete tmpConn;
+ return true;
+ }
+ if (tmpConn->databaseExists( m_migrateData->destination->databaseName() )) {
+ acceptingNeeded = true;
+ }
+ tmpConn->disconnect();
+ delete tmpConn;
+ return true;
+}
+
+bool KexiMigrate::isSourceAndDestinationDataSourceTheSame() const
+{
+ KexiDB::ConnectionData* sourcedata = m_migrateData->source;
+ KexiDB::ConnectionData* destinationdata = m_migrateData->destination->connectionData();
+ return (
+ sourcedata && destinationdata &&
+ m_migrateData->sourceName == m_migrateData->destination->databaseName() && // same database name
+ sourcedata->driverName == destinationdata->driverName && // same driver
+ sourcedata->hostName == destinationdata->hostName && // same host
+ sourcedata->fileName() == destinationdata->fileName() && // same filename
+ sourcedata->dbPath() == destinationdata->dbPath() && // same database path
+ sourcedata->dbFileName() == destinationdata->dbFileName() // same database filename
+ );
+}
+
+//=============================================================================
+// Perform Import operation
+bool KexiMigrate::performImport(Kexi::ObjectStatus* result)
+{
+ if (result)
+ result->clearStatus();
+
+ KexiDB::DriverManager drvManager;
+ KexiDB::Driver *destDriver = drvManager.driver(
+ m_migrateData->destination->connectionData()->driverName);
+ if (!destDriver) {
+ result->setStatus(&drvManager,
+ i18n("Could not create database \"%1\".")
+ .arg(m_migrateData->destination->databaseName()));
+ return false;
+ }
+
+ QStringList tables;
+
+ // Step 1 - connect
+ kdDebug() << "KexiMigrate::performImport() CONNECTING..." << endl;
+ if (!drv_connect()) {
+ kdDebug() << "Couldnt connect to database server" << endl;
+ if (result)
+ result->setStatus(i18n("Could not connect to data source \"%1\".")
+ .arg(m_migrateData->source->serverInfoString()), "");
+ return false;
+ }
+
+ // Step 2 - get table names
+ kdDebug() << "KexiMigrate::performImport() GETTING TABLENAMES..." << endl;
+ if (!tableNames(tables)) {
+ kdDebug() << "Couldnt get list of tables" << endl;
+ if (result)
+ result->setStatus(
+ i18n("Could not get a list of table names for data source \"%1\".")
+ .arg(m_migrateData->source->serverInfoString()), "");
+ return false;
+ }
+
+ // Check if there are any tables
+ if (tables.isEmpty()) {
+ kdDebug() << "There were no tables to import" << endl;
+ if (result)
+ result->setStatus(
+ i18n("No tables to import found in data source \"%1\".")
+ .arg(m_migrateData->source->serverInfoString()), "");
+ return false;
+ }
+
+ // Step 3 - Read table schemas
+ tables.sort();
+ m_tableSchemas.clear();
+ if (!destDriver) {
+ result->setStatus(&drvManager);
+ return false;
+ }
+ const bool kexi__objects_exists = tables.find("kexi__objects")!=tables.end();
+ QStringList kexiDBTables;
+ if (kexi__objects_exists) {
+ tristate res = drv_queryStringListFromSQL(
+ QString::fromLatin1("SELECT o_name FROM kexi__objects WHERE o_type=%1")
+ .arg((int)KexiDB::TableObjectType), 0, kexiDBTables, -1);
+ if (res == true) {
+ // prepend KexiDB-compatible tables to 'tables' list, so we'll copy KexiDB-compatible tables first,
+ // to make sure existing IDs will not be in conflict with IDs newly generated for non-KexiDB tables
+ kexiDBTables.sort();
+ foreach(QStringList::ConstIterator, it, kexiDBTables)
+ tables.remove( *it );
+//kdDebug() << "KexiDB-compat tables: " << kexiDBTables << endl;
+//kdDebug() << "non-KexiDB tables: " << tables << endl;
+ }
+ }
+
+// uint i=0;
+ // -- read table schemas and create them in memory (only for non-KexiDB-compat tables)
+ foreach (QStringList::ConstIterator, it, tables) {
+ if (destDriver->isSystemObjectName( *it ) //"kexi__objects", etc.
+ || (*it).lower().startsWith("kexi__")) //tables at KexiProject level, e.g. "kexi__blobs"
+ continue;
+ // this is a non-KexiDB table: generate schema from native data source
+ const QString tableName( KexiUtils::string2Identifier(*it) );
+ KexiDB::TableSchema *tableSchema = new KexiDB::TableSchema(tableName);
+ tableSchema->setCaption( *it ); //caption is equal to the original name
+
+ if (!drv_readTableSchema(*it, *tableSchema)) {
+ delete tableSchema;
+ if (result)
+ result->setStatus(
+ i18n("Could not import project from data source \"%1\". Error reading table \"%2\".")
+ .arg(m_migrateData->source->serverInfoString()).arg(tableName), "");
+ return false;
+ }
+ //yeah, got a table
+ //Add it to list of tables which we will create if all goes well
+ m_tableSchemas.append(tableSchema);
+ }
+
+ // Step 4 - Create a new database as we have all required info
+ // - create copies of KexiDB-compat tables
+ // - create copies of non-KexiDB tables
+ delete m_destPrj;
+ m_destPrj = new KexiProject(m_migrateData->destination,
+ result ? (KexiDB::MessageHandler*)*result : 0);
+ bool ok = true == m_destPrj->create(true /*forceOverwrite*/);
+
+ KexiDB::Connection *destConn = 0;
+
+ if (ok)
+ ok = (destConn = m_destPrj->dbConnection());
+
+ KexiDB::Transaction trans;
+ if (ok) {
+ trans = destConn->beginTransaction();
+ if (trans.isNull()) {
+ ok = false;
+ if (result)
+ result->setStatus(destConn,
+ i18n("Could not create database \"%1\".")
+ .arg(m_migrateData->destination->databaseName()));
+ //later destConn->dropDatabase(m_migrateData->destination->databaseName());
+ //don't delete prj, otherwise eror message will be deleted delete prj;
+ //later return m_destPrj;
+ }
+ }
+
+ if (ok) {
+ if (drv_progressSupported())
+ progressInitialise();
+
+ // Step 5 - Create the copies of KexiDB-compat tables in memory (to maintain the same IDs)
+ m_kexiDBCompatibleTableSchemasToRemoveFromMemoryAfterImport.clear();
+ foreach (QStringList::ConstIterator, it, kexiDBTables) {
+ //load the schema from kexi__objects and kexi__fields
+ TableSchema *t = new TableSchema();
+ RowData data;
+ bool firstRecord = true;
+ if (true == drv_fetchRecordFromSQL(
+ QString("SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects "
+ "WHERE o_name='%1' AND o_type=%1").arg(*it).arg((int)KexiDB::TableObjectType),
+ data, firstRecord)
+ && destConn->setupObjectSchemaData( data, *t ))
+ {
+//! @todo to reuse Connection::setupTableSchema()'s statement somehow...
+ //load schema for every field and add it
+ firstRecord = true;
+ QString sql(
+ QString::fromLatin1("SELECT t_id, f_type, f_name, f_length, f_precision, f_constraints, "
+ "f_options, f_default, f_order, f_caption, f_help"
+ " FROM kexi__fields WHERE t_id=%1 ORDER BY f_order").arg(t->id()) );
+ while (ok) {
+ tristate res = drv_fetchRecordFromSQL(sql, data, firstRecord);
+ if (res != true) {
+ if (false == res)
+ ok = false;
+ break;
+ }
+ KexiDB::Field* f = destConn->setupField( data );
+ if (f)
+ t->addField(f);
+ else
+ ok = false;
+ }
+ if (ok)
+ ok = destConn->drv_createTable(*t);
+ if (ok)
+ m_kexiDBCompatibleTableSchemasToRemoveFromMemoryAfterImport.append(t);
+ }
+ if (!ok)
+ delete t;
+ }
+ }
+
+ // Step 6 - Copy kexi__objects NOW because we'll soon create new objects with new IDs (3.)...
+ if (ok) {
+ if (kexi__objects_exists)
+ ok = drv_copyTable("kexi__objects", destConn, destConn->tableSchema("kexi__objects"));
+ }
+
+ // Step 7 - Create the non-KexiDB-compatible tables: new IDs will be assigned to them
+ if (ok) {
+ KexiDB::TableSchema *ts;
+ for (QPtrListIterator<TableSchema> it (m_tableSchemas); (ts = it.current()); ++it) {
+ ok = destConn->createTable( ts );
+ if (!ok) {
+ kdDebug() << "Failed to create a table " << ts->name() << endl;
+ destConn->debugError();
+ if (result)
+ result->setStatus(destConn,
+ i18n("Could not create database \"%1\".")
+ .arg(m_migrateData->destination->databaseName()));
+ m_tableSchemas.remove(ts);
+ break;
+ }
+ updateProgress((Q_ULLONG)NUM_OF_ROWS_PER_CREATE_TABLE);
+ }
+ }
+
+ if (ok)
+ ok = destConn->commitTransaction(trans);
+
+ if (ok) {
+ //add compatible tables to the list, so data will be copied, if needed
+ if (m_migrateData->keepData) {
+ for(QPtrListIterator<TableSchema> it (m_kexiDBCompatibleTableSchemasToRemoveFromMemoryAfterImport);
+ it.current(); ++it)
+ {
+ m_tableSchemas.append(it.current());
+ }
+ }
+ else
+ m_tableSchemas.clear();
+ }
+
+ if (ok) {
+ if (m_destPrj->error()) {
+ ok = false;
+ if (result)
+ result->setStatus(m_destPrj,
+ i18n("Could not import project from data source \"%1\".")
+ .arg(m_migrateData->source->serverInfoString()));
+ }
+ }
+
+ // Step 8 - Copy data if asked to
+ if (ok) {
+ trans = destConn->beginTransaction();
+ ok = !trans.isNull();
+ }
+ if (ok) {
+ if (m_migrateData->keepData) {
+//! @todo check detailed "copy forms/blobs/tables" flags here when we add them
+ // Copy data for "kexi__objectdata" as well, if available in the source db
+ if (tables.find("kexi__objectdata")!=tables.end())
+ m_tableSchemas.append(destConn->tableSchema("kexi__objectdata"));
+ // Copy data for "kexi__blobs" as well, if available in the source db
+ if (tables.find("kexi__blobs")!=tables.end())
+ m_tableSchemas.append(destConn->tableSchema("kexi__blobs"));
+ // Copy data for "kexi__fields" as well, if available in the source db
+ if (tables.find("kexi__fields")!=tables.end())
+ m_tableSchemas.append(destConn->tableSchema("kexi__fields"));
+ }
+
+ for(QPtrListIterator<TableSchema> ts(m_tableSchemas); ok && ts.current() != 0 ; ++ts)
+ {
+ const QString tname( ts.current()->name().lower() );
+ if (destConn->driver()->isSystemObjectName( tname )
+//! @todo what if these two tables are not compatible with tables created in destination db
+//! because newer db format was used?
+ && tname!="kexi__objectdata" //copy this too
+ && tname!="kexi__blobs" //copy this too
+ && tname!="kexi__fields" //copy this too
+ )
+ {
+ kdDebug() << "Do not copy data for system table: " << tname << endl;
+//! @todo copy kexi__db contents!
+ continue;
+ }
+ kdDebug() << "Copying data for table: " << tname << endl;
+ QString originalTableName;
+ if (kexiDBTables.find(tname)==kexiDBTables.end())
+ //caption is equal to the original name
+ originalTableName = ts.current()->caption().isEmpty() ? tname : ts.current()->caption();
+ else
+ originalTableName = tname;
+ ok = drv_copyTable(originalTableName, destConn, ts.current());
+ if (!ok) {
+ kdDebug() << "Failed to copy table " << tname << endl;
+ if (result)
+ result->setStatus(destConn,
+ i18n("Could not copy table \"%1\" to destination database.").arg(tname));
+ break;
+ }
+ }//for
+ }
+
+ // Done.
+ if (ok)
+ ok = destConn->commitTransaction(trans);
+
+ if (ok)
+ ok = drv_disconnect();
+
+ m_kexiDBCompatibleTableSchemasToRemoveFromMemoryAfterImport.clear();
+
+ if (ok) {
+ if (destConn)
+ ok = destConn->disconnect();
+ return ok;
+ }
+
+ // Finally: error handling
+ if (result && result->error())
+ result->setStatus(destConn,
+ i18n("Could not import data from data source \"%1\".")
+ .arg(m_migrateData->source->serverInfoString()));
+ if (destConn) {
+ destConn->debugError();
+ destConn->rollbackTransaction(trans);
+ }
+ drv_disconnect();
+ if (destConn) {
+ destConn->disconnect();
+ destConn->dropDatabase(m_migrateData->destination->databaseName());
+ }
+ return false;
+}
+//=============================================================================
+
+bool KexiMigrate::performExport(Kexi::ObjectStatus* result)
+{
+ if (result)
+ result->clearStatus();
+
+ //! @todo performExport
+
+ return false;
+}
+
+//=============================================================================
+// Functions for getting table data
+bool KexiMigrate::tableNames(QStringList & tn)
+{
+ //! @todo Cache list of table names
+ kdDebug() << "Reading list of tables..." << endl;
+ return drv_tableNames(tn);
+}
+
+//=============================================================================
+// Progress functions
+bool KexiMigrate::progressInitialise() {
+ Q_ULLONG sum = 0, size;
+ emit progressPercent(0);
+
+ //! @todo Don't copy table names here
+ QStringList tables;
+ if(!tableNames(tables))
+ return false;
+
+ // 1) Get the number of rows/bytes to import
+ int tableNumber = 1;
+ for(QStringList::Iterator it = tables.begin();
+ it != tables.end(); ++it, tableNumber++)
+ {
+ if(drv_getTableSize(*it, size)) {
+ kdDebug() << "KexiMigrate::progressInitialise() - table: " << *it
+ << "size: " << (ulong)size << endl;
+ sum += size;
+ emit progressPercent(tableNumber * 5 /* 5% */ / tables.count());
+ } else {
+ return false;
+ }
+ }
+
+ kdDebug() << "KexiMigrate::progressInitialise() - job size: " << (ulong)sum << endl;
+ m_progressTotal = sum;
+ m_progressTotal += tables.count() * NUM_OF_ROWS_PER_CREATE_TABLE;
+ m_progressTotal = m_progressTotal * 105 / 100; //add 5 percent for above task 1)
+ m_progressNextReport = sum / 100;
+ m_progressDone = m_progressTotal * 5 / 100; //5 perecent already done in task 1)
+ return true;
+}
+
+
+void KexiMigrate::updateProgress(Q_ULLONG step) {
+ m_progressDone += step;
+ if (m_progressDone >= m_progressNextReport) {
+ int percent = (m_progressDone+1) * 100 / m_progressTotal;
+ m_progressNextReport = ((percent + 1) * m_progressTotal) / 100;
+ kdDebug() << "KexiMigrate::updateProgress(): " << (ulong)m_progressDone << "/"
+ << (ulong)m_progressTotal << " (" << percent << "%) next report at "
+ << (ulong)m_progressNextReport << endl;
+ emit progressPercent(percent);
+ }
+}
+
+//=============================================================================
+// Prompt the user to choose a field type
+KexiDB::Field::Type KexiMigrate::userType(const QString& fname)
+{
+ KInputDialog *dlg;
+ QStringList types;
+ QString res;
+
+ types << "Byte";
+ types << "Short Integer";
+ types << "Integer";
+ types << "Big Integer";
+ types << "Boolean";
+ types << "Date";
+ types << "Date Time";
+ types << "Time";
+ types << "Float";
+ types << "Double";
+ types << "Text";
+ types << "Long Text";
+ types << "Binary Large Object";
+
+ res = dlg->getItem( i18n("Field Type"),
+ i18n("The data type for %1 could not be determined. "
+ "Please select one of the following data "
+ "types").arg(fname),
+ types, 0, false);
+
+//! @todo use QMap<QCString, KexiDB::Field::Type> here!
+ if (res == *types.at(0))
+ return KexiDB::Field::Byte;
+ else if (res == *types.at(1))
+ return KexiDB::Field::ShortInteger;
+ else if (res == *types.at(2))
+ return KexiDB::Field::Integer;
+ else if (res == *types.at(3))
+ return KexiDB::Field::BigInteger;
+ else if (res == *types.at(4))
+ return KexiDB::Field::Boolean;
+ else if (res == *types.at(5))
+ return KexiDB::Field::Date;
+ else if (res == *types.at(6))
+ return KexiDB::Field::DateTime;
+ else if (res == *types.at(7))
+ return KexiDB::Field::Time;
+ else if (res == *types.at(8))
+ return KexiDB::Field::Float;
+ else if (res == *types.at(9))
+ return KexiDB::Field::Double;
+ else if (res == *types.at(10))
+ return KexiDB::Field::Text;
+ else if (res == *types.at(11))
+ return KexiDB::Field::LongText;
+ else if (res == *types.at(12))
+ return KexiDB::Field::BLOB;
+ else
+ return KexiDB::Field::Text;
+}
+
+QVariant KexiMigrate::propertyValue( const QCString& propName )
+{
+ return m_properties[propName.lower()];
+}
+
+QString KexiMigrate::propertyCaption( const QCString& propName ) const
+{
+ return m_propertyCaptions[propName.lower()];
+}
+
+void KexiMigrate::setPropertyValue( const QCString& propName, const QVariant& value )
+{
+ m_properties[propName.lower()] = value;
+}
+
+QValueList<QCString> KexiMigrate::propertyNames() const
+{
+ QValueList<QCString> names = m_properties.keys();
+ qHeapSort(names);
+ return names;
+}
+
+bool KexiMigrate::isValid()
+{
+ if (KexiMigration::versionMajor() != versionMajor()
+ || KexiMigration::versionMinor() != versionMinor())
+ {
+ setError(ERR_INCOMPAT_DRIVER_VERSION,
+ i18n("Incompatible migration driver's \"%1\" version: found version %2, expected version %3.")
+ .arg(name())
+ .arg(QString("%1.%2").arg(versionMajor()).arg(versionMinor()))
+ .arg(QString("%1.%2").arg(KexiMigration::versionMajor()).arg(KexiMigration::versionMinor())));
+ return false;
+ }
+ return true;
+}
+
+bool KexiMigrate::drv_queryMaxNumber(const QString& tableName,
+ const QString& columnName, int& result)
+{
+ QString string;
+ tristate r = drv_querySingleStringFromSQL(
+ QString::fromLatin1("SELECT MAX(%1) FROM %2").arg(drv_escapeIdentifier(columnName))
+ .arg(drv_escapeIdentifier(tableName)), 0, string);
+ if (r == false)
+ return false;
+ if (~r) {
+ result = 0;
+ return true;
+ }
+ bool ok;
+ int tmpResult = string.toInt(&ok);
+ if (ok)
+ result = tmpResult;
+ return ok;
+}
+
+tristate KexiMigrate::drv_querySingleStringFromSQL(
+ const QString& sqlStatement, uint columnNumber, QString& string)
+{
+ QStringList stringList;
+ const tristate res = drv_queryStringListFromSQL(sqlStatement, columnNumber, stringList, 1);
+ if (true == res)
+ string = stringList.first();
+ return res;
+}
+
+#include "keximigrate.moc"
diff --git a/kexi/migration/keximigrate.h b/kexi/migration/keximigrate.h
new file mode 100644
index 00000000..3d5ed65f
--- /dev/null
+++ b/kexi/migration/keximigrate.h
@@ -0,0 +1,314 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Adam Pigg <[email protected]>
+ Copyright (C) 2004-2006 Jaroslaw Staniek <[email protected]>
+ Copyright (C) 2005 Martin Ellis <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXI_MIGRATE_H
+#define KEXI_MIGRATE_H
+
+
+#include "kexidb/tableschema.h"
+#include "kexidb/connection.h"
+#include "keximigratedata.h"
+
+#include <kgenericfactory.h>
+#include <qstringlist.h>
+#include <qguardedptr.h>
+
+class KexiProject;
+namespace Kexi
+{
+ class ObjectStatus;
+}
+
+/*! KexiMigration implementation version.
+ It is altered after every change:
+ - major number is increased after every major Kexi release,
+ - minor is increased after adding binary-incompatible change.
+ In external code: do not use this to get library version information:
+ use KexiMigration::versionMajor() and KexiMigration::versionMinor() instead to get real version.
+*/
+#define KEXI_MIGRATION_VERSION_MAJOR 1
+#define KEXI_MIGRATION_VERSION_MINOR 1
+
+/*!
+ * \namespace KexiMigration
+ * \brief Framework for importing databases into native KexiDB databases.
+ */
+namespace KexiMigration
+{
+
+//! \return KexiMigration version info (most significant part)
+KEXIMIGR_EXPORT int versionMajor();
+
+//! \return KexiMigration version info (least significant part)
+KEXIMIGR_EXPORT int versionMinor();
+
+
+//! @short Imports non-native databases into Kexi projects.
+/*! A generic API for importing schema and data from an existing
+database into a new Kexi project. Can be also used for importing native Kexi databases.
+
+Basic idea is this:
+-# User selects an existing DB and new project (file or server based)
+-# User specifies whether to import structure and data or structure only.
+-# Import tool connects to db
+-# Checks if it is already a kexi project (not implemented yet)
+-# If not, then read structure and construct new project
+-# Ask user what to do if column type is not supported
+
+See kexi/doc/dev/kexi_import.txt for more info.
+*/
+class KEXIMIGR_EXPORT KexiMigrate : public QObject, public KexiDB::Object
+{
+ Q_OBJECT
+
+ public:
+ virtual ~KexiMigrate();
+
+//! @todo Remove this! KexiMigrate should be usable for multiple concurrent migrations!
+ KexiMigration::Data* data() const { return m_migrateData; }
+
+//! @todo Remove this! KexiMigrate should be usable for multiple concurrent migrations!
+ //! Data Setup. Requires two connection objects, a name and a bool
+ void setData(KexiMigration::Data* migrateData);
+
+ /*! Checks whether the destination database exists.
+ For file-based dest. projects, we've already asked about overwriting
+ existing project but for server-based projects it's better to ask user.
+ This method should be called before performImport() or performExport().
+
+ \return true if no connection-related errors occurred.
+ \a acceptingNeeded is set to true if destination database exists.
+ In this case you should ask about accepting database overwriting.
+ Used in ImportWizard::import(). */
+ bool checkIfDestinationDatabaseOverwritingNeedsAccepting(Kexi::ObjectStatus* result,
+ bool& acceptingNeeded);
+
+ /*! Checks if the source- and the destination databases are identical.
+ \return true if they are identical else false. */
+ bool isSourceAndDestinationDataSourceTheSame() const;
+
+ //! Perform an import operation
+ bool performImport(Kexi::ObjectStatus* result = 0);
+
+ //! Perform an export operation
+ bool performExport(Kexi::ObjectStatus* result = 0);
+
+ //! Returns true if the migration driver supports progress updates.
+ inline bool progressSupported() { return drv_progressSupported(); }
+
+ virtual int versionMajor() const = 0;
+ virtual int versionMinor() const = 0;
+
+//! @todo This is copied from KexiDB::Driver. One day it will be merged with KexiDB.
+ //! \return property value for \a propeName available for this driver.
+ //! If there's no such property defined for driver, Null QVariant value is returned.
+ virtual QVariant propertyValue( const QCString& propName );
+
+//! @todo This is copied from KexiDB::Driver. One day it will be merged with KexiDB.
+ void setPropertyValue( const QCString& propName, const QVariant& value );
+
+//! @todo This is copied from KexiDB::Driver. One day it will be merged with KexiDB.
+ //! \return translated property caption for \a propeName.
+ //! If there's no such property defined for driver, empty string value is returned.
+ QString propertyCaption( const QCString& propName ) const;
+
+//! @todo This is copied from KexiDB::Driver. One day it will be merged with KexiDB.
+ //! \return a list of property names available for this driver.
+ QValueList<QCString> propertyNames() const;
+
+ /*! \return true is driver is valid. Checks if KexiMigrate::versionMajor()
+ and KexiMigrate::versionMinor() are matching.
+ You can reimplement this but always call KexiMigrate::isValid() implementation. */
+ virtual bool isValid();
+
+ signals:
+ void progressPercent(int percent);
+
+ protected:
+ //! Used by MigrateManager.
+ KexiMigrate(QObject *parent, const char *name, const QStringList &args = QStringList());
+
+ //! Connect to source database (driver specific)
+ virtual bool drv_connect() = 0;
+ //! Disconnect from source database (driver specific)
+ virtual bool drv_disconnect() = 0;
+
+ //! Get table names in source database (driver specific)
+ virtual bool drv_tableNames(QStringList& tablenames) = 0;
+
+ //! Read schema for a given table (driver specific)
+ virtual bool drv_readTableSchema(
+ const QString& originalName, KexiDB::TableSchema& tableSchema) = 0;
+
+ /*! Fetches maximum number from table \a tableName, column \a columnName
+ into \a result. On success true is returned. If there is no records in the table,
+ \a result is set to 0 and true is returned.
+ - Note 1: implement only if the database can already contain kexidb__* tables
+ (so e.g. keximdb driver doea not need this).
+ - Note 2: default implementation uses drv_querySingleStringFromSQL()
+ with "SELECT MAX(columName) FROM tableName" statement, assuming SQL-compliant
+ backend.
+ */
+ virtual bool drv_queryMaxNumber(const QString& tableName,
+ const QString& columnName, int& result);
+
+ /*! Fetches single string at column \a columnNumber for each record from result obtained
+ by running \a sqlStatement. \a numRecords can be specified to limit number of records read.
+ If \a numRecords is -1, all records are loaded.
+ On success the result is stored in \a stringList and true is returned.
+ \return cancelled if there are no records available.
+ - Note: implement only if the database can already contain kexidb__* tables
+ (so e.g. keximdb driver does not need this). */
+//! @todo SQL-dependent!
+ virtual tristate drv_queryStringListFromSQL(
+ const QString& sqlStatement, uint columnNumber, QStringList& stringList,
+ int numRecords = -1)
+ { Q_UNUSED(sqlStatement); Q_UNUSED(columnNumber); Q_UNUSED(stringList);
+ Q_UNUSED(numRecords);
+ return cancelled; }
+
+ /*! Fetches single string at column \a columnNumber from result obtained
+ by running \a sqlStatement.
+ On success the result is stored in \a string and true is returned.
+ \return cancelled if there are no records available.
+ This implementation uses drv_queryStringListFromSQL() with numRecords == 1. */
+//! @todo SQL-dependent!
+ virtual tristate drv_querySingleStringFromSQL(const QString& sqlStatement,
+ uint columnNumber, QString& string);
+
+ /*! Fetches single record from result obtained
+ by running \a sqlStatement.
+ \a firstRecord should be first initialized to true, so the method can run
+ the query at first call and then set it will set \a firstRecord to false,
+ so subsequent calls will only fetch records.
+ On success the result is stored in \a data and true is returned,
+ \a data is resized to appropriate size. cancelled is returned on EOF. */
+//! @todo SQL-dependent!
+ virtual tristate drv_fetchRecordFromSQL(const QString& sqlStatement,
+ KexiDB::RowData& data, bool &firstRecord)
+ { Q_UNUSED(sqlStatement); Q_UNUSED(data); Q_UNUSED(firstRecord);
+ return cancelled; }
+
+ //! Copy a table from source DB to target DB (driver specific)
+ //! - create copies of KexiDB tables
+ //! - create copies of non-KexiDB tables
+ virtual bool drv_copyTable(const QString& srcTable, KexiDB::Connection *destConn,
+ KexiDB::TableSchema* dstTable) = 0;
+
+ virtual bool drv_progressSupported() { return false; }
+
+ /*! \return the size of a table to be imported, or 0 if not supported
+ Finds the size of the named table, in order to provide feedback on
+ migration progress.
+
+ The units of the return type are deliberately unspecified. Migration
+ drivers may return the number of records in the table, or the size in
+ bytes, etc. Units should be chosen in order that the driver can
+ return the size in the fastest way possible (e.g. migration from CSV
+ files should use file size to avoid counting the number of rows, and
+ migration from MDB files should return the number of rows as this is
+ stored within the file).
+
+ Obviously, the driver should use the same units when reporting
+ migration progress.
+
+ \return size of the specified table
+ */
+ virtual bool drv_getTableSize(const QString&, Q_ULLONG&)
+ { return false; }
+
+ void updateProgress(Q_ULLONG step = 1ULL);
+
+//! @todo user should be asked ONCE using a convenient wizard's page, not a popup dialog
+ //! Prompt user to select a field type for unrecognized fields
+ KexiDB::Field::Type userType(const QString& fname);
+
+ virtual QString drv_escapeIdentifier( const QString& str ) const {
+ return m_kexiDBDriver ? m_kexiDBDriver->escapeIdentifier(str) : str; }
+
+//! @todo Remove this! KexiMigrate should be usable for multiple concurrent migrations!
+ //! Migrate Options
+ KexiMigration::Data* m_migrateData;
+
+// // Temporary values used during import (set by driver specific methods)
+// KexiDB::Field* m_f;
+
+ /*! Driver properties dictionary (indexed by name),
+ useful for presenting properties to the user.
+ Set available properties here in driver implementation. */
+ QMap<QCString,QVariant> m_properties;
+
+ /*! i18n'd captions for properties. You do not need
+ to set predefined properties' caption in driver implementation
+ -it's done automatically. */
+ QMap<QCString,QString> m_propertyCaptions;
+
+ //! KexiDB driver. For instance, it is used for escaping identifiers
+ QGuardedPtr<KexiDB::Driver> m_kexiDBDriver;
+
+ private:
+ //! Get the list of tables
+ bool tableNames(QStringList& tablenames);
+
+ //! Table schemas from source DB
+ QPtrList<KexiDB::TableSchema> m_tableSchemas;
+
+ QPtrList<KexiDB::TableSchema> m_kexiDBCompatibleTableSchemasToRemoveFromMemoryAfterImport;
+
+ /*! Estimate size of migration job
+ Calls drv_getTableSize for each table to be copied.
+ \return sum of the size of all tables to be copied.
+ */
+ bool progressInitialise();
+
+ KexiProject *m_destPrj;
+
+ //! Size of migration job
+ Q_ULLONG m_progressTotal;
+
+ //! Amount of migration job complete
+ Q_ULLONG m_progressDone;
+
+ //! Don't recalculate progress done until this value is reached.
+ Q_ULLONG m_progressNextReport;
+
+ friend class MigrateManager;
+};
+
+} //namespace KexiMigration
+
+//! Driver's static version information (implementation),
+//! with KLibFactory symbol declaration.
+#define KEXIMIGRATE_DRIVER_INFO( class_name, internal_name ) \
+ int class_name::versionMajor() const { return KEXI_MIGRATION_VERSION_MAJOR; } \
+ int class_name::versionMinor() const { return KEXI_MIGRATION_VERSION_MINOR; } \
+ K_EXPORT_COMPONENT_FACTORY(keximigrate_ ## internal_name, \
+ KGenericFactory<KexiMigration::class_name>( "keximigrate_" #internal_name ))
+
+/*! Driver's static version information, automatically implemented for KexiDB drivers.
+ Put this into migration driver class declaration just like Q_OBJECT macro. */
+#define KEXIMIGRATION_DRIVER \
+ public: \
+ virtual int versionMajor() const; \
+ virtual int versionMinor() const;
+
+#endif
+
diff --git a/kexi/migration/keximigratedata.cpp b/kexi/migration/keximigratedata.cpp
new file mode 100644
index 00000000..80df12f2
--- /dev/null
+++ b/kexi/migration/keximigratedata.cpp
@@ -0,0 +1,34 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Adam Pigg <[email protected]>
+ Copyright (C) 2004 Jaroslaw Staniek <[email protected]>
+ Copyright (C) 2005 Martin Ellis <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "keximigratedata.h"
+
+using namespace KexiMigration;
+
+Data::Data()
+ : source(0)
+ , destination(0)
+{
+}
+
+Data::~Data()
+{
+}
diff --git a/kexi/migration/keximigratedata.h b/kexi/migration/keximigratedata.h
new file mode 100644
index 00000000..81e8c0f5
--- /dev/null
+++ b/kexi/migration/keximigratedata.h
@@ -0,0 +1,59 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Adam Pigg <[email protected]>
+ Copyright (C) 2004 Jaroslaw Staniek <[email protected]>
+ Copyright (C) 2005 Martin Ellis <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXI_MIGRATE_DATA_H
+#define KEXI_MIGRATE_DATA_H
+
+#include "kexidb/connection.h"
+
+class KexiProjectData;
+
+namespace KexiMigration
+{
+ //Use this class to store all possible options that could be used by keximigrate.
+ //The current members are not meant to be a definite set, for example, i envisage
+ //adding table/field lists if we allow only importing certain tables/fields
+ class KEXIMIGR_EXPORT Data
+ {
+ public:
+ Data();
+ ~Data();
+
+ //! Connection data for the source database
+ KexiDB::ConnectionData* source;
+
+ //! Name of the source database
+ QString sourceName;
+
+ //! Destination project data
+ KexiProjectData* destination;
+
+// //! Actual connection to the new database
+// KexiDB::Connection* dest;
+
+// //! New database name
+// QString destName;
+
+ //! Flag to determine structure copy, or structure + data
+ bool keepData;
+ };
+}//namespace KexiMigration
+#endif
diff --git a/kexi/migration/keximigratetest.cpp b/kexi/migration/keximigratetest.cpp
new file mode 100644
index 00000000..bb67d985
--- /dev/null
+++ b/kexi/migration/keximigratetest.cpp
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Adam Pigg *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+//#include <config.h>
+#endif
+
+#include <migration/importwizard.h>
+#include <kapplication.h>
+
+/*
+This is in no way meant to compile let alone work
+This is very preliminary and is meant for example only
+
+This will be an example program to demonstrate how to import an existing db into
+a new kexi based db
+*/
+
+using namespace KexiMigration;
+
+int main(int argc, char *argv[])
+{
+ KApplication app(argc, argv, "Kexi Migrate Test");
+
+ ImportWizard* iw = new ImportWizard();
+ iw->setGeometry(300,300,300,250);
+ app.setMainWidget(iw);
+ iw->show();
+
+ return app.exec();
+}
diff --git a/kexi/migration/keximigration_driver.desktop b/kexi/migration/keximigration_driver.desktop
new file mode 100644
index 00000000..9ccb6ff2
--- /dev/null
+++ b/kexi/migration/keximigration_driver.desktop
@@ -0,0 +1,59 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=Kexi/MigrationDriver
+Comment=Kexi Data Migration Driver
+Comment[bg]=Драйвер на Kexi за мигриране на данни
+Comment[ca]=Controlador de migració de dades de Kexi
+Comment[cy]=Gyrrydd Mudo Data Kexi
+Comment[da]=Kexi datamigrationsdriver
+Comment[de]=Datenmigrationstreiber für Kexi
+Comment[el]=Οδηγός μεταφοράς δεδομένων του Kexi
+Comment[eo]=Kexi datum-migrada pelilo
+Comment[es]=Controlador de migración de datos de Kexi
+Comment[et]=Kexi andmete migreerumisdraiver
+Comment[eu]=Kexi-ren datuak migratzeko kontrolatzailea
+Comment[fa]=گردانندۀ جابه‌جایی دادۀ Kexi
+Comment[fi]=Kexi tietojen yhdistämisajuri
+Comment[fr]=Pilote de migration de données de Kexi
+Comment[fy]=Kexi Gegevensmigraasje stjoerprogramma
+Comment[gl]=Controlador de Migración de Datos de Kexi
+Comment[he]=מנהל התקן Data-Migration ל־Kexi
+Comment[hr]=Kexi upravljački program za migraciju podataka
+Comment[hu]=Kexi adatmigrálási meghajtó
+Comment[is]=Kexi gagnaflutningsrekill
+Comment[it]=Driver di migrazione dei dati per Kexi
+Comment[ja]=Kexi データ移行ドライバ
+Comment[km]=កម្មវិធី​បញ្ជា​សម្រាប់​ផ្លាស់ប្ដូរ​ទិន្នន័យ​សម្រាប់ Kexi
+Comment[lv]=Kexi datu migrācijas draiveris
+Comment[ms]=Pemacu Migrasi Data Kexi
+Comment[nb]=Kexi-driver for datamigrering
+Comment[nds]=Datenutlagerndriever för Kexi
+Comment[ne]=केक्सी डेटा माइग्रेसन ड्राइभर
+Comment[nl]=Kexi Datamigratie Stuurprogramma
+Comment[nn]=Kexi-programtillegg for migrering av data
+Comment[pl]=Wtyczka do migracji danych programu Kexi
+Comment[pt]=Controlador de Migração de Dados do Kexi
+Comment[pt_BR]=Driver de Migração de Dados do Kexi
+Comment[ru]=Модуль драйвера миграции Kexi
+Comment[sk]=Ovládač Kexi Data Migration
+Comment[sl]=Gonilnik za prenos podatkov za Kexi
+Comment[sr]=Драјвер Kexi-ја за миграцију података
+Comment[sr@Latn]=Drajver Kexi-ja za migraciju podataka
+Comment[sv]=Kexi dataövergångsdrivrutin
+Comment[uk]=Драйвер міграції даних для Kexi
+Comment[uz]=Kexi uchun maʼlumotlar migratsiyasi drayveri
+Comment[uz@cyrillic]=Kexi учун маълумотлар миграцияси драйвери
+Comment[zh_CN]=Kexi 数据升迁驱动程序
+Comment[zh_TW]=Kexi 資料轉移驅動程式
+
+[PropertyDef::X-Kexi-FileMigrationDriverMime]
+Type=QString
+
+[PropertyDef::X-Kexi-MigrationDriverName]
+Type=QString
+
+[PropertyDef::X-Kexi-MigrationDriverType]
+Type=QString
+
+[PropertyDef::X-Kexi-KexiMigrationVersion]
+Type=QString
diff --git a/kexi/migration/migratemanager.cpp b/kexi/migration/migratemanager.cpp
new file mode 100644
index 00000000..320ad718
--- /dev/null
+++ b/kexi/migration/migratemanager.cpp
@@ -0,0 +1,384 @@
+/* This file is part of the KDE project
+ Daniel Molkentin <[email protected]>
+ Joseph Wenninger <[email protected]>
+ Copyright (C) 2003-2004 Jaroslaw Staniek <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "migratemanager.h"
+#include "migratemanager_p.h"
+#include "keximigrate.h"
+
+#include <klibloader.h>
+#include <kparts/componentfactory.h>
+#include <ktrader.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kservice.h>
+
+#include <assert.h>
+
+#include <qapplication.h>
+
+//remove debug
+#undef KexiDBDbg
+#define KexiDBDbg if (0) kdDebug()
+
+using namespace KexiMigration;
+
+MigrateManagerInternal* MigrateManagerInternal::s_self = 0L;
+
+/*! @todo
+ Temporary, needed because MigrateManagerInternal::m_drivers is autodeleted
+ drivers currently own KexiMigrate::Data members so these are destroyed when
+ last MigrateManager instance is deleted. Remove this hack when
+ KexiMigrate is splitted into Driver and Connection. */
+MigrateManager __manager;
+
+MigrateManagerInternal::MigrateManagerInternal() /* protected */
+ : QObject( 0, "KexiMigrate::MigrateManagerInternal" )
+ , Object()
+ , m_drivers(17, false)
+ , m_refCount(0)
+ , lookupDriversNeeded(true)
+{
+ m_drivers.setAutoDelete(true);
+ m_serverResultNum=0;
+
+}
+
+MigrateManagerInternal::~MigrateManagerInternal()
+{
+ KexiDBDbg << "MigrateManagerInternal::~MigrateManagerInternal()" << endl;
+ m_drivers.clear();
+ if ( s_self == this )
+ s_self = 0;
+ KexiDBDbg << "MigrateManagerInternal::~MigrateManagerInternal() ok" << endl;
+}
+
+void MigrateManagerInternal::slotAppQuits()
+{
+ if (qApp->mainWidget() && qApp->mainWidget()->isVisible())
+ return; //what a hack! - we give up when app is still there
+ KexiDBDbg << "MigrateManagerInternal::slotAppQuits(): let's clear drivers..." << endl;
+ m_drivers.clear();
+}
+
+MigrateManagerInternal *MigrateManagerInternal::self()
+{
+ if (!s_self)
+ s_self = new MigrateManagerInternal();
+
+ return s_self;
+}
+
+bool MigrateManagerInternal::lookupDrivers()
+{
+ if (!lookupDriversNeeded)
+ return true;
+
+ if (qApp) {
+ connect(qApp,SIGNAL(aboutToQuit()),this,SLOT(slotAppQuits()));
+ }
+//TODO: for QT-only version check for KInstance wrapper
+// KexiDBWarn << "DriverManagerInternal::lookupDrivers(): cannot work without KInstance (KGlobal::instance()==0)!" << endl;
+// setError("Driver Manager cannot work without KInstance (KGlobal::instance()==0)!");
+
+ lookupDriversNeeded = false;
+ clearError();
+ KTrader::OfferList tlist = KTrader::self()->query("Kexi/MigrationDriver");
+ KTrader::OfferList::ConstIterator it(tlist.constBegin());
+ for(; it != tlist.constEnd(); ++it)
+ {
+ KService::Ptr ptr = (*it);
+ QString srv_name = ptr->property("X-Kexi-MigrationDriverName").toString();
+ if (srv_name.isEmpty()) {
+ KexiDBWarn << "MigrateManagerInternal::lookupDrivers(): "
+ "X-Kexi-MigrationDriverName must be set for migration driver \""
+ << ptr->property("Name").toString() << "\" service!\n -- skipped!" << endl;
+ continue;
+ }
+ if (m_services_lcase.contains(srv_name.lower())) {
+ continue;
+ }
+
+//! @todo could be merged. Copied from KexiDB::DriverManager.
+//<COPIED>
+ QString srv_ver_str = ptr->property("X-Kexi-KexiMigrationVersion").toString();
+ QStringList lst( QStringList::split(".", srv_ver_str) );
+ int minor_ver, major_ver;
+ bool ok = (lst.count() == 2);
+ if (ok)
+ major_ver = lst[0].toUInt(&ok);
+ if (ok)
+ minor_ver = lst[1].toUInt(&ok);
+ if (!ok) {
+ KexiDBWarn << "MigrateManagerInternal::lookupDrivers(): problem with detecting '"
+ << srv_name.lower() << "' driver's version -- skipping it!" << endl;
+ possibleProblems += QString("\"%1\" migration driver has unrecognized version; "
+ "required driver version is \"%2.%3\"")
+ .arg(srv_name.lower())
+ .arg(KexiMigration::versionMajor()).arg(KexiMigration::versionMinor());
+ continue;
+ }
+ if (major_ver != KexiMigration::versionMajor() || minor_ver != KexiMigration::versionMinor()) {
+ KexiDBWarn << QString("MigrateManagerInternal::lookupDrivers(): '%1' driver"
+ " has version '%2' but required migration driver version is '%3.%4'\n"
+ " -- skipping this driver!").arg(srv_name.lower()).arg(srv_ver_str)
+ .arg(KexiMigration::versionMajor()).arg(KexiMigration::versionMinor()) << endl;
+ possibleProblems += QString("\"%1\" migration driver has version \"%2\" "
+ "but required driver version is \"%3.%4\"")
+ .arg(srv_name.lower()).arg(srv_ver_str)
+ .arg(KexiMigration::versionMajor()).arg(KexiMigration::versionMinor());
+ continue;
+ }
+//</COPIED>
+
+ QString mime = ptr->property("X-Kexi-FileDBDriverMime").toString().lower();
+ QString drvType = ptr->property("X-Kexi-MigrationDriverType").toString().lower();
+ if (drvType=="file") {
+ if (!mime.isEmpty()) {
+ if (!m_services_by_mimetype.contains(mime)) {
+ m_services_by_mimetype.insert(mime, ptr);
+ }
+ else {
+ KexiDBWarn << "MigrateManagerInternal::lookupDrivers(): more than one driver for '"
+ << mime << "' mime type!" << endl;
+ }
+ }
+ }
+ m_services.insert(srv_name, ptr);
+ m_services_lcase.insert(srv_name.lower(), ptr);
+ KexiDBDbg << "MigrateManager::lookupDrivers(): registered driver: " << ptr->name()
+ << "(" << ptr->library() << ")" << endl;
+ }
+
+ if (tlist.isEmpty())
+ {
+ setError(ERR_DRIVERMANAGER, i18n("Could not find any import/export database drivers.") );
+ return false;
+ }
+ return true;
+}
+
+KexiMigrate* MigrateManagerInternal::driver(const QString& name)
+{
+ if (!lookupDrivers())
+ return 0;
+
+ clearError();
+ KexiDBDbg << "MigrationrManagerInternal::migrationDriver(): loading " << name << endl;
+
+ KexiMigrate *drv = name.isEmpty() ? 0 : m_drivers.find(name.latin1());
+ if (drv)
+ return drv; //cached
+
+ if (!m_services_lcase.contains(name.lower())) {
+ setError(ERR_DRIVERMANAGER, i18n("Could not find import/export database driver \"%1\".").arg(name) );
+ return 0;
+ }
+
+ KService::Ptr ptr= *(m_services_lcase.find(name.lower()));
+ QString srv_name = ptr->property("X-Kexi-MigrationDriverName").toString();
+
+ KexiDBDbg << "MigrateManagerInternal::driver(): library: "<<ptr->library()<<endl;
+ drv = KParts::ComponentFactory::createInstanceFromService<KexiMigrate>(ptr,
+ this, srv_name.latin1(), QStringList(),&m_serverResultNum);
+
+ if (!drv) {
+ setError(ERR_DRIVERMANAGER, i18n("Could not load import/export database driver \"%1\".")
+ .arg(name) );
+ if (m_componentLoadingErrors.isEmpty()) {//fill errtable on demand
+ m_componentLoadingErrors[KParts::ComponentFactory::ErrNoServiceFound]="ErrNoServiceFound";
+ m_componentLoadingErrors[KParts::ComponentFactory::ErrServiceProvidesNoLibrary]="ErrServiceProvidesNoLibrary";
+ m_componentLoadingErrors[KParts::ComponentFactory::ErrNoLibrary]="ErrNoLibrary";
+ m_componentLoadingErrors[KParts::ComponentFactory::ErrNoFactory]="ErrNoFactory";
+ m_componentLoadingErrors[KParts::ComponentFactory::ErrNoComponent]="ErrNoComponent";
+ }
+ m_serverResultName=m_componentLoadingErrors[m_serverResultNum];
+ return 0;
+ }
+ KexiDBDbg << "MigrateManagerInternal::driver(): loading succeed: " << name <<endl;
+ KexiDBDbg << "drv="<<(long)drv <<endl;
+
+// drv->setName(srv_name.latin1());
+// drv->d->service = ptr; //store info
+// drv->d->fileDBDriverMimeType = ptr->property("X-Kexi-FileDBDriverMime").toString();
+// drv->d->initInternalProperties();
+
+ if (!drv->isValid()) {
+ setError(drv);
+ delete drv;
+ return 0;
+ }
+
+ m_drivers.insert(name.latin1(), drv); //cache it
+ return drv;
+}
+
+void MigrateManagerInternal::incRefCount()
+{
+ m_refCount++;
+ KexiDBDbg << "MigrateManagerInternal::incRefCount(): " << m_refCount << endl;
+}
+
+void MigrateManagerInternal::decRefCount()
+{
+ m_refCount--;
+ KexiDBDbg << "MigrateManagerInternal::decRefCount(): " << m_refCount << endl;
+// if (m_refCount<1) {
+// KexiDBDbg<<"KexiDB::DriverManagerInternal::decRefCount(): reached m_refCount<1 -->deletelater()"<<endl;
+// s_self=0;
+// deleteLater();
+// }
+}
+
+// ---------------------------
+// --- DriverManager impl. ---
+// ---------------------------
+
+MigrateManager::MigrateManager()
+ : QObject( 0, "KexiMigrate::MigrateManager" )
+ , Object()
+ , d_int( MigrateManagerInternal::self() )
+{
+ d_int->incRefCount();
+// if ( !s_self )
+// s_self = this;
+// lookupDrivers();
+}
+
+MigrateManager::~MigrateManager()
+{
+ KexiDBDbg << "MigrateManager::~MigrateManager()" << endl;
+/* Connection *conn;
+ for ( conn = m_connections.first(); conn ; conn = m_connections.next() ) {
+ conn->disconnect();
+ conn->m_driver = 0; //don't let the connection touch our driver now
+ m_connections.remove();
+ delete conn;
+ }*/
+
+ d_int->decRefCount();
+ if (d_int->m_refCount==0) {
+ //delete internal drv manager!
+ delete d_int;
+ }
+// if ( s_self == this )
+ //s_self = 0;
+ KexiDBDbg << "MigrateManager::~MigrateManager() ok" << endl;
+}
+
+
+const QStringList MigrateManager::driverNames()
+{
+ if (!d_int->lookupDrivers()) {
+ kdDebug() << "MigrateManager::driverNames() lookupDrivers failed" << endl;
+ return QStringList();
+ }
+
+ if (d_int->m_services.isEmpty()) {
+ kdDebug() << "MigrateManager::driverNames() MigrateManager::ServicesMap is empty" << endl;
+ return QStringList();
+ }
+
+ if (d_int->error()) {
+ kdDebug() << "MigrateManager::driverNames() Error: " << d_int->errorMsg() << endl;
+ return QStringList();
+ }
+
+ return d_int->m_services.keys();
+}
+
+QString MigrateManager::driverForMimeType(const QString &mimeType)
+{
+ if (!d_int->lookupDrivers()) {
+ kdDebug() << "MigrateManager::driverForMimeType() lookupDrivers() failed" << endl;
+ setError(d_int);
+ return 0;
+ }
+
+ KService::Ptr ptr = d_int->m_services_by_mimetype[mimeType.lower()];
+ if (!ptr) {
+ kdDebug() << QString("MigrateManager::driverForMimeType(%1) No such mimetype").arg(mimeType) << endl;
+ return QString::null;
+ }
+
+ return ptr->property("X-Kexi-MigrationDriverName").toString();
+}
+
+KexiMigrate* MigrateManager::driver(const QString& name)
+{
+ KexiMigrate *drv = d_int->driver(name);
+ if (d_int->error()) {
+ kdDebug() << QString("MigrateManager::driver(%1) Error: %2").arg(name).arg(d_int->errorMsg()) << endl;
+ setError(d_int);
+ }
+ return drv;
+}
+
+QString MigrateManager::serverErrorMsg()
+{
+ return d_int->m_serverErrMsg;
+}
+
+int MigrateManager::serverResult()
+{
+ return d_int->m_serverResultNum;
+}
+
+QString MigrateManager::serverResultName()
+{
+ return d_int->m_serverResultName;
+}
+
+void MigrateManager::drv_clearServerResult()
+{
+ d_int->m_serverErrMsg=QString::null;
+ d_int->m_serverResultNum=0;
+ d_int->m_serverResultName=QString::null;
+}
+
+QString MigrateManager::possibleProblemsInfoMsg() const
+{
+ if (d_int->possibleProblems.isEmpty())
+ return QString::null;
+ QString str;
+ str.reserve(1024);
+ str = "<ul>";
+ for (QStringList::ConstIterator it = d_int->possibleProblems.constBegin();
+ it!=d_int->possibleProblems.constEnd(); ++it)
+ {
+ str += (QString::fromLatin1("<li>") + *it + QString::fromLatin1("</li>"));
+ }
+ str += "</ul>";
+ return str;
+}
+
+//------------------------
+
+int KexiMigration::versionMajor()
+{
+ return KEXI_MIGRATION_VERSION_MAJOR;
+}
+
+int KexiMigration::versionMinor()
+{
+ return KEXI_MIGRATION_VERSION_MINOR;
+}
+
+#include "migratemanager_p.moc"
diff --git a/kexi/migration/migratemanager.h b/kexi/migration/migratemanager.h
new file mode 100644
index 00000000..c876ab91
--- /dev/null
+++ b/kexi/migration/migratemanager.h
@@ -0,0 +1,82 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Jaroslaw Staniek <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXI_MIGRATION_MNGR_H
+#define KEXI_MIGRATION_MNGR_H
+
+#include <qobject.h>
+#include <qcstring.h>
+#include <qmap.h>
+#include <qdict.h>
+
+#include <klibloader.h>
+#include <kservice.h>
+
+#include "keximigrate.h"
+
+namespace KexiMigration {
+
+class MigrateManagerInternal;
+
+//! @short Migration library management, for finding and loading mogration drivers.
+class KEXIMIGR_EXPORT MigrateManager : public QObject, public KexiDB::Object
+{
+ public:
+ typedef QMap<QString, KService::Ptr> ServicesMap;
+
+ MigrateManager();
+ virtual ~MigrateManager();
+
+ /*! Tries to load db driver with named name \a name.
+ The name is case insensitive.
+ \return db driver, or 0 if error (then error message is also set) */
+ KexiMigrate* driver(const QString& name);
+
+ /*! returns list of available drivers names.
+ That drivers can be loaded by first use of driver() method. */
+ const QStringList driverNames();
+
+ /*! Looks up a drivers list by MIME type of database file.
+ Only file-based database drivers are checked.
+ The lookup is case insensitive.
+ \return driver name or null string if no driver found.
+ */
+ QString driverForMimeType(const QString &mimeType);
+
+ //! server error is set if there is error at KService level (useful for debugging)
+ virtual QString serverErrorMsg();
+ virtual int serverResult();
+ virtual QString serverResultName();
+
+//! @todo copied from KexiDB::DriverManager, merge it.
+ /*! HTML information about possible problems encountered.
+ It's displayed in 'details' section, if an error encountered.
+ Currently it contains a list of incompatible migration drivers. */
+ QString possibleProblemsInfoMsg() const;
+
+ protected:
+ virtual void drv_clearServerResult();
+
+ private:
+ MigrateManagerInternal *d_int;
+};
+
+} //namespace KexiMigrate
+
+#endif
diff --git a/kexi/migration/migratemanager_p.h b/kexi/migration/migratemanager_p.h
new file mode 100644
index 00000000..0d90acfe
--- /dev/null
+++ b/kexi/migration/migratemanager_p.h
@@ -0,0 +1,85 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Jaroslaw Staniek <[email protected]>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXI_MIGRATE_MNGR_P_H
+#define KEXI_MIGRATE_MNGR_P_H
+
+#include <qobject.h>
+#include <qasciidict.h>
+
+namespace KexiMigration {
+
+/*! Internal class of driver manager.
+*/
+class MigrateManagerInternal : public QObject, public KexiDB::Object
+{
+ Q_OBJECT
+ public:
+ ~MigrateManagerInternal();
+
+ /*! Tries to load db driver \a name.
+ \return db driver, or 0 if error (then error message is also set) */
+ KexiMigrate* driver(const QString& name);
+
+ static MigrateManagerInternal *self();
+
+ /*! increments the refcount for the manager */
+ void incRefCount();
+
+ /*! decrements the refcount for the manager
+ if the refcount reaches a value less than 1 the manager is freed */
+ void decRefCount();
+
+ protected slots:
+ /*! Used to destroy all drivers on QApplication quit, so even if there are
+ DriverManager's static instances that are destroyed on program
+ "static destruction", drivers are not kept after QApplication death.
+ */
+ void slotAppQuits();
+
+ protected:
+ /*! Used by self() */
+ MigrateManagerInternal();
+
+ bool lookupDrivers();
+
+ static MigrateManagerInternal* s_self;
+
+ MigrateManager::ServicesMap m_services; //! services map
+ MigrateManager::ServicesMap m_services_lcase; //! as above but service names in lowercase
+ MigrateManager::ServicesMap m_services_by_mimetype;
+
+ QAsciiDict<KexiMigrate> m_drivers;
+ ulong m_refCount;
+
+ QString m_serverErrMsg;
+ int m_serverResultNum;
+ QString m_serverResultName;
+ //! result names for KParts::ComponentFactory::ComponentLoadingError
+ QMap<int,QString> m_componentLoadingErrors;
+
+ bool lookupDriversNeeded : 1;
+
+ QStringList possibleProblems;
+
+ friend class MigrateManager;
+};
+}
+
+#endif
diff --git a/kexi/migration/mysql/Makefile.am b/kexi/migration/mysql/Makefile.am
new file mode 100644
index 00000000..635bbf1d
--- /dev/null
+++ b/kexi/migration/mysql/Makefile.am
@@ -0,0 +1,18 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+kde_module_LTLIBRARIES = keximigrate_mysql.la
+
+INCLUDES = -I$(srcdir)/../../.. -I$(top_srcdir)/kexi $(all_includes) -I$(MYSQL_INC)
+
+keximigrate_mysql_la_METASOURCES = AUTO
+
+keximigrate_mysql_la_SOURCES = mysqlmigrate.cpp
+
+keximigrate_mysql_la_LIBADD = $(LIB_KPARTS) $(LIB_QT) ../libkeximigrate.la $(MYSQL_LIBS) -lmysqlclient
+
+keximigrate_mysql_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(VER_INFO) -no-undefined
+
+kde_services_DATA = keximigrate_mysql.desktop
+
+noinst_HEADERS = mysqlmigrate.h
+
diff --git a/kexi/migration/mysql/keximigrate_mysql.desktop b/kexi/migration/mysql/keximigrate_mysql.desktop
new file mode 100644
index 00000000..529ad459
--- /dev/null
+++ b/kexi/migration/mysql/keximigrate_mysql.desktop
@@ -0,0 +1,54 @@
+[Desktop Entry]
+Name=MySQL
+Name[ne]=मेरो एसक्यूएल
+Name[sk]=mySQL
+Comment=MySQL Migration Driver for Kexi
+Comment[bg]=Драйвер за мигриране от MySQL към Kexi
+Comment[ca]=Controlador de migració de MySQL per a Kexi
+Comment[cy]=Gyrrydd Mudo MySQL ar gyfer Kexi
+Comment[da]=MySQL Migrationsdriver for Kexi
+Comment[de]=MySQL-Migrationstreiber für Kexi
+Comment[el]=Οδηγός μεταφοράς MySQL του Kexi
+Comment[eo]=MySQL-migrada pelilo por Kexi
+Comment[es]=Controlador de migración a MySQL para Kexi
+Comment[et]=Kexi MySQL migreerumisdraiver
+Comment[eu]=Kexi-ren MySQL migraziorako kontrolatzailea
+Comment[fa]=گردانندۀ جابه‌جایی MySQL برای Kexi
+Comment[fi]=MySQL yhdistäjäajuri Kexille
+Comment[fr]=Pilote de migration MySQL pour Kexi
+Comment[fy]=MySQL-Migraasjestjoerprogramma foar Kexi
+Comment[gl]=Controlador de Migración de MySQL de Kexi
+Comment[hr]=MySQL upravljački program migracije podataka za Kexi
+Comment[hu]=Kexi MySQL-migrálási meghajtó
+Comment[is]=MySQL gagnaflutningsrekill fyrir Kexi
+Comment[it]=Driver di migrazione MySQL per Kexi
+Comment[ja]=Kexi MySQL データ移行ドライバ
+Comment[km]=កម្មវិធី​បញ្ជា​សម្រាប់​ផ្លាស់ប្ដូរ MySQL សម្រាប់ Kexi
+Comment[lv]=MySQL datu migrācijas draiveris priekš Kexi
+Comment[ms]=Pemacu Migrasi MySQL bagi Kexi
+Comment[nb]=Kexi-programmodul for migrering av MySQL-drivere
+Comment[nds]=MySQL-Datenutlagerndriever för Kexi
+Comment[ne]=केक्सीका लागि MySQL माइग्रेसन ड्राइभर
+Comment[nl]=MySQL-migratiestuurprogramma voor Kexi
+Comment[nn]=Kexi-programmodul for migrering av MySQL-drivarar
+Comment[pl]=Wtyczka migracji danych z serwera MySQL dla Kexi
+Comment[pt]=Controlador de Migração de MySQL do Kexi
+Comment[pt_BR]=Driver de Migração do MySQL para o Kexi
+Comment[ru]=Драйвер миграции MySQL для Kexi
+Comment[sk]=Ovládač MySQL Migration Driver pre Kexi
+Comment[sl]=Gonilnik MySQL za prenos podatkov za Kexi
+Comment[sr]=Драјвер Kexi-ја за миграцију са MySQL-а
+Comment[sr@Latn]=Drajver Kexi-ja za migraciju sa MySQL-a
+Comment[sv]=MySQL-övergångsdrivrutin för Kexi
+Comment[uk]=MySQL драйвер міграції даних для Kexi
+Comment[uz]=Kexi uchun MySQL migratsiya drayveri
+Comment[uz@cyrillic]=Kexi учун MySQL миграция драйвери
+Comment[zh_CN]=Kexi MySQL 升迁驱动程序
+Comment[zh_TW]=Kexi 的 MySQL 轉移驅動程式
+X-KDE-Library=keximigrate_mysql
+ServiceTypes=Kexi/MigrationDriver
+Type=Service
+InitialPreference=8
+X-Kexi-MigrationDriverName=MySQL
+X-Kexi-MigrationDriverType=Network
+X-Kexi-KexiMigrationVersion=1.1
diff --git a/kexi/migration/mysql/mysqlmigrate.cpp b/kexi/migration/mysql/mysqlmigrate.cpp
new file mode 100644
index 00000000..a2c62dd5
--- /dev/null
+++ b/kexi/migration/mysql/mysqlmigrate.cpp
@@ -0,0 +1,522 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Martin Ellis <[email protected]>
+ Copyright (C) 2006 Jaroslaw Staniek <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "mysqlmigrate.h"
+
+#include <qstring.h>
+#include <qregexp.h>
+#include <qfile.h>
+#include <qvariant.h>
+#include <qvaluelist.h>
+#include <kdebug.h>
+
+#include <mysql_version.h>
+#include <mysql.h>
+
+#include "migration/keximigratedata.h"
+#include <kexidb/cursor.h>
+#include <kexidb/field.h>
+#include <kexidb/utils.h>
+#include <kexidb/drivers/mySQL/mysqlconnection_p.cpp>
+#include <kexidb/drivermanager.h>
+#include <kexiutils/identifier.h>
+
+using namespace KexiMigration;
+
+/* This is the implementation for the MySQL specific import routines. */
+
+KEXIMIGRATE_DRIVER_INFO( MySQLMigrate, mysql )
+
+/* ************************************************************************** */
+//! Constructor
+/*MySQLMigrate::MySQLMigrate() :
+ d(new MySqlConnectionInternal())
+{
+}*/
+
+//! Constructor (needed for trading interface)
+MySQLMigrate::MySQLMigrate(QObject *parent, const char *name,
+ const QStringList &args) :
+ KexiMigrate(parent, name, args)
+ ,d(new MySqlConnectionInternal(0))
+ ,m_mysqlres(0)
+{
+ KexiDB::DriverManager manager;
+ m_kexiDBDriver = manager.driver("mysql");
+}
+
+/* ************************************************************************** */
+//! Destructor
+MySQLMigrate::~MySQLMigrate() {
+ if (m_mysqlres)
+ mysql_free_result(m_mysqlres);
+ m_mysqlres = 0;
+}
+
+
+/* ************************************************************************** */
+/*! Connect to the db backend */
+bool MySQLMigrate::drv_connect() {
+ if(d->db_connect(*m_migrateData->source)) {
+ return d->useDatabase(m_migrateData->sourceName);
+ } else {
+ return false;
+ }
+}
+
+
+/*! Disconnect from the db backend */
+bool MySQLMigrate::drv_disconnect()
+{
+ return d->db_disconnect();
+}
+
+
+/* ************************************************************************** */
+/*! Get the types and properties for each column. */
+bool MySQLMigrate::drv_readTableSchema(
+ const QString& originalName, KexiDB::TableSchema& tableSchema)
+{
+// m_table = new KexiDB::TableSchema(table);
+
+// //TODO IDEA: ask for user input for captions
+// tableSchema.setCaption(table + " table");
+
+ //Perform a query on the table to get some data
+ QString query = QString("SELECT * FROM `") + drv_escapeIdentifier(originalName) + "` LIMIT 0";
+ if(d->executeSQL(query)) {
+ MYSQL_RES *res = mysql_store_result(d->mysql);
+ if (res != NULL) {
+
+ unsigned int numFlds = mysql_num_fields(res);
+ MYSQL_FIELD *fields = mysql_fetch_fields(res);
+
+ for(unsigned int i = 0; i < numFlds; i++) {
+ QString fldName(fields[i].name);
+ QString fldID( KexiUtils::string2Identifier(fldName) );
+
+ KexiDB::Field *fld =
+ new KexiDB::Field(fldID, type(originalName, &fields[i]));
+
+ if(fld->type() == KexiDB::Field::Enum) {
+ QStringList values = examineEnumField(originalName, &fields[i]);
+ }
+
+ fld->setCaption(fldName);
+ getConstraints(fields[i].flags, fld);
+ getOptions(fields[i].flags, fld);
+ tableSchema.addField(fld);
+ }
+ mysql_free_result(res);
+ } else {
+ kdDebug() << "MySQLMigrate::drv_tableNames: null result" << endl;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+/*! Get a list of tables and put into the supplied string list */
+bool MySQLMigrate::drv_tableNames(QStringList& tableNames)
+{
+ if(d->executeSQL("SHOW TABLES")) {
+ MYSQL_RES *res = mysql_store_result(d->mysql);
+ if (res != NULL) {
+ MYSQL_ROW row;
+ while ((row = mysql_fetch_row(res)) != NULL) {
+ tableNames << QString::fromUtf8(row[0]); //utf8.. ok?
+ }
+ mysql_free_result(res);
+ } else {
+ kdDebug() << "MySQLMigrate::drv_tableNames: null result" << endl;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*! Fetches single string at column \a columnNumber for each record from result obtained
+ by running \a sqlStatement.
+ On success the result is stored in \a stringList and true is returned.
+ \return cancelled if there are no records available. */
+tristate MySQLMigrate::drv_queryStringListFromSQL(
+ const QString& sqlStatement, uint columnNumber, QStringList& stringList, int numRecords)
+{
+ stringList.clear();
+ if (d->executeSQL(sqlStatement)) {
+ MYSQL_RES *res = mysql_use_result(d->mysql);
+ if (res != NULL) {
+ for (int i=0; numRecords == -1 || i < numRecords; i++) {
+ MYSQL_ROW row = mysql_fetch_row(res);
+ if (!row) {
+ tristate r;
+ if (mysql_errno(d->mysql))
+ r = false;
+ else
+ r = (numRecords == -1) ? true : cancelled;
+ mysql_free_result(res);
+ return r;
+ }
+ uint numFields = mysql_num_fields(res);
+ if (columnNumber > (numFields-1)) {
+ kdWarning() << "MySQLMigrate::drv_querySingleStringFromSQL("<<sqlStatement
+ << "): columnNumber too large ("
+ << columnNumber << "), expected 0.." << numFields << endl;
+ mysql_free_result(res);
+ return false;
+ }
+ unsigned long *lengths = mysql_fetch_lengths(res);
+ if (!lengths) {
+ mysql_free_result(res);
+ return false;
+ }
+ stringList.append( QString::fromUtf8(row[columnNumber], lengths[columnNumber]) ); //ok? utf8?
+ }
+ mysql_free_result(res);
+ } else {
+ kdDebug() << "MySQLMigrate::drv_querySingleStringFromSQL(): null result" << endl;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*! Fetches single record from result obtained
+ by running \a sqlStatement. */
+tristate MySQLMigrate::drv_fetchRecordFromSQL(const QString& sqlStatement,
+ KexiDB::RowData& data, bool &firstRecord)
+{
+ if (firstRecord || !m_mysqlres) {
+ if (m_mysqlres) {
+ mysql_free_result(m_mysqlres);
+ m_mysqlres = 0;
+ }
+ if (!d->executeSQL(sqlStatement) || !(m_mysqlres = mysql_use_result(d->mysql)))
+ return false;
+ firstRecord = false;
+ }
+
+ MYSQL_ROW row = mysql_fetch_row(m_mysqlres);
+ if (!row) {
+ tristate r = cancelled;
+ if (mysql_errno(d->mysql))
+ r = false;
+ mysql_free_result(m_mysqlres);
+ m_mysqlres = 0;
+ return r;
+ }
+ const int numFields = mysql_num_fields(m_mysqlres);
+ unsigned long *lengths = mysql_fetch_lengths(m_mysqlres);
+ if (!lengths) {
+ mysql_free_result(m_mysqlres);
+ m_mysqlres = 0;
+ return false;
+ }
+ data.resize(numFields);
+ for (int i=0; i < numFields; i++)
+ data[i] = QString::fromUtf8(row[i], lengths[i] ); //ok? utf8?
+ return true;
+}
+
+/*! Copy MySQL table to KexiDB database */
+bool MySQLMigrate::drv_copyTable(const QString& srcTable, KexiDB::Connection *destConn,
+ KexiDB::TableSchema* dstTable)
+{
+ if(d->executeSQL("SELECT * FROM `" + drv_escapeIdentifier(srcTable)) + "`") {
+ MYSQL_RES *res = mysql_use_result(d->mysql);
+ if (res != NULL) {
+ MYSQL_ROW row;
+ const KexiDB::QueryColumnInfo::Vector fieldsExpanded( dstTable->query()->fieldsExpanded() );
+ while ((row = mysql_fetch_row(res)) != NULL) {
+ const int numFields = QMIN((int)fieldsExpanded.count(), (int)mysql_num_fields(res));
+ QValueList<QVariant> vals;
+ unsigned long *lengths = mysql_fetch_lengths(res);
+ if (!lengths) {
+ mysql_free_result(res);
+ return false;
+ }
+ for(int i = 0; i < numFields; i++)
+ vals.append( KexiDB::cstringToVariant(row[i], fieldsExpanded.at(i)->field, (int)lengths[i]) );
+ if (!destConn->insertRecord(*dstTable, vals)) {
+ mysql_free_result(res);
+ return false;
+ }
+ updateProgress();
+ }
+ if (!row && mysql_errno(d->mysql)) {
+ mysql_free_result(res);
+ return false;
+ }
+ /*! @todo Check that wasn't an error, rather than end of result set */
+ mysql_free_result(res);
+ } else {
+ kdDebug() << "MySQLMigrate::drv_copyTable: null result" << endl;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool MySQLMigrate::drv_getTableSize(const QString& table, Q_ULLONG& size) {
+ if(d->executeSQL("SELECT COUNT(*) FROM `" + drv_escapeIdentifier(table)) + "`") {
+ MYSQL_RES *res = mysql_store_result(d->mysql);
+ if (res != NULL) {
+ MYSQL_ROW row;
+ while ((row = mysql_fetch_row(res)) != NULL) {
+ //! @todo check result valid
+ size = QString(row[0]).toULongLong();
+ }
+ mysql_free_result(res);
+ } else {
+ kdDebug() << "MySQLMigrate::drv_getTableSize: null result" << endl;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+//! Convert a MySQL type to a KexiDB type, prompting user if necessary.
+KexiDB::Field::Type MySQLMigrate::type(const QString& table,
+ const MYSQL_FIELD *fld)
+{
+ // Field type
+ KexiDB::Field::Type kexiType = KexiDB::Field::InvalidType;
+
+ switch(fld->type)
+ {
+ // These are in the same order as mysql_com.h.
+ // MySQL names given on the right
+ case FIELD_TYPE_DECIMAL: // DECIMAL or NUMERIC
+ break;
+ case FIELD_TYPE_TINY: // TINYINT (-2^7..2^7-1 or 2^8)
+ kexiType = KexiDB::Field::Byte;
+ break;
+ case FIELD_TYPE_SHORT: // SMALLINT (-2^15..2^15-1 or 2^16)
+ kexiType = KexiDB::Field::ShortInteger;
+ break;
+ case FIELD_TYPE_LONG: // INTEGER (-2^31..2^31-1 or 2^32)
+ kexiType = KexiDB::Field::Integer;
+ break;
+ case FIELD_TYPE_FLOAT: // FLOAT
+ kexiType = KexiDB::Field::Float;
+ break;
+ case FIELD_TYPE_DOUBLE: // DOUBLE or REAL (8 byte)
+ kexiType = KexiDB::Field::Double;
+ break;
+ case FIELD_TYPE_NULL: // WTF?
+ break;
+ case FIELD_TYPE_TIMESTAMP: // TIMESTAMP (promote?)
+ kexiType = KexiDB::Field::DateTime;
+ break;
+ case FIELD_TYPE_LONGLONG: // BIGINT (-2^63..2^63-1 or 2^64)
+ case FIELD_TYPE_INT24: // MEDIUMINT (-2^23..2^23-1 or 2^24) (promote)
+ kexiType = KexiDB::Field::BigInteger;
+ break;
+ case FIELD_TYPE_DATE: // DATE
+ kexiType = KexiDB::Field::Date;
+ break;
+ case FIELD_TYPE_TIME: // TIME
+ kexiType = KexiDB::Field::Time;
+ break;
+ case FIELD_TYPE_DATETIME: // DATETIME
+ kexiType = KexiDB::Field::DateTime;
+ break;
+ case FIELD_TYPE_YEAR: // YEAR (promote)
+ kexiType = KexiDB::Field::ShortInteger;
+ break;
+ case FIELD_TYPE_NEWDATE: // WTF?
+ case FIELD_TYPE_ENUM: // ENUM
+ // If MySQL did what it's documentation said it did, we would come here
+ // for enum fields ...
+ kexiType = KexiDB::Field::Enum;
+ break;
+ case FIELD_TYPE_SET: // SET
+ //! @todo: Support set column type
+ break;
+ case FIELD_TYPE_TINY_BLOB:
+ case FIELD_TYPE_MEDIUM_BLOB:
+ case FIELD_TYPE_LONG_BLOB:
+ case FIELD_TYPE_BLOB: // BLOB or TEXT
+ case FIELD_TYPE_VAR_STRING: // VARCHAR
+ case FIELD_TYPE_STRING: // CHAR
+
+ if (fld->flags & ENUM_FLAG) {
+ // ... instead we come here, using the ENUM_FLAG which is supposed to
+ // be deprecated! Duh.
+ kexiType = KexiDB::Field::Enum;
+ break;
+ }
+ kexiType = examineBlobField(table, fld);
+ break;
+ default:
+ kexiType = KexiDB::Field::InvalidType;
+ }
+
+ if (kexiType == KexiDB::Field::InvalidType) {
+ return userType(table);
+ }
+ return kexiType;
+}
+
+
+//! Distinguish between a BLOB and a TEXT field
+/*! MySQL uses the same field type to identify BLOB and TEXT fields.
+ This method queries the server to find out if a field is a binary
+ field or a text field. It also considers the length of CHAR and VARCHAR
+ fields to see whether Text or LongText is the appropriate Kexi field type.
+ Assumes fld is a CHAR, VARCHAR, one of the BLOBs or TEXTs.
+ \return KexiDB::Field::Text, KexiDB::Field::LongText or KexiDB::Field::BLOB
+*/
+KexiDB::Field::Type MySQLMigrate::examineBlobField(const QString& table,
+ const MYSQL_FIELD* fld) {
+ QString mysqlType;
+ KexiDB::Field::Type kexiType;
+ QString query = "SHOW COLUMNS FROM `" + drv_escapeIdentifier(table) +
+ "` LIKE '" + QString::fromLatin1(fld->name) + "'";
+
+ if(d->executeSQL(query)) {
+ MYSQL_RES *res = mysql_store_result(d->mysql);
+
+ if (res != NULL) {
+ MYSQL_ROW row;
+ while ((row = mysql_fetch_row(res)) != NULL) {
+ mysqlType = QString(row[1]);
+ }
+ mysql_free_result(res);
+ } else {
+ kdDebug() << "MySQLMigrate::examineBlobField: null result" << endl;
+ }
+ } else {
+ // Huh? MySQL wont tell us what kind of field it is! Lets guess.
+ return KexiDB::Field::LongText;
+ }
+
+ kdDebug() << "MySQLMigrate::examineBlobField: considering "
+ << mysqlType << endl;
+ if(mysqlType.contains("blob", false) != 0) {
+ // Doesn't matter how big it is, it's binary
+ kexiType = KexiDB::Field::BLOB;
+ } else if(mysqlType.contains("text", false) != 0) {
+ // All the TEXT types are too big for Kexi text.
+ kexiType = KexiDB::Field::BLOB;
+ } else if(fld->length < 200) {
+ kexiType = KexiDB::Field::Text;
+ } else {
+ kexiType = KexiDB::Field::LongText;
+ }
+ return kexiType;
+}
+
+
+//! Get the strings that identify values in an enum field
+/*! Parse the type of a MySQL enum field as returned by the server in a
+ 'DESCRIBE table' or 'SHOW COLUMNS FROM table' statement. The string
+ returned by the server is in the form 'enum('option1','option2').
+ In this example, the result should be a string list containing two
+ strings, "option1", "option2".
+ \return list of possible values the field can take
+ */
+QStringList MySQLMigrate::examineEnumField(const QString& table,
+ const MYSQL_FIELD* fld) {
+ QString vals;
+ QString query = "SHOW COLUMNS FROM `" + drv_escapeIdentifier(table) +
+ "` LIKE '" + QString::fromLatin1(fld->name) + "'";
+
+ if(d->executeSQL(query)) {
+ MYSQL_RES *res = mysql_store_result(d->mysql);
+
+ if (res != NULL) {
+ MYSQL_ROW row;
+ while ((row = mysql_fetch_row(res)) != NULL) {
+ vals = QString(row[1]);
+ }
+ mysql_free_result(res);
+ } else {
+ kdDebug() << "MySQLMigrate::examineEnumField: null result" << endl;
+ }
+ } else {
+ // Huh? MySQL wont tell us what values it can take.
+ return QStringList();
+ }
+
+ kdDebug() << "MySQLMigrate::examineEnumField: considering "
+ << vals << endl;
+
+ // Crash and burn if we get confused...
+ if(!vals.startsWith("enum(")) {
+ // Huh? We're supposed to be parsing an enum!
+ kdDebug() << "MySQLMigrate::examineEnumField:1 not an enum!" << endl;
+ return QStringList();
+ }
+ if(!vals.endsWith(")")) {
+ kdDebug() << "MySQLMigrate::examineEnumField:2 not an enum!" << endl;
+ return QStringList();
+ }
+
+ // It'd be nice to use QString.section or QStringList.split, but we need
+ // to be careful as enum values can have commas and quote marks in them
+ // e.g. CREATE TABLE t(f enum('option,''') gives one option: "option,'"
+ vals = vals.remove(0,5);
+ QRegExp rx = QRegExp("^'((?:[^,']|,|'')*)'");
+ QStringList values = QStringList();
+ int index = 0;
+
+ while ((index = rx.search(vals, index, QRegExp::CaretAtOffset)) != -1) {
+ int len = rx.matchedLength();
+ if (len != -1) {
+ kdDebug() << "MySQLMigrate::examineEnumField:3 " << rx.cap(1) << endl;
+ values << rx.cap(1);
+ } else {
+ kdDebug() << "MySQLMigrate::examineEnumField:4 lost" << endl;
+ }
+
+ QChar next = vals[index + len];
+ if (next != QChar(',') && next != QChar(')')) {
+ kdDebug() << "MySQLMigrate::examineEnumField:5 " << (char)next << endl;
+ }
+ index += len + 1;
+ }
+
+ return values;
+}
+
+
+void MySQLMigrate::getConstraints(int flags, KexiDB::Field* fld) {
+ fld->setPrimaryKey(flags & PRI_KEY_FLAG);
+ fld->setAutoIncrement(flags & AUTO_INCREMENT_FLAG);
+ fld->setNotNull(flags & NOT_NULL_FLAG);
+ fld->setUniqueKey(flags & UNIQUE_KEY_FLAG);
+ //! @todo: Keys and uniqueness
+}
+
+
+void MySQLMigrate::getOptions(int flags, KexiDB::Field* fld) {
+ fld->setUnsigned(flags & UNSIGNED_FLAG);
+}
+
+
+#include "mysqlmigrate.moc"
diff --git a/kexi/migration/mysql/mysqlmigrate.h b/kexi/migration/mysql/mysqlmigrate.h
new file mode 100644
index 00000000..9f32bd2f
--- /dev/null
+++ b/kexi/migration/mysql/mysqlmigrate.h
@@ -0,0 +1,85 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Martin Ellis <[email protected]>
+ Copyright (C) 2006 Jaroslaw Staniek <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MYSQLMIGRATE_H
+#define MYSQLMIGRATE_H
+
+#include "migration/keximigrate.h"
+#include "kexidb/drivers/mySQL/mysqlconnection_p.h"
+
+namespace KexiMigration
+{
+
+ class MySQLMigrate : public KexiMigrate
+ {
+ Q_OBJECT
+ KEXIMIGRATION_DRIVER
+
+ private:
+ MySqlConnectionInternal *d;
+ MYSQL_RES *m_mysqlres;
+
+ protected:
+ //Driver specific function to return table names
+ virtual bool drv_tableNames(QStringList& tablenames);
+
+ //Driver specific implementation to read a table schema
+ virtual bool drv_readTableSchema(
+ const QString& originalName, KexiDB::TableSchema& tableSchema);
+ //Driver specific connection implementation
+ virtual bool drv_connect();
+ virtual bool drv_disconnect();
+
+ virtual tristate drv_queryStringListFromSQL(
+ const QString& sqlStatement, uint columnNumber,
+ QStringList& stringList, int numRecords = -1);
+
+ virtual tristate drv_fetchRecordFromSQL(const QString& sqlStatement,
+ KexiDB::RowData& data, bool &firstRecord);
+
+ virtual bool drv_copyTable(const QString& srcTable,
+ KexiDB::Connection *destConn, KexiDB::TableSchema* dstTable);
+
+ virtual bool drv_progressSupported() { return true; }
+ virtual bool drv_getTableSize(const QString& table, Q_ULLONG& size);
+
+//TODO: move this somewhere to low level class (MIGRATION?)
+// virtual bool drv_getTablesList( QStringList &list );
+//TODO: move this somewhere to low level class (MIGRATION?)
+// virtual bool drv_containsTable( const QString &tableName );
+
+ public:
+// MySQLMigrate();
+ MySQLMigrate(QObject *parent, const char *name, const QStringList& args = QStringList());
+ ~MySQLMigrate();
+
+ KexiDB::Field::Type type(const QString& table, const MYSQL_FIELD* t);
+
+ KexiDB::Field::Type examineBlobField(const QString& table,
+ const MYSQL_FIELD* fld);
+
+ QStringList examineEnumField(const QString& table,
+ const MYSQL_FIELD* fld);
+ void getConstraints(int mysqlConstraints, KexiDB::Field* fld);
+ void getOptions(int flags, KexiDB::Field* fld);
+ };
+}
+
+#endif
diff --git a/kexi/migration/pqxx/Makefile.am b/kexi/migration/pqxx/Makefile.am
new file mode 100644
index 00000000..d49027f1
--- /dev/null
+++ b/kexi/migration/pqxx/Makefile.am
@@ -0,0 +1,20 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+kde_module_LTLIBRARIES = keximigrate_pqxx.la
+
+INCLUDES = -I$(srcdir)/../../.. -I$(top_srcdir)/kexi $(all_includes) -I$(PG_INCDIR) -I$(PQXX_INCDIR)
+
+keximigrate_pqxx_la_METASOURCES = AUTO
+
+keximigrate_pqxx_la_SOURCES = pqxxmigrate.cpp
+
+#TODO share -libs with pqxx kexidb drv!
+#keximigrate_pqxx_la_LIBADD = $(LIB_KPARTS) $(LIB_QT) -lcom_err -lkrb5 -lssl -lcrypto -lcrypt -lpqxx ../libkeximigrate.la
+keximigrate_pqxx_la_LIBADD = $(LIB_KPARTS) $(LIB_QT) -lpqxx ../libkeximigrate.la
+
+keximigrate_pqxx_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -L$(PQXX_LIBDIR) -L$(PG_LIBDIR) $(VER_INFO) -no-undefined
+
+kde_services_DATA = keximigrate_pqxx.desktop
+
+noinst_HEADERS = pqxxmigrate.h pg_type.h
+
diff --git a/kexi/migration/pqxx/keximigrate_pqxx.desktop b/kexi/migration/pqxx/keximigrate_pqxx.desktop
new file mode 100644
index 00000000..3f88cbef
--- /dev/null
+++ b/kexi/migration/pqxx/keximigrate_pqxx.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Name=PostgreSQL
+Name[hi]=पोस्टग्रे-एसक्यूएल
+Name[ne]=पोस्ट ग्रे एसक्यूएल
+Comment=PostgreSQL Migration Driver for Kexi
+Comment[bg]=Драйвер за мигриране от PostgreSQL към Kexi
+Comment[ca]=Controlador de migració de PostgreSQL per a Kexi
+Comment[cy]=Gyrrydd Mudo PostgreSQL ar gyfer Kexi
+Comment[da]=PostgreSQL Migrationsdriver for Kexi
+Comment[de]=PostgreSQL-Migrationstreiber für Kexi
+Comment[el]=Οδηγός μεταφοράς PostgreSQL του Kexi
+Comment[eo]=PostgreSQL-migrada pelilo por Kexi
+Comment[es]=Controlador de migración a PostgreSQL para Kexi
+Comment[et]=Kexi PostgreSQL migreerumisdraiver
+Comment[eu]=Kexi-ren PostgreSQL migraziorako kontrolatzailea
+Comment[fa]=گردانندۀ جابه‌جایی PostgreSQL برای Kexi
+Comment[fi]=PostgreSQL yhdistämisajuri Kexille
+Comment[fr]=Pilote de migration PostgreSQL pour Kexi
+Comment[fy]=PostgreSQL-Migraasjestjoerprogramma foar Kexi
+Comment[gl]=Controlador de Migración de PostgreSQL de Kexi
+Comment[hr]=PostgreSQL upravljački program migracije podataka za Kexi
+Comment[hu]=Kexi PostgreSQL-migrálási meghajtó
+Comment[is]=PostgreSQL gagnaflutngingsrekill fyrir Kexi
+Comment[it]=Driver di migrazione PostgreSQL per Kexi
+Comment[ja]=Kexi PostgreSQL データ移行ドライバ
+Comment[km]=កម្មវិធី​បញ្ជា​សម្រាប់​ផ្លាស់ប្ដូរ PostgreSQL សម្រាប់ Kexi
+Comment[lv]=PostgreSQL datu migrācijas draiveris priekš Kexi
+Comment[nb]=Kexi-programmodul for migrering av MySQL-drivere
+Comment[nds]=PostgreSQL-Datenutlagerndriever för Kexi
+Comment[ne]=केक्सीका लागि पोस्टग्रेसSQL मापग्रेसन ड्राइभर
+Comment[nl]=PostgreSQL-migratiestuurprogramma voor Kexi
+Comment[nn]=Kexi-programmodul for migrering av MySQL-drivarar
+Comment[pl]=Wtyczka migracji danych z serwera PostgreSQL dla Kexi
+Comment[pt]=Controlador de Migração de PostgreSQL do Kexi
+Comment[pt_BR]=Driver de Migração do PostgreSQL para o Kexi
+Comment[ru]=Драйвер миграции PostrgeSQL для Kexi
+Comment[sk]=Ovládač PostgreSQL Migration pre Kexi
+Comment[sl]=Gonilnik PostgreSQL za prenos podatkov za Kexi
+Comment[sr]=Драјвер Kexi-ја за миграцију са PostgreSQL-а
+Comment[sr@Latn]=Drajver Kexi-ja za migraciju sa PostgreSQL-a
+Comment[sv]=PostgreSQL-övergångsdrivrutin för Kexi
+Comment[uk]=PostgreSQL драйвер міграції даних для Kexi
+Comment[uz]=Kexi uchun PostgreSQL migratsiya drayveri
+Comment[uz@cyrillic]=Kexi учун PostgreSQL миграция драйвери
+Comment[zh_CN]=Kexi PostgreSQL 升迁驱动程序
+Comment[zh_TW]=Kexi 的 PostgreSQL 轉移驅動程式
+X-KDE-Library=keximigrate_pqxx
+ServiceTypes=Kexi/MigrationDriver
+Type=Service
+InitialPreference=8
+X-Kexi-MigrationDriverName=PostgreSQL
+X-Kexi-MigrationDriverType=Network
+X-Kexi-KexiMigrationVersion=1.1
diff --git a/kexi/migration/pqxx/pg_type.h b/kexi/migration/pqxx/pg_type.h
new file mode 100644
index 00000000..e0ead91a
--- /dev/null
+++ b/kexi/migration/pqxx/pg_type.h
@@ -0,0 +1,192 @@
+//
+//
+// C++ Interface: pg_type
+//
+// Description:
+//
+//
+// Author: Adam Pigg <[email protected]>, (C) 2003
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+//boolean, 'true'/'false'
+#define BOOLOID 16
+
+//Unknown Type
+#define UNKNOWNOID 705
+
+//Numberic Types
+//==============
+
+//~18 digit integer, 8-byte storage
+#define INT8OID 20
+
+//-32 thousand to 32 thousand, 2-byte storage
+#define INT2OID 21
+
+//array of INDEX_MAX_KEYS int2 integers, used in system tables
+#define INT2VECTOROID 22
+
+//-2 billion to 2 billion integer, 4-byte storage
+#define INT4OID 23
+
+//single-precision floating point number, 4-byte storage
+#define FLOAT4OID 700
+
+//double-precision floating point number, 8-byte storage
+#define FLOAT8OID 701
+
+//monetary amounts, $d,ddd.cc
+#define CASHOID 790
+
+//numeric(precision, decimal), arbitrary precision number
+#define NUMERICOID 1700
+
+//==================================
+
+//Text Types
+//==========
+//variable-length string, binary values escaped
+#define BYTEAOID 17
+
+//single character
+#define CHAROID 18
+
+//variable-length string, no limit specified
+#define TEXTOID 25
+
+//char(length), blank-padded string, fixed storage length
+#define BPCHAROID 1042
+
+//varchar(length), non-blank-padded string, variable storage length
+#define VARCHAROID 1043
+
+//fixed-length bit string
+#define BITOID 1560
+
+//variable-length bit string
+#define VARBITOID 1562
+
+//==================================
+
+//Date Time Types
+//===============
+//absolute, limited-range date and time (Unix system time)
+#define ABSTIMEOID 702
+
+//relative, limited-range time interval (Unix delta time)
+#define RELTIMEOID 703
+
+//(abstime,abstime), time interval
+#define TINTERVALOID 704
+
+//ANSI SQL date
+#define DATEOID 1082
+
+//hh:mm:ss, ANSI SQL time
+#define TIMEOID 1083
+
+//date and time
+#define TIMESTAMPOID 1114
+
+//date and time with time zone
+#define TIMESTAMPTZOID 1184
+
+//@ <number> <units>, time interval
+#define INTERVALOID 1186
+
+//hh:mm:ss, ANSI SQL time
+#define TIMETZOID 1266
+
+
+//==================================
+
+//Internal OID Types
+//==================
+//object identifier(oid), maximum 4 billion
+#define OIDOID 26
+
+//(Block, offset), physical location of tuple
+#define TIDOID 27
+
+//transaction id
+#define XIDOID 28
+
+//command identifier type, sequence in transaction id
+#define CIDOID 29
+
+//array of INDEX_MAX_KEYS oids, used in system tables
+#define OIDVECTOROID 30
+
+
+//==================================
+
+//Geometric Types
+//===============
+//geometric point '(x, y)'
+#define POINTOID 600
+
+//geometric line segment '(pt1,pt2)'
+#define LSEGOID 601
+
+//geometric path '(pt1,...)'
+#define PATHOID 602
+
+//geometric box '(lower left,upper right)'
+#define BOXOID 603
+
+//geometric polygon '(pt1,...)'
+#define POLYGONOID 604
+
+//geometric line (not implemented)'
+#define LINEOID 628
+
+//geometric circle '(center,radius)'
+#define CIRCLEOID 718
+
+//==================================
+
+//Network Types
+//=============
+//XX:XX:XX:XX:XX:XX, MAC address
+#define MACADDROID 829
+
+//IP address/netmask, host address, netmask optional
+#define INETOID 869
+
+//network IP address/netmask, network address
+#define CIDROID 650
+
+//access control list
+#define ACLITEMOID 1033
+
+
+//==================================
+
+//Miscellaneous Types
+//===================
+//63-character type for storing system identifiers
+#define NAMEOID 19
+
+//registered procedure
+#define REGPROCOID 24
+
+//reference cursor (portal name)
+#define REFCURSOROID 1790
+
+//registered procedure (with args)
+#define REGPROCEDUREOID 2202
+
+//registered operator
+#define REGOPEROID 2203
+
+//registered operator (with args)
+#define REGOPERATOROID 2204
+
+//registered class
+#define REGCLASSOID 2205
+
+//registered type
+#define REGTYPEOID 2206
+
diff --git a/kexi/migration/pqxx/pqxxmigrate.cpp b/kexi/migration/pqxx/pqxxmigrate.cpp
new file mode 100644
index 00000000..15715897
--- /dev/null
+++ b/kexi/migration/pqxx/pqxxmigrate.cpp
@@ -0,0 +1,660 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Adam Pigg <[email protected]>
+ Copyright (C) 2006 Jaroslaw Staniek <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "pqxxmigrate.h"
+#include "pg_type.h"
+
+#include <qstring.h>
+#include <kdebug.h>
+#include <qstringlist.h>
+
+//I maybe should not use stl?
+#include <string>
+#include <vector>
+
+#include <kexidb/cursor.h>
+#include <kexidb/utils.h>
+#include <kexidb/drivermanager.h>
+#include <kexiutils/identifier.h>
+#include <kexidb/drivers/pqxx/pqxxcursor.h> //for pgsqlCStrToVariant()
+
+using namespace KexiDB;
+using namespace KexiMigration;
+
+/*
+This is the implementation for the pqxx specific import routines
+Thi is currently pre alpha and in no way is it meant
+to compile, let alone work. This is meant as an example of
+what the system might be and is a work in progress
+*/
+
+KEXIMIGRATE_DRIVER_INFO( PqxxMigrate, pqxx )
+
+//==================================================================================
+//Constructor
+/*PqxxMigrate::PqxxMigrate()
+ : KexiMigrate(parent, name, args)
+{
+ m_res=0;
+ m_trans=0;
+ m_conn=0;
+}*/
+
+PqxxMigrate::PqxxMigrate(QObject *parent, const char *name, const QStringList &args)
+ : KexiMigrate(parent, name, args)
+{
+ m_res=0;
+ m_trans=0;
+ m_conn=0;
+ KexiDB::DriverManager manager;
+ m_kexiDBDriver = manager.driver("pqxx");
+}
+//==================================================================================
+//Destructor
+PqxxMigrate::~PqxxMigrate()
+{
+ clearResultInfo();
+}
+
+//==================================================================================
+//This is probably going to be quite complex...need to get the types for all columns
+//any any other attributes required by kexi
+//helped by reading the 'tables' test program
+bool PqxxMigrate::drv_readTableSchema(
+ const QString& originalName, KexiDB::TableSchema& tableSchema)
+{
+// m_table = new KexiDB::TableSchema(table);
+
+ //TODO IDEA: ask for user input for captions
+//moved m_table->setCaption(table + " table");
+
+ //Perform a query on the table to get some data
+ if (query("select * from \"" + originalName + "\" limit 1"))
+ {
+ //Loop round the fields
+ for (uint i = 0; i < (uint)m_res->columns(); i++)
+ {
+ QString fldName(m_res->column_name(i));
+ KexiDB::Field::Type fldType = type(m_res->column_type(i), fldName);
+ QString fldID( KexiUtils::string2Identifier(fldName) );
+ const pqxx::oid toid = tableOid(originalName);
+ if (toid==0)
+ return false;
+ KexiDB::Field *f = new KexiDB::Field(fldID, fldType);
+ f->setCaption(fldName);
+ f->setPrimaryKey(primaryKey(toid, i));
+ f->setUniqueKey(uniqueKey(toid, i));
+ f->setAutoIncrement(autoInc(toid, i));//This should be safe for all field types
+ tableSchema.addField(f);
+
+ // Do this for var/char types
+ //m_f->setLength(m_res->at(0)[i].size());
+
+ // Do this for numeric type
+ /*m_f->setScale(0);
+ m_f->setPrecision(0);*/
+
+ kdDebug() << "Added field [" << f->name() << "] type [" << f->typeName()
+ << "]" << endl;
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//==================================================================================
+//get a list of tables and put into the supplied string list
+bool PqxxMigrate::drv_tableNames(QStringList& tableNames)
+{
+ /*
+ //pg_ = standard postgresql tables, pga_ = tables added by pgaccess, sql_ = probably information schemas, kexi__ = existing kexi tables
+ if (query("SELECT relname FROM pg_class WHERE ((relkind = 'r') AND ((relname !~ '^pg_') AND (relname !~ '^pga_') AND (relname !~ '^sql_') AND (relname !~ '^kexi__')))"))
+ */
+ if (query("SELECT relname FROM pg_class WHERE ((relkind = 'r') AND ((relname !~ '^pg_') AND (relname !~ '^pga_') AND (relname !~ '^sql_')))"))
+ {
+ for (pqxx::result::const_iterator c = m_res->begin(); c != m_res->end(); ++c)
+ {
+ // Copy the result into the return list
+ tableNames << QString::fromLatin1 (c[0].c_str());
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//==================================================================================
+//Convert a postgresql type to a kexi type
+KexiDB::Field::Type PqxxMigrate::type(int t, const QString& fname)
+{
+ switch(t)
+ {
+ case UNKNOWNOID:
+ return KexiDB::Field::InvalidType;
+ case BOOLOID:
+ return KexiDB::Field::Boolean;
+ case INT2OID:
+ return KexiDB::Field::ShortInteger;
+ case INT4OID:
+ return KexiDB::Field::Integer;
+ case INT8OID:
+ return KexiDB::Field::BigInteger;
+ case FLOAT4OID:
+ return KexiDB::Field::Float;
+ case FLOAT8OID:
+ return KexiDB::Field::Double;
+ case NUMERICOID:
+ return KexiDB::Field::Double;
+ case DATEOID:
+ return KexiDB::Field::Date;
+ case TIMEOID:
+ return KexiDB::Field::Time;
+ case TIMESTAMPOID:
+ return KexiDB::Field::DateTime;
+ case BYTEAOID:
+ return KexiDB::Field::BLOB;
+ case BPCHAROID:
+ return KexiDB::Field::Text;
+ case VARCHAROID:
+ return KexiDB::Field::Text;
+ case TEXTOID:
+ return KexiDB::Field::LongText;
+ }
+
+ //Ask the user what to do with this field
+ return userType(fname);
+}
+
+//==================================================================================
+//Connect to the db backend
+bool PqxxMigrate::drv_connect()
+{
+ kdDebug() << "drv_connect: " << m_migrateData->sourceName << endl;
+
+ QString conninfo;
+ QString socket;
+
+ //Setup local/remote connection
+ if (m_migrateData->source->hostName.isEmpty())
+ {
+ if (m_migrateData->source->fileName().isEmpty())
+ {
+ socket="/tmp/.s.PGSQL.5432";
+ }
+ else
+ {
+ socket=m_migrateData->source->fileName();
+ }
+ }
+ else
+ {
+ conninfo = "host='" + m_migrateData->source->hostName + "'";
+ }
+
+ //Build up the connection string
+ if (m_migrateData->source->port == 0)
+ m_migrateData->source->port = 5432;
+
+ conninfo += QString::fromLatin1(" port='%1'").arg(m_migrateData->source->port);
+
+ conninfo += QString::fromLatin1(" dbname='%1'").arg(m_migrateData->sourceName);
+
+ if (!m_migrateData->source->userName.isNull())
+ conninfo += QString::fromLatin1(" user='%1'").arg(m_migrateData->source->userName);
+
+ if (!m_migrateData->source->password.isNull())
+ conninfo += QString::fromLatin1(" password='%1'").arg(m_migrateData->source->password);
+
+ try
+ {
+ m_conn = new pqxx::connection( conninfo.latin1() );
+ return true;
+ }
+ catch(const std::exception &e)
+ {
+ kdDebug() << "PqxxMigrate::drv_connect:exception - " << e.what() << endl;
+ }
+ catch(...)
+ {
+ kdDebug() << "PqxxMigrate::drv_connect:exception(...)??" << endl;
+ }
+ return false;
+}
+
+//==================================================================================
+//Connect to the db backend
+bool PqxxMigrate::drv_disconnect()
+{
+ if (m_conn)
+ {
+ m_conn->disconnect();
+ delete m_conn;
+ m_conn = 0;
+ }
+ return true;
+}
+//==================================================================================
+//Perform a query on the database and store result in m_res
+bool PqxxMigrate::query(const QString& statement)
+{
+ kdDebug() << "query: " << statement.latin1() << endl;
+
+ Q_ASSERT (m_conn);
+
+ // Clear the last result information...
+ clearResultInfo ();
+
+ try
+ {
+ //Create a transaction
+ m_trans = new pqxx::nontransaction(*m_conn);
+ //Create a result opject through the transaction
+ m_res = new pqxx::result(m_trans->exec(statement.latin1()));
+ //Commit the transaction
+ m_trans->commit();
+ //If all went well then return true, errors picked up by the catch block
+ return true;
+ }
+ catch (const std::exception &e)
+ {
+ //If an error ocurred then put the error description into _dbError
+ kdDebug() << "pqxxImport::query:exception - " << e.what() << endl;
+ return false;
+ }
+ catch(...)
+ {
+ kdDebug() << "PqxxMigrate::query:exception(...)??" << endl;
+ }
+ return true;
+}
+
+//=========================================================================
+//Clears the current result
+void PqxxMigrate::clearResultInfo()
+{
+ delete m_res;
+ m_res = 0;
+
+ delete m_trans;
+ m_trans = 0;
+}
+
+//=========================================================================
+//Return the OID for a table
+pqxx::oid PqxxMigrate::tableOid(const QString& table)
+{
+ QString statement;
+ static QString otable;
+ static pqxx::oid toid;
+
+ pqxx::nontransaction* tran = 0;
+ pqxx::result* tmpres = 0;
+
+ //Some simple result caching
+ if (table == otable)
+ {
+ kdDebug() << "Returning table OID from cache..." << endl;
+ return toid;
+ }
+ else
+ {
+ otable = table;
+ }
+
+ try
+ {
+ statement = "SELECT relfilenode FROM pg_class WHERE (relname = '";
+ statement += table;
+ statement += "')";
+
+ tran = new pqxx::nontransaction(*m_conn, "find_t_oid");
+ tmpres = new pqxx::result(tran->exec(statement.latin1()));
+
+ tran->commit();
+ if (tmpres->size() > 0)
+ {
+ //We have a key field for this table, lets check if its this column
+ tmpres->at(0).at(0).to(toid);
+ }
+ else
+ {
+ toid = 0;
+ }
+ }
+ catch(const std::exception &e)
+ {
+ kdDebug() << "pqxxSqlDB::tableOid:exception - " << e.what() << endl;
+ kdDebug() << "pqxxSqlDB::tableOid:failed statement - " << statement << endl;
+ toid = 0;
+ }
+ catch(...)
+ {
+ kdDebug() << "PqxxMigrate::tableOid:exception(...)??" << endl;
+ }
+ delete tmpres;
+ tmpres = 0;
+
+ delete tran;
+ tran = 0;
+
+ kdDebug() << "OID for table [" << table << "] is [" << toid << "]" << endl;
+ return toid;
+}
+
+//=========================================================================
+//Return whether or not the curent field is a primary key
+//TODO: Add result caching for speed
+bool PqxxMigrate::primaryKey(pqxx::oid table_uid, int col) const
+{
+ QString statement;
+ bool pkey;
+ int keyf;
+
+ pqxx::nontransaction* tran = 0;
+ pqxx::result* tmpres = 0;
+
+ try
+ {
+ statement = QString("SELECT indkey FROM pg_index WHERE ((indisprimary = true) AND (indrelid = %1))").arg(table_uid);
+
+ tran = new pqxx::nontransaction(*m_conn, "find_pkey");
+ tmpres = new pqxx::result(tran->exec(statement.latin1()));
+
+ tran->commit();
+ if (tmpres->size() > 0)
+ {
+ //We have a key field for this table, lets check if its this column
+ tmpres->at(0).at(0).to(keyf);
+ if (keyf-1 == col) //-1 because pg counts from 1 and we count from 0
+ {
+ pkey = true;
+ kdDebug() << "Field is pkey" << endl;
+ }
+ else
+ {
+ pkey = false;
+ kdDebug() << "Field is NOT pkey" << endl;
+ }
+ }
+ else
+ {
+ pkey = false;
+ kdDebug() << "Field is NOT pkey" << endl;
+ }
+ }
+ catch(const std::exception &e)
+ {
+ kdDebug() << "pqxxSqlDB::primaryKey:exception - " << e.what() << endl;
+ kdDebug() << "pqxxSqlDB::primaryKey:failed statement - " << statement << endl;
+ pkey = false;
+ }
+ delete tmpres;
+ tmpres = 0;
+
+ delete tran;
+ tran = 0;
+
+ return pkey;
+}
+
+//=========================================================================
+/*! Fetches single string at column \a columnNumber from result obtained
+ by running \a sqlStatement.
+ On success the result is stored in \a string and true is returned.
+ \return cancelled if there are no records available. */
+tristate PqxxMigrate::drv_queryStringListFromSQL(
+ const QString& sqlStatement, uint columnNumber, QStringList& stringList, int numRecords)
+{
+ std::string result;
+ int i = 0;
+ if (query(sqlStatement))
+ {
+ for (pqxx::result::const_iterator it = m_res->begin();
+ it != m_res->end() && (numRecords == -1 || i < numRecords); ++it, i++)
+ {
+ if (it.size() > 0 && it.size() > columnNumber) {
+ it.at(columnNumber).to(result);
+ stringList.append( QString::fromUtf8(result.c_str()) );
+ }
+ else {
+ clearResultInfo();
+ return cancelled;
+ }
+ }
+ }
+ else
+ return false;
+ clearResultInfo();
+/* delete tmpres;
+ tmpres = 0;
+
+ delete tran;
+ tran = 0;*/
+
+ if (i < numRecords)
+ return cancelled;
+
+ return true;
+ /*
+ if (d->executeSQL(sqlStatement)) {
+ MYSQL_RES *res = mysql_use_result(d->mysql);
+ if (res != NULL) {
+ MYSQL_ROW row = mysql_fetch_row(res);
+ if (!row) {
+ tristate r = mysql_errno(d->mysql) ? false : cancelled;
+ mysql_free_result(res);
+ return r;
+ }
+ uint numFields = mysql_num_fields(res);
+ if (columnNumber > (numFields-1)) {
+ kdWarning() << "PqxxMigrate::drv_querySingleStringFromSQL("<<sqlStatement
+ << "): columnNumber too large ("
+ << columnNumber << "), expected 0.." << numFields << endl;
+ mysql_free_result(res);
+ return false;
+ }
+ unsigned long *lengths = mysql_fetch_lengths(res);
+ if (!lengths) {
+ mysql_free_result(res);
+ return false;
+ }
+ string = QString::fromLatin1(row[columnNumber], lengths[columnNumber]);
+ mysql_free_result(res);
+ } else {
+ kdDebug() << "PqxxMigrate::drv_querySingleStringFromSQL(): null result" << endl;
+ }
+ return true;
+ } else {
+ return false;
+ }*/
+}
+
+tristate PqxxMigrate::drv_fetchRecordFromSQL(const QString& sqlStatement,
+ KexiDB::RowData& data, bool &firstRecord)
+{
+ if (firstRecord || !m_res) {
+ if (m_res)
+ clearResultInfo();
+ if (!query(sqlStatement))
+ return false;
+ m_fetchRecordFromSQL_iter = m_res->begin();
+ firstRecord = false;
+ }
+ else
+ ++m_fetchRecordFromSQL_iter;
+
+ if (m_fetchRecordFromSQL_iter == m_res->end()) {
+ clearResultInfo();
+ return cancelled;
+ }
+
+ std::string result;
+ const int numFields = m_fetchRecordFromSQL_iter.size();
+ data.resize(numFields);
+ for (int i=0; i < numFields; i++)
+ data[i] = KexiDB::pgsqlCStrToVariant(m_fetchRecordFromSQL_iter.at(i));
+ return true;
+}
+
+//=========================================================================
+/*! Copy PostgreSQL table to KexiDB database */
+bool PqxxMigrate::drv_copyTable(const QString& srcTable, KexiDB::Connection *destConn,
+ KexiDB::TableSchema* dstTable)
+{
+ std::vector<std::string> R;
+
+ pqxx::work T(*m_conn, "PqxxMigrate::drv_copyTable");
+
+ pqxx::tablereader stream(T, (srcTable.latin1()));
+
+ //Loop round each row, reading into a vector of strings
+ const KexiDB::QueryColumnInfo::Vector fieldsExpanded( dstTable->query()->fieldsExpanded() );
+ for (int n=0; (stream >> R); ++n)
+ {
+ QValueList<QVariant> vals;
+ std::vector<std::string>::const_iterator i, end( R.end() );
+ int index = 0;
+ for ( i = R.begin(); i != end; ++i, index++) {
+ if (fieldsExpanded.at(index)->field->type()==KexiDB::Field::BLOB || fieldsExpanded.at(index)->field->type()==KexiDB::Field::LongText)
+ vals.append( KexiDB::pgsqlByteaToByteArray((*i).c_str(), (*i).size()) );
+ else
+ vals.append( KexiDB::cstringToVariant((*i).c_str(),
+ fieldsExpanded.at(index)->field, (*i).size()) );
+ }
+ if (!destConn->insertRecord(*dstTable, vals))
+ return false;
+ updateProgress();
+ R.clear();
+ }
+
+ //This does not work in <libpqxx 2.2
+ //stream.complete();
+
+ return true;
+}
+
+//=========================================================================
+//Return whether or not the curent field is a primary key
+//TODO: Add result caching for speed
+bool PqxxMigrate::uniqueKey(pqxx::oid table_uid, int col) const
+{
+ QString statement;
+ bool ukey;
+ int keyf;
+
+ pqxx::nontransaction* tran = 0;
+ pqxx::result* tmpres = 0;
+
+ try
+ {
+ statement = QString("SELECT indkey FROM pg_index WHERE ((indisunique = true) AND (indrelid = %1))").arg(table_uid);
+
+ tran = new pqxx::nontransaction(*m_conn, "find_ukey");
+ tmpres = new pqxx::result(tran->exec(statement.latin1()));
+
+ tran->commit();
+ if (tmpres->size() > 0)
+ {
+ //We have a key field for this table, lets check if its this column
+ tmpres->at(0).at(0).to(keyf);
+ if (keyf-1 == col) //-1 because pg counts from 1 and we count from 0
+ {
+ ukey = true;
+ kdDebug() << "Field is unique" << endl;
+ }
+ else
+ {
+ ukey = false;
+ kdDebug() << "Field is NOT unique" << endl;
+ }
+ }
+ else
+ {
+ ukey = false;
+ kdDebug() << "Field is NOT unique" << endl;
+ }
+ }
+ catch(const std::exception &e)
+ {
+ kdDebug() << "uniqueKey:exception - " << e.what() << endl;
+ kdDebug() << "uniqueKey:failed statement - " << statement << endl;
+ ukey = false;
+ }
+
+ delete tmpres;
+ tmpres = 0;
+
+ delete tran;
+ tran = 0;
+
+ return ukey;
+}
+
+//==================================================================================
+//TODO::Implement
+bool PqxxMigrate::autoInc(pqxx::oid /*table_uid*/, int /*col*/) const
+{
+ return false;
+}
+
+//==================================================================================
+//TODO::Implement
+bool PqxxMigrate::notNull(pqxx::oid /*table_uid*/, int /*col*/) const
+{
+ return false;
+}
+
+//==================================================================================
+//TODO::Implement
+bool PqxxMigrate::notEmpty(pqxx::oid /*table_uid*/, int /*col*/) const
+{
+ return false;
+}
+
+//==================================================================================
+//Return a list of database names
+/*bool PqxxMigrate::drv_getDatabasesList( QStringList &list )
+{
+ KexiDBDrvDbg << "pqxxSqlConnection::drv_getDatabaseList" << endl;
+
+ if (executeSQL("SELECT datname FROM pg_database WHERE datallowconn = TRUE"))
+ {
+ std::string N;
+ for (pqxx::result::const_iterator c = m_res->begin(); c != m_res->end(); ++c)
+ {
+ // Read value of column 0 into a string N
+ c[0].to(N);
+ // Copy the result into the return list
+ list << QString::fromLatin1 (N.c_str());
+ KexiDBDrvDbg << N.c_str() << endl;
+ }
+ return true;
+ }
+
+ return false;
+}*/
+
+
+#include "pqxxmigrate.moc"
diff --git a/kexi/migration/pqxx/pqxxmigrate.h b/kexi/migration/pqxx/pqxxmigrate.h
new file mode 100644
index 00000000..c09c8a7a
--- /dev/null
+++ b/kexi/migration/pqxx/pqxxmigrate.h
@@ -0,0 +1,120 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Adam Pigg <[email protected]>
+ Copyright (C) 2006 Jaroslaw Staniek <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PQXXIMPORT_H
+#define PQXXIMPORT_H
+
+#include <migration/keximigrate.h>
+
+//Kexi Includes
+#include <kexidb/field.h>
+#include <kexidb/connection.h>
+
+#include <pqxx/pqxx>
+
+namespace KexiMigration
+{
+ class PqxxMigrate : public KexiMigrate
+ {
+ Q_OBJECT
+ KEXIMIGRATION_DRIVER
+
+ public:
+ PqxxMigrate(QObject *parent, const char *name, const QStringList &args = QStringList());
+ virtual ~PqxxMigrate();
+
+ protected:
+ //Driver specific function to return table names
+ virtual bool drv_tableNames(QStringList& tablenames);
+
+ //Driver specific implementation to read a table schema
+ virtual bool drv_readTableSchema(
+ const QString& originalName, KexiDB::TableSchema& tableSchema);
+
+ //Driver specific connection implementation
+ virtual bool drv_connect();
+ virtual bool drv_disconnect();
+
+ virtual tristate drv_queryStringListFromSQL(
+ const QString& sqlStatement, uint columnNumber, QStringList& stringList,
+ int numRecords = -1);
+
+ /*! Fetches single record from result obtained
+ by running \a sqlStatement.
+ \a firstRecord should be first initialized to true, so the method can run
+ the query at first call and then set it will set \a firstRecord to false,
+ so subsequent calls will only fetch records.
+ On success the result is stored in \a data and true is returned,
+ \a data is resized to appropriate size. cancelled is returned on EOF. */
+//! @todo SQL-dependent!
+ virtual tristate drv_fetchRecordFromSQL(const QString& sqlStatement,
+ KexiDB::RowData& data, bool &firstRecord);
+
+ virtual bool drv_copyTable(const QString& srcTable,
+ KexiDB::Connection *destConn, KexiDB::TableSchema* dstTable);
+
+ private:
+ //lowlevel functions/objects
+ //database connection
+ pqxx::connection* m_conn;
+
+ //transaction
+ pqxx::nontransaction* m_trans;
+
+ //lowlevel result
+ pqxx::result* m_res;
+
+ //! Used in drv_fetchRecordFromSQL
+ pqxx::result::const_iterator m_fetchRecordFromSQL_iter;
+
+ //perform a query on the database
+ bool query(const QString& statement);
+
+ //Clear the result info
+ void clearResultInfo ();
+
+ pqxx::oid tableOid(const QString& tablename);
+
+ //Convert the pqxx type to a kexi type
+ KexiDB::Field::Type type(int t, const QString& fname);
+
+ //Find out the field constraints
+ //Return whether or not the field is a pkey
+ bool primaryKey(pqxx::oid table, int col) const;
+
+ //Return whether or not the field is unique
+ bool uniqueKey(pqxx::oid table, int col) const;
+
+ //Return whether or not the field is a foreign key
+ bool foreignKey(pqxx::oid table, int col) const;
+
+ //Return whether or not the field is not null
+ bool notNull(pqxx::oid table, int col) const;
+
+ //Return whether or not the field is not empty
+ bool notEmpty(pqxx::oid table, int col) const;
+
+ //Return whether or not the field is auto incrementing
+ bool autoInc(pqxx::oid table, int col) const;
+
+ };
+}
+
+#endif
diff --git a/kexi/migration/txt/Makefile.am b/kexi/migration/txt/Makefile.am
new file mode 100644
index 00000000..46964222
--- /dev/null
+++ b/kexi/migration/txt/Makefile.am
@@ -0,0 +1,18 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+kde_module_LTLIBRARIES = keximigrate_txtmigrate.la
+
+INCLUDES = -I$(srcdir)/../../.. -I$(top_srcdir)/kexi $(all_includes)
+
+keximigrate_txtmigrate_la_METASOURCES = AUTO
+
+keximigrate_txtmigrate_la_SOURCES = txtmigrate.cpp
+
+keximigrate_txtmigrate_la_LIBADD = $(LIB_KPARTS) $(LIB_QT) ../libkeximigrate.la
+
+keximigrate_txtmigrate_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(VER_INFO) -no-undefined
+
+kde_services_DATA = keximigrate_txtmigrate.desktop
+
+noinst_HEADERS = txtmigrate.h
+
diff --git a/kexi/migration/txt/txtmigrate.cpp b/kexi/migration/txt/txtmigrate.cpp
new file mode 100644
index 00000000..8109a5b1
--- /dev/null
+++ b/kexi/migration/txt/txtmigrate.cpp
@@ -0,0 +1,27 @@
+//
+// C++ Implementation: txtmigrate
+//
+// Description:
+//
+//
+// Author: Adam Pigg <[email protected]>, (C) 2004
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "txtmigrate.h"
+
+namespace KexiMigration {
+
+TxtMigrate::TxtMigrate()
+ : KexiMigrate()
+{
+}
+
+
+TxtMigrate::~TxtMigrate()
+{
+}
+
+
+};
diff --git a/kexi/migration/txt/txtmigrate.h b/kexi/migration/txt/txtmigrate.h
new file mode 100644
index 00000000..e4b830c0
--- /dev/null
+++ b/kexi/migration/txt/txtmigrate.h
@@ -0,0 +1,33 @@
+//
+// C++ Interface: txtmigrate
+//
+// Description:
+//
+//
+// Author: Adam Pigg <[email protected]>, (C) 2004
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef KEXIMIGRATIONTXTMIGRATE_H
+#define KEXIMIGRATIONTXTMIGRATE_H
+
+#include <keximigrate.h>
+
+namespace KexiMigration {
+
+/**
+@author Adam Pigg
+*/
+class TxtMigrate : public KexiMigrate
+{
+public:
+ TxtMigrate();
+
+ ~TxtMigrate();
+
+};
+
+};
+
+#endif