~ubuntu-branches/debian/sid/kexi/sid

« back to all changes in this revision

Viewing changes to src/migration/xbase/xbasemigrate.cpp

  • Committer: Package Import Robot
  • Author(s): Pino Toscano
  • Date: 2017-06-24 20:10:10 UTC
  • Revision ID: package-import@ubuntu.com-20170624201010-5lrzd5r2vwthwifp
Tags: upstream-3.0.1.1
ImportĀ upstreamĀ versionĀ 3.0.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the KDE project
 
2
   Copyright (C) 2008 Sharan Rao <sharanrao@gmail.com>
 
3
 
 
4
   This program is free software; you can redistribute it and/or
 
5
   modify it under the terms of the GNU Library General Public
 
6
   License as published by the Free Software Foundation; either
 
7
   version 2 of the License, or (at your option) any later version.
 
8
 
 
9
   This program is distributed in the hope that it will be useful,
 
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the GNU
 
12
   Library General Public License for more details.
 
13
 
 
14
   You should have received a copy of the GNU Library General Public License
 
15
   along with this program; see the file COPYING.  If not, write to
 
16
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
17
 * Boston, MA 02110-1301, USA.
 
18
*/
 
19
 
 
20
#include "xbasemigrate.h"
 
21
#include <migration/keximigratedata.h>
 
22
#include <kexi.h>
 
23
 
 
24
#include <KDbCursor>
 
25
#include <KDbField>
 
26
#include <KDbUtils>
 
27
#include <KDbDriverManager>
 
28
#include <KDb>
 
29
 
 
30
#include <QString>
 
31
#include <QVariant>
 
32
#include <QList>
 
33
#include <QDir>
 
34
#include <QDebug>
 
35
 
 
36
using namespace KexiMigration;
 
37
 
 
38
/* This is the implementation for the xBase specific import routines. */
 
39
KEXI_PLUGIN_FACTORY(xBaseMigrate, "keximigrate_xbase.json")
 
40
 
 
41
//! Constructor (needed for trading interface)
 
42
xBaseMigrate::xBaseMigrate(QObject *parent, const QVariantList& args) :
 
43
  KexiMigrate(parent, args)
 
44
{
 
45
  KDbDriverManager manager;
 
46
  setDriver(manager.driver("xbase"));
 
47
}
 
48
 
 
49
/* ************************************************************************** */
 
50
//! Destructor
 
51
xBaseMigrate::~xBaseMigrate()
 
52
{
 
53
}
 
54
 
 
55
 
 
56
/* ************************************************************************** */
 
57
/*! Connect to the db backend */
 
58
bool xBaseMigrate::drv_connect()
 
59
{
 
60
  // Get the xbase directory path
 
61
  Data* migrationData = data();
 
62
  KDbConnectionData* dataSource = migrationData->source;
 
63
  QString dbPath = dataSource->dbPath();
 
64
 
 
65
  QDir xBaseDirectory( dbPath );
 
66
 
 
67
  // set filters
 
68
  QStringList dbfFilters;
 
69
//! @todo use application/x-dbase mime type as soon as share mime db provides info on file extensions
 
70
  dbfFilters<<"*.dbf"<<"*.DBF";
 
71
 
 
72
  xBaseDirectory.setNameFilters( dbfFilters );
 
73
  QStringList dbfFiles = xBaseDirectory.entryList(); // set a readable files filter here ?
 
74
 
 
75
  foreach( const QString& fileName, dbfFiles ) {
 
76
    xbDbf* table = new xbDbf( this );
 
77
    // Calling OpenDatabase, will automatically add the pointer `table`
 
78
    // to the dbfList of xbXBase class ( if there is no error )
 
79
    QString absoluteFileName = xBaseDirectory.filePath( fileName );
 
80
 
 
81
    // remove the letters '.dbf'. Hence the -4
 
82
    QString choppedFileName = fileName.left( fileName.length() - 4 ).toLower();
 
83
    m_tableNamePathMap[choppedFileName] = absoluteFileName;
 
84
    qDebug()<<choppedFileName<<" Path:"<<absoluteFileName;
 
85
 
 
86
    int returnCode;
 
87
    QByteArray ba = absoluteFileName.toUtf8();
 
88
    if (  ( returnCode = table->OpenDatabase( ba.constData() ) ) != XB_NO_ERROR ) {
 
89
      switch( returnCode ) {
 
90
        case XB_OPEN_ERROR:
 
91
          qDebug()<<"Couldn't open "<<absoluteFileName<<".Skipping it.";
 
92
          break;
 
93
        case XB_NO_MEMORY:
 
94
          qDebug()<<"Memory allocation error in XBase library";
 
95
          return false;
 
96
        case XB_NOT_XBASE:
 
97
          qDebug()<<absoluteFileName<<" is not a DBF file.Skipping it.";
 
98
          break;
 
99
        default:
 
100
          qDebug()<<"Error code "<<returnCode;
 
101
          return false;
 
102
      }
 
103
    }
 
104
  }
 
105
 
 
106
  qDebug()<<"Successfully processed all the dbf files in the directory";
 
107
  return true;
 
108
}
 
109
 
 
110
 
 
111
/*! Disconnect from the db backend */
 
112
bool xBaseMigrate::drv_disconnect()
 
113
{
 
114
  // delete all dbf pointers here ?
 
115
  xbDbList* tempDbfList = DbfList;
 
116
 
 
117
  while ( tempDbfList != NULL ) {
 
118
    xbDbf* currentDbf = tempDbfList->dbf;
 
119
    tempDbfList = tempDbfList->NextDbf;
 
120
    if (currentDbf->CloseDatabase() != XB_NO_ERROR) {
 
121
      // File not open error
 
122
      qDebug()<<"File Not Open";
 
123
    }
 
124
    // delete currentDbf here ?
 
125
  }
 
126
 
 
127
  return true;
 
128
}
 
129
 
 
130
 
 
131
/* ************************************************************************** */
 
132
/*! Get the types and properties for each column. */
 
133
bool xBaseMigrate::drv_readTableSchema(
 
134
  const QString& originalName, KDbTableSchema *tableSchema)
 
135
{
 
136
  // Steps
 
137
  // 1. Get the number of fields
 
138
  // 2. for i = 1 to no_of_fields
 
139
  // 3.     Get the fieldName of the i th    field
 
140
  // 4.     Generate a fieldId
 
141
  // 5.     Create a KDbField object, using the fieldId and the fieldType ( you may need to write a type conversion function here )
 
142
  // 6.     Examine enum fields of any
 
143
  // 7.     Set the caption of the field
 
144
  // 8.     Set other properties of the field ( pertaining to constraints like pkey, unique etc, and  AutoIncrement etc )
 
145
  // 9.     Add the field to the KDbTableSchema
 
146
  // 10. end for
 
147
 
 
148
  // Get table path
 
149
  QString tablePath = m_tableNamePathMap.value( originalName );
 
150
  // get dbf pointer for table
 
151
  xbDbf* tableDbf = GetDbfPtr(qPrintable(tablePath));
 
152
 
 
153
  xbLong numFlds = tableDbf->FieldCount();
 
154
 
 
155
  bool ok = true;
 
156
  for( xbShort i = 0; i < numFlds; ++i ) {
 
157
    QString fldName = QString::fromLatin1( tableDbf->GetFieldName( i ) );
 
158
    QString fldID( KDb::stringToIdentifier( fldName.toLower() ) );
 
159
 
 
160
    KDbField *fld =
 
161
        new KDbField( fldID, type( tableDbf->GetFieldType( i ) ) );
 
162
 
 
163
    if ( fld->type() == KDbField::Text ) {
 
164
      int len = tableDbf->GetFieldLen(i);
 
165
      if (len < 255) { // limit for small lengths only
 
166
          fld->setMaxLength(len);
 
167
      }
 
168
    }
 
169
 
 
170
    if ( fld->isFPNumericType() ) {
 
171
      fld->setScale( tableDbf->GetFieldDecimal(i) );
 
172
    }
 
173
 
 
174
    getConstraints(originalName, fld);
 
175
 
 
176
    if (!tableSchema->addField(fld)) {
 
177
      delete fld;
 
178
      tableSchema->clear();
 
179
      ok = false;
 
180
      break;
 
181
    }
 
182
  }
 
183
  return ok;
 
184
}
 
185
 
 
186
 
 
187
/*! Get a list of tables and put into the supplied string list */
 
188
bool xBaseMigrate::drv_tableNames(QStringList *tableNames)
 
189
{
 
190
  // Get the names from the map directly
 
191
  tableNames->append(m_tableNamePathMap.keys());
 
192
  //qDebug()<<"Tables "<<tableNames;
 
193
  return true;
 
194
}
 
195
 
 
196
//! Copy xBase table to KDb table
 
197
bool xBaseMigrate::drv_copyTable(const QString& srcTable, KDbConnection *destConn,
 
198
  KDbTableSchema* dstTable, const RecordFilter *recordFilter)
 
199
{
 
200
  // Steps
 
201
  // 1. for all records in the table
 
202
  // 2.    num_fields = number of fields in the table
 
203
  // 3.    for each field in the table
 
204
  // 4.        get the length of the field in the table
 
205
  // 5.        Append the field to the variant list ( vals )
 
206
  // 6.    end for
 
207
  // 7.    Insert the record into the destinationConnection into the destinationTable
 
208
  // 8. end for
 
209
 
 
210
  // get dbf pointer for table
 
211
  QString tablePath = m_tableNamePathMap.value( srcTable );
 
212
  xbDbf* tableDbf = GetDbfPtr(qPrintable(tablePath));
 
213
 
 
214
  xbLong numRecords = tableDbf->NoOfRecords();
 
215
 
 
216
  const KDbQueryColumnInfo::Vector fieldsExpanded( dstTable->query()->fieldsExpanded() );
 
217
  // records are indexed from 1
 
218
  for ( xbULong i = 1; i <= (xbULong)numRecords ; ++i ) {
 
219
    tableDbf->GetRecord( i );
 
220
    QList<QVariant> vals;
 
221
 
 
222
    xbLong numFlds = tableDbf->FieldCount();
 
223
    // fields are indexed from 0
 
224
    for( xbShort j = 0; j < numFlds; ++j ) {
 
225
      char data[1024];
 
226
      tableDbf->GetField(j, data);
 
227
      QVariant val;
 
228
 
 
229
      #ifdef XB_MEMO_FIELDS
 
230
        int blobFieldLength;
 
231
        char* memoBuffer = 0;
 
232
        int returnCode;
 
233
      #endif
 
234
 
 
235
      switch ( type( tableDbf->GetFieldType( j ) ) ) {
 
236
        case KDbField::Date:
 
237
          val = QDate::fromString( data, "yyyyMMdd" );
 
238
          break;
 
239
        case KDbField::Boolean:
 
240
          switch(data[0]) {
 
241
            case 'Y': case 'y': case 'T': case 't':
 
242
              val = true;
 
243
              break;
 
244
            case 'N': case 'n': case 'F' : case'f':
 
245
              val = false;
 
246
              break;
 
247
            default:
 
248
              val = false;
 
249
              break;
 
250
          }
 
251
          break;
 
252
        case KDbField::BLOB:
 
253
        #ifdef XB_MEMO_FIELDS
 
254
          blobFieldLength = tableDbf->GetMemoFieldLen(j);
 
255
          memoBuffer = new char[blobFieldLength];
 
256
 
 
257
          #ifdef XB_LOCKING_ON
 
258
            tableDbf->LockMemoFile( F_SETLK, F_RDLCK );
 
259
          #endif
 
260
 
 
261
          if ( ( returnCode = tableDbf->GetMemoField( j , blobFieldLength, memoBuffer, F_SETLKW ) ) != XB_NO_ERROR ) {
 
262
            qDebug()<<"Error reading blob field. Error code: "<<returnCode; // make error message more verbose
 
263
          } else {
 
264
            bool ok;
 
265
            val = KDb::cstringToVariant( memoBuffer, fieldsExpanded.at(j)->field->type(), 0, blobFieldLength );
 
266
          }
 
267
          #ifdef XB_LOCKING_ON
 
268
            tableDbf->LockMemoFile( F_SETLK, F_UNLCK );
 
269
          #endif
 
270
 
 
271
          break;
 
272
        #else
 
273
          qDebug()<<"XB_MEMO_FIELDS support disabled during compilation of XBase libraries";
 
274
        #endif
 
275
 
 
276
        default:
 
277
          val = KDb::cstringToVariant(data, fieldsExpanded.at(j)->field->type());
 
278
          break;
 
279
      }
 
280
      vals.append( val );
 
281
    }
 
282
    if (recordFilter && !(*recordFilter)(vals)) {
 
283
        continue;
 
284
    }
 
285
    if (!destConn->insertRecord(*dstTable, vals)) {
 
286
      return false;
 
287
    }
 
288
  }
 
289
 
 
290
  return true;
 
291
}
 
292
 
 
293
KDbField::Type KexiMigration::xBaseMigrate::type(char xBaseColumnType)
 
294
{
 
295
  KDbField::Type kexiType = KDbField::InvalidType;
 
296
 
 
297
  switch( xBaseColumnType ) {
 
298
    case XB_CHAR_FLD:
 
299
      kexiType = KDbField::Text;
 
300
      break;
 
301
    case XB_LOGICAL_FLD:
 
302
      kexiType = KDbField::Boolean;
 
303
      break;
 
304
    case XB_NUMERIC_FLD:
 
305
      kexiType = KDbField::Float;
 
306
      break;
 
307
    case XB_DATE_FLD:
 
308
      kexiType = KDbField::Date;
 
309
      break;
 
310
    case XB_MEMO_FLD:
 
311
      kexiType = KDbField::BLOB;
 
312
      break;
 
313
    case XB_FLOAT_FLD:
 
314
      kexiType = KDbField::Double;
 
315
      break;
 
316
    default:
 
317
      kexiType = KDbField::InvalidType;
 
318
      break;
 
319
  }
 
320
 
 
321
  return kexiType;
 
322
}
 
323
 
 
324
void KexiMigration::xBaseMigrate::getConstraints(const QString& tableName, KDbField* fld)
 
325
{
 
326
  // 1. Get the names of the index files
 
327
  // 2. Create appropriate xbIndex type object ( xbNdx or xbNtx ) depending on extension
 
328
  // 3. Open the index file
 
329
  // 4. Check the expression of the index to crosscheck whether this is indeed the index file on the required field.
 
330
  // 5. Determine the index type ( unique or not )
 
331
  // 6. Set appropriate properties to the field
 
332
 
 
333
  // Create a base class pointer to an xbIndex
 
334
  xbIndex* index = 0;
 
335
 
 
336
  QStringList indexFileNames = getIndexFileNames(tableName, fld->name());
 
337
 
 
338
  if ( indexFileNames.isEmpty() ) {
 
339
    // no index files exist for this field
 
340
    return;
 
341
  }
 
342
 
 
343
  foreach( const QString& indexFileName, indexFileNames ) {
 
344
 
 
345
    // get dbf pointer for table
 
346
    QString tablePath = m_tableNamePathMap.value( tableName );
 
347
    xbDbf* tableDbf = GetDbfPtr(qPrintable(tablePath));
 
348
 
 
349
    // determine type of indexFile
 
350
    // currently done by checking extension.
 
351
    //! @TODO Check mimetype instead
 
352
    QString fileExtension = indexFileName.right( 3 );
 
353
 
 
354
    if ( fileExtension.toLower() == "ndx" ) {
 
355
      index = new xbNdx( tableDbf );
 
356
    } else if ( fileExtension.toLower() == "ntx" ) {
 
357
      index = new xbNtx( tableDbf );
 
358
    } else {
 
359
      // couldn't recognize extension
 
360
      qDebug()<<"Couldn't recognize extension";
 
361
      return;
 
362
    }
 
363
 
 
364
    if ( index->OpenIndex(qPrintable(indexFileName)) != XB_NO_ERROR ) {
 
365
      qDebug()<<"Couldn't open index file"<<indexFileName;
 
366
      return;
 
367
    }
 
368
 
 
369
    // verfiy if this index is on the required field
 
370
    char buf[256];
 
371
    index->GetExpression( buf, 256 );
 
372
    QString expressionName = QString::fromLatin1( buf );
 
373
 
 
374
    if ( expressionName.toLower() != fld->name() ) {
 
375
      qDebug()<<"Expression mismatch in "<<indexFileName;
 
376
      continue;
 
377
    }
 
378
 
 
379
    // all is well, set the index
 
380
    if ( index->UniqueIndex() == XB_UNIQUE ) {
 
381
      fld->setUniqueKey( true );
 
382
      qDebug()<<"Unique Index on "<<fld->name();
 
383
    } else {  // index->UniqueIndex() == XB_NOT_UNIQUE
 
384
      fld->setIndexed( true );
 
385
      qDebug()<<"Normal Index on "<<fld->name();
 
386
    }
 
387
 
 
388
    // ok, moving through the loop is fairly useless as we can only set a single index on a field anyway
 
389
    // does any one use multiple indexes on the same field ?
 
390
    // well anyway, when Kexi supports it, we'll use IndexSchemas till then ...
 
391
  }
 
392
}
 
393
 
 
394
QStringList KexiMigration::xBaseMigrate::getIndexFileNames(const QString& tableName, const QString& fieldName)
 
395
{
 
396
  // this function needs to return a lits of index files corresponding to the given tablename and field.
 
397
  // The current policy uses the xbsql ( http://www.quaking.demon.co.uk/xbsql/ ) semantics for determining
 
398
  // the filenames of the index files
 
399
  // index files are assumed to be of the type <tablename>_<fieldname>.ndx or .ntx
 
400
 
 
401
  // Though the current semantics allows only one index on a field ( actually two, considering we can
 
402
  // have both .ndx and .ntx index, there can be multiple indices, hence a list of filenames is returned
 
403
  // (Note: Kexi fields support only a single index. But we have a separate KDbIndexSchema class ...)
 
404
 
 
405
  QString dbPath = data()->source->dbPath();
 
406
  QDir xBaseDirectory( dbPath );
 
407
 
 
408
  QString fileName = tableName + '_' + fieldName;
 
409
 
 
410
  QStringList indexFilters;
 
411
  indexFilters<<fileName+'*'; // filter all files of the form <tableName>_<fieldName>
 
412
 
 
413
  xBaseDirectory.setNameFilters( indexFilters );
 
414
  QStringList fileNameList = xBaseDirectory.entryList();
 
415
 
 
416
  QStringList absolutePathNames;
 
417
  foreach( const QString& fileName, fileNameList ) {
 
418
    absolutePathNames<<xBaseDirectory.filePath( fileName );
 
419
  }
 
420
 
 
421
  return absolutePathNames;
 
422
}
 
423