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

0001 /* This file is part of the KDE project
0002    Copyright (C) 2004 Martin Ellis <m.a.ellis@ncl.ac.uk>
0003    Copyright (C) 2006-2016 Jarosław Staniek <staniek@kde.org>
0004 
0005    This program is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This program is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this program; see the file COPYING.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "KexiSqlMigrate.h"
0022 #include <keximigratedata.h>
0023 #include <kexi.h>
0024 
0025 #include <KDbDriverManager>
0026 #include <KDbConnectionProxy>
0027 #include <KDbSqlResult>
0028 #include <KDbSqlString>
0029 #include <KDbQueryColumnInfo>
0030 #include <KDbQuerySchema>
0031 
0032 KexiSqlMigrate::KexiSqlMigrate(const QString &kdbDriverId, QObject *parent,
0033                                const QVariantList& args)
0034         : KexiMigration::KexiMigrate(parent, args)
0035         , m_kdbDriverId(kdbDriverId)
0036 {
0037     Q_ASSERT(!m_kdbDriverId.isEmpty());
0038 }
0039 
0040 KexiSqlMigrate::~KexiSqlMigrate()
0041 {
0042 }
0043 
0044 KDbConnection* KexiSqlMigrate::drv_createConnection()
0045 {
0046     KDbDriverManager manager;
0047     KDbDriver *driver = manager.driver(m_kdbDriverId);
0048     if (!driver) {
0049         m_result = manager.result();
0050         return nullptr;
0051     }
0052     KDbConnection *c = driver->createConnection(*data()->source);
0053     m_result = c ? KDbResult() : driver->result();
0054     return c;
0055 }
0056 
0057 bool KexiSqlMigrate::drv_readTableSchema(
0058     const QString& originalName, KDbTableSchema *tableSchema)
0059 {
0060 //! @todo IDEA: ask for user input for captions
0061 
0062     //Perform a query on the table to get some data
0063     KDbEscapedString sql = KDbEscapedString("SELECT * FROM %1 LIMIT 0")
0064             .arg(sourceConnection()->escapeIdentifier(tableSchema->name()));
0065     QSharedPointer<KDbSqlResult> result = sourceConnection()->prepareSql(sql);
0066     if (!result) {
0067         return false;
0068     }
0069 
0070     bool ok = true;
0071     const int fieldsCount = result->fieldsCount();
0072     for (int i = 0; i < fieldsCount; i++) {
0073         KDbField *field = result->createField(originalName, i);
0074         if (field->type() == KDbField::InvalidType) {
0075             field->setType(userType(originalName + '.' + field->name()));
0076         }
0077         if (!tableSchema->addField(field)) {
0078             delete field;
0079             tableSchema->clear();
0080             ok = false;
0081             break;
0082         }
0083     }
0084     return ok;
0085 }
0086 
0087 bool KexiSqlMigrate::drv_tableNames(QStringList *tableNames)
0088 {
0089     bool ok;
0090     *tableNames = sourceConnection()->drv_getTableNames(&ok);
0091     return ok;
0092 }
0093 
0094 tristate KexiSqlMigrate::drv_queryStringListFromSql(
0095     const KDbEscapedString& sqlStatement, int fieldIndex, QStringList *stringList, int numRecords)
0096 {
0097     QSharedPointer<KDbSqlResult> result= sourceConnection()->prepareSql(sqlStatement);
0098     if (!result) {
0099         return true;
0100     }
0101     if (result->fieldsCount() < (fieldIndex+1)) {
0102         qWarning() << sqlStatement << ": fieldIndex too large ("
0103                    << fieldIndex << "), expected 0.." << result->fieldsCount() - 1;
0104         return false;
0105     }
0106     for (int i = 0; numRecords == -1 || i < numRecords; i++) {
0107         QSharedPointer<KDbSqlRecord> record = result->fetchRecord();
0108         if (!record) {
0109             if (numRecords != -1 || result->lastResult().isError()) {
0110                 return false;
0111             }
0112             return true;
0113         }
0114         stringList->append(record->stringValue(fieldIndex));
0115     }
0116     return true;
0117 }
0118 
0119 bool KexiSqlMigrate::drv_copyTable(const QString& srcTable, KDbConnection *destConn,
0120                                  KDbTableSchema* dstTable,
0121                                  const RecordFilter *recordFilter)
0122 {
0123     QSharedPointer<KDbSqlResult> result = sourceConnection()->prepareSql(
0124         KDbEscapedString("SELECT * FROM %1").arg(sourceConnection()->escapeIdentifier(srcTable)));
0125     if (!result) {
0126         return false;
0127     }
0128     const KDbQueryColumnInfo::Vector fieldsExpanded(dstTable->query()->fieldsExpanded(destConn));
0129     const int numFields = qMin(fieldsExpanded.count(), result->fieldsCount());
0130     Q_FOREVER {
0131         QSharedPointer<KDbSqlRecord> record = result->fetchRecord();
0132         if (!record) {
0133             if (!result->lastResult().isError()) {
0134                 break;
0135             }
0136             return false;
0137         }
0138         if (recordFilter) {
0139             if (!(*recordFilter)(record)) {
0140                 continue;
0141             }
0142         }
0143         QList<QVariant> vals;
0144         for(int i = 0; i < numFields; ++i) {
0145             const KDbSqlString s(record->cstringValue(i));
0146             vals.append(KDb::cstringToVariant(
0147                             s.string, fieldsExpanded.at(i)->field()->type(), 0, s.length));
0148         }
0149         updateProgress();
0150         if (recordFilter) {
0151             if (!(*recordFilter)(vals)) {
0152                 continue;
0153             }
0154         }
0155         if (!destConn->insertRecord(dstTable, vals)) {
0156             return false;
0157         }
0158     }
0159     /*! @todo Check that wasn't an error, rather than end of result set */
0160     return true;
0161 }
0162 
0163 bool KexiSqlMigrate::drv_getTableSize(const QString& table, quint64 *size)
0164 {
0165     Q_ASSERT(size);
0166     QSharedPointer<KDbSqlResult> result
0167         = sourceConnection()->prepareSql(KDbEscapedString("SELECT COUNT(*) FROM %1")
0168                                              .arg(sourceConnection()->escapeIdentifier(table)));
0169     if (!result) {
0170         return false;
0171     }
0172     QSharedPointer<KDbSqlRecord> record = result->fetchRecord();
0173     if (!result || result->fieldsCount() == 0) {
0174         return false;
0175     }
0176     bool ok;
0177     quint64 value = record->toByteArray(0).toULongLong(&ok);
0178     if (!ok) {
0179         value = -1;
0180     }
0181     *size = value;
0182     return ok;
0183 }
0184 
0185 QSharedPointer<KDbSqlResult> KexiSqlMigrate::drv_readFromTable(const QString& tableName)
0186 {
0187     QSharedPointer<KDbSqlResult> result = sourceConnection()->prepareSql(
0188         KDbEscapedString("SELECT * FROM %1").arg(sourceConnection()->escapeIdentifier(tableName)));
0189     if (!result || result->lastResult().isError()) {
0190         m_result = sourceConnection()->result();
0191         qWarning() << m_result;
0192         result.clear();
0193     }
0194     return result;
0195 }