From 76287af2c44c9e73cfa4e7db3d959f1837daec2a Mon Sep 17 00:00:00 2001 From: Julien Cabieces Date: Wed, 18 Aug 2021 17:37:23 +0200 Subject: [PATCH] [Oracle] Fix arc creation --- .../oracle/ocispatial/qsql_ocispatial.cpp | 24 ++--- src/providers/oracle/qgsoracleconn.cpp | 2 + src/providers/oracle/qgsoracleprovider.cpp | 4 +- tests/src/python/test_provider_oracle.py | 93 ++++++++++++++++--- 4 files changed, 96 insertions(+), 27 deletions(-) diff --git a/src/providers/oracle/ocispatial/qsql_ocispatial.cpp b/src/providers/oracle/ocispatial/qsql_ocispatial.cpp index 4e3bb668e1d3..a45205edede9 100644 --- a/src/providers/oracle/ocispatial/qsql_ocispatial.cpp +++ b/src/providers/oracle/ocispatial/qsql_ocispatial.cpp @@ -2628,7 +2628,7 @@ bool QOCISpatialCols::convertToWkb( QVariant &v, int index ) int wkbSize = 0; - if ( nPoints > nDims ) + if ( iType == GtMultiPoint ) wkbSize += 1 + 2 * sizeof( int ); wkbSize += ( nPoints / nDims ) * ( 1 + sizeof( int ) ) + nPoints * sizeof( double ); @@ -2637,7 +2637,7 @@ bool QOCISpatialCols::convertToWkb( QVariant &v, int index ) ba.resize( wkbSize ); ptr.cPtr = ba.data(); - if ( nPoints > nDims ) + if ( iType == GtMultiPoint ) { *ptr.ucPtr++ = byteorder(); *ptr.iPtr++ = nDims == 2 ? WKBMultiPoint : WKBMultiPoint25D; @@ -2709,11 +2709,11 @@ bool QOCISpatialCols::convertToWkb( QVariant &v, int index ) } int binarySize = 1 + sizeof( int ) ; - if ( lines.size() > 1 ) + if ( iType == GtMultiLine ) binarySize += sizeof( int ); for ( int partIndex = 0; partIndex < lines.size(); ++partIndex ) { - if ( lines.size() > 1 ) + if ( iType == GtMultiLine ) binarySize += 1 + sizeof( int ); auto &line = lines[ partIndex ]; @@ -2739,14 +2739,11 @@ bool QOCISpatialCols::convertToWkb( QVariant &v, int index ) ba.resize( binarySize ); ptr.cPtr = ba.data(); - *ptr.ucPtr++ = byteorder(); - if ( lines.size() == 1 ) - { - *ptr.iPtr++ = lines[0].first; - } - else + Q_ASSERT( iType == GtMultiLine || lines.size() == 1 ); + if ( iType == GtMultiLine ) { + *ptr.ucPtr++ = byteorder(); if ( isCurved ) *ptr.iPtr++ = nDims == 2 ? WKBMultiCurve : WKBMultiCurveZ; else @@ -2756,11 +2753,8 @@ bool QOCISpatialCols::convertToWkb( QVariant &v, int index ) for ( const auto &line : qAsConst( lines ) ) { - if ( lines.size() > 1 ) - { - *ptr.ucPtr++ = byteorder(); - *ptr.iPtr++ = line.first; - } + *ptr.ucPtr++ = byteorder(); + *ptr.iPtr++ = line.first; if ( line.first == WKBCompoundCurve || line.first == WKBCompoundCurveZ ) { diff --git a/src/providers/oracle/qgsoracleconn.cpp b/src/providers/oracle/qgsoracleconn.cpp index af9f92babbbe..fcbaa1702e5f 100644 --- a/src/providers/oracle/qgsoracleconn.cpp +++ b/src/providers/oracle/qgsoracleconn.cpp @@ -639,8 +639,10 @@ QString QgsOracleConn::databaseTypeFilter( const QString &alias, QString geomCol { case QgsWkbTypes::Point: case QgsWkbTypes::Point25D: + case QgsWkbTypes::PointZ: case QgsWkbTypes::MultiPoint: case QgsWkbTypes::MultiPoint25D: + case QgsWkbTypes::MultiPointZ: return QStringLiteral( "mod(%1.sdo_gtype,100) IN (1,5)" ).arg( geomCol ); case QgsWkbTypes::LineString: case QgsWkbTypes::LineString25D: diff --git a/src/providers/oracle/qgsoracleprovider.cpp b/src/providers/oracle/qgsoracleprovider.cpp index 7129aa3b2edb..9526a5d13a02 100644 --- a/src/providers/oracle/qgsoracleprovider.cpp +++ b/src/providers/oracle/qgsoracleprovider.cpp @@ -745,6 +745,9 @@ bool QgsOracleProvider::hasSufficientPermsAndCapabilities() mEnabledCapabilities = QgsVectorDataProvider::SelectAtId | QgsVectorDataProvider::TransactionSupport; + // supports circular geometries + mEnabledCapabilities |= QgsVectorDataProvider::CircularGeometries; + QgsOracleConn *conn = connectionRO(); QSqlQuery qry( *conn ); if ( !mIsQuery ) @@ -2061,7 +2064,6 @@ void QgsOracleProvider::appendGeomParam( const QgsGeometry &geom, QSqlQuery &qry QgsWkbTypes::Type lineType = curveType; if ( curveType == QgsWkbTypes::CompoundCurve || curveType == QgsWkbTypes::CompoundCurveZ ) { - g.gtype = SDO_GTYPE( dim, GtMultiLine ); nLines = *ptr.iPtr++; // Oracle don't store compound curve with only one line diff --git a/tests/src/python/test_provider_oracle.py b/tests/src/python/test_provider_oracle.py index b6c9c58ec7b5..cc7c4bc4be3f 100644 --- a/tests/src/python/test_provider_oracle.py +++ b/tests/src/python/test_provider_oracle.py @@ -266,6 +266,47 @@ def testPoints(self): self.assertEqual(features[6].geometry().asWkt(), 'Point (3 4)') self.assertEqual(features[7].geometry().asWkt(), 'Point (5 6)') + def testEditPoints(self): + + self.createTable('EDIT_POINTS_DATA', 2, 3857) + # We choose SRID=5698 to get Oracle valid geometries because it support 3D + self.createTable('EDIT_POINTSZ_DATA', 3, 5698) + + points = QgsVectorLayer( + self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=Point table="QGIS"."EDIT_POINTS_DATA" (GEOM) sql=', + 'test_lines', 'oracle') + self.assertTrue(points.isValid()) + + fid = 1 + self.check_geom(points, fid, 'Point (1 2)') + + points_z = QgsVectorLayer( + self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=PointZ table="QGIS"."EDIT_POINTSZ_DATA" (GEOM) sql=', + 'test_lines', 'oracle') + self.assertTrue(points_z.isValid()) + + fid += 1 + self.check_geom(points_z, fid, 'PointZ (1 2 3)') + + multipoints = QgsVectorLayer( + self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPoint table="QGIS"."EDIT_POINTS_DATA" (GEOM) sql=', + 'test_lines', 'oracle') + self.assertTrue(multipoints.isValid()) + + fid += 1 + self.check_geom(multipoints, fid, 'MultiPoint ((1 2),(3 4))') + + fid += 1 + self.check_geom(multipoints, fid, 'MultiPoint ((1 2))') + + multipoints_z = QgsVectorLayer( + self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPointZ table="QGIS"."EDIT_POINTSZ_DATA" (GEOM) sql=', + 'test_lines', 'oracle') + self.assertTrue(multipoints_z.isValid()) + + fid += 1 + self.check_geom(multipoints_z, fid, 'MultiPointZ ((1 2 7),(3 4 8))') + def testCurves(self): vl = QgsVectorLayer('%s table="QGIS"."LINE_DATA" (GEOM) srid=4326 type=LINESTRING sql=' % (self.dbconn), "testlines", "oracle") @@ -337,9 +378,14 @@ def testEditCurves(self): 'test_lines', 'oracle') self.assertTrue(lines.isValid()) - self.check_geom(lines, 1, 'LineString (1 2, 3 4, 5 6)') - self.check_geom(lines, 2, 'CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)') - self.check_geom(lines, 3, 'CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))') + fid = 1 + self.check_geom(lines, fid, 'LineString (1 2, 3 4, 5 6)') + + fid += 1 + self.check_geom(lines, fid, 'CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)') + + fid += 1 + self.check_geom(lines, fid, 'CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))') # We choose SRID=5698 (see https://docs.oracle.com/database/121/SPATL/three-dimensional-coordinate-reference-system-support.htm#SPATL626) # to get Oracle valid geometries because it support 3D and arcs (arcs are not supported in geodetic projection) @@ -348,28 +394,45 @@ def testEditCurves(self): 'test_lines', 'oracle') self.assertTrue(lines_z.isValid()) - self.check_geom(lines_z, 4, 'LineStringZ (1 2 3, 4 5 6, 7 8 9)') + fid += 1 + self.check_geom(lines_z, fid, 'LineStringZ (1 2 3, 4 5 6, 7 8 9)') # 3D arcs and compound curve are invalid # https://support.oracle.com/knowledge/Oracle%20Database%20Products/1446335_1.html # https://support.oracle.com/knowledge/Oracle%20Database%20Products/1641672_1.html - self.check_geom(lines_z, 5, 'CircularStringZ (1 2 1, 5 4 2, 7 2.2 3, 10 0.1 4, 13 4 5)', check_valid=False) - self.check_geom(lines_z, 6, 'CompoundCurveZ ((-1 -5 1, 1 2 2),CircularStringZ (1 2 2, 5 4 3, 7 2.20 4, 10 0.1 5, 13 4 6),(13 4 6, 17 -6 7))', check_valid=False) + + fid += 1 + self.check_geom(lines_z, fid, 'CircularStringZ (1 2 1, 5 4 2, 7 2.2 3, 10 0.1 4, 13 4 5)', check_valid=False) + + fid += 1 + self.check_geom(lines_z, fid, 'CompoundCurveZ ((-1 -5 1, 1 2 2),CircularStringZ (1 2 2, 5 4 3, 7 2.20 4, 10 0.1 5, 13 4 6),(13 4 6, 17 -6 7))', check_valid=False) multi_lines = QgsVectorLayer( self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiLineString table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=', 'test_multilines', 'oracle') self.assertTrue(multi_lines.isValid()) - self.check_geom(multi_lines, 7, 'MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10), (11 12, 13 14))') - self.check_geom(multi_lines, 8, 'MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10))') + fid += 1 + self.check_geom(multi_lines, fid, 'MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10), (11 12, 13 14))') + + fid += 1 + self.check_geom(multi_lines, fid, 'MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10))') + + fid += 1 + self.check_geom(multi_lines, fid, 'MultiLineString ((1 2, 3 4))') multi_lines_z = QgsVectorLayer( self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=MultiLineStringZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=', 'test_multilines', 'oracle') self.assertTrue(multi_lines_z.isValid()) - self.check_geom(multi_lines_z, 9, 'MultiLineStringZ ((1 2 11, 3 4 -11),(5 6 9, 7 8 1, 9 10 -3))') - self.check_geom(multi_lines_z, 10, 'MultiLineStringZ ((1 2 1, 3 4 2),(5 6 3, 7 8 4, 9 10 5), (11 12 6, 13 14 7))') + fid += 1 + self.check_geom(multi_lines_z, fid, 'MultiLineStringZ ((1 2 11, 3 4 -11),(5 6 9, 7 8 1, 9 10 -3))') + + fid += 1 + self.check_geom(multi_lines_z, fid, 'MultiLineStringZ ((1 2 1, 3 4 2),(5 6 3, 7 8 4, 9 10 5), (11 12 6, 13 14 7))') + + fid += 1 + self.check_geom(multi_lines_z, fid, 'MultiLineStringZ ((1 2 1, 3 4 2))') multi_curves = QgsVectorLayer( self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiCurve table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=', @@ -380,7 +443,7 @@ def testEditCurves(self): # if SDO_ETYPE = 4, n must be greater than 1 : https://docs.oracle.com/database/121/SPATL/sdo_geometry-object-type.htm#GUID-270AE39D-7B83-46D0-9DD6-E5D99C045021__BGHDGCCE # So, this two different WKTs inputs generate the same data in Oracle database, and so the same WKT # output representation (with CompoundCurve() around each MultiCurve parts) - fid = 11 + fid += 1 self.check_geom(multi_curves, fid, 'MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))') fid += 1 @@ -390,7 +453,10 @@ def testEditCurves(self): fid += 1 self.check_geom(multi_curves, fid, 'MultiCurve (CompoundCurve ((-1 -5, 1 2),(1 2, 17 -6)),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4))') + fid += 1 + self.check_geom(multi_curves, fid, + 'MultiCurve (CompoundCurve ((-1 -5, 1 2),(1 2, 17 -6)))') multi_curves_z = QgsVectorLayer( self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=MultiCurveZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=', @@ -398,6 +464,7 @@ def testEditCurves(self): self.assertTrue(multi_curves_z.isValid()) # ora-54530 : 3D compound lines are invalid since 11.2.0.3 : https://support.oracle.com/knowledge/Oracle%20Database%20Products/1446335_1.html + fid += 1 self.check_geom(multi_curves_z, fid, 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)), CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6),LineStringZ (-11 -3 1, 5 7 2, 10 -1 3))', check_valid=False) @@ -406,7 +473,11 @@ def testEditCurves(self): 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)),CompoundCurveZ (CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6)),(-11 -3 1, 5 7 2, 10 -1 3))', 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)), CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6),LineStringZ (-11 -3 1, 5 7 2, 10 -1 3))', check_valid=False) + fid += 1 + self.check_geom(multi_curves_z, fid, + 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),(1 2 4, 17 -6 8)))', + check_valid=False) def testSurfaces(self): vl = QgsVectorLayer('%s table="QGIS"."POLY_DATA" (GEOM) srid=4326 type=POLYGON sql=' %