Skip to content

Commit

Permalink
[FEATURE] oracle provider: initial expression compiler support
Browse files Browse the repository at this point in the history
  • Loading branch information
jef-n committed Dec 5, 2015
1 parent 5e4312b commit 65ee183
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/providers/oracle/CMakeLists.txt
Expand Up @@ -14,6 +14,7 @@ SET(ORACLE_SRCS
qgsoraclecolumntypethread.cpp
qgsoraclefeatureiterator.cpp
qgsoracleconnpool.cpp
qgsoracleexpressioncompiler.cpp
)

SET(ORACLE_MOC_HDRS
Expand All @@ -25,6 +26,7 @@ SET(ORACLE_MOC_HDRS
qgsoracletablemodel.h
qgsoraclecolumntypethread.h
qgsoracleconnpool.h
qgsoracleexpressioncompiler.h
)


Expand Down
73 changes: 73 additions & 0 deletions src/providers/oracle/qgsoracleexpressioncompiler.cpp
@@ -0,0 +1,73 @@
/***************************************************************************
qgsoracleexpressioncompiler.cpp
----------------------------------------------------
date : December 2015
copyright : (C) 2015 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 "qgsoracleexpressioncompiler.h"
#include "qgssqlexpressioncompiler.h"

QgsOracleExpressionCompiler::QgsOracleExpressionCompiler( QgsOracleFeatureSource* source )
: QgsSqlExpressionCompiler( source->mFields )
{
}

QgsSqlExpressionCompiler::Result QgsOracleExpressionCompiler::compileNode( const QgsExpression::Node* node, QString& result )
{
if ( node->nodeType() == QgsExpression::ntBinaryOperator )
{
const QgsExpression::NodeBinaryOperator *bin( static_cast<const QgsExpression::NodeBinaryOperator*>( node ) );

switch ( bin->op() )
{
case QgsExpression::boPow:
case QgsExpression::boRegexp:
{
QString op1, op2;

if ( compileNode( bin->opLeft(), op1 ) != Complete ||
compileNode( bin->opRight(), op2 ) != Complete )
return Fail;

switch ( bin->op() )
{
case QgsExpression::boPow:
result = QString( "power(%1,%2)" ).arg( op1, op2 );
return Complete;

case QgsExpression::boRegexp:
result = QString( "regexp_like(%1,%2)" ).arg( op1, op2 );
return Complete;

default:
break;
}
}

default:
break;
}
}

//fallback to default handling
return QgsSqlExpressionCompiler::compileNode( node, result );
}

QString QgsOracleExpressionCompiler::quotedIdentifier( const QString& identifier )
{
return QgsOracleConn::quotedIdentifier( identifier );
}

QString QgsOracleExpressionCompiler::quotedValue( const QVariant& value )
{
return QgsOracleConn::quotedValue( value );
}
35 changes: 35 additions & 0 deletions src/providers/oracle/qgsoracleexpressioncompiler.h
@@ -0,0 +1,35 @@
/***************************************************************************
qgsoracleexpressioncompiler.h
----------------------------------------------------
date : December 2015
copyright : (C) 2015 by Jürgen 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 QGSORACLEEXPRESSIONCOMPILER_H
#define QGSORACLEEXPRESSIONCOMPILER_H

#include "qgssqlexpressioncompiler.h"
#include "qgsexpression.h"
#include "qgsoraclefeatureiterator.h"

class QgsOracleExpressionCompiler : public QgsSqlExpressionCompiler
{
public:

explicit QgsOracleExpressionCompiler( QgsOracleFeatureSource* source );

protected:
virtual Result compileNode( const QgsExpression::Node* node, QString& result ) override;
virtual QString quotedIdentifier( const QString& identifier ) override;
virtual QString quotedValue( const QVariant& value ) override;
};

#endif // QGSORACLEEXPRESSIONCOMPILER_H
20 changes: 20 additions & 0 deletions src/providers/oracle/qgsoraclefeatureiterator.cpp
Expand Up @@ -16,16 +16,19 @@
#include "qgsoraclefeatureiterator.h"
#include "qgsoracleprovider.h"
#include "qgsoracleconnpool.h"
#include "qgsoracleexpressioncompiler.h"

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

#include <QObject>
#include <QSettings>

QgsOracleFeatureIterator::QgsOracleFeatureIterator( QgsOracleFeatureSource* source, bool ownSource, const QgsFeatureRequest &request )
: QgsAbstractFeatureIteratorFromSource<QgsOracleFeatureSource>( source, ownSource, request )
, mRewind( false )
, mExpressionCompiled( false )
{
mConnection = QgsOracleConnPool::instance()->acquireConnection( mSource->mUri.connectionInfo() );
if ( !mConnection )
Expand Down Expand Up @@ -90,6 +93,15 @@ QgsOracleFeatureIterator::QgsOracleFeatureIterator( QgsOracleFeatureSource* sour
break;

case QgsFeatureRequest::FilterExpression:
if ( QSettings().value( "/qgis/compileExpressions", true ).toBool() )
{
QgsOracleExpressionCompiler compiler( mSource );
if ( compiler.compile( request.filterExpression() ) == QgsSqlExpressionCompiler::Complete )
{
whereClause = QgsOracleUtils::andWhereClauses( whereClause, compiler.result() );
mExpressionCompiled = true;
}
}
break;

case QgsFeatureRequest::FilterRect:
Expand Down Expand Up @@ -128,6 +140,14 @@ QgsOracleFeatureIterator::~QgsOracleFeatureIterator()
close();
}

bool QgsOracleFeatureIterator::nextFeatureFilterExpression( QgsFeature& f )
{
if ( !mExpressionCompiled )
return QgsAbstractFeatureIterator::nextFeatureFilterExpression( f );
else
return fetchFeature( f );
}

bool QgsOracleFeatureIterator::fetchFeature( QgsFeature& feature )
{
feature.setValid( false );
Expand Down
11 changes: 8 additions & 3 deletions src/providers/oracle/qgsoraclefeatureiterator.h
Expand Up @@ -52,6 +52,7 @@ class QgsOracleFeatureSource : public QgsAbstractFeatureSource
QSharedPointer<QgsOracleSharedData> mShared;

friend class QgsOracleFeatureIterator;
friend class QgsOracleExpressionCompiler;
};


Expand All @@ -63,20 +64,24 @@ class QgsOracleFeatureIterator : public QgsAbstractFeatureIteratorFromSource<Qgs
~QgsOracleFeatureIterator();

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

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

protected:
//! fetch next feature, return true on success
virtual bool fetchFeature( QgsFeature& feature );
virtual bool fetchFeature( QgsFeature& feature ) override;

//! fetch next feature filter expression
bool nextFeatureFilterExpression( QgsFeature& f ) override;

bool openQuery( QString whereClause );

QgsOracleConn *mConnection;
QSqlQuery mQry;
bool mRewind;
bool mExpressionCompiled;
QgsAttributeList mAttributeList;
};

Expand Down
4 changes: 2 additions & 2 deletions src/providers/postgres/qgspostgresexpressioncompiler.cpp
@@ -1,6 +1,6 @@
/***************************************************************************
----------------------------------------------------
qgspostgresexpressioncompiler.cpp
----------------------------------------------------
date : 22.4.2015
copyright : (C) 2015 by Matthias Kuhn
email : matthias (at) opengis.ch
Expand Down
4 changes: 2 additions & 2 deletions src/providers/postgres/qgspostgresexpressioncompiler.h
@@ -1,6 +1,6 @@
/***************************************************************************
----------------------------------------------------
qgspostgresexpressioncompiler.h
----------------------------------------------------
date : 22.4.2015
copyright : (C) 2015 by Matthias Kuhn
email : matthias (at) opengis.ch
Expand Down

1 comment on commit 65ee183

@nyalldawson
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jef-n great to see this! Can i suggest you also implement the provider test for Oracle, as it was designed to accompany expression compilation and identify if any special handling needs to be done wrt case sensitivity/etc.

It's really simple, see: https://github.com/qgis/QGIS/blob/master/tests/testdata/provider/testdata.sql
and https://github.com/qgis/QGIS/blob/master/tests/src/python/test_provider_postgres.py up to line 56

Please sign in to comment.