31 changes: 27 additions & 4 deletions src/core/qgsvectorlayerimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ QgsVectorLayerImport::QgsVectorLayerImport( const QString &uri,
QGis::WkbType geometryType,
const QgsCoordinateReferenceSystem* crs,
bool overwrite,
const QMap<QString, QVariant> *options )
const QMap<QString, QVariant> *options,
QProgressDialog *progress )
: mErrorCount( 0 )
, mProgress( progress )
{
mProvider = NULL;

Expand Down Expand Up @@ -86,7 +88,7 @@ QgsVectorLayerImport::QgsVectorLayerImport( const QString &uri,
QgsDebugMsg( "Created empty layer" );

QgsVectorDataProvider *vectorProvider = ( QgsVectorDataProvider* ) pReg->provider( providerKey, uri );
if ( !vectorProvider || !vectorProvider->isValid() )
if ( !vectorProvider || !vectorProvider->isValid() || ( vectorProvider->capabilities() & QgsVectorDataProvider::AddFeatures ) == 0 )
{
mError = ErrInvalidLayer;
mErrorMessage = QObject::tr( "Loading of layer failed" );
Expand Down Expand Up @@ -196,7 +198,8 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
bool onlySelected,
QString *errorMessage,
bool skipAttributeCreation,
QMap<QString, QVariant> *options )
QMap<QString, QVariant> *options,
QProgressDialog *progress )
{
const QgsCoordinateReferenceSystem* outputCRS;
QgsCoordinateTransform* ct = 0;
Expand All @@ -219,6 +222,7 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
outputCRS = &layer->crs();
}


bool overwrite = false;
bool forceSinglePartGeom = false;
if ( options )
Expand Down Expand Up @@ -269,7 +273,7 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
}

QgsVectorLayerImport * writer =
new QgsVectorLayerImport( uri, providerKey, fields, wkbType, outputCRS, overwrite, options );
new QgsVectorLayerImport( uri, providerKey, fields, wkbType, outputCRS, overwrite, options, progress );

// check whether file creation was successful
ImportError err = writer->hasError();
Expand Down Expand Up @@ -312,9 +316,23 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
*errorMessage = QObject::tr( "Feature write errors:" );
}

if ( progress )
{
progress->setRange( 0, layer->featureCount() );
}

// write all features
while ( layer->nextFeature( fet ) )
{
if ( progress && progress->wasCanceled() )
{
if ( errorMessage )
{
*errorMessage += "\n" + QObject::tr( "Import was canceled at %1 of %2" ).arg( progress->value() ).arg( progress->maximum() );
}
break;
}

if ( writer->errorCount() > 1000 )
{
if ( errorMessage )
Expand Down Expand Up @@ -362,6 +380,11 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
}
}
n++;

if ( progress )
{
progress->setValue( n );
}
}

// flush the buffer to be sure that all features are written
Expand Down
9 changes: 7 additions & 2 deletions src/core/qgsvectorlayerimport.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"

class QProgressDialog;

/** \ingroup core
* A convenience class for writing vector files to disk.
There are two possibilities how to use this class:
Expand Down Expand Up @@ -59,7 +61,8 @@ class CORE_EXPORT QgsVectorLayerImport
bool onlySelected = false,
QString *errorMessage = 0,
bool skipAttributeCreation = false,
QMap<QString, QVariant> *options = 0
QMap<QString, QVariant> *options = 0,
QProgressDialog *progress = 0
);

/** create a empty layer and add fields to it */
Expand All @@ -69,7 +72,8 @@ class CORE_EXPORT QgsVectorLayerImport
QGis::WkbType geometryType,
const QgsCoordinateReferenceSystem* crs,
bool overwrite = false,
const QMap<QString, QVariant> *options = 0
const QMap<QString, QVariant> *options = 0,
QProgressDialog *progress = 0
);

/** checks whether there were any errors */
Expand Down Expand Up @@ -105,6 +109,7 @@ class CORE_EXPORT QgsVectorLayerImport
QMap<int, int> mOldToNewAttrIdx;

QgsFeatureList mFeatureBuffer;
QProgressDialog *mProgress;
};

#endif
1 change: 1 addition & 0 deletions src/gui/attributetable/qgsattributetablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,7 @@ void QgsAttributeTableModel::executeAction( int action, const QModelIndex &idx )
QgsFeature QgsAttributeTableModel::feature( const QModelIndex &idx ) const
{
QgsFeature f;
f.initAttributes( mAttributes.size() );
f.setFeatureId( rowToId( idx.row() ) );
for ( int i = 0; i < mAttributes.size(); i++ )
{
Expand Down
1 change: 1 addition & 0 deletions src/providers/oracle/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ SET(ORACLE_SRCS
qgsoraclenewconnection.cpp
qgsoracletablemodel.cpp
qgsoraclecolumntypethread.cpp
qgsoraclefeatureiterator.cpp
)

SET(ORACLE_MOC_HDRS
Expand Down
316 changes: 316 additions & 0 deletions src/providers/oracle/qgsoraclefeatureiterator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,316 @@
/***************************************************************************
qgsoraclefeatureiterator.cpp - Oracle feature iterator
---------------------
begin : December 2012
copyright : (C) 2012 by Juergen E. Fischer
email : jef at norbit dot de
***************************************************************************
* *
* 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 "qgsoraclefeatureiterator.h"
#include "qgsoracleprovider.h"

#include "qgslogger.h"
#include "qgsmessagelog.h"
#include "qgsgeometry.h"

#include <QObject>

QgsOracleFeatureIterator::QgsOracleFeatureIterator( QgsOracleProvider *p, const QgsFeatureRequest &request )
: QgsAbstractFeatureIterator( request )
, P( p )
, mRewind( false )
{
mQry = QSqlQuery( *P->mConnection );

if( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
{
mAttributeList = mRequest.subsetOfAttributes();
if( mAttributeList.isEmpty() )
mAttributeList = P->attributeIndexes();
}
else
mAttributeList = P->attributeIndexes();

QString whereClause;

switch( request.filterType() )
{
case QgsFeatureRequest::FilterRect:
if( !P->mGeometryColumn.isNull() )
{
QgsRectangle rect( mRequest.filterRect() );
QString bbox = QString( "mdsys.sdo_geometry(2003,%1,NULL,"
"mdsys.sdo_elem_info_array(1,1003,3),"
"mdsys.sdo_ordinate_array(%2,%3,%4,%5)"
")" )
.arg( P->mSrid < 1 ? "NULL" : QString::number( P->mSrid ) )
.arg( rect.xMinimum(), 0, 'f', 16 )
.arg( rect.yMinimum(), 0, 'f', 16 )
.arg( rect.xMaximum(), 0, 'f', 16 )
.arg( rect.yMaximum(), 0, 'f', 16 );

if ( !P->mSpatialIndex.isNull() )
{
whereClause = QString( "sdo_filter(%1,%2)='TRUE'" ).arg( P->quotedIdentifier( P->mGeometryColumn ) ).arg( bbox );
#if 0
if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect )
{
whereClause += QString( " AND sdo_relate(%1,%2,'mask=ANYINTERACT')='TRUE'" )
.arg( quotedIdentifier( P->mGeometryColumn ) )
.arg( bbox );
}
#endif
}
}
break;

case QgsFeatureRequest::FilterFid:
whereClause = P->whereClause( request.filterFid() );
break;

case QgsFeatureRequest::FilterNone:
break;
}

if ( P->mRequestedGeomType != QGis::WKBUnknown && P->mRequestedGeomType != P->mDetectedGeomType )
{
if ( !whereClause.isEmpty() )
whereClause += " AND ";

whereClause += QgsOracleConn::databaseTypeFilter( "featureRequest", P->mGeometryColumn, P->mRequestedGeomType );
}

if ( !P->mSqlWhereClause.isEmpty() )
{
if ( !whereClause.isEmpty() )
whereClause += " AND ";
whereClause += "(" + P->mSqlWhereClause + ")";
}

if ( !openQuery( whereClause ) )
return;
}

QgsOracleFeatureIterator::~QgsOracleFeatureIterator()
{
close();
}

bool QgsOracleFeatureIterator::nextFeature( QgsFeature& feature )
{
feature.setValid( false );

if( !mQry.isActive() )
return false;

for ( ;; )
{
feature.initAttributes( P->fields().count() );
feature.setGeometry( 0 );

if ( mRewind )
{
mRewind = false;
if( !mQry.first() )
return true;
}
else if( !mQry.next() )
{
return false;
}

int col = 0;

if ( (mRequest.flags() & QgsFeatureRequest::NoGeometry ) == 0 ||
( (mRequest.flags() & QgsFeatureRequest::ExactIntersect ) != 0 && !P->mConnection->hasSpatial() ) )
{
QByteArray *ba = static_cast<QByteArray*>( mQry.value( col++ ).data() );
unsigned char *copy = new unsigned char[ba->size()];
memcpy( copy, ba->constData(), ba->size() );

feature.setGeometryAndOwnership( copy, ba->size() );

if ( !P->mConnection->hasSpatial() &&
mRequest.filterType() == QgsFeatureRequest::FilterRect &&
(mRequest.flags() & QgsFeatureRequest::ExactIntersect ) != 0 &&
(!feature.geometry() || !feature.geometry()->intersects( mRequest.filterRect() ) ) )
{
// skip feature that don't intersect with our rectangle
QgsDebugMsg( "no intersect" );
continue;
}


if ( (mRequest.flags() & QgsFeatureRequest::NoGeometry ) != 0 )
{
feature.setGeometryAndOwnership( 0, 0 );
}
}

QgsFeatureId fid = 0;

switch ( P->mPrimaryKeyType )
{
case QgsOracleProvider::pktInt:
// get 64bit integer from result
fid = mQry.value( col++ ).toLongLong();
if ( mAttributeList.contains( P->mPrimaryKeyAttrs[0] ) )
feature.setAttribute( P->mPrimaryKeyAttrs[0], fid );
break;

case QgsOracleProvider::pktRowId:
case QgsOracleProvider::pktFidMap:
{
QList<QVariant> primaryKeyVals;

if ( P->mPrimaryKeyType == QgsOracleProvider::pktFidMap )
{
foreach ( int idx, P->mPrimaryKeyAttrs )
{
const QgsField &fld = P->field( idx );

QVariant v = P->convertValue( fld.type(), mQry.value( col ).toString() );
primaryKeyVals << v;

if ( mAttributeList.contains( idx ) )
feature.setAttribute( idx, v );

col++;
}
}
else
{
primaryKeyVals << mQry.value( col++ );
}

fid = P->lookupFid( QVariant( primaryKeyVals ) );
}
break;

case QgsOracleProvider::pktUnknown:
Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" );
return false;
}

feature.setFeatureId( fid );
QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 5 );

// iterate attributes
foreach ( int idx, mAttributeList )
{
if ( P->mPrimaryKeyAttrs.contains( idx ) )
continue;

const QgsField &fld = P->field( idx );

QVariant v = P->convertValue( fld.type(), mQry.value( col ).toString() );
feature.setAttribute( idx, v );

col++;
}

feature.setValid( true );
return true;
}
}

bool QgsOracleFeatureIterator::rewind()
{
if ( !mQry.isActive() )
return false;

// move cursor to first record
mRewind = true;
return true;
}

bool QgsOracleFeatureIterator::close()
{
if ( !mQry.isActive() )
return false;

mQry.finish();

return true;
}

bool QgsOracleFeatureIterator::openQuery( QString whereClause )
{
if ( ( mRequest.flags() & QgsFeatureRequest::NoGeometry ) == 0 && P->mGeometryColumn.isNull() )
{
return false;
}

try
{
QString query = "SELECT ", delim = "";

if ( ( mRequest.flags() & QgsFeatureRequest::NoGeometry ) == 0 )
{
query += P->quotedIdentifier( P->mGeometryColumn );
delim = ",";
}

switch ( P->mPrimaryKeyType )
{
case QgsOracleProvider::pktRowId:
query += delim + P->quotedIdentifier( "ROWID" );
delim = ",";
break;

case QgsOracleProvider::pktInt:
query += delim + P->quotedIdentifier( P->field( P->mPrimaryKeyAttrs[0] ).name() );
delim = ",";
break;

case QgsOracleProvider::pktFidMap:
foreach ( int idx, P->mPrimaryKeyAttrs )
{
query += delim + P->mConnection->fieldExpression( P->field( idx ) );
delim = ",";
}
break;

case QgsOracleProvider::pktUnknown:
QgsDebugMsg( "Cannot query without primary key." );
return false;
break;
}

foreach ( int idx, mAttributeList )
{
if ( P->mPrimaryKeyAttrs.contains( idx ) )
continue;

query += delim + P->mConnection->fieldExpression( P->field( idx ) );
}

query += QString( " FROM %1 \"featureRequest\"" ).arg( P->mQuery );

if ( !whereClause.isEmpty() )
query += QString( " WHERE %1" ).arg( whereClause );

QgsDebugMsg( QString( "Fetch features: %1" ).arg( query ) );
if ( !P->exec( mQry, query ) )
{
QgsMessageLog::logMessage( QObject::tr( "Fetching features failed.\nSQL:%1\nError: %2" )
.arg( mQry.lastQuery() )
.arg( mQry.lastError().text() ),
QObject::tr( "Oracle" ) );
return false;
}
}
catch ( QgsOracleProvider::OracleFieldNotFound )
{
return false;
}

return true;
}
56 changes: 56 additions & 0 deletions src/providers/oracle/qgsoraclefeatureiterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/***************************************************************************
qgsoraclefeatureiterator.h - QGIS data provider for Oracle layers
-------------------
begin : December 2012
copyright : (C) 2012 by Juergen E. Fischer
email : jef at norbit dot de
***************************************************************************/

/***************************************************************************
* *
* 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 QGSORACLEFEATUREITERATOR_H
#define QGSORACLEFEATUREITERATOR_H

#include "qgsfeatureiterator.h"

#include <QSqlQuery>


class QgsOracleProvider;

class QgsOracleFeatureIterator : public QgsAbstractFeatureIterator
{
public:
QgsOracleFeatureIterator( QgsOracleProvider *p, const QgsFeatureRequest &request );

~QgsOracleFeatureIterator();

//! fetch next feature, return true on success
virtual bool nextFeature( QgsFeature& feature );

//! reset the iterator to the starting position
virtual bool rewind();

//! end of iterating: free the resources / lock
virtual bool close();

protected:
QgsOracleProvider *P;

bool openQuery( QString whereClause );

bool getFeature( QgsFeature &feature );

QSqlQuery mQry;
bool mRewind;
QgsAttributeList mAttributeList;
};

#endif // QGSORACLEFEATUREITERATOR_H
560 changes: 112 additions & 448 deletions src/providers/oracle/qgsoracleprovider.cpp

Large diffs are not rendered by default.

69 changes: 14 additions & 55 deletions src/providers/oracle/qgsoracleprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@
class QgsFeature;
class QgsField;
class QgsGeometry;

#include "qgsdatasourceuri.h"
#include "ocispatial/wkbptr.h"
class QgsOracleFeatureIterator;

/**
\class QgsOracleProvider
Expand All @@ -53,7 +51,7 @@ class QgsOracleProvider : public QgsVectorDataProvider
/** Import a vector layer into the database */
static QgsVectorLayerImport::ImportError createEmptyLayer(
const QString& uri,
const QgsFieldMap &fields,
const QgsFields &fields,
QGis::WkbType wkbType,
const QgsCoordinateReferenceSystem *srs,
bool overwrite,
Expand Down Expand Up @@ -85,38 +83,6 @@ class QgsOracleProvider : public QgsVectorDataProvider
*/
virtual QgsCoordinateReferenceSystem crs();

/** Select features based on a bounding rectangle. Features can be retrieved with calls to nextFeature.
* @param fetchAttributes list of attributes which should be fetched
* @param rect spatial filter
* @param fetchGeometry true if the feature geometry should be fetched
* @param useIntersect true if an accurate intersection test should be used,
* false if a test based on bounding box is sufficient
*/
virtual void select( QgsAttributeList fetchAttributes = QgsAttributeList(),
QgsRectangle rect = QgsRectangle(),
bool fetchGeometry = true,
bool useIntersect = false );

/**
* Get the next feature resulting from a select operation.
* @param feature feature which will receive data from the provider
* @return true when there was a feature to fetch, false when end was hit
*/
virtual bool nextFeature( QgsFeature& feature );

/**
* Gets the feature at the given feature ID.
* @param featureId id of the feature
* @param feature feature which will receive the data
* @param fetchGeoemtry if true, geometry will be fetched from the provider
* @param fetchAttributes a list containing the indexes of the attribute fields to copy
* @return True when feature was found, otherwise false
*/
virtual bool featureAtId( QgsFeatureId featureId,
QgsFeature& feature,
bool fetchGeometry = true,
QgsAttributeList fetchAttributes = QgsAttributeList() );

/** Get the feature type. This corresponds to
* WKBPoint,
* WKBLineString,
Expand Down Expand Up @@ -170,7 +136,7 @@ class QgsOracleProvider : public QgsVectorDataProvider
* Get the field information for the layer
* @return vector of QgsField objects
*/
const QgsFieldMap &fields() const;
const QgsFields &fields() const;

/**
* Return a short comment for the data that this provider is
Expand Down Expand Up @@ -199,8 +165,6 @@ class QgsOracleProvider : public QgsVectorDataProvider
*/
bool isValid();

QgsAttributeList attributeIndexes();

QgsAttributeList pkAttributeIndexes() { return mPrimaryKeyAttrs; }

/**Returns the default value for field specified by @c fieldName */
Expand Down Expand Up @@ -289,18 +253,14 @@ class QgsOracleProvider : public QgsVectorDataProvider
*/
QString description() const;

/**
* Query the provider for features specified in request.
*/
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest& request = QgsFeatureRequest() );

static bool exec( QSqlQuery &qry, QString sql );

private:
bool openQuery( QString alias,
const QgsAttributeList &fetchAttributes,
bool fetchGeometry,
QString whereClause );

bool getFeature( bool fetchGeometry,
QgsFeature &feature,
const QgsAttributeList &fetchAttributes );

QString whereClause( QgsFeatureId featureId ) const;
QString pkParamWhereClause() const;
QString paramValue( QString fieldvalue, const QString &defaultValue ) const;
Expand All @@ -318,8 +278,8 @@ class QgsOracleProvider : public QgsVectorDataProvider
/** convert a QgsField to work with Oracle */
static bool convertField( QgsField &field );

QgsFieldMap mAttributeFields;
QMap<int, QVariant> mDefaultValues;
QgsFields mAttributeFields; //! List of fields
QVariantList mDefaultValues; //! List of default values
QString mDataComment;

//! Data source URI struct for this layer
Expand Down Expand Up @@ -427,12 +387,11 @@ class QgsOracleProvider : public QgsVectorDataProvider
QMap<QgsFeatureId, QVariant> mFidToKey; //! map feature back to fea
QgsFeatureId mFidCounter; //! next feature id if map is used
QgsOracleConn *mConnection;
QSqlQuery mQry;
bool mFetchGeomRequested; //! geometry was requested
bool mIntersectResult; //! need to intersect the results (Oracle Locator only)
bool mHasSpatial; //! Oracle Spatial is installed

QString mSpatialIndex; //! name of spatial index of geometry column
QgsRectangle mIntersectRect; //! rectangle to intersect with (if any)
bool mHasSpatial; //! Oracle Spatial is installed

friend QgsOracleFeatureIterator;
};

#endif
14 changes: 7 additions & 7 deletions src/providers/postgres/qgspostgresprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1435,12 +1435,12 @@ bool QgsPostgresProvider::getTopoLayerInfo( )
void QgsPostgresProvider::dropOrphanedTopoGeoms( )
{
QString sql = QString( "DELETE FROM %1.relation WHERE layer_id = %2 AND "
"topogeo_id NOT IN ( SELECT id(%3) FROM %4.%5 )" )
.arg( quotedIdentifier(mTopoLayerInfo.topologyName) )
"topogeo_id NOT IN ( SELECT id(%3) FROM %4.%5 )" )
.arg( quotedIdentifier( mTopoLayerInfo.topologyName ) )
.arg( mTopoLayerInfo.layerId )
.arg( quotedIdentifier(mGeometryColumn) )
.arg( quotedIdentifier(mSchemaName) )
.arg( quotedIdentifier(mTableName) )
.arg( quotedIdentifier( mGeometryColumn ) )
.arg( quotedIdentifier( mSchemaName ) )
.arg( quotedIdentifier( mTableName ) )
;

QgsDebugMsg( "TopoGeom orphans cleanup query: " + sql );
Expand Down Expand Up @@ -1601,7 +1601,7 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist )

if ( i == flist.size() )
{
if ( attributevec[idx] == defVal )
if ( v == defVal )
{
if ( defVal.isNull() )
{
Expand Down Expand Up @@ -2739,7 +2739,7 @@ bool QgsPostgresProvider::getGeometryDetails()
mEnabledCapabilities &= ~( QgsVectorDataProvider::ChangeGeometries | QgsVectorDataProvider::AddFeatures );
}

QgsDebugMsg( QString( "Feature type name is %1" ).arg( QGis::qgisFeatureTypes[ geometryType()] ) );
QgsDebugMsg( QString( "Feature type name is %1" ).arg( QGis::featureType( geometryType() ) ) );
QgsDebugMsg( QString( "Spatial column type is %1" ).arg( QgsPostgresConn::displayStringForGeomType( mSpatialColType ) ) );

return mValid;
Expand Down
2 changes: 1 addition & 1 deletion tests/src/core/testqgsvectordataprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ void TestQgsVectorDataProvider::featureAtId()

QVERIFY( fi.nextFeature( feature ) );
QVERIFY( feature.isValid() );
qDebug( "FID: %d", feature.id() );
qDebug( "FID: %lld", feature.id() );
QVERIFY( feature.id() == 4 );

// further invocations are not valid
Expand Down