| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
|
|
||
| ######################################################## | ||
| # Files | ||
|
|
||
| SET(DB2_SRCS | ||
| qgsdb2geometrycolumns.cpp | ||
| qgsdb2expressioncompiler.cpp | ||
| qgsdb2provider.cpp | ||
| qgsdb2dataitems.cpp | ||
| qgsdb2newconnection.cpp | ||
| qgsdb2tablemodel.cpp | ||
| qgsdb2featureiterator.cpp | ||
| qgsdb2sourceselect.cpp | ||
| ) | ||
| SET(DB2_MOC_HDRS | ||
| qgsdb2provider.h | ||
| qgsdb2dataitems.h | ||
| qgsdb2newconnection.h | ||
| qgsdb2tablemodel.h | ||
| qgsdb2sourceselect.h | ||
| ) | ||
|
|
||
| ######################################################## | ||
| # Build | ||
|
|
||
| QT4_WRAP_CPP(DB2_MOC_SRCS ${DB2_MOC_HDRS}) | ||
|
|
||
| INCLUDE_DIRECTORIES( | ||
| . | ||
| ../../core | ||
| ../../core/auth | ||
| ../../core/geometry | ||
| ../../gui | ||
| ../../gui/auth | ||
| ../../ui | ||
| ${CMAKE_CURRENT_BINARY_DIR}/../../ui | ||
| ) | ||
|
|
||
| INCLUDE_DIRECTORIES(SYSTEM | ||
| ${GEOS_INCLUDE_DIR} | ||
| ${QT_INCLUDE_DIR} | ||
| ) | ||
|
|
||
| ADD_LIBRARY (db2provider MODULE ${DB2_SRCS} ${DB2_HDRS} ${DB2_MOC_SRCS}) | ||
|
|
||
| TARGET_LINK_LIBRARIES (db2provider | ||
| qgis_core | ||
| qgis_gui | ||
| ${QT_QTSQL_LIBRARY} | ||
| ) | ||
|
|
||
|
|
||
| ######################################################## | ||
| # Install | ||
|
|
||
| INSTALL(TARGETS db2provider | ||
| RUNTIME DESTINATION ${QGIS_PLUGIN_DIR} | ||
| LIBRARY DESTINATION ${QGIS_PLUGIN_DIR}) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| /*************************************************************************** | ||
| qgsdb2dataitems.h - Browser Panel object population | ||
| -------------------------------------- | ||
| Date : 2016-01-27 | ||
| Copyright : (C) 2016 by David Adler | ||
| Shirley Xiao, David Nguyen | ||
| Email : dadler at adtechgeospatial.com | ||
| xshirley2012 at yahoo.com, davidng0123 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 "qgsdb2provider.h" | ||
| #include "qgsdb2sourceselect.h" | ||
| #include <qgsdataitem.h> | ||
|
|
||
| class QgsDb2RootItem; | ||
| class QgsDb2Connection; | ||
| class QgsDb2SchemaItem; | ||
| class QgsDb2LayerItem; | ||
|
|
||
| /** | ||
| * @class QgsDb2RootItem | ||
| * @brief Browser Panel DB2 root object. | ||
| */ | ||
| class QgsDb2RootItem : public QgsDataCollectionItem | ||
| { | ||
| Q_OBJECT | ||
|
|
||
| public: | ||
| QgsDb2RootItem( QgsDataItem* parent, QString name, QString path ); | ||
| ~QgsDb2RootItem(); | ||
|
|
||
| /** | ||
| * Add saved connections as children. | ||
| */ | ||
| QVector<QgsDataItem*> createChildren() override; | ||
|
|
||
| virtual QWidget * paramWidget() override; | ||
|
|
||
| virtual QList<QAction*> actions() override; | ||
|
|
||
| public slots: | ||
| //void connectionsChanged(); | ||
| void newConnection(); | ||
| }; | ||
|
|
||
| /** | ||
| * @class QgsDb2ConnectionItem | ||
| * @brief Browser Panel DB2 connection object (under root). | ||
| */ | ||
| class QgsDb2ConnectionItem : public QgsDataCollectionItem | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| QgsDb2ConnectionItem( QgsDataItem* parent, QString name, QString path ); | ||
| ~QgsDb2ConnectionItem(); | ||
|
|
||
| static bool ConnInfoFromSettings( const QString connName, | ||
| QString &connInfo, QString &errorMsg ); | ||
|
|
||
| static bool ConnInfoFromParameters( | ||
| const QString &service, | ||
| const QString &driver, | ||
| const QString &host, | ||
| const QString &port, | ||
| const QString &database, | ||
| const QString &username, | ||
| const QString &password, | ||
| const QString &authcfg, | ||
| QString &connInfo, | ||
| QString &errorMsg ); | ||
| /** | ||
| * Fetch geometry column data from server and populate Browser Panel with | ||
| * schemas and layers. | ||
| */ | ||
| QVector<QgsDataItem*> createChildren() override; | ||
| virtual bool equal( const QgsDataItem *other ) override; | ||
|
|
||
| /** | ||
| * Add Refresh, Edit, and Delete actions for every QgsDb2ConnectionItem. | ||
| */ | ||
| virtual QList<QAction*> actions() override; | ||
|
|
||
| virtual bool acceptDrop() override { return true; } | ||
| virtual bool handleDrop( const QMimeData * data, Qt::DropAction action ) override; | ||
| bool handleDrop( const QMimeData * data, const QString& toSchema ); | ||
| void refresh() override; | ||
|
|
||
| QString connInfo() const { return mConnInfo; } | ||
|
|
||
| signals: | ||
| void addGeometryColumn( QgsDb2LayerProperty ); | ||
|
|
||
| public slots: | ||
| /** | ||
| * Refresh with saved connection data. | ||
| */ | ||
| void refreshConnection(); | ||
|
|
||
| /** | ||
| * Show dialog to edit and save connection data. | ||
| */ | ||
| void editConnection(); | ||
|
|
||
| /** | ||
| * Delete saved connection data and remove from Browser Panel. | ||
| */ | ||
| void deleteConnection(); | ||
| //void setAllowGeometrylessTables( bool allow ); | ||
|
|
||
| //void setLayerType( QgsDb2LayerProperty layerProperty ); | ||
|
|
||
| private: | ||
| QString mConnInfo; | ||
| QString mService; | ||
| QString mHost; | ||
| QString mDriver; | ||
| QString mPort; | ||
| QString mDatabase; | ||
| QString mUsername; | ||
| QString mPassword; | ||
| QString mAuthcfg; | ||
| int mEnvironment; | ||
| bool mUseGeometryColumns; | ||
| bool mUseEstimatedMetadata; | ||
| bool mAllowGeometrylessTables; | ||
|
|
||
| void readConnectionSettings(); | ||
| }; | ||
|
|
||
| /** | ||
| * @class QgsDb2SchemaItem | ||
| * @brief Browser Panel DB2 schema object (under connections). | ||
| */ | ||
| class QgsDb2SchemaItem : public QgsDataCollectionItem | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| QgsDb2SchemaItem( QgsDataItem* parent, QString name, QString path ); | ||
| ~QgsDb2SchemaItem(); | ||
|
|
||
| QVector<QgsDataItem*> createChildren() override; | ||
|
|
||
| QgsDb2LayerItem* addLayer( QgsDb2LayerProperty layerProperty, bool refresh ); | ||
|
|
||
| void refresh() override {} // do not refresh directly | ||
| void addLayers( QgsDataItem* newLayers ); | ||
| virtual bool acceptDrop() override { return true; } | ||
| virtual bool handleDrop( const QMimeData * data, Qt::DropAction action ) override; | ||
| }; | ||
|
|
||
| /** | ||
| * @class QgsDb2LayerItem | ||
| * @brief Browser Panel DB2 layer object (under schemas). | ||
| */ | ||
| class QgsDb2LayerItem : public QgsLayerItem | ||
| { | ||
| Q_OBJECT | ||
|
|
||
| public: | ||
| QgsDb2LayerItem( QgsDataItem* parent, QString name, QString path, QgsLayerItem::LayerType layerType, QgsDb2LayerProperty layerProperties ); | ||
| ~QgsDb2LayerItem(); | ||
|
|
||
| QString createUri(); | ||
|
|
||
| QgsDb2LayerItem* createClone(); | ||
|
|
||
| private: | ||
| QgsDb2LayerProperty mLayerProperty; | ||
| }; | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,246 @@ | ||
| /*************************************************************************** | ||
| qgsdb2expressioncompiler.cpp - DB2 expression compiler | ||
| -------------------------------------- | ||
| Date : 2016-01-27 | ||
| Copyright : (C) 2016 by David Adler | ||
| Shirley Xiao, David Nguyen | ||
| Email : dadler at adtechgeospatial.com | ||
| xshirley2012 at yahoo.com, davidng0123 at gmail.com | ||
| Adapted from MSSQL provider by Tamas Szekeres | ||
| **************************************************************************** | ||
| * | ||
| * 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 "qgsdb2expressioncompiler.h" | ||
|
|
||
| QgsDb2ExpressionCompiler::QgsDb2ExpressionCompiler( QgsDb2FeatureSource* source ) | ||
| : QgsSqlExpressionCompiler( source->mFields | ||
| ) | ||
| { | ||
|
|
||
| } | ||
|
|
||
| QString nodeType( const QgsExpression::Node* node ) | ||
| { | ||
| QString opString = "?"; | ||
| if ( node->nodeType() == QgsExpression::ntUnaryOperator ) opString = "ntUnaryOperator"; | ||
| if ( node->nodeType() == QgsExpression::ntBinaryOperator ) opString = "ntBinaryOperator"; | ||
| if ( node->nodeType() == QgsExpression::ntInOperator ) opString = "ntInOperator"; | ||
| if ( node->nodeType() == QgsExpression::ntFunction ) opString = "ntFunction"; | ||
| if ( node->nodeType() == QgsExpression::ntLiteral ) opString = "ntLiteral"; | ||
| if ( node->nodeType() == QgsExpression::ntColumnRef ) opString = "ntColumnRef"; | ||
| if ( node->nodeType() == QgsExpression::ntCondition ) opString = "ntCondition"; | ||
| QString result = QString( "%1 - " ).arg( node->nodeType() ) + opString; | ||
| return result; | ||
|
|
||
| } | ||
|
|
||
| QString resultType( QgsSqlExpressionCompiler::Result result ) | ||
| { | ||
| if ( result == QgsSqlExpressionCompiler::None ) return "None"; | ||
| if ( result == QgsSqlExpressionCompiler::Complete ) return "Complete"; | ||
| if ( result == QgsSqlExpressionCompiler::Partial ) return "Partial"; | ||
| if ( result == QgsSqlExpressionCompiler::Fail ) return "Fail"; | ||
| return "Other result"; | ||
|
|
||
| } | ||
|
|
||
| QgsSqlExpressionCompiler::Result QgsDb2ExpressionCompiler::compileNode( const QgsExpression::Node* node, QString& result ) | ||
| { | ||
| QgsDebugMsg( QString( "nodeType: %1" ).arg( nodeType( node ) ) ); | ||
| if ( node->nodeType() == QgsExpression::ntColumnRef ) | ||
| { | ||
| const QgsExpression::NodeColumnRef *n( static_cast<const QgsExpression::NodeColumnRef*>( node ) ); | ||
| QgsDebugMsg( QString( "column ref node: " ) + n->dump() ); | ||
| // TODO - consider escaped names - not sure how to handle | ||
| QString upperName = n->name().toUpper(); | ||
| int idx = mFields.indexFromName( upperName ); | ||
| QgsDebugMsg( QString( "%1 - %2" ).arg( idx ).arg( upperName ) ); | ||
| if ( idx > -1 ) | ||
| { | ||
| result = upperName; | ||
| QgsDebugMsg( "return Complete" ); | ||
| return Complete; | ||
| } | ||
| QgsDebugMsg( "return Fail" ); | ||
| return Fail; | ||
| } | ||
| // Seemed necessary in initial Python testing but can't identify failing case now | ||
| #if 0 | ||
| if ( node->nodeType() == QgsExpression::ntLiteral ) | ||
| { | ||
| const QgsExpression::NodeLiteral* n = static_cast<const QgsExpression::NodeLiteral*>( node ); | ||
|
|
||
| bool ok = false; | ||
| if ( n->dump().toUpper() == "NULL" ) // expression compiler doesn't handle this correctly | ||
| { | ||
| result = "NULL"; | ||
| ok = true; | ||
| } | ||
| else | ||
| { | ||
| result = quotedValue( n->value(), ok ); | ||
| } | ||
| QgsDebugMsg( QString( "ok: %1; literal node: " ).arg( ok ) + n->value().toString() + "; result: " + result ); | ||
| QgsDebugMsg( QString( "n->dump: " ) + n->dump() ); | ||
| QgsDebugMsg( QString( "type: %1; typeName: %2" ).arg( n->value().type() ).arg( n->value().typeName() ) ); | ||
| if ( ok ) | ||
| { | ||
| QgsDebugMsg( "return Complete" ); | ||
| return Complete; | ||
| } | ||
| else | ||
| { | ||
| QgsDebugMsg( "return Fail" ); | ||
| return Fail; | ||
| } | ||
|
|
||
| } | ||
| #endif | ||
| if ( node->nodeType() == QgsExpression::ntUnaryOperator ) | ||
| { | ||
| const QgsExpression::NodeUnaryOperator* n = static_cast<const QgsExpression::NodeUnaryOperator*>( node ); | ||
| Result rr = Fail; | ||
| switch ( n->op() ) | ||
| { | ||
| case QgsExpression::uoNot: | ||
| rr = compileNode( n->operand(), result ); | ||
| if ( "NULL" == result.toUpper() ) | ||
| { | ||
| result = ""; | ||
| return Fail; | ||
| } | ||
|
|
||
| result = "NOT " + result; | ||
| QgsDebugMsg( QString( "NOT; result: %1; right: %2" ).arg( resultType( rr ) ).arg( result ) ); | ||
| return rr; | ||
|
|
||
| case QgsExpression::uoMinus: | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| if ( node->nodeType() == QgsExpression::ntBinaryOperator ) | ||
| { | ||
| const QgsExpression::NodeBinaryOperator *bin( static_cast<const QgsExpression::NodeBinaryOperator*>( node ) ); | ||
| QString left, right; | ||
|
|
||
| Result lr = compileNode( bin->opLeft(), left ); | ||
| Result rr = compileNode( bin->opRight(), right ); | ||
| Result compileResult; | ||
| QgsDebugMsg( "left: '" + left + "'; right: '" + right + | ||
| QString( "'; op: %1; lr: %2; rr: %3" ).arg( bin->op() ).arg( lr ).arg( rr ) ); | ||
| if ( lr == Fail || rr == Fail ) | ||
| return Fail; | ||
| // NULL can not appear on the left, only as part of IS NULL or IS NOT NULL | ||
| if ( "NULL" == left.toUpper() ) return Fail; | ||
| // NULL can only be on the right for IS and IS NOT | ||
| if ( "NULL" == right.toUpper() && ( bin->op() != QgsExpression::boIs && bin->op() != QgsExpression::boIsNot ) ) | ||
| return Fail; | ||
|
|
||
| switch ( bin->op() ) | ||
| { | ||
| case QgsExpression::boMod: | ||
| result = QString( "MOD(%1,%2)" ).arg( left, right ); | ||
| compileResult = ( lr == Partial || rr == Partial ) ? Partial : Complete; | ||
| QgsDebugMsg( QString( "MOD compile status: %1" ).arg( compileResult ) + "; " + result ); | ||
| return compileResult; | ||
|
|
||
| case QgsExpression::boPow: | ||
| result = QString( "power(%1,%2)" ).arg( left, right ); | ||
| compileResult = ( lr == Partial || rr == Partial ) ? Partial : Complete; | ||
| QgsDebugMsg( QString( "POWER compile status: %1" ).arg( compileResult ) + "; " + result ); | ||
| return compileResult; | ||
|
|
||
| case QgsExpression::boRegexp: | ||
| return Fail; //not supported, regexp syntax is too different to Qt | ||
|
|
||
| case QgsExpression::boConcat: | ||
| result = QString( "%1 || %2" ).arg( left, right ); | ||
| compileResult = ( lr == Partial || rr == Partial ) ? Partial : Complete; | ||
| QgsDebugMsg( QString( "CONCAT compile status: %1" ).arg( compileResult ) + "; " + result ); | ||
| return compileResult; | ||
|
|
||
| case QgsExpression::boILike: | ||
| QgsDebugMsg( "ILIKE is not supported by DB2" ); | ||
| return Fail; | ||
| /* | ||
| result = QString( "%1 LIKE %2" ).arg( left, right ); | ||
| compileResult = (lr == Partial || rr == Partial) ? Partial : Complete; | ||
| QgsDebugMsg(QString("ILIKE compile status: %1").arg(compileResult) + "; " + result); | ||
| return compileResult; | ||
| */ | ||
|
|
||
| case QgsExpression::boNotILike: | ||
| QgsDebugMsg( "NOT ILIKE is not supported by DB2" ); | ||
| return Fail; | ||
| /* | ||
| result = QString( "%1 NOT LIKE %2" ).arg( left, right ); | ||
| compileResult = (lr == Partial || rr == Partial) ? Partial : Complete; | ||
| QgsDebugMsg(QString("NOT ILIKE compile status: %1").arg(compileResult) + "; " + result); | ||
| return compileResult; | ||
| */ | ||
|
|
||
| // We only support IS NULL if the operand on the left is a column | ||
| case QgsExpression::boIs: | ||
| if ( "NULL" == right.toUpper() ) | ||
| { | ||
| if ( bin->opLeft()->nodeType() != QgsExpression::ntColumnRef ) | ||
| { | ||
| QgsDebugMsg( "Failing IS NULL with non-column on left: " + left ); | ||
| return Fail; | ||
| } | ||
| } | ||
| break; | ||
| // We only support IS NULL if the operand on the left is a column | ||
| case QgsExpression::boIsNot: | ||
| if ( "NULL" == right.toUpper() ) | ||
| { | ||
| if ( bin->opLeft()->nodeType() != QgsExpression::ntColumnRef ) | ||
| { | ||
| QgsDebugMsg( "Failing IS NOT NULL with non-column on left: " + left ); | ||
| return Fail; | ||
| } | ||
| } | ||
| break; | ||
|
|
||
| default: | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| //fallback to default handling | ||
| QgsDebugMsg( QString( "fallback: %1 - " ).arg( nodeType( node ) ) ); | ||
| QgsSqlExpressionCompiler::Result rc = QgsSqlExpressionCompiler::compileNode( node, result ); | ||
| QgsDebugMsg( QString( "fallback: %1 - " ).arg( resultType( rc ) ) + result ); | ||
| return rc; | ||
| } | ||
|
|
||
| QString QgsDb2ExpressionCompiler::quotedValue( const QVariant& value, bool& ok ) | ||
| { | ||
| ok = true; | ||
| // Seemed necessary in initial Python testing but can't identify failing case now | ||
| #if 0 | ||
| if ( value.isNull() ) | ||
| { | ||
| //no NULL literal support | ||
| ok = false; | ||
| return QString(); | ||
| } | ||
| #endif | ||
| switch ( value.type() ) | ||
| { | ||
| case QVariant::Bool: | ||
| //no boolean literal support in db2, so fake it | ||
| return value.toBool() ? "(1=1)" : "(1=0)"; | ||
|
|
||
| default: | ||
| QString result = QgsSqlExpressionCompiler::quotedValue( value, ok ); | ||
| return QgsSqlExpressionCompiler::quotedValue( value, ok ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| /*************************************************************************** | ||
| qgsdb2expressioncompiler.h - DB2 expression compiler | ||
| -------------------------------------- | ||
| Date : 2016-01-27 | ||
| Copyright : (C) 2016 by David Adler | ||
| Shirley Xiao, David Nguyen | ||
| Email : dadler at adtechgeospatial.com | ||
| xshirley2012 at yahoo.com, davidng0123 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 QGSDB2LEXPRESSIONCOMPILER_H | ||
| #define QGSDB2LEXPRESSIONCOMPILER_H | ||
|
|
||
| #include "qgssqlexpressioncompiler.h" | ||
| #include "qgsexpression.h" | ||
| #include "qgsdb2featureiterator.h" | ||
|
|
||
| class QgsDb2ExpressionCompiler : public QgsSqlExpressionCompiler | ||
| { | ||
| public: | ||
|
|
||
| explicit QgsDb2ExpressionCompiler( QgsDb2FeatureSource* source ); | ||
|
|
||
| protected: | ||
| virtual Result compileNode( const QgsExpression::Node* node, QString& result ) override; | ||
| virtual QString quotedValue( const QVariant& value, bool& ok ) override; | ||
|
|
||
| }; | ||
|
|
||
| #endif // QGSDB2EXPRESSIONCOMPILER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| /*************************************************************************** | ||
| qgsdb2featureiterator.h - DB2 spatial feature processing | ||
| -------------------------------------- | ||
| Date : 2016-01-27 | ||
| Copyright : (C) 2016 by David Adler | ||
| Shirley Xiao, David Nguyen | ||
| Email : dadler at adtechgeospatial.com | ||
| xshirley2012 at yahoo.com, davidng0123 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 QGSDB2FEATUREITERATOR_H | ||
| #define QGSDB2FEATUREITERATOR_H | ||
|
|
||
| #include "qgsfeatureiterator.h" | ||
| #include <QtSql/QSqlDatabase> | ||
| #include <QtSql/QSqlQuery> | ||
| #include <QtSql/QSqlError> | ||
|
|
||
| class QgsDb2Provider; | ||
|
|
||
| class QgsDb2FeatureSource : public QgsAbstractFeatureSource | ||
| { | ||
| public: | ||
| explicit QgsDb2FeatureSource( const QgsDb2Provider* p ); | ||
| ~QgsDb2FeatureSource(); | ||
|
|
||
| virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest& request ) override; | ||
|
|
||
| protected: | ||
| QgsFields mFields; | ||
| QString mFidColName; | ||
| long mSRId; | ||
|
|
||
| QString mGeometryColName; | ||
| QString mGeometryColType; | ||
|
|
||
| // current layer name | ||
| QString mSchemaName; | ||
| QString mTableName; | ||
|
|
||
| // server access | ||
| QString mConnInfo; | ||
|
|
||
| // SQL statement used to limit the features retrieved | ||
| QString mSqlWhereClause; | ||
|
|
||
| // Return True if this feature source has spatial attributes. | ||
| bool isSpatial() { return !mGeometryColName.isEmpty() || !mGeometryColType.isEmpty(); } | ||
|
|
||
| friend class QgsDb2FeatureIterator; | ||
| friend class QgsDb2ExpressionCompiler; | ||
| }; | ||
|
|
||
| class QgsDb2FeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsDb2FeatureSource> | ||
| { | ||
| public: | ||
| QgsDb2FeatureIterator( QgsDb2FeatureSource* source, bool ownSource, const QgsFeatureRequest& request ); | ||
|
|
||
| ~QgsDb2FeatureIterator(); | ||
|
|
||
| //! reset the iterator to the starting position | ||
| virtual bool rewind() override; | ||
|
|
||
| //! end of iterating: free the resources / lock | ||
| virtual bool close() override; | ||
|
|
||
| protected: | ||
| void BuildStatement( const QgsFeatureRequest& request ); | ||
|
|
||
| //! fetch next feature, return true on success | ||
| virtual bool fetchFeature( QgsFeature& feature ) override; | ||
|
|
||
| //! fetch next feature filter expression | ||
| bool nextFeatureFilterExpression( QgsFeature& f ) override; | ||
|
|
||
| private: | ||
|
|
||
| virtual bool prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys ) override; | ||
|
|
||
|
|
||
| // The current database | ||
| QSqlDatabase mDatabase; | ||
| QString mOrderByClause; | ||
|
|
||
| // The current sql query | ||
| QSqlQuery* mQuery; | ||
|
|
||
| // The current sql statement | ||
| QString mStatement; | ||
|
|
||
| // Field index of FID column | ||
| long mFidCol; | ||
|
|
||
| // List of attribute indices to fetch with nextFeature calls | ||
| QgsAttributeList mAttributesToFetch; | ||
|
|
||
| bool mExpressionCompiled; | ||
| bool mOrderByCompiled; | ||
|
|
||
| int mFetchCount; | ||
| }; | ||
|
|
||
| #endif // QGSDB2FEATUREITERATOR_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| /*************************************************************************** | ||
| qgsdb2geometrycolumns.cpp - Access DB2 geometry columns table | ||
| -------------------------------------- | ||
| Date : 2016-01-27 | ||
| Copyright : (C) 2016 by David Adler | ||
| Shirley Xiao, David Nguyen | ||
| Email : dadler at adtechgeospatial.com | ||
| xshirley2012 at yahoo.com, davidng0123 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 "qgsdb2geometrycolumns.h" | ||
| #include "qgsdb2tablemodel.h" // needed for QgsDB2LayerProperty | ||
| #include "qgsdb2newconnection.h" // needed for ENV_ZOS, ENV_LUW | ||
| #include <QtSql> | ||
| #include <qgslogger.h> | ||
|
|
||
|
|
||
| QgsDb2GeometryColumns::QgsDb2GeometryColumns( const QSqlDatabase db ) | ||
| : mDatabase( db ) | ||
| { | ||
| QgsDebugMsg( "constructing" ); | ||
| } | ||
| QgsDb2GeometryColumns::~QgsDb2GeometryColumns( ) | ||
| { | ||
| mQuery.clear(); | ||
| } | ||
|
|
||
|
|
||
| int QgsDb2GeometryColumns::open() | ||
| { | ||
| return open( QString(), QString() ); | ||
| } | ||
|
|
||
| int QgsDb2GeometryColumns::open( const QString &schemaName, const QString &tableName ) | ||
| { | ||
| QString queryExtents( "SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, TYPE_NAME, " | ||
| "SRS_ID, SRS_NAME, MIN_X, MIN_Y, MAX_X, MAX_Y " | ||
| "FROM DB2GSE.ST_GEOMETRY_COLUMNS" ); | ||
| QString queryNoExtents( "SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, TYPE_NAME, " | ||
| "SRS_ID, SRS_NAME " | ||
| "FROM DB2GSE.ST_GEOMETRY_COLUMNS" ); | ||
| mQuery = QSqlQuery( mDatabase ); | ||
| int sqlcode = 0; | ||
| mEnvironment = ENV_LUW; | ||
|
|
||
| if ( !schemaName.isEmpty() && !tableName.isEmpty() ) | ||
| { | ||
| QString whereClause = QString( " WHERE TABLE_SCHEMA = '%1' AND TABLE_NAME = '%2'" ) | ||
| .arg( schemaName, tableName ); | ||
| queryExtents += whereClause; | ||
| queryNoExtents += whereClause; | ||
| } | ||
| QgsDebugMsg( queryExtents ); | ||
| // issue the sql query | ||
| if ( !mQuery.exec( queryExtents ) ) | ||
| { | ||
| QgsDebugMsg( "ST_Geometry_Columns query failed: " + mDatabase.lastError().text() ); | ||
| sqlcode = mQuery.lastError().number(); | ||
| QgsDebugMsg( QString( "SQLCODE: %1" ).arg( sqlcode ) ); | ||
| /* The MIN_X, MIN_Y, MAX_X, and MAX_Y columns are not available on z/OS (and LUW 9.5) | ||
| so SQLCODE -206 is returned when specifying non-existent columns. */ | ||
| if ( mQuery.lastError().number() == -206 ) | ||
| { | ||
| QgsDebugMsg( "Try query with no extents" ); | ||
| mQuery.clear(); | ||
|
|
||
| if ( !mQuery.exec( queryNoExtents ) ) | ||
| { | ||
| QgsDebugMsg( QString( "SQLCODE: %1" ).arg( mQuery.lastError().number() ) ); | ||
| } | ||
| else | ||
| { | ||
| QgsDebugMsg( "success; must be z/OS" ); | ||
| mEnvironment = ENV_ZOS; | ||
| sqlcode = 0; | ||
| } | ||
| } | ||
| } | ||
| // QgsDebugMsg( QString( "sqlcode: %1" ).arg( sqlcode ) ); | ||
|
|
||
| return sqlcode; | ||
| } | ||
|
|
||
| bool QgsDb2GeometryColumns::isActive() | ||
| { | ||
| return mQuery.isActive(); | ||
| } | ||
|
|
||
| int QgsDb2GeometryColumns::db2Environment() | ||
| { | ||
| return mEnvironment; | ||
| } | ||
|
|
||
| bool QgsDb2GeometryColumns::populateLayerProperty( QgsDb2LayerProperty &layer ) | ||
| { | ||
| if ( !mQuery.isActive() || !mQuery.next() ) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| layer.schemaName = mQuery.value( 0 ).toString().trimmed(); | ||
| layer.tableName = mQuery.value( 1 ).toString().trimmed(); | ||
| layer.geometryColName = mQuery.value( 2 ).toString().trimmed(); | ||
| layer.type = mQuery.value( 3 ).toString(); | ||
| if ( mQuery.value( 4 ).isNull() ) | ||
| { | ||
| layer.srid = QString( "" ); | ||
| layer.srsName = QString( "" ); | ||
| } | ||
| else | ||
| { | ||
| layer.srid = mQuery.value( 4 ).toString(); | ||
| layer.srsName = mQuery.value( 5 ).toString(); | ||
| } | ||
| layer.extents = QString( "0 0 0 0" ); // no extents | ||
| if ( ENV_LUW == mEnvironment ) | ||
| { | ||
| if ( !mQuery.value( 6 ).isNull() ) // Don't get values if null | ||
| { | ||
| layer.extents = QString( | ||
| mQuery.value( 6 ).toString() + ' ' + | ||
| mQuery.value( 7 ).toString() + ' ' + | ||
| mQuery.value( 8 ).toString() + ' ' + | ||
| mQuery.value( 9 ).toString() ).trimmed(); | ||
| } | ||
| } | ||
| QgsDebugMsg( QString( "layer: %1.%2(%3) type='%4' srid='%5' srsName='%6'" ) | ||
| .arg( layer.schemaName, layer.tableName, layer.geometryColName, | ||
| layer.type, layer.srid, layer.srsName ) ); | ||
| QgsDebugMsg( "Extents: '" + layer.extents + "'" ); | ||
|
|
||
| layer.pkCols = QStringList(); | ||
|
|
||
| // Use the Qt functionality to get the primary key information | ||
| // to set the FID column. | ||
| // We can only use the primary key if it only has one column and | ||
| // the type is Integer or BigInt. | ||
| QString table = QString( "%1.%2" ).arg( layer.schemaName, layer.tableName ); | ||
| QSqlIndex pk = mDatabase.primaryIndex( table ); | ||
| if ( pk.count() == 1 ) | ||
| { | ||
| QSqlField pkFld = pk.field( 0 ); | ||
| QVariant::Type pkType = pkFld.type(); | ||
| if (( pkType == QVariant::Int || pkType == QVariant::LongLong ) ) | ||
| { | ||
| QString fidColName = pk.fieldName( 0 ); | ||
| layer.pkCols.append( fidColName ); | ||
| QgsDebugMsg( "pk is: " + fidColName ); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| QgsDebugMsg( "Warning: table primary key count is " + QString::number( pk.count() ) ); | ||
| } | ||
| layer.pkColumnName = layer.pkCols.size() > 0 ? layer.pkCols.at( 0 ) : QString::null; | ||
| return true; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| /*************************************************************************** | ||
| qgsdb2geometrycolumns.h - Access DB2 geometry columns table | ||
| -------------------------------------- | ||
| Date : 2016-01-27 | ||
| Copyright : (C) 2016 by David Adler | ||
| Shirley Xiao, David Nguyen | ||
| Email : dadler at adtechgeospatial.com | ||
| xshirley2012 at yahoo.com, davidng0123 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 QGSDB2GEOMETRYCOLUMNS_H | ||
| #define QGSDB2GEOMETRYCOLUMNS_H | ||
|
|
||
| #include "qgsdb2tablemodel.h" // needed for QgsDB2LayerProperty | ||
| #include <QtSql> | ||
|
|
||
| /** | ||
| * @class QgsDb2GeometryColumns | ||
| * @brief Data provider for DB2 server. | ||
| */ | ||
|
|
||
| static const int ENV_LUW = 1, ENV_ZOS = 2; | ||
|
|
||
| class QgsDb2GeometryColumns | ||
| { | ||
| public: | ||
| QgsDb2GeometryColumns( const QSqlDatabase db ); | ||
|
|
||
| ~QgsDb2GeometryColumns(); | ||
|
|
||
| bool isActive(); | ||
| void close(); | ||
| int open(); | ||
| int open( const QString &schemaName, const QString &tableName ); | ||
| bool populateLayerProperty( QgsDb2LayerProperty &layer ); | ||
| int db2Environment(); | ||
|
|
||
| private: | ||
|
|
||
| QSqlDatabase mDatabase; | ||
| QSqlQuery mQuery; | ||
| int mEnvironment; | ||
|
|
||
| }; | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,199 @@ | ||
| /*************************************************************************** | ||
| qgsdb2newconnection.cpp - new DB2 connection dialog | ||
| -------------------------------------- | ||
| Date : 2016-01-27 | ||
| Copyright : (C) 2016 by David Adler | ||
| Shirley Xiao, David Nguyen | ||
| Email : dadler at adtechgeospatial.com | ||
| xshirley2012 at yahoo.com, davidng0123 at gmail.com | ||
| Adapted from MSSQL provider by Tamas Szekeres | ||
| **************************************************************************** | ||
| * | ||
| * 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 <QSettings> | ||
| #include <QInputDialog> | ||
| #include <QMessageBox> | ||
| #include <QLabel> | ||
| #include <qgslogger.h> | ||
| #include <qlistwidget.h> | ||
|
|
||
| #include <QtSql/QSqlDatabase> | ||
| #include <QtSql/QSqlError> | ||
|
|
||
| #include "qgsdb2newconnection.h" | ||
| #include "qgsdb2dataitems.h" | ||
| #include "qgsdb2provider.h" | ||
| #include "qgscontexthelp.h" | ||
|
|
||
| QgsDb2NewConnection::QgsDb2NewConnection( QWidget *parent, const QString& connName, Qt::WindowFlags fl ) | ||
| : QDialog( parent, fl ), mOriginalConnName( connName ) | ||
| , mAuthConfigSelect( nullptr ) | ||
| { | ||
| setupUi( this ); | ||
|
|
||
| mAuthConfigSelect = new QgsAuthConfigSelect( this, "db2" ); | ||
| tabAuthentication->insertTab( 1, mAuthConfigSelect, tr( "Configurations" ) ); | ||
|
|
||
| if ( !connName.isEmpty() ) | ||
| { | ||
| // populate the dialog with the information stored for the connection | ||
| // populate the fields with the stored setting parameters | ||
| QSettings settings; | ||
|
|
||
| QString key = "/DB2/connections/" + connName; | ||
| txtService->setText( settings.value( key + "/service" ).toString() ); | ||
| txtHost->setText( settings.value( key + "/host" ).toString() ); | ||
| txtPort->setText( settings.value( key + "/port" ).toString() ); | ||
| txtDriver->setText( settings.value( key + "/driver" ).toString() ); | ||
| txtDatabase->setText( settings.value( key + "/database" ).toString() ); | ||
|
|
||
|
|
||
| if ( settings.value( key + "/saveUsername" ).toString() == "true" ) | ||
| { | ||
| txtUsername->setText( settings.value( key + "/username" ).toString() ); | ||
| chkStoreUsername->setChecked( true ); | ||
| } | ||
|
|
||
| if ( settings.value( key + "/savePassword" ).toString() == "true" ) | ||
| { | ||
| txtPassword->setText( settings.value( key + "/password" ).toString() ); | ||
| chkStorePassword->setChecked( true ); | ||
| } | ||
|
|
||
| QString authcfg = settings.value( key + "/authcfg" ).toString(); | ||
| QgsDebugMsg( QString( "authcfg: %1" ).arg( authcfg ) ); | ||
| mAuthConfigSelect->setConfigId( authcfg ); | ||
| if ( !authcfg.isEmpty() ) | ||
| { | ||
| tabAuthentication->setCurrentIndex( tabAuthentication->indexOf( mAuthConfigSelect ) ); | ||
| } | ||
|
|
||
| txtName->setText( connName ); | ||
| } | ||
| } | ||
|
|
||
| /** Autoconnected SLOTS **/ | ||
| void QgsDb2NewConnection::accept() | ||
| { | ||
| QSettings settings; | ||
| QString baseKey = "/DB2/connections/"; | ||
| settings.setValue( baseKey + "selected", txtName->text() ); | ||
| bool hasAuthConfigID = !mAuthConfigSelect->configId().isEmpty(); | ||
| QgsDebugMsg( QString( "hasAuthConfigID: %1" ).arg( hasAuthConfigID ) ); | ||
| if ( !hasAuthConfigID && chkStorePassword->isChecked() && | ||
| QMessageBox::question( this, | ||
| tr( "Saving passwords" ), | ||
| tr( "WARNING: You have opted to save your password. It will be stored in plain text in your project files and in your home directory on Unix-like systems, or in your user profile on Windows. If you do not want this to happen, please press the Cancel button.\n" ), | ||
| QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel ) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // warn if entry was renamed to an existing connection | ||
| if (( mOriginalConnName.isNull() || mOriginalConnName.compare( txtName->text(), Qt::CaseInsensitive ) != 0 ) && | ||
| ( settings.contains( baseKey + txtName->text() + "/service" ) || | ||
| settings.contains( baseKey + txtName->text() + "/host" ) ) && | ||
| QMessageBox::question( this, | ||
| tr( "Save connection" ), | ||
| tr( "Should the existing connection %1 be overwritten?" ).arg( txtName->text() ), | ||
| QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel ) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // on rename delete the original entry first | ||
| if ( !mOriginalConnName.isNull() && mOriginalConnName != txtName->text() ) | ||
| { | ||
| settings.remove( baseKey + mOriginalConnName ); | ||
| settings.sync(); | ||
| } | ||
|
|
||
| baseKey += txtName->text(); | ||
|
|
||
| settings.setValue( baseKey + "/service", txtService->text().trimmed() ); | ||
| settings.setValue( baseKey + "/host", txtHost->text() ); | ||
| settings.setValue( baseKey + "/port", txtPort->text() ); | ||
| settings.setValue( baseKey + "/driver", txtDriver->text() ); | ||
| settings.setValue( baseKey + "/database", txtDatabase->text() ); | ||
| settings.setValue( baseKey + "/username", chkStoreUsername->isChecked() && !hasAuthConfigID ? txtUsername->text() : "" ); | ||
| settings.setValue( baseKey + "/password", chkStorePassword->isChecked() && !hasAuthConfigID ? txtPassword->text() : "" ); | ||
| settings.setValue( baseKey + "/saveUsername", chkStoreUsername->isChecked() && !hasAuthConfigID ? "true" : "false" ); | ||
| settings.setValue( baseKey + "/savePassword", chkStorePassword->isChecked() && !hasAuthConfigID ? "true" : "false" ); | ||
| settings.setValue( baseKey + "/authcfg", mAuthConfigSelect->configId() ); | ||
|
|
||
| QDialog::accept(); | ||
| } | ||
|
|
||
| void QgsDb2NewConnection::on_btnConnect_clicked() | ||
| { | ||
| QgsDebugMsg( "DB2: TestDatabase; button clicked" ); | ||
| testConnection(); | ||
| } | ||
|
|
||
| void QgsDb2NewConnection::on_btnListDatabase_clicked() | ||
| { | ||
| listDatabases(); | ||
| } | ||
|
|
||
| void QgsDb2NewConnection::on_cb_trustedConnection_clicked() | ||
| { | ||
|
|
||
| } | ||
|
|
||
| /** End Autoconnected SLOTS **/ | ||
|
|
||
| QgsDb2NewConnection::~QgsDb2NewConnection() | ||
| { | ||
|
|
||
| } | ||
|
|
||
| bool QgsDb2NewConnection::testConnection() | ||
| { | ||
| QSqlDatabase db; | ||
|
|
||
| QString authcfg; | ||
| QString connInfo; | ||
| QString errMsg; | ||
| bool rc = QgsDb2ConnectionItem::ConnInfoFromParameters( | ||
| txtService->text().trimmed(), | ||
| txtDriver->text().trimmed(), | ||
| txtHost->text().trimmed(), | ||
| txtPort->text().trimmed(), | ||
| txtDatabase->text().trimmed(), | ||
| txtUsername->text().trimmed(), | ||
| txtPassword->text().trimmed(), | ||
| authcfg, | ||
| connInfo, errMsg ); | ||
|
|
||
| if ( !rc ) | ||
| { | ||
| db2ConnectStatus -> setText( errMsg ); | ||
| QgsDebugMsg( "errMsg: " + errMsg ); | ||
| return false; | ||
| } | ||
|
|
||
| db = QgsDb2Provider::getDatabase( connInfo, errMsg ); | ||
| if ( errMsg.isEmpty() ) | ||
| { | ||
| QgsDebugMsg( "connection open succeeded " + connInfo ); | ||
| db2ConnectStatus -> setText( "DB2 connection open succeeded" ); | ||
| return true; | ||
| } | ||
| else | ||
| { | ||
| QgsDebugMsg( "connection open failed: " + errMsg ); | ||
| db2ConnectStatus -> setText( "DB2 connection failed : " + errMsg ); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| void QgsDb2NewConnection::listDatabases() | ||
| { | ||
| QgsDebugMsg( "DB2 New Connection Dialogue : list database" ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| /*************************************************************************** | ||
| qgsdb2newconnection.h - new DB2 connection dialog | ||
| -------------------------------------- | ||
| Date : 2016-01-27 | ||
| Copyright : (C) 2016 by David Adler | ||
| Shirley Xiao, David Nguyen | ||
| Email : dadler at adtechgeospatial.com | ||
| xshirley2012 at yahoo.com, davidng0123 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 QGSDB2NEWCONNECTION_H | ||
| #define QGSDB2NEWCONNECTION_H | ||
| #include "ui_qgsdb2newconnectionbase.h" | ||
| #include "qgisgui.h" | ||
| #include "qgscontexthelp.h" | ||
| #include "qgsauthconfigselect.h" | ||
|
|
||
| /** \class QgsDb2NewConnection | ||
| * \brief Dialog to allow the user to configure and save connection | ||
| * information for an DB2 database | ||
| */ | ||
| class QgsDb2NewConnection : public QDialog, private Ui::QgsDb2NewConnectionBase | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| //! Constructor | ||
| QgsDb2NewConnection( QWidget *parent = 0, const QString& connName = QString::null, Qt::WindowFlags fl = QgisGui::ModalDialogFlags ); | ||
|
|
||
| //! Destructor | ||
| ~QgsDb2NewConnection(); | ||
|
|
||
| //! Tests the connection using the parameters supplied | ||
| bool testConnection(); | ||
| /** | ||
| * @brief List all databases found for the given server. | ||
| */ | ||
| void listDatabases(); | ||
| public slots: | ||
| void accept() override; | ||
| void on_btnListDatabase_clicked(); | ||
| void on_btnConnect_clicked(); | ||
| void on_cb_trustedConnection_clicked(); | ||
| void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); } | ||
| private: | ||
| QString mOriginalConnName; //store initial name to delete entry in case of rename | ||
| QgsAuthConfigSelect * mAuthConfigSelect; | ||
| }; | ||
|
|
||
| #endif // QGSDB2NEWCONNECTION_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,201 @@ | ||
| /*************************************************************************** | ||
| qgsdb2provider.h - Data provider for DB2 server | ||
| -------------------------------------- | ||
| Date : 2016-01-27 | ||
| Copyright : (C) 2016 by David Adler | ||
| Shirley Xiao, David Nguyen | ||
| Email : dadler at adtechgeospatial.com | ||
| xshirley2012 at yahoo.com, davidng0123 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 QGSDB2PROVIDER_H | ||
| #define QGSDB2PROVIDER_H | ||
|
|
||
| #include "qgsvectordataprovider.h" | ||
| #include "qgsvectorlayerimport.h" | ||
| #include <qgscoordinatereferencesystem.h> | ||
| #include "qgsgeometry.h" | ||
| #include <QtSql> | ||
|
|
||
| /** | ||
| * @class QgsDb2Provider | ||
| * @brief Data provider for DB2 server. | ||
| */ | ||
| class QgsDb2Provider : public QgsVectorDataProvider | ||
| { | ||
| Q_OBJECT | ||
|
|
||
| public: | ||
| explicit QgsDb2Provider( QString uri = QString() ); | ||
|
|
||
| virtual ~QgsDb2Provider(); | ||
|
|
||
| /** | ||
| * Returns a QSqlDatabase object that can connect to DB2 for LUW or z/OS. | ||
| * | ||
| * If service is provided, then username and password is required. | ||
| * If service is not provided, the remaining arguments are required. | ||
| * | ||
| * @param connInfo A string containing all connection information. | ||
| */ | ||
| static QSqlDatabase getDatabase( const QString &connInfo, QString &errMsg ); | ||
|
|
||
| static bool openDatabase( QSqlDatabase db ); | ||
|
|
||
| virtual QgsAbstractFeatureSource* featureSource() const override; | ||
|
|
||
| /** | ||
| * Get feature iterator. | ||
| * @return QgsFeatureIterator to iterate features. | ||
| */ | ||
| virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest& request = QgsFeatureRequest() ) override; | ||
|
|
||
| /** | ||
| * Get feature type. | ||
| * @return int representing the feature type | ||
| */ | ||
| virtual QGis::WkbType geometryType() const override; | ||
|
|
||
| /** | ||
| * Number of features in the layer | ||
| * @return long containing number of features | ||
| */ | ||
| virtual long featureCount() const override; | ||
|
|
||
| /** | ||
| * Update the extent for this layer. | ||
| */ | ||
| void updateStatistics(); | ||
|
|
||
| /** | ||
| * Return a map of indexes with field names for this layer. | ||
| * @return map of fields | ||
| */ | ||
| virtual const QgsFields &fields() const override; | ||
|
|
||
| virtual QgsCoordinateReferenceSystem crs() override; | ||
|
|
||
| /** | ||
| * Return the extent for this data layer. | ||
| */ | ||
| virtual QgsRectangle extent() override; | ||
|
|
||
| /** | ||
| * Returns true if this is a valid data source. | ||
| */ | ||
| virtual bool isValid() override; | ||
|
|
||
| /** | ||
| * Accessor for SQL WHERE clause used to limit dataset. | ||
| */ | ||
| QString subsetString() override; | ||
|
|
||
| /** | ||
| * Mutator for SQL WHERE clause used to limit dataset size. | ||
| */ | ||
| bool setSubsetString( const QString& theSQL, bool updateFeatureCount = true ) override; | ||
|
|
||
| virtual bool supportsSubsetString() override { return true; } | ||
|
|
||
| /** Return a provider name | ||
| Essentially just returns the provider key. Should be used to build file | ||
| dialogs so that providers can be shown with their supported types. Thus | ||
| if more than one provider supports a given format, the user is able to | ||
| select a specific provider to open that file. | ||
| */ | ||
| virtual QString name() const override; | ||
|
|
||
| /** Return description | ||
| Return a terse string describing what the provider is. | ||
| */ | ||
| virtual QString description() const override; | ||
|
|
||
| /** Returns a bitmask containing the supported capabilities | ||
| Note, some capabilities may change depending on whether | ||
| a spatial filter is active on this provider, so it may | ||
| be prudent to check this value per intended operation. | ||
| */ | ||
| virtual int capabilities() const override; | ||
|
|
||
| /** Writes a list of features to the database*/ | ||
| virtual bool addFeatures( QgsFeatureList & flist ) override; | ||
|
|
||
| /** Deletes a feature*/ | ||
| virtual bool deleteFeatures( const QgsFeatureIds & id ) override; | ||
|
|
||
| /** Changes attribute values of existing features */ | ||
| virtual bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override; | ||
|
|
||
| /** Changes existing geometries*/ | ||
| virtual bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override; | ||
|
|
||
| /** Import a vector layer into the database */ | ||
| static QgsVectorLayerImport::ImportError createEmptyLayer( | ||
| const QString& uri, | ||
| const QgsFields &fields, | ||
| QGis::WkbType wkbType, | ||
| const QgsCoordinateReferenceSystem *srs, | ||
| bool overwrite, | ||
| QMap<int, int> *oldToNewAttrIdxMap, | ||
| QString *errorMessage = nullptr, | ||
| const QMap<QString, QVariant> *options = nullptr | ||
| ); | ||
|
|
||
| /** Convert a QgsField to work with DB2 */ | ||
| static bool convertField( QgsField &field ); | ||
|
|
||
| /** Convert a QgsField to work with DB2 */ | ||
| static QString qgsFieldToDb2Field( QgsField field ); | ||
|
|
||
| protected: | ||
| /** Loads fields from input file to member attributeFields */ | ||
| QVariant::Type decodeSqlType( int typeId ); | ||
| void loadMetadata(); | ||
| void loadFields(); | ||
|
|
||
| private: | ||
| static void db2WkbTypeAndDimension( QGis::WkbType wkbType, QString &geometryType, int &dim ); | ||
| static QString db2TypeName( int typeId ); | ||
|
|
||
| QgsFields mAttributeFields; //fields | ||
| QMap<int, QVariant> mDefaultValues; | ||
| QgsRectangle mExtent; //layer extent | ||
| bool mValid; | ||
| bool mUseEstimatedMetadata; | ||
| bool mSkipFailures; | ||
| long mNumberFeatures; | ||
| QString mFidColName; | ||
| QString mExtents; | ||
| long mSRId; | ||
| int mEnvironment; | ||
| QString mSrsName; | ||
| QString mGeometryColName, mGeometryColType; | ||
| QString mLastError; //string containing the last reported error message | ||
| QgsCoordinateReferenceSystem mCrs; //coordinate reference system | ||
| QGis::WkbType mWkbType; | ||
| QSqlQuery mQuery; //current SQL query | ||
| QString mConnInfo; // full connection information | ||
| QString mSchemaName, mTableName; //current layer schema/name | ||
| QString mSqlWhereClause; //SQL statement used to limit the features retrieved | ||
| QSqlDatabase mDatabase; //the database object | ||
| static int sConnectionId; | ||
|
|
||
| //sets the error messages | ||
| void setLastError( const QString& error ) | ||
| { | ||
| mLastError = error; | ||
| } | ||
|
|
||
| friend class QgsDb2FeatureSource; | ||
| }; | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,191 @@ | ||
| /*************************************************************************** | ||
| qgsdb2sourceselect.h | ||
| dialog to select DB2 layer(s) and add to the map canvas | ||
| -------------------------------------- | ||
| Date : 2016-01-27 | ||
| Copyright : (C) 2016 by David Adler | ||
| Shirley Xiao, David Nguyen | ||
| Email : dadler at adtechgeospatial.com | ||
| xshirley2012 at yahoo.com, davidng0123 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 QGSDB2SOURCESELECT_H | ||
| #define QGSDB2SOURCESELECT_H | ||
|
|
||
| #include "ui_qgsdbsourceselectbase.h" | ||
| #include "qgisgui.h" | ||
| #include "qgsdbfilterproxymodel.h" | ||
| #include "qgsdb2tablemodel.h" | ||
| #include "qgscontexthelp.h" | ||
|
|
||
| #include <QMap> | ||
| #include <QPair> | ||
| #include <QIcon> | ||
| #include <QItemDelegate> | ||
| #include <QThread> | ||
|
|
||
| class QPushButton; | ||
| class QStringList; | ||
| class QgsGeomColumnTypeThread; | ||
| class QgisApp; | ||
|
|
||
| class QgsDb2SourceSelectDelegate : public QItemDelegate | ||
| { | ||
| Q_OBJECT | ||
|
|
||
| public: | ||
| explicit QgsDb2SourceSelectDelegate( QObject *parent = NULL ) | ||
| : QItemDelegate( parent ) | ||
| {} | ||
|
|
||
| QWidget *createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const override; | ||
| void setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const override; | ||
| }; | ||
|
|
||
| // A class that determines the geometry type of a given database | ||
| // schema.table.column, with the option of doing so in a separate | ||
| // thread. | ||
|
|
||
| class QgsDb2GeomColumnTypeThread : public QThread | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| QgsDb2GeomColumnTypeThread( QString connectionName, bool useEstimatedMetadata ); | ||
|
|
||
| // These functions get the layer types and pass that information out | ||
| // by emitting the setLayerType() signal. | ||
| virtual void run() override; | ||
|
|
||
| signals: | ||
| void setLayerType( QgsDb2LayerProperty layerProperty ); | ||
|
|
||
| public slots: | ||
| void addGeometryColumn( QgsDb2LayerProperty layerProperty ); | ||
| void stop(); | ||
|
|
||
| private: | ||
| QgsDb2GeomColumnTypeThread() {} | ||
|
|
||
| QString mConnectionName; | ||
| bool mUseEstimatedMetadata; | ||
| bool mStopped; | ||
| QList<QgsDb2LayerProperty> layerProperties; | ||
| }; | ||
|
|
||
|
|
||
| /** \class QgsDb2SourceSelect | ||
| * \brief Dialog to create connections and add tables from Db2. | ||
| * | ||
| * This dialog allows the user to define and save connection information | ||
| * for Db2 databases. The user can then connect and add | ||
| * tables from the database to the map canvas. | ||
| */ | ||
| class QgsDb2SourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase | ||
| { | ||
| Q_OBJECT | ||
|
|
||
| public: | ||
|
|
||
| //! static function to delete a connection | ||
| static void deleteConnection( QString key ); | ||
|
|
||
| //! Constructor | ||
| QgsDb2SourceSelect( QWidget *parent = 0, Qt::WindowFlags fl = QgisGui::ModalDialogFlags, bool managerMode = false, bool embeddedMode = false ); | ||
| //! Destructor | ||
| ~QgsDb2SourceSelect(); | ||
| //! Populate the connection list combo box | ||
| void populateConnectionList(); | ||
| //! String list containing the selected tables | ||
| QStringList selectedTables(); | ||
| //! Connection info (database, host, user, password) | ||
| QString connectionInfo(); | ||
|
|
||
| signals: | ||
| void addDatabaseLayers( QStringList const & layerPathList, QString const & providerKey ); | ||
| void connectionsChanged(); | ||
| void addGeometryColumn( QgsDb2LayerProperty ); | ||
|
|
||
| public slots: | ||
| //! Determines the tables the user selected and closes the dialog | ||
| void addTables(); | ||
| void buildQuery(); | ||
|
|
||
| /** Connects to the database using the stored connection parameters. | ||
| * Once connected, available layers are displayed. | ||
| */ | ||
| void on_btnConnect_clicked(); | ||
| void on_cbxAllowGeometrylessTables_stateChanged( int ); | ||
| //! Opens the create connection dialog to build a new connection | ||
| void on_btnNew_clicked(); | ||
| //! Opens a dialog to edit an existing connection | ||
| void on_btnEdit_clicked(); | ||
| //! Deletes the selected connection | ||
| void on_btnDelete_clicked(); | ||
| //! Saves the selected connections to file | ||
| void on_btnSave_clicked(); | ||
| //! Loads the selected connections from file | ||
| void on_btnLoad_clicked(); | ||
| void on_mSearchGroupBox_toggled( bool ); | ||
| void on_mSearchTableEdit_textChanged( const QString & text ); | ||
| void on_mSearchColumnComboBox_currentIndexChanged( const QString & text ); | ||
| void on_mSearchModeComboBox_currentIndexChanged( const QString & text ); | ||
| void setSql( const QModelIndex& index ); | ||
| //! Store the selected database | ||
| void on_cmbConnections_activated( int ); | ||
| void setLayerType( QgsDb2LayerProperty layerProperty ); | ||
| void on_mTablesTreeView_clicked( const QModelIndex &index ); | ||
| void on_mTablesTreeView_doubleClicked( const QModelIndex &index ); | ||
| //!Sets a new regular expression to the model | ||
| void setSearchExpression( const QString& regexp ); | ||
|
|
||
| void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); } | ||
|
|
||
| void columnThreadFinished(); | ||
|
|
||
| private: | ||
| typedef QPair<QString, QString> geomPair; | ||
| typedef QList<geomPair> geomCol; | ||
|
|
||
| //! Connections manager mode | ||
| bool mManagerMode; | ||
|
|
||
| //! Embedded mode, without 'Close' | ||
| bool mEmbeddedMode; | ||
|
|
||
| // queue another query for the thread | ||
| void addSearchGeometryColumn( QString connectionName, QgsDb2LayerProperty layerProperty, bool estimateMetadata ); | ||
|
|
||
| // Set the position of the database connection list to the last | ||
| // used one. | ||
| void setConnectionListPosition(); | ||
| // Combine the schema, table and column data into a single string | ||
| // useful for display to the user | ||
| QString fullDescription( QString schema, QString table, QString column, QString type ); | ||
| // The column labels | ||
| QStringList mColumnLabels; | ||
| // Our thread for doing long running queries | ||
| QgsDb2GeomColumnTypeThread* mColumnTypeThread; | ||
| QString mConnInfo; | ||
| QStringList mSelectedTables; | ||
| bool mUseEstimatedMetadata; | ||
| // Storage for the range of layer type icons | ||
| QMap<QString, QPair<QString, QIcon> > mLayerIcons; | ||
|
|
||
| //! Model that acts as datasource for mTableTreeWidget | ||
| QgsDb2TableModel mTableModel; | ||
| QgsDbFilterProxyModel mProxyModel; | ||
|
|
||
| QPushButton *mBuildQueryButton; | ||
| QPushButton *mAddButton; | ||
|
|
||
| void finishList(); | ||
| }; | ||
|
|
||
| #endif // QGSDb2SOURCESELECT_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| /*************************************************************************** | ||
| qgsdb2tablemodel.h - description | ||
| -------------------------------------- | ||
| Date : 2016-01-27 | ||
| Copyright : (C) 2016 by David Adler | ||
| Shirley Xiao, David Nguyen | ||
| Email : dadler at adtechgeospatial.com | ||
| xshirley2012 at yahoo.com, davidng0123 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 QGSDB2TABLEMODEL_H | ||
| #define QGSDB2TABLEMODEL_H | ||
|
|
||
| #include <QStandardItemModel> | ||
| #include <qgsdataitem.h> | ||
| #include "qgis.h" | ||
|
|
||
| /** Layer Property structure */ | ||
| struct QgsDb2LayerProperty | ||
| { | ||
| QString type; | ||
| QString schemaName; | ||
| QString tableName; | ||
| QString geometryColName; | ||
| QStringList pkCols; | ||
| QString pkColumnName; | ||
| QString srid; | ||
| QString srsName; | ||
| QString sql; | ||
| QString extents; | ||
| }; | ||
|
|
||
|
|
||
| class QIcon; | ||
|
|
||
| /** A model that holds the tables of a database in a hierarchy where the | ||
| schemas are the root elements that contain the individual tables as children. | ||
| The tables have the following columns: Type, Schema, Tablename, Geometry Column, Sql*/ | ||
| class QgsDb2TableModel : public QStandardItemModel | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| QgsDb2TableModel(); | ||
| ~QgsDb2TableModel(); | ||
|
|
||
| /** Adds entry for one database table to the model*/ | ||
| void addTableEntry( const QgsDb2LayerProperty &property ); | ||
|
|
||
| /** Sets an sql statement that belongs to a cell specified by a model index*/ | ||
| void setSql( const QModelIndex& index, const QString& sql ); | ||
|
|
||
| /** Sets one or more geometry types to a row. In case of several types, additional rows are inserted. | ||
| This is for tables where the type is dectected later by thread*/ | ||
| void setGeometryTypesForTable( QgsDb2LayerProperty layerProperty ); | ||
|
|
||
| /** Returns the number of tables in the model*/ | ||
| int tableCount() const { return mTableCount; } | ||
|
|
||
| enum columns | ||
| { | ||
| dbtmSchema = 0, | ||
| dbtmTable, | ||
| dbtmType, | ||
| dbtmGeomCol, | ||
| dbtmSrid, | ||
| dbtmPkCol, | ||
| dbtmSelectAtId, | ||
| dbtmSql, | ||
| dbtmColumns | ||
| }; | ||
|
|
||
| bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole ) override; | ||
|
|
||
| QString layerURI( const QModelIndex &index, const QString &connInfo, bool useEstimatedMetadata ); | ||
|
|
||
| static QIcon iconForWkbType( QGis::WkbType type ); | ||
|
|
||
| static QGis::WkbType wkbTypeFromDb2( QString dbType, int dim = 2 ); | ||
|
|
||
| static QString displayStringForWkbType( QGis::WkbType type ); | ||
|
|
||
| private: | ||
| /** Number of tables in the model*/ | ||
| int mTableCount; | ||
| }; | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,358 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <ui version="4.0"> | ||
| <class>QgsDb2NewConnectionBase</class> | ||
| <widget class="QDialog" name="QgsDb2NewConnectionBase"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>0</x> | ||
| <y>0</y> | ||
| <width>749</width> | ||
| <height>582</height> | ||
| </rect> | ||
| </property> | ||
| <property name="windowTitle"> | ||
| <string>Create a New DB2 connection</string> | ||
| </property> | ||
| <widget class="QDialogButtonBox" name="buttonBox"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>450</x> | ||
| <y>440</y> | ||
| <width>221</width> | ||
| <height>32</height> | ||
| </rect> | ||
| </property> | ||
| <property name="orientation"> | ||
| <enum>Qt::Horizontal</enum> | ||
| </property> | ||
| <property name="standardButtons"> | ||
| <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | ||
| </property> | ||
| </widget> | ||
| <widget class="QGroupBox" name="groupBox"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>10</x> | ||
| <y>30</y> | ||
| <width>671</width> | ||
| <height>371</height> | ||
| </rect> | ||
| </property> | ||
| <property name="title"> | ||
| <string>Connection Properties</string> | ||
| </property> | ||
| <widget class="QLabel" name="DB2HostLabel"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>20</x> | ||
| <y>110</y> | ||
| <width>91</width> | ||
| <height>20</height> | ||
| </rect> | ||
| </property> | ||
| <property name="text"> | ||
| <string>DB2 Host:</string> | ||
| </property> | ||
| </widget> | ||
| <widget class="QLabel" name="DB2port"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>20</x> | ||
| <y>150</y> | ||
| <width>91</width> | ||
| <height>19</height> | ||
| </rect> | ||
| </property> | ||
| <property name="text"> | ||
| <string>DB2 Port:</string> | ||
| </property> | ||
| </widget> | ||
| <widget class="QLabel" name="database"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>20</x> | ||
| <y>180</y> | ||
| <width>91</width> | ||
| <height>19</height> | ||
| </rect> | ||
| </property> | ||
| <property name="text"> | ||
| <string>Database:</string> | ||
| </property> | ||
| </widget> | ||
| <widget class="QLineEdit" name="txtPort"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>140</x> | ||
| <y>140</y> | ||
| <width>231</width> | ||
| <height>31</height> | ||
| </rect> | ||
| </property> | ||
| </widget> | ||
| <widget class="QLineEdit" name="txtDatabase"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>140</x> | ||
| <y>180</y> | ||
| <width>231</width> | ||
| <height>31</height> | ||
| </rect> | ||
| </property> | ||
| </widget> | ||
| <widget class="QLineEdit" name="txtHost"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>140</x> | ||
| <y>100</y> | ||
| <width>231</width> | ||
| <height>31</height> | ||
| </rect> | ||
| </property> | ||
| </widget> | ||
| <widget class="QPushButton" name="btnConnect"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>520</x> | ||
| <y>250</y> | ||
| <width>141</width> | ||
| <height>34</height> | ||
| </rect> | ||
| </property> | ||
| <property name="text"> | ||
| <string>Test connection</string> | ||
| </property> | ||
| </widget> | ||
| <widget class="QLineEdit" name="txtService"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>560</x> | ||
| <y>70</y> | ||
| <width>111</width> | ||
| <height>31</height> | ||
| </rect> | ||
| </property> | ||
| </widget> | ||
| <widget class="QLabel" name="DB2ServiceLabel"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>430</x> | ||
| <y>70</y> | ||
| <width>121</width> | ||
| <height>19</height> | ||
| </rect> | ||
| </property> | ||
| <property name="text"> | ||
| <string>Service/DSN:</string> | ||
| </property> | ||
| </widget> | ||
| <widget class="QLineEdit" name="txtDriver"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>140</x> | ||
| <y>60</y> | ||
| <width>231</width> | ||
| <height>31</height> | ||
| </rect> | ||
| </property> | ||
| </widget> | ||
| <widget class="QLabel" name="DB2ServiceLabel_2"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>20</x> | ||
| <y>70</y> | ||
| <width>91</width> | ||
| <height>19</height> | ||
| </rect> | ||
| </property> | ||
| <property name="text"> | ||
| <string>Driver:</string> | ||
| </property> | ||
| </widget> | ||
| <widget class="QLineEdit" name="txtName"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>560</x> | ||
| <y>20</y> | ||
| <width>121</width> | ||
| <height>31</height> | ||
| </rect> | ||
| </property> | ||
| </widget> | ||
| <widget class="QLabel" name="DB2ServiceLabel_3"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>390</x> | ||
| <y>20</y> | ||
| <width>161</width> | ||
| <height>20</height> | ||
| </rect> | ||
| </property> | ||
| <property name="text"> | ||
| <string>Connection Name:</string> | ||
| </property> | ||
| </widget> | ||
| <widget class="QTabWidget" name="tabAuthentication"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>20</x> | ||
| <y>230</y> | ||
| <width>417</width> | ||
| <height>131</height> | ||
| </rect> | ||
| </property> | ||
| <property name="sizePolicy"> | ||
| <sizepolicy hsizetype="Expanding" vsizetype="Maximum"> | ||
| <horstretch>0</horstretch> | ||
| <verstretch>0</verstretch> | ||
| </sizepolicy> | ||
| </property> | ||
| <property name="currentIndex"> | ||
| <number>0</number> | ||
| </property> | ||
| <widget class="QWidget" name="tabBasic"> | ||
| <attribute name="title"> | ||
| <string>Authentication</string> | ||
| </attribute> | ||
| <layout class="QGridLayout" name="gridLayout"> | ||
| <property name="leftMargin"> | ||
| <number>5</number> | ||
| </property> | ||
| <property name="topMargin"> | ||
| <number>5</number> | ||
| </property> | ||
| <property name="rightMargin"> | ||
| <number>5</number> | ||
| </property> | ||
| <property name="bottomMargin"> | ||
| <number>5</number> | ||
| </property> | ||
| <item row="0" column="0"> | ||
| <widget class="QLabel" name="TextLabel3"> | ||
| <property name="text"> | ||
| <string>Username</string> | ||
| </property> | ||
| <property name="buddy"> | ||
| <cstring>txtUsername</cstring> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item row="1" column="1"> | ||
| <widget class="QLineEdit" name="txtPassword"> | ||
| <property name="echoMode"> | ||
| <enum>QLineEdit::Password</enum> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item row="0" column="2"> | ||
| <widget class="QCheckBox" name="chkStoreUsername"> | ||
| <property name="text"> | ||
| <string>Save</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item row="1" column="0"> | ||
| <widget class="QLabel" name="TextLabel3_2"> | ||
| <property name="text"> | ||
| <string>Password</string> | ||
| </property> | ||
| <property name="buddy"> | ||
| <cstring>txtPassword</cstring> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item row="0" column="1"> | ||
| <widget class="QLineEdit" name="txtUsername"/> | ||
| </item> | ||
| <item row="1" column="2"> | ||
| <widget class="QCheckBox" name="chkStorePassword"> | ||
| <property name="text"> | ||
| <string>Save</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </widget> | ||
| </widget> | ||
| <widget class="QLabel" name="db2ConnectStatus"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>20</x> | ||
| <y>410</y> | ||
| <width>711</width> | ||
| <height>31</height> | ||
| </rect> | ||
| </property> | ||
| <property name="text"> | ||
| <string>DB2 Connect Status: </string> | ||
| </property> | ||
| </widget> | ||
| </widget> | ||
| <tabstops> | ||
| <tabstop>txtName</tabstop> | ||
| <tabstop>txtService</tabstop> | ||
| <tabstop>txtDriver</tabstop> | ||
| <tabstop>txtHost</tabstop> | ||
| <tabstop>txtPort</tabstop> | ||
| <tabstop>txtDatabase</tabstop> | ||
| <tabstop>tabAuthentication</tabstop> | ||
| <tabstop>txtUsername</tabstop> | ||
| <tabstop>chkStoreUsername</tabstop> | ||
| <tabstop>txtPassword</tabstop> | ||
| <tabstop>chkStorePassword</tabstop> | ||
| <tabstop>btnConnect</tabstop> | ||
| <tabstop>buttonBox</tabstop> | ||
| </tabstops> | ||
| <resources/> | ||
| <connections> | ||
| <connection> | ||
| <sender>btnConnect</sender> | ||
| <signal>released()</signal> | ||
| <receiver>QgsDb2NewConnectionBase</receiver> | ||
| <slot>on_btnConnect_clicked()</slot> | ||
| <hints> | ||
| <hint type="sourcelabel"> | ||
| <x>20</x> | ||
| <y>20</y> | ||
| </hint> | ||
| <hint type="destinationlabel"> | ||
| <x>20</x> | ||
| <y>20</y> | ||
| </hint> | ||
| </hints> | ||
| </connection> | ||
| <connection> | ||
| <sender>buttonBox</sender> | ||
| <signal>accepted()</signal> | ||
| <receiver>QgsDb2NewConnectionBase</receiver> | ||
| <slot>accept()</slot> | ||
| <hints> | ||
| <hint type="sourcelabel"> | ||
| <x>248</x> | ||
| <y>254</y> | ||
| </hint> | ||
| <hint type="destinationlabel"> | ||
| <x>157</x> | ||
| <y>274</y> | ||
| </hint> | ||
| </hints> | ||
| </connection> | ||
| <connection> | ||
| <sender>buttonBox</sender> | ||
| <signal>rejected()</signal> | ||
| <receiver>QgsDb2NewConnectionBase</receiver> | ||
| <slot>reject()</slot> | ||
| <hints> | ||
| <hint type="sourcelabel"> | ||
| <x>316</x> | ||
| <y>260</y> | ||
| </hint> | ||
| <hint type="destinationlabel"> | ||
| <x>286</x> | ||
| <y>274</y> | ||
| </hint> | ||
| </hints> | ||
| </connection> | ||
| </connections> | ||
| </ui> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # -*- coding: utf-8 -*- | ||
| """QGIS Unit tests for the MS SQL provider. | ||
| .. note:: 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. | ||
| """ | ||
| __author__ = 'David Adler' | ||
| __date__ = '2016-03-01' | ||
| __copyright__ = 'Copyright 2016, The QGIS Project' | ||
| # This will get replaced with a git SHA1 when you do a git archive | ||
| __revision__ = '$Format:%H$' | ||
|
|
||
| import qgis | ||
| import os | ||
| import sys | ||
| from qgis.core import NULL | ||
| from pprint import pprint | ||
| from qgis.core import ( | ||
| QgsVectorLayer, | ||
| QgsFeatureRequest, | ||
| QgsFeature, | ||
| QgsProviderRegistry | ||
| ) | ||
|
|
||
| from PyQt4.QtCore import ( | ||
| QSettings, | ||
| QDate, | ||
| QTime, | ||
| QDateTime, | ||
| QVariant | ||
| ) | ||
|
|
||
| from utilities import unitTestDataPath | ||
| from qgis.testing import ( | ||
| start_app, | ||
| unittest | ||
| ) | ||
| from providertestbase import ProviderTestCase | ||
|
|
||
| start_app() | ||
| TEST_DATA_DIR = unitTestDataPath() | ||
|
|
||
|
|
||
| class TestPyQgsDb2Provider(unittest.TestCase, ProviderTestCase): | ||
|
|
||
| @classmethod | ||
| def setUpClass(cls): | ||
| """Run before all tests""" | ||
| cls.dbconn = u"dbname='ostest' driver='IBM DB2 ODBC DRIVER' host=dadler.dynalias.org port=50000 user='osuser' password='osuserpw'" | ||
| if 'QGIS_DB2_DB' in os.environ: | ||
| cls.dbconn = os.environ['QGIS_DB2TEST_DB'] | ||
| # Create test layer | ||
| cls.vl = QgsVectorLayer(cls.dbconn + ' srid=4326 type=Point table="QGIS_TEST"."SOMEDATA" (GEOM) sql=', 'test', 'DB2') | ||
| assert(cls.vl.isValid()) | ||
| cls.provider = cls.vl.dataProvider() | ||
| cls.poly_vl = QgsVectorLayer( | ||
| cls.dbconn + ' srid=4326 type=POLYGON table="QGIS_TEST"."SOME_POLY_DATA" (geom) sql=', 'test', 'DB2') | ||
| assert(cls.poly_vl.isValid()) | ||
| cls.poly_provider = cls.poly_vl.dataProvider() | ||
|
|
||
| @classmethod | ||
| def tearDownClass(cls): | ||
| """Run after all tests""" | ||
|
|
||
| def setUp(self): | ||
| print ("starting " + self._testMethodName) | ||
|
|
||
| def getSubsetString(self): | ||
| """Individual providers may need to override this depending on their subset string formats""" | ||
| return 'cnt > 100 and cnt < 410' | ||
|
|
||
| def enableCompiler(self): | ||
| QSettings().setValue(u'/qgis/compileExpressions', True) | ||
|
|
||
| def disableCompiler(self): | ||
| QSettings().setValue(u'/qgis/compileExpressions', False) | ||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| DROP TABLE qgis_test.someData; | ||
| DROP TABLE qgis_test.some_poly_data; | ||
| DROP TABLE qgis_test.date_times; | ||
|
|
||
| CREATE TABLE qgis_test.someData ( | ||
| pk integer NOT NULL PRIMARY KEY, | ||
| cnt integer, | ||
| name varchar(32) DEFAULT 'qgis', | ||
| name2 varchar(32) DEFAULT 'qgis', | ||
| num_char char(1), | ||
| geom db2gse.st_point | ||
| ); | ||
|
|
||
| CREATE TABLE qgis_test.some_poly_data ( | ||
| pk integer NOT NULL PRIMARY KEY, | ||
| geom db2gse.st_polygon | ||
| ); | ||
|
|
||
| CREATE TABLE qgis_test.date_times ( | ||
| id integer NOT NULL PRIMARY KEY, | ||
| date_field date, | ||
| time_field time, | ||
| datetime_field timestamp | ||
| ); | ||
|
|
||
| INSERT INTO qgis_test.someData (pk, cnt, name, name2, num_char, geom) VALUES | ||
| (5, -200, NULL, 'NuLl', '5', db2gse.st_point( 'Point(-71.123 78.23)', 4326 )), | ||
| (3, 300, 'Pear', 'PEaR', '3', NULL), | ||
| (1, 100, 'Orange', 'oranGe', '1', db2gse.st_point( 'Point(-70.332 66.33)', 4326 )), | ||
| (2, 200, 'Apple', 'Apple', '2', db2gse.st_point( 'Point(-68.2 70.8)', 4326 )), | ||
| (4, 400, 'Honey', 'Honey', '4', db2gse.st_point( 'Point(-65.32 78.3)', 4326 )) | ||
| ; | ||
|
|
||
| INSERT INTO qgis_test.some_poly_data (pk, geom) VALUES | ||
| (1, db2gse.st_polygon('Polygon ((-69.0 81.4, -69.0 80.2, -73.7 80.2, -73.7 76.3, -74.9 76.3, -74.9 81.4, -69.0 81.4))', 4326 )), | ||
| (2, db2gse.st_polygon('Polygon ((-67.6 81.2, -66.3 81.2, -66.3 76.9, -67.6 76.9, -67.6 81.2))', 4326 )), | ||
| (3, db2gse.st_polygon('Polygon ((-68.4 75.8, -67.5 72.6, -68.6 73.7, -70.2 72.9, -68.4 75.8))', 4326 )), | ||
| (4, NULL) | ||
| ; | ||
|
|
||
|
|
||
| INSERT INTO qgis_test.date_times (id, date_field, time_field, datetime_field ) VALUES | ||
| (1, '2004-03-04', '13:41:52', '2004-03-04 13:41:52' ); |