Skip to content

Commit

Permalink
Implement missing functionality for HANA provider
Browse files Browse the repository at this point in the history
  • Loading branch information
Maksim Rylov authored and mrylov committed Dec 7, 2020
1 parent a64982b commit 6f6bd52
Show file tree
Hide file tree
Showing 13 changed files with 475 additions and 225 deletions.
1 change: 1 addition & 0 deletions src/providers/hana/CMakeLists.txt
Expand Up @@ -12,6 +12,7 @@ SET (HANA_SRCS
qgshanaexpressioncompiler.cpp
qgshanafeatureiterator.cpp
qgshanaprovider.cpp
qgshanaresultset.cpp
qgshanasettings.cpp
qgshanatablemodel.cpp
qgshanautils.cpp
Expand Down
19 changes: 8 additions & 11 deletions src/providers/hana/qgshanaconnection.cpp
Expand Up @@ -41,14 +41,11 @@
using namespace odbc;
using namespace std;

namespace
{

static const uint8_t CREDENTIALS_INPUT_MAX_ATTEMPTS = 5;
static const uint8_t CREDENTIALS_INPUT_MAX_ATTEMPTS = 5;

void addNewLayer( QVector<QgsHanaLayerProperty> &list,
const QgsHanaLayerProperty &layerProperty, bool checkDuplicates = false )
{
static void addNewLayer( QVector<QgsHanaLayerProperty> &list,
const QgsHanaLayerProperty &layerProperty, bool checkDuplicates = false )
{
if ( checkDuplicates )
{
auto res = std::find_if( list.begin(), list.end(),
Expand All @@ -60,8 +57,6 @@ namespace
}

list << layerProperty;
}

}

bool QgsHanaConnection::sConnectionAttemptCanceled = false;
Expand Down Expand Up @@ -134,8 +129,9 @@ QgsHanaConnection *QgsHanaConnection::createConnection( const QgsDataSourceUri &
}
catch ( const exception &ex )
{
QgsMessageLog::logMessage(
QObject::tr( "Connection to database failed" ) + '\n' + QgsHanaUtils::formatErrorMessage( ex.what() ), tr( "HANA" ) );
QString msg = QObject::tr( "Connection to database failed" ) + '\n' + QgsHanaUtils::formatErrorMessage( ex.what() );
QgsDebugMsg( msg );
QgsMessageLog::logMessage( msg, tr( "HANA" ) );
}

return conn;
Expand All @@ -155,6 +151,7 @@ bool QgsHanaConnection::connect(
catch ( const Exception &ex )
{
errorMessage = QgsHanaUtils::formatErrorMessage( ex.what() );
QgsDebugMsg( errorMessage );
}

return conn->connected();
Expand Down
161 changes: 19 additions & 142 deletions src/providers/hana/qgshanafeatureiterator.cpp
Expand Up @@ -32,19 +32,14 @@

using namespace odbc;

namespace
static QString andWhereClauses( const QString &c1, const QString &c2 )
{

QString andWhereClauses( const QString &c1, const QString &c2 )
{
if ( c1.isEmpty() )
return c2;
if ( c2.isEmpty() )
return c1;

return QStringLiteral( "(%1) AND (%2)" ).arg( c1, c2 );
}

}

QgsHanaFeatureIterator::QgsHanaFeatureIterator(
Expand Down Expand Up @@ -81,7 +76,9 @@ QgsHanaFeatureIterator::QgsHanaFeatureIterator(

try
{
buildStatement( request );
QString sql = buildSQLStatement( request );
PreparedStatementRef stmt = mConnRef->getNativeRef()->prepareStatement( sql.toStdString().c_str() );
mStatement = sql;
mClosed = false;
rewind();
}
Expand All @@ -102,16 +99,9 @@ bool QgsHanaFeatureIterator::rewind()
if ( mClosed )
return false;

try
{
mResultSet.reset();
mResultSet = mStatement->executeQuery();
}
catch ( const Exception &ex )
{
throw QgsHanaException( ex.what() );
}

mResultSet.reset();
PreparedStatementRef stmt = mConnRef->getNativeRef()->prepareStatement( mStatement.toStdString().c_str() );
mResultSet = QgsHanaResultSet::create(stmt);
return true;
}

Expand Down Expand Up @@ -139,34 +129,38 @@ bool QgsHanaFeatureIterator::fetchFeature( QgsFeature &feature )
if ( !mResultSet->next() )
return false;

feature.initAttributes( mSource->mFields.count() );
unsigned short paramIndex = 1;

// Read feature id
if ( mHasFidColumn )
{
feature.setId( *mResultSet->getLong( paramIndex ) );
++paramIndex;
QVariant id = mResultSet->getValue(paramIndex);
feature.setId( id.toLongLong() );
feature.setAttribute( 0, id );
++paramIndex;
}
else
{
feature.setId( 0u );
}

// Read attributes
feature.initAttributes( mSource->mFields.count() );
if ( mHasAttributes )
{
Q_FOREACH ( int idx, mAttributesToFetch )
for(int i = 0; i < mAttributesToFetch.size(); ++i )
{
fetchFeatureAttribute( idx, paramIndex, feature );
feature.setAttribute( paramIndex - 1, mResultSet->getValue(paramIndex ));
++paramIndex;
}
}

// Read geometry
if ( mHasGeometryColumn )
{
fetchFeatureGeometry( paramIndex, feature );
QgsGeometry geom = mResultSet->getGeometry(paramIndex);
if (!geom.isNull())
feature.setGeometry( geom );
++paramIndex;
}
else
Expand All @@ -186,114 +180,6 @@ bool QgsHanaFeatureIterator::fetchFeature( QgsFeature &feature )
return true;
}

void QgsHanaFeatureIterator::fetchFeatureAttribute(
int attrIndex,
unsigned short paramIndex,
QgsFeature &feature )
{
QgsField field = mSource->mFields.at( attrIndex );
FieldInfo fieldInfo = mSource->mFieldInfos.at( attrIndex );
switch ( fieldInfo.type )
{
case SQLDataTypes::Boolean:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getBoolean( paramIndex ), QVariant::Bool ) );
break;
case SQLDataTypes::Char:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getByte( paramIndex ) ) );
break;
case SQLDataTypes::WChar:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getUByte( paramIndex ) ) );
break;
case SQLDataTypes::SmallInt:
if ( field.type() == QVariant::Int )
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getShort( paramIndex ) ) );
else
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getUShort( paramIndex ) ) );
break;
case SQLDataTypes::Integer:
if ( field.type() == QVariant::Int )
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getInt( paramIndex ), QVariant::Int ) );
else
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getUInt( paramIndex ), QVariant::UInt ) );
break;
case SQLDataTypes::BigInt:
if ( field.type() == QVariant::LongLong )
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getLong( paramIndex ) ) );
else
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getULong( paramIndex ) ) );
break;
case SQLDataTypes::Double:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getDouble( paramIndex ), QVariant::Double ) );
break;
case SQLDataTypes::Decimal:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getDouble( paramIndex ), QVariant::Double ) );
break;
case SQLDataTypes::Numeric:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getDouble( paramIndex ), QVariant::Double ) );
break;
case SQLDataTypes::Date:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getDate( paramIndex ) ) );
break;
case SQLDataTypes::Time:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getTime( paramIndex ) ) );
break;
case SQLDataTypes::Timestamp:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getTimestamp( paramIndex ) ) );
break;
case SQLDataTypes::VarChar:
case SQLDataTypes::LongVarChar:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getString( paramIndex ) ) );
break;
case SQLDataTypes::WVarChar:
case SQLDataTypes::WLongVarChar:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getNString( paramIndex ) ) );
break;
case SQLDataTypes::Binary:
case SQLDataTypes::VarBinary:
case SQLDataTypes::LongVarBinary:
feature.setAttribute( attrIndex, QgsHanaUtils::toVariant( mResultSet->getBinary( paramIndex ) ) );
break;
default:
break;
}
}

void QgsHanaFeatureIterator::fetchFeatureGeometry( unsigned short paramIndex, QgsFeature &feature )
{
size_t bufLength = mResultSet->getBinaryLength( paramIndex );
unsigned char *bufPtr = nullptr;

if ( bufLength == ResultSet::UNKNOWN_LENGTH )
{
Binary wkb = mResultSet->getBinary( paramIndex );
if ( wkb.isNull() || wkb->size() == 0 )
bufLength = 0;
else
bufPtr = ( unsigned char * )wkb->data();
}
else if ( bufLength != 0 && bufLength != odbc::ResultSet::NULL_DATA )
{
ensureBufferCapacity( bufLength );
mResultSet->getBinaryData( paramIndex, mBuffer.data(), bufLength );

bufPtr = mBuffer.data();
}

if ( bufLength == 0 || bufPtr == nullptr )
{
QgsDebugMsg( QStringLiteral( "Geometry is empty" ) );
feature.clearGeometry();
}
else
{
unsigned char *wkbGeom = new unsigned char[bufLength];
memcpy( wkbGeom, bufPtr, bufLength );
QgsGeometry geom;
geom.fromWkb( wkbGeom, static_cast<int>( bufLength ) );
feature.setGeometry( geom );
}
}

bool QgsHanaFeatureIterator::nextFeatureFilterExpression( QgsFeature &feature )
{
if ( !mExpressionCompiled )
Expand All @@ -320,7 +206,7 @@ QString QgsHanaFeatureIterator::getBBOXFilter( const QgsRectangle &bbox,
QString::number( mSource->mSrid ) );
}

void QgsHanaFeatureIterator::buildStatement( const QgsFeatureRequest &request )
QString QgsHanaFeatureIterator::buildSQLStatement( const QgsFeatureRequest &request )
{
QgsRectangle filterRect = mFilterRect;
if ( !mSrsExtent.isEmpty() )
Expand Down Expand Up @@ -468,16 +354,7 @@ void QgsHanaFeatureIterator::buildStatement( const QgsFeatureRequest &request )
sql += QStringLiteral( " LIMIT %1" ).arg( mRequest.limit() );

QgsDebugMsg( sql );

mStatement = mConnRef->getNativeRef()->prepareStatement( sql.toStdString().c_str() );
}

void QgsHanaFeatureIterator::ensureBufferCapacity( size_t capacity )
{
if ( capacity > mBuffer.size() )
{
mBuffer.reserve( capacity );
}
return sql;
}

QgsHanaFeatureSource::QgsHanaFeatureSource( const QgsHanaProvider *p )
Expand Down
11 changes: 4 additions & 7 deletions src/providers/hana/qgshanafeatureiterator.h
Expand Up @@ -20,6 +20,7 @@
#include "qgsfeatureiterator.h"
#include "qgshanaconnection.h"
#include "qgshanaprovider.h"
#include "qgshanaresultset.h"

#include "odbc/Forwards.h"

Expand Down Expand Up @@ -67,24 +68,20 @@ class QgsHanaFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsHa

protected:
bool fetchFeature( QgsFeature &feature ) override;
void fetchFeatureAttribute( int attrIndex, unsigned short paramIndex, QgsFeature &feature );
void fetchFeatureGeometry( unsigned short paramIndex, QgsFeature &feature );
bool nextFeatureFilterExpression( QgsFeature &feature ) override;

private:
void buildStatement( const QgsFeatureRequest &request );
void ensureBufferCapacity( std::size_t capacity );
QString buildSQLStatement( const QgsFeatureRequest &request );
QString getBBOXFilter( const QgsRectangle &bbox, const QVersionNumber &dbVersion ) const;

private:
QgsHanaConnectionRef mConnRef;
odbc::PreparedStatementRef mStatement;
odbc::ResultSetRef mResultSet;
QgsHanaResultSetRef mResultSet;
QString mStatement;
QgsCoordinateTransform mTransform;
QgsRectangle mFilterRect;
QgsRectangle mSrsExtent;
QgsAttributeList mAttributesToFetch;
std::vector<unsigned char> mBuffer;
bool mHasFidColumn;
bool mHasAttributes;
bool mHasGeometryColumn;
Expand Down

0 comments on commit 6f6bd52

Please sign in to comment.