Skip to content

Commit

Permalink
[mssql] Compile make_datetime, make_date, make_time
Browse files Browse the repository at this point in the history
Allows efficient use of SQL server tables along with temporal mode
  • Loading branch information
nyalldawson committed May 22, 2020
1 parent 0618b2e commit b17da05
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 43 deletions.
2 changes: 1 addition & 1 deletion src/core/qgsvectorlayerexporter.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ QgsVectorLayerExporter::QgsVectorLayerExporter( const QString &uri,


mAttributeCount++; mAttributeCount++;


QgsDebugMsg( QStringLiteral( "Created empty layer" ) ); QgsDebugMsgLevel( QStringLiteral( "Created empty layer" ), 2 );


QString uriUpdated( uri ); QString uriUpdated( uri );
// HACK sorry... // HACK sorry...
Expand Down
121 changes: 88 additions & 33 deletions src/providers/mssql/qgsmssqlexpressioncompiler.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -25,45 +25,70 @@ QgsMssqlExpressionCompiler::QgsMssqlExpressionCompiler( QgsMssqlFeatureSource *s


QgsSqlExpressionCompiler::Result QgsMssqlExpressionCompiler::compileNode( const QgsExpressionNode *node, QString &result ) QgsSqlExpressionCompiler::Result QgsMssqlExpressionCompiler::compileNode( const QgsExpressionNode *node, QString &result )
{ {
if ( node->nodeType() == QgsExpressionNode::ntBinaryOperator ) switch ( node->nodeType() )
{ {
const QgsExpressionNodeBinaryOperator *bin( static_cast<const QgsExpressionNodeBinaryOperator *>( node ) ); case QgsExpressionNode::ntBinaryOperator:
switch ( bin->op() )
{ {
// special handling const QgsExpressionNodeBinaryOperator *bin( static_cast<const QgsExpressionNodeBinaryOperator *>( node ) );
case QgsExpressionNodeBinaryOperator::boPow: switch ( bin->op() )
case QgsExpressionNodeBinaryOperator::boRegexp: {
case QgsExpressionNodeBinaryOperator::boConcat: // special handling
break; case QgsExpressionNodeBinaryOperator::boPow:

case QgsExpressionNodeBinaryOperator::boRegexp:
default: case QgsExpressionNodeBinaryOperator::boConcat:
// fallback to default handling break;
return QgsSqlExpressionCompiler::compileNode( node, result );;
default:
// fallback to default handling
return QgsSqlExpressionCompiler::compileNode( node, result );;
}

QString op1, op2;

Result result1 = compileNode( bin->opLeft(), op1 );
Result result2 = compileNode( bin->opRight(), op2 );
if ( result1 == Fail || result2 == Fail )
return Fail;

switch ( bin->op() )
{
case QgsExpressionNodeBinaryOperator::boPow:
result = QStringLiteral( "power(%1,%2)" ).arg( op1, op2 );
return result1 == Partial || result2 == Partial ? Partial : Complete;

case QgsExpressionNodeBinaryOperator::boRegexp:
return Fail; //not supported, regexp syntax is too different to Qt

case QgsExpressionNodeBinaryOperator::boConcat:
result = QStringLiteral( "%1 + %2" ).arg( op1, op2 );
return result1 == Partial || result2 == Partial ? Partial : Complete;

default:
break;
}

break;
} }


QString op1, op2; case QgsExpressionNode::ntFunction:

Result result1 = compileNode( bin->opLeft(), op1 );
Result result2 = compileNode( bin->opRight(), op2 );
if ( result1 == Fail || result2 == Fail )
return Fail;

switch ( bin->op() )
{ {
case QgsExpressionNodeBinaryOperator::boPow: const QgsExpressionNodeFunction *n = static_cast<const QgsExpressionNodeFunction *>( node );
result = QStringLiteral( "power(%1,%2)" ).arg( op1, op2 ); QgsExpressionFunction *fd = QgsExpression::Functions()[n->fnIndex()];
return result1 == Partial || result2 == Partial ? Partial : Complete;

if ( fd->name() == QLatin1String( "make_datetime" ) || fd->name() == QLatin1String( "make_date" ) || fd->name() == QLatin1String( "make_time" ) )
case QgsExpressionNodeBinaryOperator::boRegexp: {
return Fail; //not supported, regexp syntax is too different to Qt const auto constList = n->args()->list();

for ( const QgsExpressionNode *ln : constList )
case QgsExpressionNodeBinaryOperator::boConcat: {
result = QStringLiteral( "%1 + %2" ).arg( op1, op2 ); if ( ln->nodeType() != QgsExpressionNode::ntLiteral )
return result1 == Partial || result2 == Partial ? Partial : Complete; return Fail;

}
default: }
break; return QgsSqlExpressionCompiler::compileNode( node, result );
} }

default:
break;
} }


//fallback to default handling //fallback to default handling
Expand Down Expand Up @@ -138,9 +163,39 @@ static const QMap<QString, QString> FUNCTION_NAMES_SQL_FUNCTIONS_MAP
{ "trim", "trim" }, { "trim", "trim" },
{ "lower", "lower" }, { "lower", "lower" },
{ "upper", "upper" }, { "upper", "upper" },
{ "make_datetime", "" },
{ "make_date", "" },
{ "make_time", "" },
}; };


QString QgsMssqlExpressionCompiler::sqlFunctionFromFunctionName( const QString &fnName ) const QString QgsMssqlExpressionCompiler::sqlFunctionFromFunctionName( const QString &fnName ) const
{ {
return FUNCTION_NAMES_SQL_FUNCTIONS_MAP.value( fnName, QString() ); return FUNCTION_NAMES_SQL_FUNCTIONS_MAP.value( fnName, QString() );
} }

QStringList QgsMssqlExpressionCompiler::sqlArgumentsFromFunctionName( const QString &fnName, const QStringList &fnArgs ) const
{
QStringList args( fnArgs );
if ( fnName == QLatin1String( "make_datetime" ) )
{
args = QStringList( QStringLiteral( "'%1-%2-%3T%4:%5:%6Z'" ).arg( args[0].rightJustified( 4, '0' ) )
.arg( args[1].rightJustified( 2, '0' ) )
.arg( args[2].rightJustified( 2, '0' ) )
.arg( args[3].rightJustified( 2, '0' ) )
.arg( args[4].rightJustified( 2, '0' ) )
.arg( args[5].rightJustified( 2, '0' ) ) );
}
else if ( fnName == QLatin1String( "make_date" ) )
{
args = QStringList( QStringLiteral( "'%1-%2-%3'" ).arg( args[0].rightJustified( 4, '0' ) )
.arg( args[1].rightJustified( 2, '0' ) )
.arg( args[2].rightJustified( 2, '0' ) ) );
}
else if ( fnName == QLatin1String( "make_time" ) )
{
args = QStringList( QStringLiteral( "'%1:%2:%3'" ).arg( args[0].rightJustified( 2, '0' ) )
.arg( args[1].rightJustified( 2, '0' ) )
.arg( args[2].rightJustified( 2, '0' ) ) );
}
return args;
}
2 changes: 1 addition & 1 deletion src/providers/mssql/qgsmssqlexpressioncompiler.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class QgsMssqlExpressionCompiler : public QgsSqlExpressionCompiler
QString castToReal( const QString &value ) const override; QString castToReal( const QString &value ) const override;
QString castToInt( const QString &value ) const override; QString castToInt( const QString &value ) const override;
QString sqlFunctionFromFunctionName( const QString &fnName ) const override; QString sqlFunctionFromFunctionName( const QString &fnName ) const override;

QStringList sqlArgumentsFromFunctionName( const QString &fnName, const QStringList &fnArgs ) const override;
}; };


#endif // QGSMSSQLEXPRESSIONCOMPILER_H #endif // QGSMSSQLEXPRESSIONCOMPILER_H
8 changes: 5 additions & 3 deletions src/providers/mssql/qgsmssqlprovider.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -741,8 +741,10 @@ void QgsMssqlProvider::UpdateStatistics( bool estimate ) const
return; return;
} }
} }

else
QgsDebugMsg( query.lastError().text() ); {
QgsDebugMsg( query.lastError().text() );
}


// If we can't find the extents in the spatial index table just do what we normally do. // If we can't find the extents in the spatial index table just do what we normally do.
bool readAllGeography = false; bool readAllGeography = false;
Expand Down Expand Up @@ -2317,7 +2319,7 @@ QString QgsMssqlProviderMetadata::loadStyle( const QString &uri, QString &errCau


if ( !query.exec( selectQmlQuery ) ) if ( !query.exec( selectQmlQuery ) )
{ {
QgsDebugMsg( QStringLiteral( "Load of style failed" ) ); QgsDebugMsgLevel( QStringLiteral( "Load of style failed" ), 2 );
QString msg = query.lastError().text(); QString msg = query.lastError().text();
errCause = msg; errCause = msg;
QgsDebugMsg( msg ); QgsDebugMsg( msg );
Expand Down
5 changes: 0 additions & 5 deletions tests/src/python/test_provider_mssql.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -215,13 +215,8 @@ def uncompiledFilters(self):
'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
'"dt" <= make_datetime(2020, 5, 4, 12, 13, 14)',
'"dt" < make_date(2020, 5, 4)',
'"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')', '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')',
'"date" <= make_datetime(2020, 5, 4, 12, 13, 14)',
'"date" >= make_date(2020, 5, 4)',
'"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')', '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')',
'"time" >= make_time(12, 14, 14)',
'"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')' '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')'
]) ])
return filters return filters
Expand Down

0 comments on commit b17da05

Please sign in to comment.