From be8f135abb8d1280738b7c672bbd8d804243f02c Mon Sep 17 00:00:00 2001 From: szekerest Date: Thu, 12 Apr 2012 13:44:15 +0200 Subject: [PATCH] Fix for issues with sql server geography type (fixes #5229 fixes #5302) --- .../mssql/qgsmssqlgeometryparser.cpp | 25 +++++- src/providers/mssql/qgsmssqlprovider.cpp | 85 +++++++++++++++++-- src/providers/mssql/qgsmssqlprovider.h | 3 + 3 files changed, 100 insertions(+), 13 deletions(-) diff --git a/src/providers/mssql/qgsmssqlgeometryparser.cpp b/src/providers/mssql/qgsmssqlgeometryparser.cpp index 5c766ef86803..06fe198b1a5b 100644 --- a/src/providers/mssql/qgsmssqlgeometryparser.cpp +++ b/src/providers/mssql/qgsmssqlgeometryparser.cpp @@ -121,6 +121,22 @@ void QgsMssqlGeometryParser::CopyBytes( void* src, int len ) nWkbLen += len; } +/************************************************************************/ +/* CopyCoordinates() */ +/************************************************************************/ + +void QgsMssqlGeometryParser::CopyCoordinates( unsigned char* src ) +{ + if (IsGeography) + { + CopyBytes( src + 8, 8 ); // longitude + CopyBytes( src, 8 ); // latitude + } + else + // copy geometry coords + CopyBytes( src, nPointSize ); +} + /************************************************************************/ /* CopyPoint() */ /************************************************************************/ @@ -137,7 +153,7 @@ void QgsMssqlGeometryParser::CopyPoint( int iPoint ) wkbType = QGis::WKBPoint; CopyBytes( &wkbType, 4 ); // copy coordinates - CopyBytes( pszData + nPointPos + nPointSize * iPoint, nPointSize ); + CopyCoordinates( pszData + nPointPos + nPointSize * iPoint ); } /************************************************************************/ @@ -216,7 +232,7 @@ void QgsMssqlGeometryParser::ReadLineString( int iShape ) i = 0; while ( iPoint < iNextPoint ) { - CopyBytes( pszData + nPointPos + nPointSize * iPoint, nPointSize ); + CopyCoordinates( pszData + nPointPos + nPointSize * iPoint ); ++iPoint; ++i; } @@ -290,7 +306,7 @@ void QgsMssqlGeometryParser::ReadPolygon( int iShape ) i = 0; while ( iPoint < iNextPoint ) { - CopyBytes( pszData + nPointPos + nPointSize * iPoint, nPointSize ); + CopyCoordinates( pszData + nPointPos + nPointSize * iPoint ); ++iPoint; ++i; } @@ -460,7 +476,8 @@ unsigned char* QgsMssqlGeometryParser::ParseSqlGeometry( unsigned char* pszInput int iCount = 2; CopyBytes( &iCount, 4 ); // copy points - CopyBytes( pszData + nPointPos, nPointSize * 2 ); + CopyCoordinates( pszData + nPointPos ); + CopyCoordinates( pszData + nPointPos + nPointSize ); } else { diff --git a/src/providers/mssql/qgsmssqlprovider.cpp b/src/providers/mssql/qgsmssqlprovider.cpp index 7cb12a0049f1..dce244a95529 100644 --- a/src/providers/mssql/qgsmssqlprovider.cpp +++ b/src/providers/mssql/qgsmssqlprovider.cpp @@ -341,6 +341,7 @@ void QgsMssqlProvider::loadFields() { mGeometryColName = mQuery.value( 3 ).toString(); mGeometryColType = sqlTypeName; + parser.IsGeography = sqlTypeName == "geography"; } else { @@ -565,8 +566,20 @@ void QgsMssqlProvider::select( QgsAttributeList fetchAttributes, // set spatial filter if ( !rect.isEmpty() ) { + // polygons should be CCW for SqlGeography + QString r; + QTextStream foo( &r ); + + foo.setRealNumberPrecision( 8 ); + foo.setRealNumberNotation( QTextStream::FixedNotation ); + foo << rect.xMinimum() << " " << rect.yMinimum() << ", " + << rect.xMaximum() << " " << rect.yMinimum() << ", " + << rect.xMaximum() << " " << rect.yMaximum() << ", " + << rect.xMinimum() << " " << rect.yMaximum() << ", " + << rect.xMinimum() << " " << rect.yMinimum(); + mStatement += QString( " where [%1].STIntersects([%2]::STGeomFromText('POLYGON((%3))',%4)) = 1" ).arg( - mGeometryColName, mGeometryColType, rect.asPolygon(), QString::number( mSRId ) ); + mGeometryColName, mGeometryColType, r, QString::number( mSRId ) ); } mFetchGeom = fetchGeometry; mAttributesToFetch = fetchAttributes; @@ -593,13 +606,23 @@ void QgsMssqlProvider::UpdateStatistics( bool estimate ) mNumberFeatures = 0; // get features to calculate the statistics QString statement; + bool readAll = false; if ( estimate ) { - statement = QString( "select min([%1].STPointN(1).STX), min([%1].STPointN(1).STY), max([%1].STPointN(1).STX), max([%1].STPointN(1).STY), COUNT([%1])" ).arg( mGeometryColName ); + if ( mGeometryColType == "geometry" ) + statement = QString( "select min([%1].STPointN(1).STX), min([%1].STPointN(1).STY), max([%1].STPointN(1).STX), max([%1].STPointN(1).STY), COUNT([%1])" ).arg( mGeometryColName ); + else + statement = QString( "select min([%1].STPointN(1).Long), min([%1].STPointN(1).Lat), max([%1].STPointN(1).Long), max([%1].STPointN(1).Lat), COUNT([%1])" ).arg( mGeometryColName ); } else { - statement = QString( "select min([%1].STEnvelope().STPointN(1).STX), min([%1].STEnvelope().STPointN(1).STY), max([%1].STEnvelope().STPointN(2).STX), max([%1].STEnvelope().STPointN(2).STY), count([%1])" ).arg( mGeometryColName ); + if ( mGeometryColType == "geometry" ) + statement = QString( "select min([%1].STEnvelope().STPointN(1).STX), min([%1].STEnvelope().STPointN(1).STY), max([%1].STEnvelope().STPointN(3).STX), max([%1].STEnvelope().STPointN(3).STY), count([%1])" ).arg( mGeometryColName ); + else + { + statement = QString( "select [%1]" ).arg( mGeometryColName ); + readAll = true; + } } if ( mSchemaName.isEmpty() ) @@ -619,13 +642,49 @@ void QgsMssqlProvider::UpdateStatistics( bool estimate ) if ( mQuery.isActive() ) { QgsGeometry geom; - if ( mQuery.next() ) + if ( !readAll ) { - mExtent.setXMinimum( mQuery.value( 0 ).toDouble() ); - mExtent.setYMinimum( mQuery.value( 1 ).toDouble() ); - mExtent.setXMaximum( mQuery.value( 2 ).toDouble() ); - mExtent.setYMaximum( mQuery.value( 3 ).toDouble() ); - mNumberFeatures = mQuery.value( 4 ).toInt(); + if ( mQuery.next() ) + { + mExtent.setXMinimum( mQuery.value( 0 ).toDouble() ); + mExtent.setYMinimum( mQuery.value( 1 ).toDouble() ); + mExtent.setXMaximum( mQuery.value( 2 ).toDouble() ); + mExtent.setYMaximum( mQuery.value( 3 ).toDouble() ); + mNumberFeatures = mQuery.value( 4 ).toInt(); + } + } + else + { + // read all features + while ( mQuery.next() ) + { + QByteArray ar = mQuery.value( 0 ).toByteArray(); + unsigned char* wkb = parser.ParseSqlGeometry(( unsigned char* )ar.data(), ar.size() ); + if ( wkb ) + { + geom.fromWkb( wkb, parser.GetWkbLen() ); + QgsRectangle rect = geom.boundingBox(); + + if ( mNumberFeatures > 0 ) + { + if ( rect.xMinimum() < mExtent.xMinimum() ) + mExtent.setXMinimum( rect.xMinimum() ); + if ( rect.yMinimum() < mExtent.yMinimum() ) + mExtent.setYMinimum( rect.yMinimum() ); + if ( rect.xMaximum() > mExtent.xMaximum() ) + mExtent.setXMaximum( rect.xMaximum() ); + if ( rect.yMaximum() > mExtent.yMaximum() ) + mExtent.setYMaximum( rect.yMaximum() ); + } + else + { + mExtent = rect; + mWkbType = geom.wkbType(); + mSRId = parser.GetSRSId(); + } + ++mNumberFeatures; + } + } } } } @@ -761,7 +820,12 @@ bool QgsMssqlProvider::addFeatures( QgsFeatureList & flist ) QString msg = mQuery.lastError().text(); QgsDebugMsg( msg ); if ( !mSkipFailures ) + { + QString msg = mQuery.lastError().text(); + QgsDebugMsg( msg ); + pushError( msg ); return false; + } else continue; } @@ -826,7 +890,10 @@ bool QgsMssqlProvider::addFeatures( QgsFeatureList & flist ) QString msg = mQuery.lastError().text(); QgsDebugMsg( msg ); if ( !mSkipFailures ) + { + pushError( msg ); return false; + } } } diff --git a/src/providers/mssql/qgsmssqlprovider.h b/src/providers/mssql/qgsmssqlprovider.h index 87b19b290892..cac91bbfa46b 100644 --- a/src/providers/mssql/qgsmssqlprovider.h +++ b/src/providers/mssql/qgsmssqlprovider.h @@ -67,6 +67,7 @@ class QgsMssqlGeometryParser protected: void CopyBytes( void* src, int len ); + void CopyCoordinates( unsigned char* src ); void CopyPoint( int iPoint ); void ReadPoint( int iShape ); void ReadMultiPoint( int iShape ); @@ -82,6 +83,8 @@ class QgsMssqlGeometryParser int GetSRSId() { return nSRSId; }; int GetWkbLen() { return nWkbLen; }; void DumpMemoryToLog( const char* pszMsg, unsigned char* pszInput, int nLen ); + /* sql geo type */ + bool IsGeography; };