Skip to content

Commit

Permalink
[Oracle] Fix arc creation
Browse files Browse the repository at this point in the history
  • Loading branch information
troopa81 authored and nyalldawson committed Aug 18, 2021
1 parent e88dfd0 commit 76287af
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 27 deletions.
24 changes: 9 additions & 15 deletions src/providers/oracle/ocispatial/qsql_ocispatial.cpp
Expand Up @@ -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 );
Expand All @@ -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;
Expand Down Expand Up @@ -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 ];

Expand All @@ -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
Expand All @@ -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 )
{
Expand Down
2 changes: 2 additions & 0 deletions src/providers/oracle/qgsoracleconn.cpp
Expand Up @@ -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:
Expand Down
4 changes: 3 additions & 1 deletion src/providers/oracle/qgsoracleprovider.cpp
Expand Up @@ -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 )
Expand Down Expand Up @@ -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
Expand Down
93 changes: 82 additions & 11 deletions tests/src/python/test_provider_oracle.py
Expand Up @@ -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")
Expand Down Expand Up @@ -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)
Expand All @@ -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=',
Expand All @@ -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
Expand All @@ -390,14 +453,18 @@ 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=',
'test_multicurves_z', 'oracle')
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)
Expand All @@ -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=' %
Expand Down

0 comments on commit 76287af

Please sign in to comment.