mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Move import feature main code to QgsVectorLayerImport and keep just few methods in providers
This commit is contained in:
parent
b6587d300e
commit
6eb406b122
@ -83,6 +83,7 @@
|
||||
%Include qgsvectordataprovider.sip
|
||||
%Include qgsvectorfilewriter.sip
|
||||
%Include qgsvectorlayer.sip
|
||||
%Include qgsvectorlayerimport.sip
|
||||
%Include qgsvectoroverlay.sip
|
||||
|
||||
%Include qgsnetworkaccessmanager.sip
|
||||
|
@ -61,21 +61,6 @@ class QgsProviderRegistry
|
||||
*/
|
||||
virtual QString protocolDrivers() const;
|
||||
|
||||
/** allows to import a vector layer using the provider
|
||||
* @note this method was added in QGIS 1.8
|
||||
*/
|
||||
int importVector( QgsVectorLayer* layer,
|
||||
const QString& providerKey,
|
||||
const QString& uri,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected = FALSE,
|
||||
QString *errorMessage /Out/ = 0,
|
||||
bool skipAttributeCreation = FALSE,
|
||||
const QMap<QString, QVariant> *options = 0
|
||||
) const;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/** ctor private since instance() creates it */
|
||||
|
65
python/core/qgsvectorlayerimport.sip
Normal file
65
python/core/qgsvectorlayerimport.sip
Normal file
@ -0,0 +1,65 @@
|
||||
|
||||
/**
|
||||
There are two possibilities how to use this class:
|
||||
1. static call to QgsVectorLayerImport::importLayer(...) which saves the whole vector layer
|
||||
2. create an instance of the class and issue calls to addFeature(...)
|
||||
*/
|
||||
class QgsVectorLayerImport
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <qgsvectorlayerimport.h>
|
||||
#include <qgsfield.h>
|
||||
%End
|
||||
|
||||
public:
|
||||
|
||||
enum ImportError
|
||||
{
|
||||
NoError = 0,
|
||||
ErrDriverNotFound,
|
||||
ErrCreateDataSource,
|
||||
ErrCreateLayer,
|
||||
ErrAttributeTypeUnsupported,
|
||||
ErrAttributeCreationFailed,
|
||||
ErrProjection,
|
||||
ErrFeatureWriteFailed,
|
||||
ErrInvalidLayer,
|
||||
ErrInvalidProvider,
|
||||
ErrProviderUnsupportedFeature,
|
||||
ErrConnectionFailed
|
||||
};
|
||||
|
||||
/** Write contents of vector layer to a different datasource */
|
||||
static ImportError importLayer( QgsVectorLayer* layer,
|
||||
const QString& uri,
|
||||
const QString& providerKey,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected = FALSE,
|
||||
QString *errorMessage /Out/ = 0,
|
||||
bool skipAttributeCreation = FALSE,
|
||||
QMap<QString, QVariant> *options = 0
|
||||
);
|
||||
|
||||
/** create a empty layer and add fields to it */
|
||||
QgsVectorLayerImport( const QString &uri,
|
||||
const QString &provider,
|
||||
const QgsFieldMap& fields,
|
||||
QGis::WkbType geometryType,
|
||||
const QgsCoordinateReferenceSystem* crs,
|
||||
bool overwrite = false,
|
||||
const QMap<QString, QVariant> *options = 0
|
||||
);
|
||||
|
||||
/** checks whether there were any errors */
|
||||
ImportError hasError();
|
||||
|
||||
/** retrieves error message */
|
||||
QString errorMessage();
|
||||
|
||||
/** add feature to the new created layer */
|
||||
bool addFeature( QgsFeature& feature );
|
||||
|
||||
/** close the new created layer */
|
||||
~QgsVectorLayerImport();
|
||||
};
|
||||
|
@ -97,6 +97,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgsvectordataprovider.cpp
|
||||
qgsvectorfilewriter.cpp
|
||||
qgsvectorlayer.cpp
|
||||
qgsvectorlayerimport.cpp
|
||||
qgsvectorlayerjoinbuffer.cpp
|
||||
qgsvectorlayerundocommand.cpp
|
||||
qgsvectoroverlay.cpp
|
||||
@ -327,6 +328,7 @@ SET(QGIS_CORE_HDRS
|
||||
qgsvectordataprovider.h
|
||||
qgsvectorfilewriter.h
|
||||
qgsvectorlayer.h
|
||||
qgsvectorlayerimport.h
|
||||
qgsvectoroverlay.h
|
||||
qgstolerance.h
|
||||
|
||||
|
@ -43,14 +43,6 @@ typedef QString directoryDrivers_t();
|
||||
typedef QString protocolDrivers_t();
|
||||
//typedef int dataCapabilities_t();
|
||||
//typedef QgsDataItem * dataItem_t(QString);
|
||||
typedef int importVector_t( QgsVectorLayer* layer,
|
||||
const QString& uri,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected = false,
|
||||
QString *errorMessage = 0,
|
||||
bool skipAttributeCreation = false,
|
||||
const QMap<QString, QVariant> *options = 0
|
||||
);
|
||||
|
||||
QgsProviderRegistry *QgsProviderRegistry::_instance = 0;
|
||||
|
||||
@ -540,35 +532,3 @@ QgsProviderRegistry::openVector( QString const & dataSource, QString const & pro
|
||||
return getProvider( providerKey, dataSource );
|
||||
} // QgsProviderRegistry::openVector
|
||||
*/
|
||||
|
||||
|
||||
int QgsProviderRegistry::importVector( QgsVectorLayer* layer,
|
||||
const QString& providerKey,
|
||||
const QString& uri,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected,
|
||||
QString *errorMessage,
|
||||
bool skipAttributeCreation,
|
||||
const QMap<QString, QVariant> *options
|
||||
) const
|
||||
{
|
||||
QLibrary *myLib = providerLibrary( providerKey );
|
||||
if ( !myLib )
|
||||
{
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "unable to load %1 provider" ).arg( providerKey );
|
||||
return -1;
|
||||
}
|
||||
|
||||
importVector_t * pImport = ( importVector_t * ) cast_to_fptr( myLib->resolve( "importVector" ) );
|
||||
if ( !pImport )
|
||||
{
|
||||
delete myLib;
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "provider %1 has no importVector feature" ).arg( providerKey );
|
||||
return -2;
|
||||
}
|
||||
|
||||
delete myLib;
|
||||
return pImport( layer, uri, destCRS, onlySelected, errorMessage, skipAttributeCreation, options );
|
||||
}
|
||||
|
@ -140,17 +140,6 @@ class CORE_EXPORT QgsProviderRegistry
|
||||
/** type for data provider metadata associative container */
|
||||
typedef std::map<QString, QgsProviderMetadata*> Providers;
|
||||
|
||||
/** allows to import a vector layer using the provider */
|
||||
int importVector( QgsVectorLayer* layer,
|
||||
const QString& providerKey,
|
||||
const QString& uri,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected = false,
|
||||
QString *errorMessage = 0,
|
||||
bool skipAttributeCreation = false,
|
||||
const QMap<QString, QVariant> *options = 0
|
||||
) const;
|
||||
|
||||
private:
|
||||
|
||||
/** ctor private since instance() creates it */
|
||||
|
@ -116,6 +116,8 @@ class CORE_EXPORT QgsVectorFileWriter
|
||||
/** add feature to the currently opened shapefile */
|
||||
bool addFeature( QgsFeature& feature );
|
||||
|
||||
QMap<int, int> attrIdxToOgrIdx() { return mAttrIdxToOgrIdx; }
|
||||
|
||||
/** close opened shapefile for writing */
|
||||
~QgsVectorFileWriter();
|
||||
|
||||
|
300
src/core/qgsvectorlayerimport.cpp
Normal file
300
src/core/qgsvectorlayerimport.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
/***************************************************************************
|
||||
qgsvectorlayerimport.cpp
|
||||
vector layer importer
|
||||
-------------------
|
||||
begin : Thu Aug 25 2011
|
||||
copyright : (C) 2011 by Giuseppe Sucameli
|
||||
email : brush.tyler at gmail.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsfield.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsgeometry.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgsvectorlayerimport.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QSettings>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QTextCodec>
|
||||
#include <QTextStream>
|
||||
#include <QSet>
|
||||
#include <QMetaType>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib> // size_t
|
||||
#include <limits> // std::numeric_limits
|
||||
|
||||
typedef QgsVectorLayerImport::ImportError createEmptyLayer_t(
|
||||
const QString &uri,
|
||||
const QgsFieldMap &fields,
|
||||
QGis::WkbType geometryType,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool overwrite,
|
||||
QMap<int, int> *oldToNewAttrIdx,
|
||||
QString *errorMessage = 0,
|
||||
const QMap<QString, QVariant> *options = 0
|
||||
);
|
||||
|
||||
|
||||
QgsVectorLayerImport::QgsVectorLayerImport(
|
||||
const QString &uri,
|
||||
const QString &providerKey,
|
||||
const QgsFieldMap& fields,
|
||||
QGis::WkbType geometryType,
|
||||
const QgsCoordinateReferenceSystem* crs,
|
||||
bool overwrite,
|
||||
const QMap<QString, QVariant> *options )
|
||||
{
|
||||
mProvider = NULL;
|
||||
QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
|
||||
|
||||
QLibrary *myLib = pReg->providerLibrary( providerKey );
|
||||
if ( !myLib )
|
||||
{
|
||||
mError = ErrInvalidProvider;
|
||||
mErrorMessage = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
|
||||
return;
|
||||
}
|
||||
|
||||
createEmptyLayer_t * pCreateEmpty = ( createEmptyLayer_t * ) cast_to_fptr( myLib->resolve( "createEmptyLayer" ) );
|
||||
if ( !pCreateEmpty )
|
||||
{
|
||||
delete myLib;
|
||||
mError = ErrProviderUnsupportedFeature;
|
||||
mErrorMessage = QObject::tr( "Provider %1 has no createEmptyLayer method" ).arg( providerKey );
|
||||
return;
|
||||
}
|
||||
|
||||
delete myLib;
|
||||
|
||||
// create an empty layer
|
||||
QString errMsg;
|
||||
mError = pCreateEmpty( uri, fields, geometryType, crs, overwrite, &mOldToNewAttrIdx, &errMsg, options );
|
||||
if ( hasError() )
|
||||
{
|
||||
mErrorMessage = errMsg;
|
||||
return;
|
||||
}
|
||||
|
||||
QgsDebugMsg( "Created empty layer" );
|
||||
|
||||
QgsVectorDataProvider *vectorProvider = ( QgsVectorDataProvider* ) pReg->provider( providerKey, uri );
|
||||
if ( !vectorProvider || !vectorProvider->isValid() )
|
||||
{
|
||||
mError = ErrInvalidLayer;
|
||||
mErrorMessage = QObject::tr( "Loading of layer failed" );
|
||||
|
||||
if ( vectorProvider )
|
||||
delete vectorProvider;
|
||||
return;
|
||||
}
|
||||
|
||||
mProvider = vectorProvider;
|
||||
mError = NoError;
|
||||
}
|
||||
|
||||
QgsVectorLayerImport::~QgsVectorLayerImport()
|
||||
{
|
||||
if ( mProvider )
|
||||
delete mProvider;
|
||||
}
|
||||
|
||||
QgsVectorLayerImport::ImportError QgsVectorLayerImport::hasError()
|
||||
{
|
||||
return mError;
|
||||
}
|
||||
|
||||
QString QgsVectorLayerImport::errorMessage()
|
||||
{
|
||||
return mErrorMessage;
|
||||
}
|
||||
|
||||
bool QgsVectorLayerImport::addFeature( QgsFeature& feat )
|
||||
{
|
||||
const QgsAttributeMap &attrs = feat.attributeMap();
|
||||
|
||||
QgsAttributeMap newAttrs;
|
||||
for ( QgsAttributeMap::const_iterator it = attrs.begin(); it != attrs.end(); it++ )
|
||||
{
|
||||
if ( mOldToNewAttrIdx.contains( it.key() ) )
|
||||
{
|
||||
QgsDebugMsgLevel( QString( "moving field from pos %1 to %2" ).arg( it.key() ).arg( mOldToNewAttrIdx.value( it.key() ) ), 3 );
|
||||
newAttrs.insert( mOldToNewAttrIdx.value( it.key() ), *it );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsgLevel( QString( "added attr pos %1" ).arg( it.key() ), 3 );
|
||||
newAttrs.insert( it.key(), *it );
|
||||
}
|
||||
}
|
||||
feat.setAttributeMap( newAttrs );
|
||||
|
||||
if ( !mProvider->addFeatures( QgsFeatureList() << feat ) )
|
||||
{
|
||||
mErrorMessage = QObject::tr( "Feature #%1 creation error" ).arg( feat.id() );
|
||||
mError = ErrFeatureWriteFailed;
|
||||
|
||||
QgsDebugMsg( mErrorMessage );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QgsVectorLayerImport::ImportError
|
||||
QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
|
||||
const QString& uri,
|
||||
const QString& providerKey,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected,
|
||||
QString *errorMessage,
|
||||
bool skipAttributeCreation,
|
||||
QMap<QString, QVariant> *options )
|
||||
{
|
||||
const QgsCoordinateReferenceSystem* outputCRS;
|
||||
QgsCoordinateTransform* ct = 0;
|
||||
int shallTransform = false;
|
||||
|
||||
if ( layer == NULL )
|
||||
{
|
||||
return ErrInvalidLayer;
|
||||
}
|
||||
|
||||
if ( destCRS && destCRS->isValid() )
|
||||
{
|
||||
// This means we should transform
|
||||
outputCRS = destCRS;
|
||||
shallTransform = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This means we shouldn't transform, use source CRS as output (if defined)
|
||||
outputCRS = &layer->crs();
|
||||
}
|
||||
|
||||
QgsVectorLayerImport * writer =
|
||||
new QgsVectorLayerImport( uri, providerKey, skipAttributeCreation ? QgsFieldMap() : layer->pendingFields(), layer->wkbType(), outputCRS, false, options );
|
||||
|
||||
// check whether file creation was successful
|
||||
ImportError err = writer->hasError();
|
||||
if ( err != NoError )
|
||||
{
|
||||
if ( errorMessage )
|
||||
*errorMessage = writer->errorMessage();
|
||||
delete writer;
|
||||
return err;
|
||||
}
|
||||
|
||||
if ( errorMessage )
|
||||
{
|
||||
errorMessage->clear();
|
||||
}
|
||||
|
||||
QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList();
|
||||
QgsFeature fet;
|
||||
|
||||
layer->select( allAttr, QgsRectangle(), layer->wkbType() != QGis::WKBNoGeometry );
|
||||
|
||||
const QgsFeatureIds& ids = layer->selectedFeaturesIds();
|
||||
|
||||
// Create our transform
|
||||
if ( destCRS )
|
||||
{
|
||||
ct = new QgsCoordinateTransform( layer->crs(), *destCRS );
|
||||
}
|
||||
|
||||
// Check for failure
|
||||
if ( ct == NULL )
|
||||
{
|
||||
shallTransform = false;
|
||||
}
|
||||
|
||||
int n = 0, errors = 0;
|
||||
|
||||
// write all features
|
||||
while ( layer->nextFeature( fet ) )
|
||||
{
|
||||
if ( onlySelected && !ids.contains( fet.id() ) )
|
||||
continue;
|
||||
|
||||
if ( shallTransform )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( fet.geometry() )
|
||||
{
|
||||
fet.geometry()->transform( *ct );
|
||||
}
|
||||
}
|
||||
catch ( QgsCsException &e )
|
||||
{
|
||||
delete ct;
|
||||
delete writer;
|
||||
|
||||
QString msg = QObject::tr( "Failed to transform a point while drawing a feature of type '%1'. Writing stopped. (Exception: %2)" )
|
||||
.arg( fet.typeName() ).arg( e.what() );
|
||||
QgsLogger::warning( msg );
|
||||
if ( errorMessage )
|
||||
*errorMessage = msg;
|
||||
|
||||
return ErrProjection;
|
||||
}
|
||||
}
|
||||
if ( skipAttributeCreation )
|
||||
{
|
||||
fet.clearAttributeMap();
|
||||
}
|
||||
if ( !writer->addFeature( fet ) )
|
||||
{
|
||||
if ( writer->hasError() && errorMessage )
|
||||
{
|
||||
if ( errorMessage->isEmpty() )
|
||||
{
|
||||
*errorMessage = QObject::tr( "Feature write errors:" );
|
||||
}
|
||||
*errorMessage += "\n" + writer->errorMessage();
|
||||
}
|
||||
errors++;
|
||||
|
||||
if ( errors > 1000 )
|
||||
{
|
||||
if ( errorMessage )
|
||||
{
|
||||
*errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors );
|
||||
}
|
||||
|
||||
n = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
delete writer;
|
||||
|
||||
if ( shallTransform )
|
||||
{
|
||||
delete ct;
|
||||
}
|
||||
|
||||
if ( errors > 0 && errorMessage && n > 0 )
|
||||
{
|
||||
*errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
|
||||
}
|
||||
|
||||
return errors == 0 ? NoError : ErrFeatureWriteFailed;
|
||||
}
|
99
src/core/qgsvectorlayerimport.h
Normal file
99
src/core/qgsvectorlayerimport.h
Normal file
@ -0,0 +1,99 @@
|
||||
/***************************************************************************
|
||||
qgsvectorlayerimport.cpp
|
||||
vector layer importer
|
||||
-------------------
|
||||
begin : Thu Aug 25 2011
|
||||
copyright : (C) 2011 by Giuseppe Sucameli
|
||||
email : brush.tyler at gmail.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _QGSVECTORLAYERIMPORT_H_
|
||||
#define _QGSVECTORLAYERIMPORT_H_
|
||||
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
|
||||
/** \ingroup core
|
||||
* A convenience class for writing vector files to disk.
|
||||
There are two possibilities how to use this class:
|
||||
1. static call to QgsVectorFileWriter::writeAsShapefile(...) which saves the whole vector layer
|
||||
2. create an instance of the class and issue calls to addFeature(...)
|
||||
|
||||
Currently supports only writing to shapefiles, but shouldn't be a problem to add capability
|
||||
to support other OGR-writable formats.
|
||||
*/
|
||||
class CORE_EXPORT QgsVectorLayerImport
|
||||
{
|
||||
public:
|
||||
|
||||
enum ImportError
|
||||
{
|
||||
NoError = 0,
|
||||
ErrDriverNotFound,
|
||||
ErrCreateDataSource,
|
||||
ErrCreateLayer,
|
||||
ErrAttributeTypeUnsupported,
|
||||
ErrAttributeCreationFailed,
|
||||
ErrProjection,
|
||||
ErrFeatureWriteFailed,
|
||||
ErrInvalidLayer,
|
||||
ErrInvalidProvider,
|
||||
ErrProviderUnsupportedFeature,
|
||||
ErrConnectionFailed
|
||||
};
|
||||
|
||||
|
||||
/** Write contents of vector layer to a different datasource */
|
||||
static ImportError importLayer( QgsVectorLayer* layer,
|
||||
const QString& uri,
|
||||
const QString& providerKey,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected = false,
|
||||
QString *errorMessage = 0,
|
||||
bool skipAttributeCreation = false,
|
||||
QMap<QString, QVariant> *options = 0
|
||||
);
|
||||
|
||||
/** create a empty layer and add fields to it */
|
||||
QgsVectorLayerImport( const QString &uri,
|
||||
const QString &provider,
|
||||
const QgsFieldMap& fields,
|
||||
QGis::WkbType geometryType,
|
||||
const QgsCoordinateReferenceSystem* crs,
|
||||
bool overwrite = false,
|
||||
const QMap<QString, QVariant> *options = 0
|
||||
);
|
||||
|
||||
/** checks whether there were any errors */
|
||||
ImportError hasError();
|
||||
|
||||
/** retrieves error message */
|
||||
QString errorMessage();
|
||||
|
||||
/** add feature to the new created layer */
|
||||
bool addFeature( QgsFeature& feature );
|
||||
|
||||
/** close the new created layer */
|
||||
~QgsVectorLayerImport();
|
||||
|
||||
protected:
|
||||
/** contains error value */
|
||||
ImportError mError;
|
||||
QString mErrorMessage;
|
||||
|
||||
QgsVectorDataProvider *mProvider;
|
||||
|
||||
/** map attribute indexes to new field indexes */
|
||||
QMap<int, int> mOldToNewAttrIdx;
|
||||
};
|
||||
|
||||
#endif
|
@ -42,7 +42,7 @@ email : sherman at mrcc.com
|
||||
#include "qgsfield.h"
|
||||
#include "qgsgeometry.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsvectorlayerimport.h"
|
||||
|
||||
static const QString TEXT_PROVIDER_KEY = "ogr";
|
||||
static const QString TEXT_PROVIDER_DESCRIPTION =
|
||||
@ -83,15 +83,54 @@ class QgsCPLErrorHandler
|
||||
};
|
||||
|
||||
|
||||
bool QgsOgrProvider::convertField( QgsField &field, const QTextCodec &encoding )
|
||||
{
|
||||
OGRFieldType ogrType = OFTString; //default to string
|
||||
int ogrWidth = field.length();
|
||||
int ogrPrecision = field.precision();
|
||||
switch ( field.type() )
|
||||
{
|
||||
case QVariant::LongLong:
|
||||
ogrType = OFTString;
|
||||
ogrWidth = ogrWidth > 0 && ogrWidth <= 21 ? ogrWidth : 21;
|
||||
ogrPrecision = -1;
|
||||
break;
|
||||
|
||||
QgsVectorFileWriter::WriterError
|
||||
QgsOgrProvider::importVector(
|
||||
QgsVectorLayer *layer,
|
||||
const QString& fileName,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected,
|
||||
case QVariant::String:
|
||||
ogrType = OFTString;
|
||||
if ( ogrWidth < 0 || ogrWidth > 255 )
|
||||
ogrWidth = 255;
|
||||
break;
|
||||
|
||||
case QVariant::Int:
|
||||
ogrType = OFTInteger;
|
||||
ogrWidth = ogrWidth > 0 && ogrWidth <= 10 ? ogrWidth : 10;
|
||||
ogrPrecision = 0;
|
||||
break;
|
||||
|
||||
case QVariant::Double:
|
||||
ogrType = OFTReal;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
field.setTypeName( encoding.toUnicode( OGR_GetFieldTypeName( ogrType ) ) );
|
||||
field.setLength( ogrWidth );
|
||||
field.setPrecision( ogrPrecision );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QgsVectorLayerImport::ImportError QgsOgrProvider::createEmptyLayer(
|
||||
const QString& uri,
|
||||
const QgsFieldMap &fields,
|
||||
QGis::WkbType wkbType,
|
||||
const QgsCoordinateReferenceSystem *srs,
|
||||
bool overwrite,
|
||||
QMap<int, int> *oldToNewAttrIdxMap,
|
||||
QString *errorMessage,
|
||||
bool skipAttributeCreation,
|
||||
const QMap<QString,QVariant> *options )
|
||||
{
|
||||
QString encoding;
|
||||
@ -113,9 +152,48 @@ QgsOgrProvider::importVector(
|
||||
layerOptions << options->value( "layerOptions" ).toStringList();
|
||||
}
|
||||
|
||||
return QgsVectorFileWriter::writeAsVectorFormat(
|
||||
layer, fileName, encoding, destCRS, driverName, onlySelected,
|
||||
errorMessage, dsOptions, layerOptions, skipAttributeCreation );
|
||||
if ( oldToNewAttrIdxMap )
|
||||
oldToNewAttrIdxMap->clear();
|
||||
if ( errorMessage )
|
||||
errorMessage->clear();
|
||||
|
||||
if ( !overwrite )
|
||||
{
|
||||
QFileInfo fi( uri );
|
||||
if ( fi.exists() )
|
||||
{
|
||||
if ( errorMessage )
|
||||
*errorMessage += QObject::tr( "Unable to create the datasource. %1 exists and overwrite flag is false." )
|
||||
.arg( uri );
|
||||
return QgsVectorLayerImport::ErrCreateDataSource;
|
||||
}
|
||||
}
|
||||
|
||||
QgsVectorFileWriter *writer = new QgsVectorFileWriter(
|
||||
uri, encoding, fields, wkbType,
|
||||
srs, driverName, dsOptions, layerOptions );
|
||||
|
||||
QgsVectorFileWriter::WriterError error = writer->hasError();
|
||||
if ( error )
|
||||
{
|
||||
if ( errorMessage )
|
||||
*errorMessage += writer->errorMessage();
|
||||
|
||||
delete writer;
|
||||
return ( QgsVectorLayerImport::ImportError ) error;
|
||||
}
|
||||
|
||||
if ( oldToNewAttrIdxMap )
|
||||
{
|
||||
QMap<int, int> attrIdxMap = writer->attrIdxToOgrIdx();
|
||||
for ( QMap<int, int>::const_iterator attrIt = attrIdxMap.begin(); attrIt != attrIdxMap.end(); ++attrIt )
|
||||
{
|
||||
oldToNewAttrIdxMap->insert( attrIt.key(), *attrIt );
|
||||
}
|
||||
}
|
||||
|
||||
delete writer;
|
||||
return QgsVectorLayerImport::NoError;
|
||||
}
|
||||
|
||||
|
||||
@ -2405,14 +2483,18 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
|
||||
return 0;
|
||||
}
|
||||
|
||||
QGISEXTERN int importVector(
|
||||
QgsVectorLayer *layer,
|
||||
const QString& uri,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected,
|
||||
QString *errorMessage,
|
||||
bool skipAttributeCreation,
|
||||
const QMap<QString,QVariant> *options )
|
||||
QGISEXTERN QgsVectorLayerImport::ImportError createEmptyLayer(
|
||||
const QString& uri,
|
||||
const QgsFieldMap &fields,
|
||||
QGis::WkbType wkbType,
|
||||
const QgsCoordinateReferenceSystem *srs,
|
||||
bool overwrite,
|
||||
QMap<int, int> *oldToNewAttrIdxMap,
|
||||
QString *errorMessage,
|
||||
const QMap<QString,QVariant> *options )
|
||||
{
|
||||
return QgsOgrProvider::importVector( layer, uri, destCRS, onlySelected, errorMessage, skipAttributeCreation, options );
|
||||
return QgsOgrProvider::createEmptyLayer(
|
||||
uri, fields, wkbType, srs, overwrite,
|
||||
oldToNewAttrIdxMap, errorMessage, options
|
||||
);
|
||||
}
|
||||
|
@ -19,9 +19,10 @@ email : sherman at mrcc.com
|
||||
#include "qgsrectangle.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsvectorfilewriter.h"
|
||||
#include "qgsvectorlayerimport.h"
|
||||
|
||||
class QgsFeature;
|
||||
class QgsField;
|
||||
class QgsVectorLayerImport;
|
||||
|
||||
#include <ogr_api.h>
|
||||
|
||||
@ -36,15 +37,16 @@ class QgsOgrProvider : public QgsVectorDataProvider
|
||||
public:
|
||||
|
||||
/** convert a vector layer to a vector file */
|
||||
static QgsVectorFileWriter::WriterError importVector(
|
||||
QgsVectorLayer *layer,
|
||||
const QString& fileName,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected,
|
||||
QString *errorMessage,
|
||||
bool skipAttributeCreation,
|
||||
const QMap<QString,QVariant> *options
|
||||
);
|
||||
static QgsVectorLayerImport::ImportError createEmptyLayer(
|
||||
const QString& uri,
|
||||
const QgsFieldMap &fields,
|
||||
QGis::WkbType wkbType,
|
||||
const QgsCoordinateReferenceSystem *srs,
|
||||
bool overwrite,
|
||||
QMap<int, int> *oldToNewAttrIdxMap,
|
||||
QString *errorMessage = 0,
|
||||
const QMap<QString,QVariant> *options = 0
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor of the vector provider
|
||||
@ -266,6 +268,9 @@ class QgsOgrProvider : public QgsVectorDataProvider
|
||||
/** tell OGR, which fields to fetch in nextFeature/featureAtId (ie. which not to ignore) */
|
||||
void setRelevantFields( bool fetchGeometry, const QgsAttributeList& fetchAttributes );
|
||||
|
||||
/** convert a QgsField to work with OGR */
|
||||
static bool convertField( QgsField &field, const QTextCodec &encoding );
|
||||
|
||||
private:
|
||||
bool crsFromWkt( QgsCoordinateReferenceSystem &srs, const char *wkt );
|
||||
unsigned char *getGeometryPointer( OGRFeatureH fet );
|
||||
|
@ -25,13 +25,13 @@
|
||||
|
||||
#include <qgis.h>
|
||||
#include <qgsapplication.h>
|
||||
#include <qgsvectorlayer.h>
|
||||
#include <qgsfeature.h>
|
||||
#include <qgsfield.h>
|
||||
#include <qgsgeometry.h>
|
||||
#include <qgsmessageoutput.h>
|
||||
#include <qgsrectangle.h>
|
||||
#include <qgscoordinatereferencesystem.h>
|
||||
#include "qgsvectorlayerimport.h"
|
||||
|
||||
#include "qgsprovidercountcalcevent.h"
|
||||
#include "qgsproviderextentcalcevent.h"
|
||||
@ -81,7 +81,7 @@ bool QgsPostgresProvider::convertField( QgsField &field )
|
||||
break;
|
||||
|
||||
case QVariant::Double:
|
||||
if ( fieldSize <= 0 || fieldPrec < 0)
|
||||
if ( fieldSize <= 0 || fieldPrec <= 0)
|
||||
{
|
||||
fieldType = "float";
|
||||
fieldSize = -1;
|
||||
@ -103,38 +103,17 @@ bool QgsPostgresProvider::convertField( QgsField &field )
|
||||
return true;
|
||||
}
|
||||
|
||||
QgsPostgresProvider::WriterError
|
||||
QgsPostgresProvider::importVector(
|
||||
QgsVectorLayer *layer,
|
||||
QgsVectorLayerImport::ImportError QgsPostgresProvider::createEmptyLayer(
|
||||
const QString& uri,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected,
|
||||
const QgsFieldMap &fields,
|
||||
QGis::WkbType wkbType,
|
||||
const QgsCoordinateReferenceSystem *srs,
|
||||
bool overwrite,
|
||||
QMap<int, int> *oldToNewAttrIdxMap,
|
||||
QString *errorMessage,
|
||||
bool skipAttributeCreation,
|
||||
const QMap<QString,QVariant> *options )
|
||||
{
|
||||
const QgsCoordinateReferenceSystem* outputCRS;
|
||||
QgsCoordinateTransform* ct = 0;
|
||||
int shallTransform = false;
|
||||
|
||||
if ( !layer )
|
||||
{
|
||||
return ErrInvalidLayer;
|
||||
}
|
||||
|
||||
if ( destCRS && destCRS->isValid() )
|
||||
{
|
||||
// This means we should transform
|
||||
outputCRS = destCRS;
|
||||
shallTransform = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This means we shouldn't transform, use source CRS as output (if defined)
|
||||
outputCRS = &layer->crs();
|
||||
}
|
||||
|
||||
QgsFieldMap fields = skipAttributeCreation ? QgsFieldMap() : layer->pendingFields();
|
||||
Q_UNUSED( options );
|
||||
|
||||
// populate members from the uri structure
|
||||
QgsDataSourceURI dsUri( uri );
|
||||
@ -160,184 +139,199 @@ QgsPostgresProvider::importVector(
|
||||
QgsDebugMsg( "Table name is: " + tableName );
|
||||
|
||||
// create the table
|
||||
Conn *conn = Conn::connectDb( dsUri.connectionInfo(), false );
|
||||
if ( conn == NULL )
|
||||
{
|
||||
Conn *conn = Conn::connectDb( dsUri.connectionInfo(), false );
|
||||
if ( conn == NULL )
|
||||
{
|
||||
QgsDebugMsg( "Connection to database failed. Import of layer aborted." );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "Connection to database failed" );
|
||||
return ErrConnectionFailed;
|
||||
}
|
||||
QgsDebugMsg( "Connection to database failed. Import of layer aborted." );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "Connection to database failed" );
|
||||
return QgsVectorLayerImport::ErrConnectionFailed;
|
||||
}
|
||||
|
||||
// get the pk's name and type
|
||||
if ( primaryKey.isEmpty() )
|
||||
// get the pk's name and type
|
||||
|
||||
// if no pk name was passed, define the new pk field name
|
||||
if ( primaryKey.isEmpty() )
|
||||
{
|
||||
int index = 0;
|
||||
QString pk = primaryKey = "pk";
|
||||
for ( QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
|
||||
{
|
||||
// if no pk name was passed, define the new pk field name
|
||||
int index = 0;
|
||||
QString pk = primaryKey = "pk";
|
||||
for ( QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
|
||||
if ( fldIt.value().name() == pk )
|
||||
{
|
||||
if ( fldIt.value().name() == pk )
|
||||
// it already exists, try again with a new name
|
||||
primaryKey = QString( "%1_%2" ).arg( pk ).arg( index++ );
|
||||
fldIt = fields.begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// search for the passed field
|
||||
for ( QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
|
||||
{
|
||||
if ( fldIt.value().name() == primaryKey )
|
||||
{
|
||||
// found, get the field type
|
||||
QgsField fld = fldIt.value();
|
||||
if ( convertField( fld ) )
|
||||
{
|
||||
// it already exists, try again with a new name
|
||||
primaryKey = QString( "%1_%2" ).arg( pk ).arg( index++ );
|
||||
fldIt = fields.begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// search for the passed field
|
||||
for ( QgsFieldMap::iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
|
||||
{
|
||||
if ( fldIt.value().name() == primaryKey )
|
||||
{
|
||||
// found, get the field type
|
||||
QgsField &fld = fldIt.value();
|
||||
if ( convertField( fld ) )
|
||||
{
|
||||
primaryKeyType = fld.typeName();
|
||||
}
|
||||
primaryKeyType = fld.typeName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the field doesn't not exist yet, create it as a serial field
|
||||
if ( primaryKeyType.isEmpty() )
|
||||
// if the field doesn't not exist yet, create it as a serial field
|
||||
if ( primaryKeyType.isEmpty() )
|
||||
{
|
||||
primaryKeyType = "serial";
|
||||
/* TODO
|
||||
// check the feature count to choose if create a serial8 pk field
|
||||
if ( layer->featureCount() > 0xFFFFFF )
|
||||
{
|
||||
primaryKeyType = "serial";
|
||||
// check the feature count to choose if create a serial8 pk field
|
||||
if ( layer->featureCount() > 0xFFFFFF )
|
||||
{
|
||||
primaryKeyType = "serial8";
|
||||
}
|
||||
}
|
||||
primaryKeyType = "serial8";
|
||||
}*/
|
||||
}
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
conn->PQexecNR( "BEGIN" );
|
||||
|
||||
bool exists = false;
|
||||
QString sql = QString( "SELECT 1 "
|
||||
"FROM pg_class AS cls JOIN pg_namespace AS nsp"
|
||||
" ON nsp.oid = cls.relnamespace "
|
||||
" WHERE cls.relname = %1 AND nsp.nspname = %2" )
|
||||
.arg( quotedValue( tableName ) )
|
||||
.arg( quotedValue( schemaName ) );
|
||||
|
||||
PGresult *result = conn->PQexec( sql );
|
||||
if ( PQresultStatus( result ) == PGRES_FATAL_ERROR )
|
||||
throw PGException( result );
|
||||
if ( PQntuples( result ) > 0 )
|
||||
exists = true;
|
||||
PQclear( result );
|
||||
|
||||
if ( exists && overwrite )
|
||||
{
|
||||
conn->PQexecNR( "BEGIN" );
|
||||
|
||||
// delete the table if exists, then re-create it
|
||||
QString sql = QString( "SELECT %1(%2, %3) "
|
||||
QString sql = QString( "SELECT dropgeometrytable(%1, %2) "
|
||||
"FROM pg_class AS cls JOIN pg_namespace AS nsp"
|
||||
" ON nsp.oid = cls.relnamespace "
|
||||
" WHERE cls.relname = %4 AND nsp.nspname = %5" )
|
||||
.arg( conn->majorVersion() < 2 ? "dropgeometrytable" : "st_dropgeometrytable" )
|
||||
" WHERE cls.relname = %3 AND nsp.nspname = %4" )
|
||||
.arg( quotedValue( schemaName ) )
|
||||
.arg( quotedValue( tableName ) )
|
||||
.arg( quotedValue( tableName ) )
|
||||
.arg( quotedValue( schemaName ) );
|
||||
|
||||
PGresult *result = conn->PQexec( sql );
|
||||
if ( result == 0 || PQresultStatus( result ) == PGRES_FATAL_ERROR )
|
||||
result = conn->PQexec( sql );
|
||||
if ( PQresultStatus( result ) == PGRES_FATAL_ERROR )
|
||||
throw PGException( result );
|
||||
PQclear( result );
|
||||
}
|
||||
|
||||
sql = QString( "CREATE TABLE %1 (%2 %3 PRIMARY KEY)" )
|
||||
.arg( schemaTableName )
|
||||
.arg( quotedIdentifier( primaryKey ) )
|
||||
.arg( primaryKeyType );
|
||||
sql = QString( "CREATE TABLE %1 (%2 %3 PRIMARY KEY)" )
|
||||
.arg( schemaTableName )
|
||||
.arg( quotedIdentifier( primaryKey ) )
|
||||
.arg( primaryKeyType );
|
||||
|
||||
result = conn->PQexec( sql );
|
||||
if ( PQresultStatus( result ) == PGRES_FATAL_ERROR )
|
||||
throw PGException( result );
|
||||
PQclear( result );
|
||||
|
||||
|
||||
// get geometry type, dim and srid
|
||||
int dim = 2;
|
||||
long srid = srs->postgisSrid();
|
||||
|
||||
switch( wkbType )
|
||||
{
|
||||
case QGis::WKBPoint25D:
|
||||
dim = 3;
|
||||
case QGis::WKBPoint:
|
||||
geometryType = "POINT";
|
||||
break;
|
||||
|
||||
case QGis::WKBLineString25D:
|
||||
dim = 3;
|
||||
case QGis::WKBLineString:
|
||||
geometryType = "LINESTRING";
|
||||
break;
|
||||
|
||||
case QGis::WKBPolygon25D:
|
||||
dim = 3;
|
||||
case QGis::WKBPolygon:
|
||||
geometryType = "POLYGON";
|
||||
break;
|
||||
|
||||
case QGis::WKBMultiPoint25D:
|
||||
dim = 3;
|
||||
case QGis::WKBMultiPoint:
|
||||
geometryType = "MULTIPOINT";
|
||||
break;
|
||||
|
||||
case QGis::WKBMultiLineString25D:
|
||||
dim = 3;
|
||||
case QGis::WKBMultiLineString:
|
||||
geometryType = "MULTILINESTRING";
|
||||
break;
|
||||
|
||||
case QGis::WKBMultiPolygon25D:
|
||||
dim = 3;
|
||||
case QGis::WKBMultiPolygon:
|
||||
geometryType = "MULTIPOLYGON";
|
||||
break;
|
||||
|
||||
case QGis::WKBUnknown:
|
||||
geometryType = "GEOMETRY";
|
||||
break;
|
||||
|
||||
case QGis::WKBNoGeometry:
|
||||
default:
|
||||
dim = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// create geometry column
|
||||
if ( !geometryType.isEmpty() )
|
||||
{
|
||||
sql = QString( "SELECT addgeometrycolumn(%1, %2, %3, %4, %5, %6)" )
|
||||
.arg( quotedValue( schemaName ) )
|
||||
.arg( QgsPostgresProvider::quotedValue( tableName ) )
|
||||
.arg( QgsPostgresProvider::quotedValue( geometryColumn ) )
|
||||
.arg( srid )
|
||||
.arg( QgsPostgresProvider::quotedValue( geometryType ) )
|
||||
.arg( dim );
|
||||
|
||||
result = conn->PQexec( sql );
|
||||
if ( result == 0 || PQresultStatus( result ) == PGRES_FATAL_ERROR )
|
||||
if ( PQresultStatus( result ) == PGRES_FATAL_ERROR )
|
||||
throw PGException( result );
|
||||
PQclear( result );
|
||||
|
||||
// get geometry type, dim and srid
|
||||
int dim = 2;
|
||||
long srid = outputCRS->postgisSrid();
|
||||
|
||||
switch( layer->wkbType() )
|
||||
{
|
||||
case QGis::WKBPoint25D:
|
||||
dim = 3;
|
||||
case QGis::WKBPoint:
|
||||
geometryType = "POINT";
|
||||
break;
|
||||
|
||||
case QGis::WKBLineString25D:
|
||||
dim = 3;
|
||||
case QGis::WKBLineString:
|
||||
geometryType = "LINESTRING";
|
||||
break;
|
||||
|
||||
case QGis::WKBPolygon25D:
|
||||
dim = 3;
|
||||
case QGis::WKBPolygon:
|
||||
geometryType = "POLYGON";
|
||||
break;
|
||||
|
||||
case QGis::WKBMultiPoint25D:
|
||||
dim = 3;
|
||||
case QGis::WKBMultiPoint:
|
||||
geometryType = "MULTIPOINT";
|
||||
break;
|
||||
|
||||
case QGis::WKBMultiLineString25D:
|
||||
dim = 3;
|
||||
case QGis::WKBMultiLineString:
|
||||
geometryType = "MULTILINESTRING";
|
||||
break;
|
||||
|
||||
case QGis::WKBMultiPolygon25D:
|
||||
dim = 3;
|
||||
case QGis::WKBMultiPolygon:
|
||||
geometryType = "MULTIPOLYGON";
|
||||
break;
|
||||
|
||||
case QGis::WKBUnknown:
|
||||
geometryType = "GEOMETRY";
|
||||
break;
|
||||
|
||||
case QGis::WKBNoGeometry:
|
||||
default:
|
||||
dim = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// create geometry column
|
||||
if ( !geometryType.isEmpty() && dim > 0 )
|
||||
{
|
||||
sql = QString( "SELECT %1(%2, %3, %4, %5, %6, %7)" )
|
||||
.arg( conn->majorVersion() < 2 ? "addgeometrycolumn" : "st_addgeometrycolumn" )
|
||||
.arg( quotedValue( schemaName ) )
|
||||
.arg( QgsPostgresProvider::quotedValue( tableName ) )
|
||||
.arg( QgsPostgresProvider::quotedValue( geometryColumn ) )
|
||||
.arg( srid )
|
||||
.arg( QgsPostgresProvider::quotedValue( geometryType ) )
|
||||
.arg( dim );
|
||||
|
||||
PGresult *result = conn->PQexec( sql );
|
||||
if ( result == 0 || PQresultStatus( result ) == PGRES_FATAL_ERROR )
|
||||
throw PGException( result );
|
||||
PQclear( result );
|
||||
}
|
||||
else
|
||||
{
|
||||
geometryColumn = QString();
|
||||
geometryType = QString();
|
||||
dim = 0;
|
||||
}
|
||||
|
||||
conn->PQexecNR( "COMMIT" );
|
||||
}
|
||||
catch ( PGException &e )
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( "creation of data source " + schemaTableName + " failed. " + e.errorMessage() );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "creation of data source %1 failed. %2" )
|
||||
.arg( schemaTableName )
|
||||
.arg( e.errorMessage() );
|
||||
|
||||
conn->PQexecNR( "ROLLBACK" );
|
||||
Conn::disconnectRW( conn );
|
||||
return ErrCreateLayer;
|
||||
geometryColumn.clear();
|
||||
}
|
||||
Conn::disconnectRW( conn );
|
||||
|
||||
QgsDebugMsg( "layer " + schemaTableName + " created." );
|
||||
conn->PQexecNR( "COMMIT" );
|
||||
}
|
||||
catch ( PGException &e )
|
||||
{
|
||||
QgsDebugMsg( "creation of data source " + schemaTableName + " failed. " + e.errorMessage() );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "Creation of data source %1 failed: \n%2" )
|
||||
.arg( schemaTableName )
|
||||
.arg( e.errorMessage() );
|
||||
|
||||
conn->PQexecNR( "ROLLBACK" );
|
||||
Conn::disconnectRW( conn );
|
||||
return QgsVectorLayerImport::ErrCreateLayer;
|
||||
}
|
||||
Conn::disconnectRW( conn );
|
||||
|
||||
QgsDebugMsg( "layer " + schemaTableName + " created." );
|
||||
|
||||
// use the provider to edit the table
|
||||
dsUri.setDataSource( schemaName, tableName, geometryColumn, QString(), primaryKey );
|
||||
@ -346,25 +340,33 @@ QgsPostgresProvider::importVector(
|
||||
{
|
||||
QgsDebugMsg( "The layer " + schemaTableName + " just created is not valid or not supported by the provider." );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "loading of the layer %1 failed" )
|
||||
*errorMessage = QObject::tr( "Loading of the layer %1 failed" )
|
||||
.arg( schemaTableName );
|
||||
|
||||
delete provider;
|
||||
return ErrCreateLayer;
|
||||
return QgsVectorLayerImport::ErrInvalidLayer;
|
||||
}
|
||||
|
||||
QgsDebugMsg( "layer loaded" );
|
||||
|
||||
// add fields to the layer
|
||||
if ( oldToNewAttrIdxMap )
|
||||
oldToNewAttrIdxMap->clear();
|
||||
|
||||
if ( fields.size() > 0 )
|
||||
{
|
||||
int offset = geometryColumn.isEmpty() ? 1 : 2;
|
||||
|
||||
// get the list of fields
|
||||
QList<QgsField> flist;
|
||||
for ( QgsFieldMap::iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
|
||||
for ( QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
|
||||
{
|
||||
QgsField &fld = fldIt.value();
|
||||
QgsField fld = fldIt.value();
|
||||
if ( fld.name() == primaryKey )
|
||||
{
|
||||
oldToNewAttrIdxMap->insert( fldIt.key(), 0 );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( fld.name() == geometryColumn )
|
||||
{
|
||||
@ -372,180 +374,43 @@ QgsPostgresProvider::importVector(
|
||||
continue;
|
||||
}
|
||||
|
||||
// convert field type only if the source provider is different from the destination one
|
||||
// because if both source and destination use the same provider,
|
||||
// the field type should be natively supported
|
||||
if ( layer->dataProvider()->name() != provider->name() )
|
||||
if ( !convertField( fld ) )
|
||||
{
|
||||
if ( !convertField( fld ) )
|
||||
{
|
||||
QgsDebugMsg( "error creating field " + fld.name() + ": unsupported type" );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "unsupported type for field %1" )
|
||||
.arg( fld.name() );
|
||||
QgsDebugMsg( "error creating field " + fld.name() + ": unsupported type" );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "Unsupported type for field %1" )
|
||||
.arg( fld.name() );
|
||||
|
||||
delete provider;
|
||||
return ErrAttributeTypeUnsupported;
|
||||
}
|
||||
delete provider;
|
||||
return QgsVectorLayerImport::ErrAttributeTypeUnsupported;
|
||||
}
|
||||
|
||||
flist.append( fld );
|
||||
QgsDebugMsg( "creating field " + fld.name() +
|
||||
QgsDebugMsg( "creating field #" + QString::number( fldIt.key() ) +
|
||||
" -> #" + QString::number( offset ) +
|
||||
" name " + fld.name() +
|
||||
" type " + QString( QVariant::typeToName( fld.type() ) ) +
|
||||
" typename " + fld.typeName() +
|
||||
" width " + QString::number( fld.length() ) +
|
||||
" precision " + QString::number( fld.precision() ) );
|
||||
|
||||
flist.append( fld );
|
||||
if ( oldToNewAttrIdxMap )
|
||||
oldToNewAttrIdxMap->insert( fldIt.key(), offset++ );
|
||||
}
|
||||
|
||||
if ( !provider->addAttributes( flist ) )
|
||||
{
|
||||
QgsDebugMsg( "error creating fields " );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "creation of fields failed" );
|
||||
*errorMessage = QObject::tr( "Creation of fields failed" );
|
||||
|
||||
delete provider;
|
||||
return ErrAttributeCreationFailed;
|
||||
return QgsVectorLayerImport::ErrAttributeCreationFailed;
|
||||
}
|
||||
|
||||
QgsDebugMsg( "Done creating fields" );
|
||||
}
|
||||
|
||||
QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList();
|
||||
QgsFeature fet;
|
||||
|
||||
layer->select( allAttr, QgsRectangle(), layer->wkbType() != QGis::WKBNoGeometry );
|
||||
|
||||
const QgsFeatureIds& ids = layer->selectedFeaturesIds();
|
||||
|
||||
// Create our transform
|
||||
if ( destCRS )
|
||||
{
|
||||
ct = new QgsCoordinateTransform( layer->crs(), *destCRS );
|
||||
}
|
||||
|
||||
// Check for failure
|
||||
if ( ct == NULL )
|
||||
{
|
||||
shallTransform = false;
|
||||
}
|
||||
|
||||
int n = 0, errors = 0;
|
||||
|
||||
// make all the changes using one transaction only
|
||||
if ( provider->connectRW() )
|
||||
{
|
||||
provider->connectionRW->PQexecNR( "BEGIN" );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( "unable to estabilish a RW connection" );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "unable to estabilish a RW connection. Writing of features failed" );
|
||||
|
||||
delete provider;
|
||||
return ErrFeatureWriteFailed;
|
||||
}
|
||||
|
||||
// write all features
|
||||
QgsFeatureList flist;
|
||||
while (1)
|
||||
{
|
||||
while ( layer->nextFeature( fet ) )
|
||||
{
|
||||
if ( onlySelected && !ids.contains( fet.id() ) )
|
||||
continue;
|
||||
|
||||
if ( shallTransform )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( fet.geometry() )
|
||||
{
|
||||
fet.geometry()->transform( *ct );
|
||||
}
|
||||
}
|
||||
catch ( QgsCsException &e )
|
||||
{
|
||||
delete ct;
|
||||
|
||||
QString msg = QObject::tr( "Failed to transform a point while drawing a feature of type '%1'. Writing stopped. (Exception: %2)" )
|
||||
.arg( fet.typeName() ).arg( e.what() );
|
||||
QgsLogger::warning( msg );
|
||||
if ( errorMessage )
|
||||
*errorMessage = msg;
|
||||
|
||||
provider->connectionRW->PQexecNR( "ROLLBACK" );
|
||||
delete provider;
|
||||
return ErrProjection;
|
||||
}
|
||||
}
|
||||
if ( skipAttributeCreation )
|
||||
{
|
||||
fet.clearAttributeMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
// fix attributes position based on how the table was created.
|
||||
// The first field is reserved to the primary key and the second one to
|
||||
// the geometry column (if any), so move the other attributes after these fields
|
||||
int offset = geometryColumn.isEmpty() ? 1 : 2;
|
||||
|
||||
const QgsAttributeMap &attrs = fet.attributeMap();
|
||||
QgsAttributeMap newAttrs;
|
||||
for ( QgsAttributeMap::const_iterator it = attrs.begin(); it != attrs.end(); it++ )
|
||||
{
|
||||
const QgsField &fld = fields[ it.key() ];
|
||||
if ( fld.name() == primaryKey || fld.name() == geometryColumn )
|
||||
continue;
|
||||
|
||||
newAttrs.insert( offset++, *it );
|
||||
}
|
||||
fet.setAttributeMap( newAttrs );
|
||||
|
||||
}
|
||||
|
||||
flist.append( fet );
|
||||
|
||||
// add 100 features at the same time
|
||||
if ( flist.size() == 100 )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !provider->addFeatures( flist, false ) )
|
||||
{
|
||||
QgsDebugMsg( QString( "failed while adding features from %1 to %2" )
|
||||
.arg( flist.first().id() )
|
||||
.arg( flist.last().id() )
|
||||
);
|
||||
if ( errorMessage )
|
||||
*errorMessage += QObject::tr( "failed while adding features from %1 to %2\n" )
|
||||
.arg( flist.first().id() )
|
||||
.arg( flist.last().id() );
|
||||
}
|
||||
n += flist.size();
|
||||
|
||||
if ( flist.size() < 100 )
|
||||
break;
|
||||
flist.clear();
|
||||
}
|
||||
|
||||
provider->connectionRW->PQexecNR( "COMMIT" );
|
||||
delete provider;
|
||||
|
||||
if ( shallTransform )
|
||||
{
|
||||
delete ct;
|
||||
}
|
||||
|
||||
if ( errors > 0 && n > 0 )
|
||||
{
|
||||
if ( errorMessage )
|
||||
{
|
||||
*errorMessage += QObject::tr( "Only %1 of %2 features written." ).arg( n - errors ).arg( n );
|
||||
}
|
||||
return ErrFeatureWriteFailed;
|
||||
}
|
||||
|
||||
return NoError;
|
||||
return QgsVectorLayerImport::NoError;
|
||||
}
|
||||
|
||||
|
||||
@ -2897,11 +2762,6 @@ QString QgsPostgresProvider::paramValue( QString fieldValue, const QString &defa
|
||||
}
|
||||
|
||||
bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist )
|
||||
{
|
||||
return addFeatures( flist, true );
|
||||
}
|
||||
|
||||
bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, bool useNewTransaction )
|
||||
{
|
||||
if ( flist.size() == 0 )
|
||||
return true;
|
||||
@ -2909,10 +2769,6 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, bool useNewTransac
|
||||
if ( isQuery )
|
||||
return false;
|
||||
|
||||
// if there's no rw connection opened then create a new transaction
|
||||
if ( !connectionRW )
|
||||
useNewTransaction = true;
|
||||
|
||||
if ( !connectRW() )
|
||||
return false;
|
||||
|
||||
@ -2920,8 +2776,7 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, bool useNewTransac
|
||||
|
||||
try
|
||||
{
|
||||
if ( useNewTransaction )
|
||||
connectionRW->PQexecNR( "BEGIN" );
|
||||
connectionRW->PQexecNR( "BEGIN" );
|
||||
|
||||
// Prepare the INSERT statement
|
||||
QString insert = QString( "INSERT INTO %1 (" ).arg( mQuery );
|
||||
@ -3094,22 +2949,19 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, bool useNewTransac
|
||||
flist[i].setFeatureId( newIds[i] );
|
||||
|
||||
connectionRW->PQexecNR( "DEALLOCATE addfeatures" );
|
||||
if ( useNewTransaction )
|
||||
connectionRW->PQexecNR( "COMMIT" );
|
||||
connectionRW->PQexecNR( "COMMIT" );
|
||||
|
||||
featuresCounted += flist.size();
|
||||
}
|
||||
catch ( PGException &e )
|
||||
{
|
||||
e.showErrorMessage( tr( "Error while adding features" ) );
|
||||
if ( useNewTransaction )
|
||||
connectionRW->PQexecNR( "ROLLBACK" );
|
||||
connectionRW->PQexecNR( "ROLLBACK" );
|
||||
connectionRW->PQexecNR( "DEALLOCATE addfeatures" );
|
||||
returnvalue = false;
|
||||
}
|
||||
|
||||
if ( useNewTransaction )
|
||||
rewind();
|
||||
rewind();
|
||||
return returnvalue;
|
||||
}
|
||||
|
||||
@ -4208,14 +4060,18 @@ QGISEXTERN bool isProvider()
|
||||
return true;
|
||||
}
|
||||
|
||||
QGISEXTERN int importVector(
|
||||
QgsVectorLayer *layer,
|
||||
const QString& uri,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected,
|
||||
QString *errorMessage,
|
||||
bool skipAttributeCreation,
|
||||
const QMap<QString,QVariant> *options )
|
||||
QGISEXTERN QgsVectorLayerImport::ImportError createEmptyLayer(
|
||||
const QString& uri,
|
||||
const QgsFieldMap &fields,
|
||||
QGis::WkbType wkbType,
|
||||
const QgsCoordinateReferenceSystem *srs,
|
||||
bool overwrite,
|
||||
QMap<int, int> *oldToNewAttrIdxMap,
|
||||
QString *errorMessage,
|
||||
const QMap<QString,QVariant> *options )
|
||||
{
|
||||
return QgsPostgresProvider::importVector( layer, uri, destCRS, onlySelected, errorMessage, skipAttributeCreation, options );
|
||||
return QgsPostgresProvider::createEmptyLayer(
|
||||
uri, fields, wkbType, srs, overwrite,
|
||||
oldToNewAttrIdxMap, errorMessage, options
|
||||
);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ extern "C"
|
||||
}
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsrectangle.h"
|
||||
#include "qgsvectorlayerimport.h"
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <fstream>
|
||||
@ -32,7 +33,6 @@ extern "C"
|
||||
class QgsFeature;
|
||||
class QgsField;
|
||||
class QgsGeometry;
|
||||
class QgsVectorLayer;
|
||||
|
||||
#include "qgsdatasourceuri.h"
|
||||
|
||||
@ -50,27 +50,15 @@ class QgsPostgresProvider : public QgsVectorDataProvider
|
||||
|
||||
public:
|
||||
|
||||
enum WriterError
|
||||
{
|
||||
NoError = 0,
|
||||
ErrDriverNotFound,
|
||||
ErrCreateDataSource,
|
||||
ErrCreateLayer,
|
||||
ErrAttributeTypeUnsupported,
|
||||
ErrAttributeCreationFailed,
|
||||
ErrProjection,
|
||||
ErrFeatureWriteFailed,
|
||||
ErrInvalidLayer,
|
||||
ErrConnectionFailed,
|
||||
};
|
||||
|
||||
/** Import a vector layer into the database */
|
||||
static WriterError importVector( QgsVectorLayer* layer,
|
||||
static QgsVectorLayerImport::ImportError createEmptyLayer(
|
||||
const QString& uri,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected = false,
|
||||
const QgsFieldMap &fields,
|
||||
QGis::WkbType wkbType,
|
||||
const QgsCoordinateReferenceSystem *srs,
|
||||
bool overwrite,
|
||||
QMap<int, int> *oldToNewAttrIdxMap,
|
||||
QString *errorMessage = 0,
|
||||
bool skipAttributeCreation = false,
|
||||
const QMap<QString,QVariant> *options = 0
|
||||
);
|
||||
|
||||
@ -379,15 +367,9 @@ class QgsPostgresProvider : public QgsVectorDataProvider
|
||||
*/
|
||||
bool loadFields();
|
||||
|
||||
/** convert a QgsField to work with PG
|
||||
*/
|
||||
/** convert a QgsField to work with PG */
|
||||
static bool convertField( QgsField &field );
|
||||
|
||||
/**Adds a list of features
|
||||
@param useNewTransaction create a new transaction
|
||||
@return true in case of success and false in case of failure*/
|
||||
bool addFeatures( QgsFeatureList & flist, bool useNewTransaction );
|
||||
|
||||
/**Parses the enum_range of an attribute and inserts the possible values into a stringlist
|
||||
@param enumValues the stringlist where the values are appended
|
||||
@param attributeName the name of the enum attribute
|
||||
|
@ -16,13 +16,13 @@ email : a.furieri@lqt.it
|
||||
|
||||
#include <qgis.h>
|
||||
#include <qgsapplication.h>
|
||||
#include <qgsvectorlayer.h>
|
||||
#include <qgsfeature.h>
|
||||
#include <qgsfield.h>
|
||||
#include <qgsgeometry.h>
|
||||
#include <qgsmessageoutput.h>
|
||||
#include <qgsrectangle.h>
|
||||
#include <qgscoordinatereferencesystem.h>
|
||||
#include "qgsvectorlayerimport.h"
|
||||
|
||||
#include "qgsspatialiteprovider.h"
|
||||
|
||||
@ -87,38 +87,18 @@ bool QgsSpatiaLiteProvider::convertField( QgsField &field )
|
||||
return true;
|
||||
}
|
||||
|
||||
QgsSpatiaLiteProvider::WriterError
|
||||
QgsSpatiaLiteProvider::importVector(
|
||||
QgsVectorLayer *layer,
|
||||
QgsVectorLayerImport::ImportError
|
||||
QgsSpatiaLiteProvider::createEmptyLayer(
|
||||
const QString& uri,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected,
|
||||
const QgsFieldMap &fields,
|
||||
QGis::WkbType wkbType,
|
||||
const QgsCoordinateReferenceSystem *srs,
|
||||
bool overwrite,
|
||||
QMap<int, int> *oldToNewAttrIdxMap,
|
||||
QString *errorMessage,
|
||||
bool skipAttributeCreation,
|
||||
const QMap<QString,QVariant> *options )
|
||||
{
|
||||
const QgsCoordinateReferenceSystem* outputCRS;
|
||||
QgsCoordinateTransform* ct = 0;
|
||||
int shallTransform = false;
|
||||
|
||||
if ( !layer )
|
||||
{
|
||||
return ErrInvalidLayer;
|
||||
}
|
||||
|
||||
if ( destCRS && destCRS->isValid() )
|
||||
{
|
||||
// This means we should transform
|
||||
outputCRS = destCRS;
|
||||
shallTransform = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This means we shouldn't transform, use source CRS as output (if defined)
|
||||
outputCRS = &layer->crs();
|
||||
}
|
||||
|
||||
QgsFieldMap fields = skipAttributeCreation ? QgsFieldMap() : layer->pendingFields();
|
||||
Q_UNUSED( options );
|
||||
|
||||
// populate members from the uri structure
|
||||
QgsDataSourceURI dsUri( uri );
|
||||
@ -141,6 +121,7 @@ QgsSpatiaLiteProvider::importVector(
|
||||
sqlite3 *sqliteHandle = NULL;
|
||||
char *errMsg = NULL;
|
||||
int toCommit = false;
|
||||
QString sql;
|
||||
|
||||
// trying to open the SQLite DB
|
||||
spatialite_init( 0 );
|
||||
@ -150,7 +131,7 @@ QgsSpatiaLiteProvider::importVector(
|
||||
QgsDebugMsg( "Connection to database failed. Import of layer aborted." );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "Connection to database failed" );
|
||||
return ErrConnectionFailed;
|
||||
return QgsVectorLayerImport::ErrConnectionFailed;
|
||||
}
|
||||
|
||||
sqliteHandle = handle->handle();
|
||||
@ -174,12 +155,12 @@ QgsSpatiaLiteProvider::importVector(
|
||||
else
|
||||
{
|
||||
// search for the passed field
|
||||
for ( QgsFieldMap::iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
|
||||
for ( QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
|
||||
{
|
||||
if ( fldIt.value().name() == primaryKey )
|
||||
{
|
||||
// found, get the field type
|
||||
QgsField &fld = fldIt.value();
|
||||
QgsField fld = fldIt.value();
|
||||
if ( convertField( fld ) )
|
||||
{
|
||||
primaryKeyType = fld.typeName();
|
||||
@ -192,11 +173,12 @@ QgsSpatiaLiteProvider::importVector(
|
||||
if ( primaryKeyType.isEmpty() )
|
||||
{
|
||||
primaryKeyType = "INTEGER";
|
||||
/* TODO
|
||||
// check the feature count to choose if create a bigint pk field
|
||||
if ( layer->featureCount() > 0xFFFFFF )
|
||||
{
|
||||
primaryKeyType = "BIGINT";
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
try
|
||||
@ -207,21 +189,23 @@ QgsSpatiaLiteProvider::importVector(
|
||||
|
||||
toCommit = true;
|
||||
|
||||
// delete the table if exists and the related entry in geometry_columns, then re-create it
|
||||
QString sql = QString( "DROP TABLE IF EXISTS %1" )
|
||||
.arg( quotedIdentifier( tableName ) );
|
||||
if ( overwrite )
|
||||
{
|
||||
// delete the table if exists and the related entry in geometry_columns, then re-create it
|
||||
sql = QString( "DROP TABLE IF EXISTS %1" )
|
||||
.arg( quotedIdentifier( tableName ) );
|
||||
|
||||
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), NULL, NULL, &errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
throw SLException( errMsg );
|
||||
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), NULL, NULL, &errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
throw SLException( errMsg );
|
||||
|
||||
sql = QString( "DELETE FROM geometry_columns WHERE f_table_name = %1" )
|
||||
.arg( quotedValue( tableName ) );
|
||||
|
||||
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), NULL, NULL, &errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
throw SLException( errMsg );
|
||||
sql = QString( "DELETE FROM geometry_columns WHERE f_table_name = %1" )
|
||||
.arg( quotedValue( tableName ) );
|
||||
|
||||
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), NULL, NULL, &errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
throw SLException( errMsg );
|
||||
}
|
||||
|
||||
sql = QString( "CREATE TABLE %1 (%2 %3 PRIMARY KEY)" )
|
||||
.arg( quotedIdentifier( tableName ) )
|
||||
@ -234,9 +218,9 @@ QgsSpatiaLiteProvider::importVector(
|
||||
|
||||
// get geometry type, dim and srid
|
||||
int dim = 2;
|
||||
long srid = outputCRS->postgisSrid();
|
||||
long srid = srs->postgisSrid();
|
||||
|
||||
switch( layer->wkbType() )
|
||||
switch( wkbType )
|
||||
{
|
||||
case QGis::WKBPoint25D:
|
||||
dim = 3;
|
||||
@ -285,7 +269,7 @@ QgsSpatiaLiteProvider::importVector(
|
||||
}
|
||||
|
||||
// create geometry column
|
||||
if ( !geometryType.isEmpty() && dim > 0 )
|
||||
if ( !geometryType.isEmpty() )
|
||||
{
|
||||
sql = QString( "SELECT AddGeometryColumn(%1, %2, %3, %4, %5)" )
|
||||
.arg( QgsSpatiaLiteProvider::quotedValue( tableName ) )
|
||||
@ -297,13 +281,10 @@ QgsSpatiaLiteProvider::importVector(
|
||||
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), NULL, NULL, &errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
throw SLException( errMsg );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
geometryColumn = QString();
|
||||
geometryType = QString();
|
||||
dim = 0;
|
||||
}
|
||||
|
||||
ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
|
||||
@ -331,7 +312,7 @@ QgsSpatiaLiteProvider::importVector(
|
||||
}
|
||||
|
||||
SqliteHandles::closeDb( handle );
|
||||
return ErrCreateLayer;
|
||||
return QgsVectorLayerImport::ErrCreateLayer;
|
||||
}
|
||||
|
||||
SqliteHandles::closeDb( handle );
|
||||
@ -349,19 +330,24 @@ QgsSpatiaLiteProvider::importVector(
|
||||
.arg( tableName );
|
||||
|
||||
delete provider;
|
||||
return ErrCreateLayer;
|
||||
return QgsVectorLayerImport::ErrInvalidLayer;
|
||||
}
|
||||
|
||||
QgsDebugMsg( "layer loaded" );
|
||||
|
||||
// add fields to the layer
|
||||
if ( oldToNewAttrIdxMap )
|
||||
oldToNewAttrIdxMap->clear();
|
||||
|
||||
if ( fields.size() > 0 )
|
||||
{
|
||||
int offset = 1;
|
||||
|
||||
// get the list of fields
|
||||
QList<QgsField> flist;
|
||||
for ( QgsFieldMap::iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
|
||||
for ( QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
|
||||
{
|
||||
QgsField &fld = fldIt.value();
|
||||
QgsField fld = fldIt.value();
|
||||
if ( fld.name() == primaryKey )
|
||||
continue;
|
||||
|
||||
@ -371,28 +357,28 @@ QgsSpatiaLiteProvider::importVector(
|
||||
continue;
|
||||
}
|
||||
|
||||
// convert field type only if the source provider is different from the destination one
|
||||
// because if both source and destination use the same provider,
|
||||
// the field type should be natively supported
|
||||
if ( layer->dataProvider()->name() != provider->name() )
|
||||
if ( !convertField( fld ) )
|
||||
{
|
||||
if ( !convertField( fld ) )
|
||||
{
|
||||
QgsDebugMsg( "error creating field " + fld.name() + ": unsupported type" );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "unsupported type for field %1" )
|
||||
.arg( fld.name() );
|
||||
QgsDebugMsg( "error creating field " + fld.name() + ": unsupported type" );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "unsupported type for field %1" )
|
||||
.arg( fld.name() );
|
||||
|
||||
delete provider;
|
||||
return ErrAttributeTypeUnsupported;
|
||||
}
|
||||
delete provider;
|
||||
return QgsVectorLayerImport::ErrAttributeTypeUnsupported;
|
||||
}
|
||||
|
||||
flist.append( fld );
|
||||
QgsDebugMsg( "creating field " + fld.name() +
|
||||
QgsDebugMsg( "creating field #" + QString::number( fldIt.key() ) +
|
||||
" -> #" + QString::number( offset ) +
|
||||
" name " + fld.name() +
|
||||
" type " + QString( QVariant::typeToName( fld.type() ) ) +
|
||||
" typename " + fld.typeName() +
|
||||
" width " + QString::number( fld.length() ) +
|
||||
" precision " + QString::number( fld.precision() ) );
|
||||
|
||||
flist.append( fld );
|
||||
if ( oldToNewAttrIdxMap )
|
||||
oldToNewAttrIdxMap->insert( fldIt.key(), offset++ );
|
||||
}
|
||||
|
||||
if ( !provider->addAttributes( flist ) )
|
||||
@ -402,171 +388,12 @@ QgsSpatiaLiteProvider::importVector(
|
||||
*errorMessage = QObject::tr( "creation of fields failed" );
|
||||
|
||||
delete provider;
|
||||
return ErrAttributeCreationFailed;
|
||||
return QgsVectorLayerImport::ErrAttributeCreationFailed;
|
||||
}
|
||||
|
||||
QgsDebugMsg( "Done creating fields" );
|
||||
}
|
||||
|
||||
QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList();
|
||||
QgsFeature fet;
|
||||
|
||||
layer->select( allAttr, QgsRectangle(), layer->wkbType() != QGis::WKBNoGeometry );
|
||||
|
||||
const QgsFeatureIds& ids = layer->selectedFeaturesIds();
|
||||
|
||||
// Create our transform
|
||||
if ( destCRS )
|
||||
{
|
||||
ct = new QgsCoordinateTransform( layer->crs(), *destCRS );
|
||||
}
|
||||
|
||||
// Check for failure
|
||||
if ( ct == NULL )
|
||||
{
|
||||
shallTransform = false;
|
||||
}
|
||||
|
||||
int n = 0, errors = 0;
|
||||
char *errMsg = NULL;
|
||||
|
||||
|
||||
// make all the changes using one transaction only
|
||||
int ret = sqlite3_exec( provider->sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "unable to start a new transaction" );
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "unable to start a new transaction. Writing of features failed" );
|
||||
|
||||
if ( errMsg )
|
||||
sqlite3_free( errMsg );
|
||||
|
||||
delete provider;
|
||||
return ErrFeatureWriteFailed;
|
||||
}
|
||||
|
||||
if ( errorMessage )
|
||||
errorMessage->clear();
|
||||
|
||||
// write all features
|
||||
QgsFeatureList flist;
|
||||
while (1)
|
||||
{
|
||||
while ( layer->nextFeature( fet ) )
|
||||
{
|
||||
if ( onlySelected && !ids.contains( fet.id() ) )
|
||||
continue;
|
||||
|
||||
if ( shallTransform )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( fet.geometry() )
|
||||
{
|
||||
fet.geometry()->transform( *ct );
|
||||
}
|
||||
}
|
||||
catch ( QgsCsException &e )
|
||||
{
|
||||
delete ct;
|
||||
|
||||
QString msg = QObject::tr( "Failed to transform a point while drawing a feature of type '%1'. Writing stopped. (Exception: %2)" )
|
||||
.arg( fet.typeName() ).arg( e.what() );
|
||||
QgsLogger::warning( msg );
|
||||
if ( errorMessage )
|
||||
*errorMessage = msg;
|
||||
|
||||
sqlite3_exec( provider->sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
|
||||
delete provider;
|
||||
return ErrProjection;
|
||||
}
|
||||
}
|
||||
if ( skipAttributeCreation )
|
||||
{
|
||||
fet.clearAttributeMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
// fix attributes position based on how the table was created.
|
||||
// The first field is reserved to the primary key, so move the
|
||||
// other attributes after this field
|
||||
int offset = 1;
|
||||
|
||||
const QgsAttributeMap &attrs = fet.attributeMap();
|
||||
QgsAttributeMap newAttrs;
|
||||
for ( QgsAttributeMap::const_iterator it = attrs.begin(); it != attrs.end(); it++ )
|
||||
{
|
||||
const QgsField &fld = fields[ it.key() ];
|
||||
if ( fld.name() == primaryKey || fld.name() == geometryColumn )
|
||||
continue;
|
||||
|
||||
newAttrs.insert( offset++, *it );
|
||||
}
|
||||
fet.setAttributeMap( newAttrs );
|
||||
|
||||
}
|
||||
|
||||
flist.append( fet );
|
||||
|
||||
// add 100 features at the same time
|
||||
if ( flist.size() == 100 )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !provider->addFeatures( flist, false ) )
|
||||
{
|
||||
QgsDebugMsg( QString( "failed while adding features from %1 to %2" )
|
||||
.arg( flist.first().id() )
|
||||
.arg( flist.last().id() )
|
||||
);
|
||||
if ( errorMessage )
|
||||
*errorMessage += QObject::tr( "failed while adding features from %1 to %2\n" )
|
||||
.arg( flist.first().id() )
|
||||
.arg( flist.last().id() );
|
||||
}
|
||||
n += flist.size();
|
||||
|
||||
if ( flist.size() < 100 )
|
||||
break;
|
||||
flist.clear();
|
||||
}
|
||||
|
||||
ret = sqlite3_exec( provider->sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( QString( "unable to write features on the database: failed to commit the transaction. %1" )
|
||||
.arg( errMsg ? QString::fromUtf8( errMsg ) : "unknown cause" )
|
||||
);
|
||||
if ( errorMessage )
|
||||
*errorMessage = QObject::tr( "unable to write features on the database: failed to commit the transaction. %1" )
|
||||
.arg( errMsg ? QString::fromUtf8( errMsg ) : "unknown cause" );
|
||||
|
||||
if ( errMsg )
|
||||
sqlite3_free( errMsg );
|
||||
|
||||
sqlite3_exec( provider->sqliteHandle, "ROLLBACK", NULL, NULL, NULL );
|
||||
delete provider;
|
||||
return ErrFeatureWriteFailed;
|
||||
}
|
||||
|
||||
delete provider;
|
||||
|
||||
if ( shallTransform )
|
||||
{
|
||||
delete ct;
|
||||
}
|
||||
|
||||
if ( errors > 0 && n > 0 )
|
||||
{
|
||||
if ( errorMessage )
|
||||
{
|
||||
*errorMessage += QObject::tr( "Only %1 of %2 features written." ).arg( n - errors ).arg( n );
|
||||
}
|
||||
return ErrFeatureWriteFailed;
|
||||
}
|
||||
|
||||
return NoError;
|
||||
return QgsVectorLayerImport::NoError;
|
||||
}
|
||||
|
||||
|
||||
@ -3718,11 +3545,6 @@ void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueV
|
||||
|
||||
|
||||
bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList & flist )
|
||||
{
|
||||
return addFeatures( flist, true );
|
||||
}
|
||||
|
||||
bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList & flist, bool useNewTransaction )
|
||||
{
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
char *errMsg = NULL;
|
||||
@ -3736,16 +3558,13 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList & flist, bool useNewTran
|
||||
return true;
|
||||
const QgsAttributeMap & attributevec = flist[0].attributeMap();
|
||||
|
||||
if ( useNewTransaction )
|
||||
ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
ret = sqlite3_exec( sqliteHandle, "BEGIN", NULL, NULL, &errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
// some error occurred
|
||||
goto abort;
|
||||
}
|
||||
toCommit = true;
|
||||
// some error occurred
|
||||
goto abort;
|
||||
}
|
||||
toCommit = true;
|
||||
|
||||
sql = QString( "INSERT INTO %1(" ).arg( quotedIdentifier( mTableName ) );
|
||||
values = QString( ") VALUES (" );
|
||||
@ -3877,14 +3696,11 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList & flist, bool useNewTran
|
||||
}
|
||||
sqlite3_finalize( stmt );
|
||||
|
||||
if ( useNewTransaction )
|
||||
ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
ret = sqlite3_exec( sqliteHandle, "COMMIT", NULL, NULL, &errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
// some error occurred
|
||||
goto abort;
|
||||
}
|
||||
// some error occurred
|
||||
goto abort;
|
||||
}
|
||||
return true;
|
||||
|
||||
@ -5064,14 +4880,18 @@ QGISEXTERN bool isProvider()
|
||||
return true;
|
||||
}
|
||||
|
||||
QGISEXTERN int importVector(
|
||||
QgsVectorLayer *layer,
|
||||
const QString& uri,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected,
|
||||
QString *errorMessage,
|
||||
bool skipAttributeCreation,
|
||||
const QMap<QString,QVariant> *options )
|
||||
QGISEXTERN QgsVectorLayerImport::ImportError createEmptyLayer(
|
||||
const QString& uri,
|
||||
const QgsFieldMap &fields,
|
||||
QGis::WkbType wkbType,
|
||||
const QgsCoordinateReferenceSystem *srs,
|
||||
bool overwrite,
|
||||
QMap<int, int> *oldToNewAttrIdxMap,
|
||||
QString *errorMessage,
|
||||
const QMap<QString,QVariant> *options )
|
||||
{
|
||||
return QgsSpatiaLiteProvider::importVector( layer, uri, destCRS, onlySelected, errorMessage, skipAttributeCreation, options );
|
||||
return QgsSpatiaLiteProvider::createEmptyLayer(
|
||||
uri, fields, wkbType, srs, overwrite,
|
||||
oldToNewAttrIdxMap, errorMessage, options
|
||||
);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ extern "C"
|
||||
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsrectangle.h"
|
||||
#include "qgsvectorlayerimport.h"
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <fstream>
|
||||
@ -31,7 +32,6 @@ extern "C"
|
||||
|
||||
class QgsFeature;
|
||||
class QgsField;
|
||||
class QgsVectorLayer;
|
||||
|
||||
#include "qgsdatasourceuri.h"
|
||||
|
||||
@ -47,29 +47,17 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
|
||||
{
|
||||
Q_OBJECT public:
|
||||
|
||||
enum WriterError
|
||||
{
|
||||
NoError = 0,
|
||||
ErrDriverNotFound,
|
||||
ErrCreateDataSource,
|
||||
ErrCreateLayer,
|
||||
ErrAttributeTypeUnsupported,
|
||||
ErrAttributeCreationFailed,
|
||||
ErrProjection,
|
||||
ErrFeatureWriteFailed,
|
||||
ErrInvalidLayer,
|
||||
ErrConnectionFailed,
|
||||
};
|
||||
|
||||
/** Import a vector layer into the database */
|
||||
static WriterError importVector( QgsVectorLayer* layer,
|
||||
const QString& uri,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected = false,
|
||||
QString *errorMessage = 0,
|
||||
bool skipAttributeCreation = false,
|
||||
const QMap<QString,QVariant> *options = 0
|
||||
);
|
||||
static QgsVectorLayerImport::ImportError createEmptyLayer(
|
||||
const QString& uri,
|
||||
const QgsFieldMap &fields,
|
||||
QGis::WkbType wkbType,
|
||||
const QgsCoordinateReferenceSystem *srs,
|
||||
bool overwrite,
|
||||
QMap<int, int> *oldToNewAttrIdxMap,
|
||||
QString *errorMessage = 0,
|
||||
const QMap<QString,QVariant> *options = 0
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor of the vector provider
|
||||
@ -288,8 +276,7 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
|
||||
/** loads fields from input file to member attributeFields */
|
||||
void loadFields();
|
||||
|
||||
/** convert a QgsField to work with SL
|
||||
*/
|
||||
/** convert a QgsField to work with SL */
|
||||
static bool convertField( QgsField &field );
|
||||
|
||||
QgsFieldMap attributeFields;
|
||||
@ -395,11 +382,6 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
|
||||
|
||||
const QgsField & field( int index ) const;
|
||||
|
||||
/**Adds a list of features
|
||||
@param useNewTransaction create a new transaction
|
||||
@return true in case of success and false in case of failure*/
|
||||
bool addFeatures( QgsFeatureList & flist, bool useNewTransaction = true );
|
||||
|
||||
/**
|
||||
* internal utility functions used to handle common SQLite tasks
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user