File indexing completed on 2024-05-12 16:40:15

0001 /* This file is part of the KDE project
0002    Copyright (C) 2004 Adam Pigg <adam@piggz.co.uk>
0003    Copyright (C) 2004-2016 Jarosław Staniek <staniek@kde.org>
0004    Copyright (C) 2005 Martin Ellis <martin.ellis@kdemail.net>
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This program is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this program; see the file COPYING.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #ifndef KEXI_MIGRATE_H
0023 #define KEXI_MIGRATE_H
0024 
0025 #include "keximigratedata.h"
0026 #include "KexiVersion.h"
0027 
0028 #include <KDbConnection>
0029 #include <KDbSqlRecord>
0030 #include <KDbTableSchema>
0031 
0032 #include <QVariantList>
0033 
0034 class KDbConnectionProxy;
0035 
0036 namespace Kexi
0037 {
0038 class ObjectStatus;
0039 }
0040 class KexiMigratePluginMetaData;
0041 
0042 /*! KexiMigration implementation version.
0043  It is altered after every change:
0044  - major number is increased after incompatible change ofthe plugin interface/behavior
0045  - minor number is increased after minor changes
0046  @note Do not use these constants to get library version information in external code.
0047        Use KexiMigratePluginMetaData::*version() functions instead.
0048 */
0049 #define KEXI_MIGRATION_VERSION_MAJOR KEXI_STABLE_VERSION_MAJOR
0050 #define KEXI_MIGRATION_VERSION_MINOR KEXI_STABLE_VERSION_MINOR
0051 
0052 /*!
0053  * \namespace KexiMigration
0054  * \brief Framework for importing databases into native KDb databases.
0055  */
0056 namespace KexiMigration
0057 {
0058 
0059 //! \return KexiMigration library version info
0060 KEXIMIGRATE_EXPORT KDbVersionInfo version();
0061 
0062 //! @short A base class for a migrate plugin that imports native databases into Kexi projects
0063 /*! A generic API for importing schema and data from an existing
0064 database into a new Kexi project. Can be also used for importing native Kexi databases.
0065 
0066 Basic idea is this:
0067 -# User selects an existing DB and new project (file or server based)
0068 -# User specifies whether to import structure and data or structure only.
0069 -# Import tool connects to db
0070 -# Checks if it is already a kexi project (not implemented yet)
0071 -# If not, then read structure and construct new project
0072 -# Ask user what to do if column type is not supported
0073 
0074 See kexi/doc/dev/kexi_import.txt for more info.
0075 */
0076 class KEXIMIGRATE_EXPORT KexiMigrate : public QObject, public KDbResultable
0077 {
0078     Q_OBJECT
0079 
0080 public:
0081     virtual ~KexiMigrate();
0082 
0083     //! Info about the driver's plugin
0084     const KexiMigratePluginMetaData* metaData() const;
0085 
0086 //! @todo Remove this! KexiMigrate should be usable for multiple concurrent migrations!
0087     KexiMigration::Data* data();
0088 
0089 //! @todo Remove this! KexiMigrate should be usable for multiple concurrent migrations!
0090     //! Data Setup.  Requires two connection objects, a name and a bool
0091     //! Ownership of @a migrateData is transferred to the KexiMigrate object.
0092     //! Any previous data is removed if it is different than @a migrateData.
0093     void setData(KexiMigration::Data* migrateData);
0094 
0095     /*! Checks whether the destination database exists.
0096      For file-based dest. projects, we've already asked about overwriting
0097      existing project but for server-based projects it's better to ask user.
0098      This method should be called before performImport() or performExport().
0099 
0100      \return true if no connection-related errors occurred.
0101      \a acceptingNeeded is set to true if destination database exists.
0102      In this case you should ask about accepting database overwriting.
0103      Used in ImportWizard::import(). */
0104     bool checkIfDestinationDatabaseOverwritingNeedsAccepting(Kexi::ObjectStatus* result,
0105             bool* acceptingNeeded);
0106 
0107     /*! Checks if the source- and the destination databases are identical.
0108     \return true if they are identical else false. */
0109     bool isSourceAndDestinationDataSourceTheSame() const;
0110 
0111     //! Connects, perform an import operation, and disconnects
0112     bool performImport(Kexi::ObjectStatus* result = 0);
0113 
0114     //! Perform an export operation
0115     bool performExport(Kexi::ObjectStatus* result = 0);
0116 
0117     //! Returns true if the migration driver supports progress updates.
0118     inline bool progressSupported() {
0119         return drv_progressSupported();
0120     }
0121 
0122 //! @todo This is copied from KDbDriver. One day it will be merged with KDb.
0123     //! \return property value for \a propertyName available for this driver.
0124     //! If there's no such property defined for driver, Null QVariant value is returned.
0125     virtual QVariant propertyValue(const QByteArray& propertyName);
0126 
0127 //! @todo This is copied from KDbDriver. One day it will be merged with KDb.
0128     void setPropertyValue(const QByteArray& propertyName, const QVariant& value);
0129 
0130 //! @todo This is copied from KDbDriver. One day it will be merged with KDb.
0131     //! \return translated property caption for \a propertyName.
0132     //! If there's no such property defined for driver, empty string value is returned.
0133     QString propertyCaption(const QByteArray& propertyName) const;
0134 
0135     //! @todo This is copied from KDbDriver. One day it will be merged with KDb.
0136     //! Set translated property caption for \a propertyName.
0137     void setPropertyCaption(const QByteArray& propertyName, const QString &caption);
0138 
0139 //! @todo This is copied from KDbDriver. One day it will be merged with KDb.
0140     //! \return a list of property names available for this driver.
0141     QList<QByteArray> propertyNames() const;
0142 
0143     //! Extension of existing API to provide generic row access to external data for ImportTableWizard.
0144     //! @todo refactor
0145     bool connectSource(Kexi::ObjectStatus* result);
0146 
0147     //! Extension of existing API to close connection for ImportTableWizard.
0148     //! @todo refactor
0149     bool disconnectSource();
0150 
0151     //! Get table names in source database (driver specific)
0152     bool tableNames(QStringList *tablenames);
0153 
0154     //! Read schema for a given table (driver specific)
0155     bool readTableSchema(const QString& originalName, KDbTableSchema *tableSchema);
0156 
0157     //! Starts reading data from the source dataset's table
0158     QSharedPointer<KDbSqlResult> readFromTable(const QString& tableName);
0159 
0160     //!Move to the next row
0161     bool moveNext();
0162 
0163     //!Move to the previous row
0164     bool movePrevious();
0165 
0166     //!Move to the next row
0167     bool moveFirst();
0168 
0169     //!Move to the previous row
0170     bool moveLast();
0171 
0172     //!Read the data at the given row/field
0173     QVariant value(int i);
0174 
0175 Q_SIGNALS:
0176     void progressPercent(int percent);
0177 
0178 protected:
0179     //! Used by MigrateManager.
0180     explicit KexiMigrate(QObject *parent, const QVariantList &args = QVariantList());
0181 
0182     /*! Used by the migration driver manager to set metaData for just loaded driver. */
0183     void setMetaData(const KexiMigratePluginMetaData *metaData);
0184 
0185     //! Creates connection to source database and connects.
0186     //! If it is a database supported by low-level routines of KDb, sourceConnection() will
0187     //! be available afterwards.
0188     //! If not, connectInternal() can still return true but sourceConnection() will return
0189     //! @c nullptr.
0190     //! @see drv_createConnection() drv_connect()
0191     bool connectInternal(Kexi::ObjectStatus* result);
0192 
0193     //! Disconnects from source database. If it is a database supported by low-level routines
0194     //! of KDb, destroys the connection object pointed by sourceConnection() too.
0195     //! @return true on success.
0196     //! @see drv_disconnect() connectInternal()
0197     bool disconnectInternal();
0198 
0199     //! @return connection to source database if it is a database supported by low-level
0200     //! routines of KDb. In other cases such as importing from a TSV file, this function
0201     //! returns @c nullptr.
0202     KDbConnectionProxy* sourceConnection();
0203 
0204     //! Migration drivers that use low-level routines KDb to access the source database
0205     //! should create and return a driver-specific KDbConnection object that handles
0206     //! connection to the source database.
0207     //! Migration drivers that use custom data sources (not KDb-compatible) should return
0208     //! @c nullptr.
0209     //! @note KexiMigrate::m_result should be set to a result of the operation.
0210     virtual KDbConnection* drv_createConnection() = 0;
0211 
0212     //! Connects to source database using (driver specific).
0213     //! Default implementation calls sourceConnection()->drv_connect() and if it succeeds,
0214     //! it calls sourceConnection()->drv_useDatabase(data()->sourceName), then returns
0215     //! the result. If this is enough for connecting for a migration driver, there is no need
0216     //! to reimplement drv_connect().
0217     //! If sourceConnection() is @c nullptr (custom types of sources),
0218     //! default implementation just returns @c false. In this case drv_connect() should
0219     //! be implemented.
0220     virtual bool drv_connect();
0221 
0222     //! Disconnect from source database (driver specific).
0223     //! If the source database is supported by low-level routines KDb,
0224     //! KDbConnection::disconnect() is called for this connection.
0225     //! For other types of sources @c false is returned so in these cases this method
0226     //! should be reimplemented.
0227     virtual bool drv_disconnect();
0228 
0229     //! Get table names in source database (driver specific)
0230     /*! @return List of table names available for this connection.
0231      The names are in lower case. The method should return true only if there was no
0232      error on getting database names list from the server. */
0233     virtual bool drv_tableNames(QStringList *tablenames) = 0;
0234 
0235     //! Read schema for a given table (driver specific)
0236     virtual bool drv_readTableSchema(
0237         const QString& originalName, KDbTableSchema *tableSchema) = 0;
0238 
0239     /*! Fetches maximum number from table \a tableName, column \a columnName
0240      into \a result. On success true is returned. If there is no records in the table,
0241      \a result is set to 0 and true is returned.
0242      - Note 1: implement only if the database can already contain kexidb__* tables
0243        (so e.g. keximdb driver doea not need this).
0244      - Note 2: default implementation uses drv_querySingleStringFromSql()
0245        with "SELECT MAX(columName) FROM tableName" statement, assuming SQL-compliant
0246        backend.
0247     */
0248     virtual bool drv_queryMaxNumber(const QString& tableName,
0249                                     const QString& columnName, int *result);
0250 
0251     /*! Fetches single string at column \a columnNumber for each record from result obtained
0252      by running \a sqlStatement. \a numRecords can be specified to limit number of records read.
0253      If \a numRecords is -1, all records are loaded.
0254      On success the result is stored in \a stringList and true is returned.
0255      \return cancelled if there are no records available.
0256      - Note: implement only if the database can already contain kexidb__* tables
0257       (so e.g. keximdb driver does not need this). */
0258 //! @todo SQL-dependent!
0259     virtual tristate drv_queryStringListFromSql(
0260         const KDbEscapedString& sqlStatement, int columnNumber, QStringList *stringList,
0261         int numRecords = -1)
0262     {
0263         Q_UNUSED(sqlStatement); Q_UNUSED(columnNumber); Q_UNUSED(stringList);
0264         Q_UNUSED(numRecords);
0265         return cancelled;
0266     }
0267 
0268     /*! Fetches single string at column \a columnNumber from result obtained
0269      by running \a sqlStatement.
0270      On success the result is stored in \a string and true is returned.
0271      \return cancelled if there are no records available.
0272      This implementation uses drv_queryStringListFromSql() with numRecords == 1. */
0273 //! @todo SQL-dependent!
0274     virtual tristate drv_querySingleStringFromSql(const KDbEscapedString& sqlStatement,
0275             int columnNumber, QString *string);
0276 
0277     //! A functor for filtering records
0278     //! @see drv_copyTable()
0279     class RecordFilter {
0280     public:
0281         RecordFilter() {}
0282         virtual ~RecordFilter() {}
0283         virtual bool operator() (const QSharedPointer<KDbSqlRecord> &record) const = 0;
0284         virtual bool operator() (const QList<QVariant> &record) const = 0;
0285     };
0286 
0287     //! Copy a table from source DB to target DB (driver specific)
0288     //! - create copies of KDb tables
0289     //! - create copies of non-KDb tables
0290     virtual bool drv_copyTable(const QString& srcTable, KDbConnection *destConn,
0291                                KDbTableSchema* dstTable,
0292                                const RecordFilter *recordFilter = nullptr) = 0;
0293 
0294     virtual bool drv_progressSupported() {
0295         return false;
0296     }
0297 
0298     /*! \return the size of a table to be imported, or 0 if not supported
0299       Finds the size of the named table, in order to provide feedback on
0300       migration progress.
0301 
0302       The units of the return type are deliberately unspecified.  Migration
0303       drivers may return the number of records in the table, or the size in
0304       bytes, etc.  Units should be chosen in order that the driver can
0305       return the size in the fastest way possible (e.g. migration from CSV
0306       files should use file size to avoid counting the number of rows, and
0307       migration from MDB files should return the number of rows as this is
0308       stored within the file).
0309 
0310       Obviously, the driver should use the same units when reporting
0311       migration progress.
0312 
0313       \return size of the specified table
0314     */
0315     virtual bool drv_getTableSize(const QString&, quint64*) {
0316         return false;
0317     }
0318 
0319     void updateProgress(quint64 step = 1ULL);
0320 
0321 //! @todo user should be asked ONCE using a convenient wizard's page, not a popup dialog
0322     //! Prompt user to select a field type for unrecognized fields
0323     KDbField::Type userType(const QString& fname);
0324 
0325     virtual QString drv_escapeIdentifier(const QString& str) const;
0326 
0327     //Extended API
0328     //! Position the source dataset at the start of a table
0329     virtual QSharedPointer<KDbSqlResult> drv_readFromTable(const QString & tableName) {
0330       Q_UNUSED(tableName);
0331       return QSharedPointer<KDbSqlResult>();
0332     }
0333 
0334     //! Move to the next row
0335     virtual bool drv_moveNext() { return false; }
0336 
0337     //! Move to the previous row
0338     virtual bool drv_movePrevious() { return false; }
0339 
0340     //! Move to the next row
0341     virtual bool drv_moveFirst() { return false; }
0342 
0343     //! Move to the previous row
0344     virtual bool drv_moveLast() { return false; }
0345 
0346     //! Read the data at the given row/field
0347     virtual QVariant drv_value(int i) { Q_UNUSED(i); return QVariant(); };
0348 
0349     //! @return Database driver for this migration.
0350     KDbDriver *driver();
0351 
0352     //! Sets database driver for this migration.
0353     void setDriver(KDbDriver *driver);
0354 
0355 private:
0356     /*! Estimate size of migration job
0357      Calls drv_getTableSize for each table to be copied.
0358      \return sum of the size of all tables to be copied.
0359     */
0360     bool progressInitialise();
0361 
0362     //! Perform an import operation. It is assumed that source connection is established.
0363     //! @see performImport()
0364     bool performImportInternal(Kexi::ObjectStatus* result);
0365 
0366     //! Reads schema for table @a tableName from kexi__objects and kexi__fields.
0367     //! On success:
0368     //! - copies one record from the original kexi__objects table to the destination
0369     //!   database's table kexi__objects
0370     //! - copies all related records from the original kexi__fields table to the destination
0371     //!   database's table kexi__fields
0372     bool importTable(const QString& tableName, KDbConnectionProxy *destConn);
0373 
0374     class Private;
0375     Private * const d;
0376 
0377     friend class MigrateManager;
0378     friend class MigrateManagerInternal;
0379 };
0380 
0381 } //namespace KexiMigration
0382 
0383 #endif