Skip to content

Commit be8f135

Browse files
committed
Fix for issues with sql server geography type (fixes #5229 fixes #5302)
1 parent 2a126af commit be8f135

File tree

3 files changed

+100
-13
lines changed

3 files changed

+100
-13
lines changed

src/providers/mssql/qgsmssqlgeometryparser.cpp

+21-4
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,22 @@ void QgsMssqlGeometryParser::CopyBytes( void* src, int len )
121121
nWkbLen += len;
122122
}
123123

124+
/************************************************************************/
125+
/* CopyCoordinates() */
126+
/************************************************************************/
127+
128+
void QgsMssqlGeometryParser::CopyCoordinates( unsigned char* src )
129+
{
130+
if (IsGeography)
131+
{
132+
CopyBytes( src + 8, 8 ); // longitude
133+
CopyBytes( src, 8 ); // latitude
134+
}
135+
else
136+
// copy geometry coords
137+
CopyBytes( src, nPointSize );
138+
}
139+
124140
/************************************************************************/
125141
/* CopyPoint() */
126142
/************************************************************************/
@@ -137,7 +153,7 @@ void QgsMssqlGeometryParser::CopyPoint( int iPoint )
137153
wkbType = QGis::WKBPoint;
138154
CopyBytes( &wkbType, 4 );
139155
// copy coordinates
140-
CopyBytes( pszData + nPointPos + nPointSize * iPoint, nPointSize );
156+
CopyCoordinates( pszData + nPointPos + nPointSize * iPoint );
141157
}
142158

143159
/************************************************************************/
@@ -216,7 +232,7 @@ void QgsMssqlGeometryParser::ReadLineString( int iShape )
216232
i = 0;
217233
while ( iPoint < iNextPoint )
218234
{
219-
CopyBytes( pszData + nPointPos + nPointSize * iPoint, nPointSize );
235+
CopyCoordinates( pszData + nPointPos + nPointSize * iPoint );
220236
++iPoint;
221237
++i;
222238
}
@@ -290,7 +306,7 @@ void QgsMssqlGeometryParser::ReadPolygon( int iShape )
290306
i = 0;
291307
while ( iPoint < iNextPoint )
292308
{
293-
CopyBytes( pszData + nPointPos + nPointSize * iPoint, nPointSize );
309+
CopyCoordinates( pszData + nPointPos + nPointSize * iPoint );
294310
++iPoint;
295311
++i;
296312
}
@@ -460,7 +476,8 @@ unsigned char* QgsMssqlGeometryParser::ParseSqlGeometry( unsigned char* pszInput
460476
int iCount = 2;
461477
CopyBytes( &iCount, 4 );
462478
// copy points
463-
CopyBytes( pszData + nPointPos, nPointSize * 2 );
479+
CopyCoordinates( pszData + nPointPos );
480+
CopyCoordinates( pszData + nPointPos + nPointSize );
464481
}
465482
else
466483
{

src/providers/mssql/qgsmssqlprovider.cpp

+76-9
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ void QgsMssqlProvider::loadFields()
341341
{
342342
mGeometryColName = mQuery.value( 3 ).toString();
343343
mGeometryColType = sqlTypeName;
344+
parser.IsGeography = sqlTypeName == "geography";
344345
}
345346
else
346347
{
@@ -565,8 +566,20 @@ void QgsMssqlProvider::select( QgsAttributeList fetchAttributes,
565566
// set spatial filter
566567
if ( !rect.isEmpty() )
567568
{
569+
// polygons should be CCW for SqlGeography
570+
QString r;
571+
QTextStream foo( &r );
572+
573+
foo.setRealNumberPrecision( 8 );
574+
foo.setRealNumberNotation( QTextStream::FixedNotation );
575+
foo << rect.xMinimum() << " " << rect.yMinimum() << ", "
576+
<< rect.xMaximum() << " " << rect.yMinimum() << ", "
577+
<< rect.xMaximum() << " " << rect.yMaximum() << ", "
578+
<< rect.xMinimum() << " " << rect.yMaximum() << ", "
579+
<< rect.xMinimum() << " " << rect.yMinimum();
580+
568581
mStatement += QString( " where [%1].STIntersects([%2]::STGeomFromText('POLYGON((%3))',%4)) = 1" ).arg(
569-
mGeometryColName, mGeometryColType, rect.asPolygon(), QString::number( mSRId ) );
582+
mGeometryColName, mGeometryColType, r, QString::number( mSRId ) );
570583
}
571584
mFetchGeom = fetchGeometry;
572585
mAttributesToFetch = fetchAttributes;
@@ -593,13 +606,23 @@ void QgsMssqlProvider::UpdateStatistics( bool estimate )
593606
mNumberFeatures = 0;
594607
// get features to calculate the statistics
595608
QString statement;
609+
bool readAll = false;
596610
if ( estimate )
597611
{
598-
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 );
612+
if ( mGeometryColType == "geometry" )
613+
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 );
614+
else
615+
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 );
599616
}
600617
else
601618
{
602-
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 );
619+
if ( mGeometryColType == "geometry" )
620+
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 );
621+
else
622+
{
623+
statement = QString( "select [%1]" ).arg( mGeometryColName );
624+
readAll = true;
625+
}
603626
}
604627

605628
if ( mSchemaName.isEmpty() )
@@ -619,13 +642,49 @@ void QgsMssqlProvider::UpdateStatistics( bool estimate )
619642
if ( mQuery.isActive() )
620643
{
621644
QgsGeometry geom;
622-
if ( mQuery.next() )
645+
if ( !readAll )
623646
{
624-
mExtent.setXMinimum( mQuery.value( 0 ).toDouble() );
625-
mExtent.setYMinimum( mQuery.value( 1 ).toDouble() );
626-
mExtent.setXMaximum( mQuery.value( 2 ).toDouble() );
627-
mExtent.setYMaximum( mQuery.value( 3 ).toDouble() );
628-
mNumberFeatures = mQuery.value( 4 ).toInt();
647+
if ( mQuery.next() )
648+
{
649+
mExtent.setXMinimum( mQuery.value( 0 ).toDouble() );
650+
mExtent.setYMinimum( mQuery.value( 1 ).toDouble() );
651+
mExtent.setXMaximum( mQuery.value( 2 ).toDouble() );
652+
mExtent.setYMaximum( mQuery.value( 3 ).toDouble() );
653+
mNumberFeatures = mQuery.value( 4 ).toInt();
654+
}
655+
}
656+
else
657+
{
658+
// read all features
659+
while ( mQuery.next() )
660+
{
661+
QByteArray ar = mQuery.value( 0 ).toByteArray();
662+
unsigned char* wkb = parser.ParseSqlGeometry(( unsigned char* )ar.data(), ar.size() );
663+
if ( wkb )
664+
{
665+
geom.fromWkb( wkb, parser.GetWkbLen() );
666+
QgsRectangle rect = geom.boundingBox();
667+
668+
if ( mNumberFeatures > 0 )
669+
{
670+
if ( rect.xMinimum() < mExtent.xMinimum() )
671+
mExtent.setXMinimum( rect.xMinimum() );
672+
if ( rect.yMinimum() < mExtent.yMinimum() )
673+
mExtent.setYMinimum( rect.yMinimum() );
674+
if ( rect.xMaximum() > mExtent.xMaximum() )
675+
mExtent.setXMaximum( rect.xMaximum() );
676+
if ( rect.yMaximum() > mExtent.yMaximum() )
677+
mExtent.setYMaximum( rect.yMaximum() );
678+
}
679+
else
680+
{
681+
mExtent = rect;
682+
mWkbType = geom.wkbType();
683+
mSRId = parser.GetSRSId();
684+
}
685+
++mNumberFeatures;
686+
}
687+
}
629688
}
630689
}
631690
}
@@ -761,7 +820,12 @@ bool QgsMssqlProvider::addFeatures( QgsFeatureList & flist )
761820
QString msg = mQuery.lastError().text();
762821
QgsDebugMsg( msg );
763822
if ( !mSkipFailures )
823+
{
824+
QString msg = mQuery.lastError().text();
825+
QgsDebugMsg( msg );
826+
pushError( msg );
764827
return false;
828+
}
765829
else
766830
continue;
767831
}
@@ -826,7 +890,10 @@ bool QgsMssqlProvider::addFeatures( QgsFeatureList & flist )
826890
QString msg = mQuery.lastError().text();
827891
QgsDebugMsg( msg );
828892
if ( !mSkipFailures )
893+
{
894+
pushError( msg );
829895
return false;
896+
}
830897
}
831898
}
832899

src/providers/mssql/qgsmssqlprovider.h

+3
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class QgsMssqlGeometryParser
6767

6868
protected:
6969
void CopyBytes( void* src, int len );
70+
void CopyCoordinates( unsigned char* src );
7071
void CopyPoint( int iPoint );
7172
void ReadPoint( int iShape );
7273
void ReadMultiPoint( int iShape );
@@ -82,6 +83,8 @@ class QgsMssqlGeometryParser
8283
int GetSRSId() { return nSRSId; };
8384
int GetWkbLen() { return nWkbLen; };
8485
void DumpMemoryToLog( const char* pszMsg, unsigned char* pszInput, int nLen );
86+
/* sql geo type */
87+
bool IsGeography;
8588
};
8689

8790

0 commit comments

Comments
 (0)