1 /******************************************************************************
2 *
3 * Project: Oracle Spatial Driver
4 * Purpose: Implementation of the OGROCILayer class. This is layer semantics
5 * shared between table accessors and ExecuteSQL() result
6 * pseudo-layers.
7 * Author: Frank Warmerdam, warmerdam@pobox.com
8 *
9 ******************************************************************************
10 * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include "ogr_oci.h"
32 #include "cpl_conv.h"
33
34 CPL_CVSID("$Id: ogrocilayer.cpp 22f8ae3bf7bc3cccd970992655c63fc5254d3206 2018-04-08 20:13:05 +0200 Even Rouault $")
35
36 /************************************************************************/
37 /* OGROCILayer() */
38 /************************************************************************/
39
OGROCILayer()40 OGROCILayer::OGROCILayer()
41
42 {
43 poFeatureDefn = nullptr;
44 poDS = nullptr;
45 poStatement = nullptr;
46
47 pszQueryStatement = nullptr;
48 nResultOffset = 0;
49 pszGeomName = nullptr;
50 iGeomColumn = -1;
51 pszFIDName = nullptr;
52 iFIDColumn = -1;
53
54 hLastGeom = nullptr;
55 hLastGeomInd = nullptr;
56
57 iNextShapeId = 0;
58 }
59
60 /************************************************************************/
61 /* ~OGROCILayer() */
62 /************************************************************************/
63
~OGROCILayer()64 OGROCILayer::~OGROCILayer()
65
66 {
67 if( m_nFeaturesRead > 0 && poFeatureDefn != nullptr )
68 {
69 CPLDebug( "OCI", "%d features read on layer '%s'.",
70 (int) m_nFeaturesRead,
71 poFeatureDefn->GetName() );
72 }
73
74 OGROCILayer::ResetReading();
75
76 CPLFree( pszGeomName );
77 pszGeomName = nullptr;
78
79 CPLFree( pszFIDName );
80 pszFIDName = nullptr;
81
82 CPLFree( pszQueryStatement );
83 pszQueryStatement = nullptr;
84
85 if( poFeatureDefn != nullptr )
86 poFeatureDefn->Release();
87 }
88
89 /************************************************************************/
90 /* ResetReading() */
91 /************************************************************************/
92
ResetReading()93 void OGROCILayer::ResetReading()
94
95 {
96 if( poStatement != nullptr )
97 delete poStatement;
98 poStatement = nullptr;
99
100 iNextShapeId = 0;
101 }
102
103 /************************************************************************/
104 /* GetNextFeature() */
105 /* */
106 /* By default we implement the full spatial and attribute query */
107 /* semantics manually here. The table query class will */
108 /* override this method and implement these inline, but the */
109 /* simple SELECT statement evaluator (OGROCISelectLayer) will */
110 /* depend us this code implementing additional spatial or */
111 /* attribute query semantics. */
112 /************************************************************************/
113
GetNextFeature()114 OGRFeature *OGROCILayer::GetNextFeature()
115
116 {
117 while( true )
118 {
119 OGRFeature *poFeature;
120
121 poFeature = GetNextRawFeature();
122 if( poFeature == nullptr )
123 return nullptr;
124
125 if( (m_poFilterGeom == nullptr
126 || FilterGeometry( poFeature->GetGeometryRef() ) )
127 && (m_poAttrQuery == nullptr
128 || m_poAttrQuery->Evaluate( poFeature )) )
129 return poFeature;
130
131 delete poFeature;
132 }
133 }
134
135 /************************************************************************/
136 /* GetNextRawFeature() */
137 /************************************************************************/
138
GetNextRawFeature()139 OGRFeature *OGROCILayer::GetNextRawFeature()
140
141 {
142 /* -------------------------------------------------------------------- */
143 /* Do we need to establish an initial query? */
144 /* -------------------------------------------------------------------- */
145 if( iNextShapeId == 0 && poStatement == nullptr )
146 {
147 if( !ExecuteQuery(pszQueryStatement) )
148 return nullptr;
149 }
150
151 /* -------------------------------------------------------------------- */
152 /* Have we run out of query results, such that we have no */
153 /* statement left? */
154 /* -------------------------------------------------------------------- */
155 if( poStatement == nullptr )
156 return nullptr;
157
158 /* -------------------------------------------------------------------- */
159 /* Are we in some sort of error condition? */
160 /* -------------------------------------------------------------------- */
161 hLastGeom = nullptr;
162
163 char **papszResult = poStatement->SimpleFetchRow();
164
165 if( papszResult == nullptr )
166 {
167 iNextShapeId = MAX(1,iNextShapeId);
168 delete poStatement;
169 poStatement = nullptr;
170 return nullptr;
171 }
172
173 /* -------------------------------------------------------------------- */
174 /* Create a feature from the current result. */
175 /* -------------------------------------------------------------------- */
176 int iField;
177 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
178
179 poFeature->SetFID( iNextShapeId );
180 iNextShapeId++;
181 m_nFeaturesRead++;
182
183 if( iFIDColumn != -1 && papszResult[iFIDColumn] != nullptr )
184 poFeature->SetFID( atoi(papszResult[iFIDColumn]) );
185
186 for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
187 {
188 if( papszResult[iField] != nullptr )
189 poFeature->SetField( iField, papszResult[iField] );
190 else
191 poFeature->SetFieldNull( iField );
192 }
193
194 /* -------------------------------------------------------------------- */
195 /* Translate geometry if we have it. */
196 /* -------------------------------------------------------------------- */
197 if( iGeomColumn != -1 )
198 {
199 poFeature->SetGeometryDirectly( TranslateGeometry() );
200
201 OGROCISession *poSession = poDS->GetSession();
202
203 if( poFeature->GetGeometryRef() != nullptr && hLastGeom != nullptr )
204 poSession->Failed(
205 OCIObjectFree(poSession->hEnv, poSession->hError,
206 (dvoid *) hLastGeom,
207 (ub2)OCI_OBJECTFREE_FORCE) );
208
209 hLastGeom = nullptr;
210 hLastGeomInd = nullptr;
211 }
212
213 nResultOffset++;
214
215 return poFeature;
216 }
217
218 /************************************************************************/
219 /* ExecuteQuery() */
220 /* */
221 /* This is invoke when the first request for a feature is */
222 /* made. It executes the query, and binds columns as needed. */
223 /* The OGROCIStatement is used for most of the work. */
224 /************************************************************************/
225
ExecuteQuery(const char * pszReqQuery)226 int OGROCILayer::ExecuteQuery( const char *pszReqQuery )
227
228 {
229 OGROCISession *poSession = poDS->GetSession();
230
231 CPLAssert( pszReqQuery != nullptr );
232 CPLAssert( poStatement == nullptr );
233
234 /* -------------------------------------------------------------------- */
235 /* Execute the query. */
236 /* -------------------------------------------------------------------- */
237 poStatement = new OGROCIStatement( poSession );
238 if( poStatement->Execute( pszReqQuery ) != CE_None )
239 {
240 delete poStatement;
241 poStatement = nullptr;
242 return FALSE;
243 }
244 nResultOffset = 0;
245
246 /* -------------------------------------------------------------------- */
247 /* Do additional work binding the geometry column. */
248 /* -------------------------------------------------------------------- */
249 if( iGeomColumn != -1 )
250 {
251 OCIDefine *hGDefine = nullptr;
252
253 if( poSession->Failed(
254 OCIDefineByPos(poStatement->GetStatement(), &hGDefine,
255 poSession->hError,
256 (ub4) iGeomColumn+1, (dvoid *)nullptr, (sb4)0, SQLT_NTY,
257 (dvoid *)nullptr, (ub2 *)nullptr, (ub2 *)nullptr, (ub4)OCI_DEFAULT),
258 "OCIDefineByPos(geometry)") )
259 return FALSE;
260
261 if( poSession->Failed(
262 OCIDefineObject(hGDefine, poSession->hError,
263 poSession->hGeometryTDO,
264 (dvoid **) &hLastGeom, (ub4 *)nullptr,
265 (dvoid **) &hLastGeomInd, (ub4 *)nullptr ),
266 "OCIDefineObject") )
267 return FALSE;
268 }
269
270 return TRUE;
271 }
272
273 /************************************************************************/
274 /* TranslateGeometry() */
275 /************************************************************************/
276
TranslateGeometry()277 OGRGeometry *OGROCILayer::TranslateGeometry()
278
279 {
280 OGROCISession *poSession = poDS->GetSession();
281
282 /* -------------------------------------------------------------------- */
283 /* Is the geometry NULL? */
284 /* -------------------------------------------------------------------- */
285 if( hLastGeom == nullptr || hLastGeomInd == nullptr
286 || hLastGeomInd->_atomic == OCI_IND_NULL )
287 return nullptr;
288
289 /* -------------------------------------------------------------------- */
290 /* Get the size of the sdo_elem_info and sdo_ordinates arrays. */
291 /* -------------------------------------------------------------------- */
292 int nElemCount, nOrdCount;
293
294 if( poSession->Failed(
295 OCICollSize( poSession->hEnv, poSession->hError,
296 (OCIColl *)(hLastGeom->sdo_elem_info), &nElemCount),
297 "OCICollSize(sdo_elem_info)" ) )
298 return nullptr;
299
300 if( poSession->Failed(
301 OCICollSize( poSession->hEnv, poSession->hError,
302 (OCIColl *)(hLastGeom->sdo_ordinates), &nOrdCount),
303 "OCICollSize(sdo_ordinates)" ) )
304 return nullptr;
305
306 /* -------------------------------------------------------------------- */
307 /* Get the GType. */
308 /* -------------------------------------------------------------------- */
309 int nGType;
310
311 if( poSession->Failed(
312 OCINumberToInt(poSession->hError, &(hLastGeom->sdo_gtype),
313 (uword)sizeof(int), OCI_NUMBER_SIGNED,
314 (dvoid *)&nGType),
315 "OCINumberToInt(GType)" ) )
316 return nullptr;
317
318 /* -------------------------------------------------------------------- */
319 /* Establish the dimension. */
320 /* -------------------------------------------------------------------- */
321 int nDimension = MAX(2,(nGType / 1000));
322
323 /* -------------------------------------------------------------------- */
324 /* Handle point data directly from built-in point info. */
325 /* -------------------------------------------------------------------- */
326 if( ORA_GTYPE_MATCH(nGType,ORA_GTYPE_POINT)
327 && hLastGeomInd->sdo_point._atomic == OCI_IND_NOTNULL
328 && hLastGeomInd->sdo_point.x == OCI_IND_NOTNULL
329 && hLastGeomInd->sdo_point.y == OCI_IND_NOTNULL )
330 {
331 double dfX, dfY, dfZ = 0.0;
332
333 OCINumberToReal(poSession->hError, &(hLastGeom->sdo_point.x),
334 (uword)sizeof(double), (dvoid *)&dfX);
335 OCINumberToReal(poSession->hError, &(hLastGeom->sdo_point.y),
336 (uword)sizeof(double), (dvoid *)&dfY);
337 if( hLastGeomInd->sdo_point.z == OCI_IND_NOTNULL )
338 OCINumberToReal(poSession->hError, &(hLastGeom->sdo_point.z),
339 (uword)sizeof(double), (dvoid *)&dfZ);
340
341 if( nDimension == 3 )
342 return new OGRPoint( dfX, dfY, dfZ );
343 else
344 return new OGRPoint( dfX, dfY );
345 }
346
347 /* -------------------------------------------------------------------- */
348 /* If this is a sort of container geometry, create the */
349 /* container now. */
350 /* -------------------------------------------------------------------- */
351 OGRGeometryCollection *poCollection = nullptr;
352 OGRPolygon *poPolygon = nullptr;
353
354 if( ORA_GTYPE_MATCH(nGType,ORA_GTYPE_POLYGON) )
355 poPolygon = new OGRPolygon();
356 else if( ORA_GTYPE_MATCH(nGType,ORA_GTYPE_COLLECTION) )
357 poCollection = new OGRGeometryCollection();
358 else if( ORA_GTYPE_MATCH(nGType,ORA_GTYPE_MULTIPOINT) )
359 poCollection = new OGRMultiPoint();
360 else if( ORA_GTYPE_MATCH(nGType,ORA_GTYPE_MULTILINESTRING) )
361 poCollection = new OGRMultiLineString();
362 else if( ORA_GTYPE_MATCH(nGType,ORA_GTYPE_MULTIPOLYGON) )
363 poCollection = new OGRMultiPolygon();
364
365 /* ==================================================================== */
366 /* Loop over the component elements. */
367 /* ==================================================================== */
368 for( int iElement = 0; iElement < nElemCount; iElement += 3 )
369 {
370 int nInterpretation, nEType;
371 int nStartOrdinal, nElemOrdCount;
372
373 LoadElementInfo( iElement, nElemCount, nOrdCount,
374 &nEType, &nInterpretation,
375 &nStartOrdinal, &nElemOrdCount );
376
377 /* -------------------------------------------------------------------- */
378 /* Translate this element. */
379 /* -------------------------------------------------------------------- */
380 OGRGeometry *poGeom;
381
382 poGeom = TranslateGeometryElement( &iElement, nGType, nDimension,
383 nEType, nInterpretation,
384 nStartOrdinal - 1, nElemOrdCount );
385
386 if( poGeom == nullptr )
387 return nullptr;
388
389 /* -------------------------------------------------------------------- */
390 /* Based on GType do what is appropriate. */
391 /* -------------------------------------------------------------------- */
392 if( ORA_GTYPE_MATCH(nGType,ORA_GTYPE_LINESTRING) )
393 {
394 CPLAssert(wkbFlatten(poGeom->getGeometryType()) == wkbLineString);
395 return poGeom;
396 }
397
398 else if( ORA_GTYPE_MATCH(nGType,ORA_GTYPE_POINT) )
399 {
400 CPLAssert(wkbFlatten(poGeom->getGeometryType()) == wkbPoint);
401 return poGeom;
402 }
403
404 else if( ORA_GTYPE_MATCH(nGType,ORA_GTYPE_POLYGON) )
405 {
406 CPLAssert(wkbFlatten(poGeom->getGeometryType()) == wkbLineString );
407 poPolygon->addRingDirectly( poGeom->toLinearRing() );
408 }
409 else
410 {
411 CPLAssert( poCollection != nullptr );
412 if( wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint )
413 {
414 OGRMultiPoint *poMP = poGeom->toMultiPoint();
415 for( auto&& poPoint: *poMP )
416 poCollection->addGeometry(poPoint);
417 delete poMP;
418 }
419 else if( nEType % 1000 == 3 )
420 {
421 /* its one poly ring, create new poly or add to existing */
422 if( nEType == 1003 )
423 {
424 if( poPolygon != nullptr
425 && poPolygon->getExteriorRing() != nullptr )
426 {
427 poCollection->addGeometryDirectly( poPolygon );
428 poPolygon = nullptr;
429 }
430
431 poPolygon = new OGRPolygon();
432 }
433
434 if( poPolygon != nullptr )
435 poPolygon->addRingDirectly( poGeom->toLinearRing() );
436 else
437 {
438 CPLAssert( poPolygon != nullptr );
439 }
440 }
441 else
442 poCollection->addGeometryDirectly( poGeom );
443 }
444 }
445
446 if( poCollection != nullptr
447 && poPolygon != nullptr )
448 poCollection->addGeometryDirectly( poPolygon );
449
450 /* -------------------------------------------------------------------- */
451 /* Return resulting collection geometry. */
452 /* -------------------------------------------------------------------- */
453 if( poCollection == nullptr )
454 return poPolygon;
455 else
456 return poCollection;
457 }
458
459 /************************************************************************/
460 /* LoadElementInfo() */
461 /* */
462 /* Fetch the start ordinal, count, EType and interpretation */
463 /* values for a particular element. */
464 /************************************************************************/
465
466 int
LoadElementInfo(int iElement,int nElemCount,int nTotalOrdCount,int * pnEType,int * pnInterpretation,int * pnStartOrdinal,int * pnElemOrdCount)467 OGROCILayer::LoadElementInfo( int iElement, int nElemCount, int nTotalOrdCount,
468 int *pnEType, int *pnInterpretation,
469 int *pnStartOrdinal, int *pnElemOrdCount )
470
471 {
472 OGROCISession *poSession = poDS->GetSession();
473 boolean bExists;
474 OCINumber *hNumber;
475 /* -------------------------------------------------------------------- */
476 /* Get the details about element from the elem_info array. */
477 /* -------------------------------------------------------------------- */
478 OCICollGetElem(poSession->hEnv, poSession->hError,
479 (OCIColl *)(hLastGeom->sdo_elem_info),
480 (sb4)(iElement+0), (boolean *)&bExists,
481 (dvoid **)&hNumber, nullptr );
482 OCINumberToInt(poSession->hError, hNumber, (uword)sizeof(ub4),
483 OCI_NUMBER_UNSIGNED, (dvoid *) pnStartOrdinal );
484
485 OCICollGetElem(poSession->hEnv, poSession->hError,
486 (OCIColl *)(hLastGeom->sdo_elem_info),
487 (sb4)(iElement+1), (boolean *)&bExists,
488 (dvoid **)&hNumber, nullptr );
489 OCINumberToInt(poSession->hError, hNumber, (uword)sizeof(ub4),
490 OCI_NUMBER_UNSIGNED, (dvoid *) pnEType );
491
492 OCICollGetElem(poSession->hEnv, poSession->hError,
493 (OCIColl *)(hLastGeom->sdo_elem_info),
494 (sb4)(iElement+2), (boolean *)&bExists,
495 (dvoid **)&hNumber, nullptr );
496 OCINumberToInt(poSession->hError, hNumber, (uword)sizeof(ub4),
497 OCI_NUMBER_UNSIGNED, (dvoid *) pnInterpretation );
498
499 if( iElement < nElemCount-3 )
500 {
501 ub4 nNextStartOrdinal;
502
503 OCICollGetElem(poSession->hEnv, poSession->hError,
504 (OCIColl *)(hLastGeom->sdo_elem_info),
505 (sb4)(iElement+3), (boolean *)&bExists,
506 (dvoid **)&hNumber,nullptr);
507 OCINumberToInt(poSession->hError, hNumber, (uword)sizeof(ub4),
508 OCI_NUMBER_UNSIGNED, (dvoid *) &nNextStartOrdinal );
509
510 *pnElemOrdCount = nNextStartOrdinal - *pnStartOrdinal;
511 }
512 else
513 *pnElemOrdCount = nTotalOrdCount - *pnStartOrdinal + 1;
514
515 return TRUE;
516 }
517
518 /************************************************************************/
519 /* TranslateGeometryElement() */
520 /************************************************************************/
521
522 OGRGeometry *
TranslateGeometryElement(int * piElement,int nGType,int nDimension,int nEType,int nInterpretation,int nStartOrdinal,int nElemOrdCount)523 OGROCILayer::TranslateGeometryElement( int *piElement,
524 int nGType, int nDimension,
525 int nEType, int nInterpretation,
526 int nStartOrdinal, int nElemOrdCount )
527
528 {
529 /* -------------------------------------------------------------------- */
530 /* Handle simple point. */
531 /* -------------------------------------------------------------------- */
532 if( nEType == 1 && nInterpretation == 1 )
533 {
534 OGRPoint *poPoint = new OGRPoint();
535 double dfX, dfY, dfZ = 0.0;
536
537 GetOrdinalPoint( nStartOrdinal, nDimension, &dfX, &dfY, &dfZ );
538
539 poPoint->setX( dfX );
540 poPoint->setY( dfY );
541 if( nDimension == 3 )
542 poPoint->setZ( dfZ );
543
544 return poPoint;
545 }
546
547 /* -------------------------------------------------------------------- */
548 /* Handle multipoint. */
549 /* -------------------------------------------------------------------- */
550 else if( nEType == 1 && nInterpretation > 1 )
551 {
552 OGRMultiPoint *poMP = new OGRMultiPoint();
553 double dfX, dfY, dfZ = 0.0;
554 int i;
555
556 CPLAssert( nInterpretation == nElemOrdCount / nDimension );
557
558 for( i = 0; i < nInterpretation; i++ )
559 {
560 GetOrdinalPoint( nStartOrdinal + i*nDimension, nDimension,
561 &dfX, &dfY, &dfZ );
562
563 OGRPoint *poPoint = (nDimension == 3) ? new OGRPoint( dfX, dfY, dfZ ): new OGRPoint( dfX, dfY );
564 poMP->addGeometryDirectly( poPoint );
565 }
566 return poMP;
567 }
568
569 /* -------------------------------------------------------------------- */
570 /* Discard orientations for oriented points. */
571 /* -------------------------------------------------------------------- */
572 else if( nEType == 1 && nInterpretation == 0 )
573 {
574 CPLDebug( "OCI", "Ignoring orientations for oriented points." );
575 return nullptr;
576 }
577
578 /* -------------------------------------------------------------------- */
579 /* Handle line strings consisting of straight segments. */
580 /* -------------------------------------------------------------------- */
581 else if( nEType == 2 && nInterpretation == 1 )
582 {
583 OGRLineString *poLS = new OGRLineString();
584 int nPointCount = nElemOrdCount / nDimension, i;
585
586 poLS->setNumPoints( nPointCount );
587
588 for( i = 0; i < nPointCount; i++ )
589 {
590 double dfX, dfY, dfZ = 0.0;
591
592 GetOrdinalPoint( i*nDimension + nStartOrdinal, nDimension,
593 &dfX, &dfY, &dfZ );
594 if (nDimension == 3)
595 poLS->setPoint( i, dfX, dfY, dfZ );
596 else
597 poLS->setPoint( i, dfX, dfY );
598 }
599
600 return poLS;
601 }
602
603 /* -------------------------------------------------------------------- */
604 /* Handle line strings consisting of circular arcs. */
605 /* -------------------------------------------------------------------- */
606 else if( nEType == 2 && nInterpretation == 2 )
607 {
608 OGRLineString *poLS = new OGRLineString();
609 int nPointCount = nElemOrdCount / nDimension, i;
610
611 for( i = 0; i < nPointCount-2; i += 2 )
612 {
613 double dfStartX, dfStartY, dfStartZ = 0.0;
614 double dfMidX, dfMidY, dfMidZ = 0.0;
615 double dfEndX, dfEndY, dfEndZ = 0.0;
616
617 GetOrdinalPoint( i*nDimension + nStartOrdinal, nDimension,
618 &dfStartX, &dfStartY, &dfStartZ );
619 GetOrdinalPoint( (i+1)*nDimension + nStartOrdinal, nDimension,
620 &dfMidX, &dfMidY, &dfMidZ );
621 GetOrdinalPoint( (i+2)*nDimension + nStartOrdinal, nDimension,
622 &dfEndX, &dfEndY, &dfEndZ );
623
624 OGROCIStrokeArcToOGRGeometry_Points( dfStartX, dfStartY,
625 dfMidX, dfMidY,
626 dfEndX, dfEndY,
627 6.0, FALSE, poLS );
628 }
629
630 return poLS;
631 }
632
633 /* -------------------------------------------------------------------- */
634 /* Handle polygon rings. Treat curves as if they were */
635 /* linestrings. */
636 /* -------------------------------------------------------------------- */
637 else if( nEType % 1000 == 3 && nInterpretation == 1 )
638 {
639 OGRLinearRing *poLS = new OGRLinearRing();
640 int nPointCount = nElemOrdCount / nDimension, i;
641
642 poLS->setNumPoints( nPointCount );
643
644 for( i = 0; i < nPointCount; i++ )
645 {
646 double dfX, dfY, dfZ = 0.0;
647
648 GetOrdinalPoint( i*nDimension + nStartOrdinal, nDimension,
649 &dfX, &dfY, &dfZ );
650 if (nDimension == 3)
651 poLS->setPoint( i, dfX, dfY, dfZ );
652 else
653 poLS->setPoint( i, dfX, dfY );
654 }
655
656 return poLS;
657 }
658
659 /* -------------------------------------------------------------------- */
660 /* Handle polygon rings made of circular arcs. */
661 /* -------------------------------------------------------------------- */
662 else if( nEType % 1000 == 3 && nInterpretation == 2 )
663 {
664 OGRLineString *poLS = new OGRLinearRing();
665 int nPointCount = nElemOrdCount / nDimension, i;
666
667 for( i = 0; i < nPointCount-2; i += 2 )
668 {
669 double dfStartX, dfStartY, dfStartZ = 0.0;
670 double dfMidX, dfMidY, dfMidZ = 0.0;
671 double dfEndX, dfEndY, dfEndZ = 0.0;
672
673 GetOrdinalPoint( i*nDimension + nStartOrdinal, nDimension,
674 &dfStartX, &dfStartY, &dfStartZ );
675 GetOrdinalPoint( (i+1)*nDimension + nStartOrdinal, nDimension,
676 &dfMidX, &dfMidY, &dfMidZ );
677 GetOrdinalPoint( (i+2)*nDimension + nStartOrdinal, nDimension,
678 &dfEndX, &dfEndY, &dfEndZ );
679
680 OGROCIStrokeArcToOGRGeometry_Points( dfStartX, dfStartY,
681 dfMidX, dfMidY,
682 dfEndX, dfEndY,
683 6.0, FALSE, poLS );
684 }
685
686 return poLS;
687 }
688
689 /* -------------------------------------------------------------------- */
690 /* Handle rectangle definitions ... translate into a linear ring. */
691 /* -------------------------------------------------------------------- */
692 else if( nEType % 1000 == 3 && nInterpretation == 3 )
693 {
694 OGRLinearRing *poLS = new OGRLinearRing();
695 double dfX1, dfY1, dfZ1 = 0.0;
696 double dfX2, dfY2, dfZ2 = 0.0;
697
698 GetOrdinalPoint( nStartOrdinal, nDimension,
699 &dfX1, &dfY1, &dfZ1 );
700 GetOrdinalPoint( nStartOrdinal + nDimension, nDimension,
701 &dfX2, &dfY2, &dfZ2 );
702
703 poLS->setNumPoints( 5 );
704
705 poLS->setPoint( 0, dfX1, dfY1, dfZ1 );
706 poLS->setPoint( 1, dfX2, dfY1, dfZ1 );
707 poLS->setPoint( 2, dfX2, dfY2, dfZ2 );
708 poLS->setPoint( 3, dfX1, dfY2, dfZ2 );
709 poLS->setPoint( 4, dfX1, dfY1, dfZ1 );
710
711 return poLS;
712 }
713
714 /* -------------------------------------------------------------------- */
715 /* Handle circle definitions ... translate into a linear ring. */
716 /* -------------------------------------------------------------------- */
717 else if( nEType % 100 == 3 && nInterpretation == 4 )
718 {
719 OGRLinearRing *poLS = new OGRLinearRing();
720 double dfX1, dfY1, dfZ1 = 0.0;
721 double dfX2, dfY2, dfZ2 = 0.0;
722 double dfX3, dfY3, dfZ3 = 0.0;
723
724 GetOrdinalPoint( nStartOrdinal, nDimension,
725 &dfX1, &dfY1, &dfZ1 );
726 GetOrdinalPoint( nStartOrdinal + nDimension, nDimension,
727 &dfX2, &dfY2, &dfZ2 );
728 GetOrdinalPoint( nStartOrdinal + nDimension*2, nDimension,
729 &dfX3, &dfY3, &dfZ3 );
730
731 OGROCIStrokeArcToOGRGeometry_Points( dfX1, dfY1,
732 dfX2, dfY2,
733 dfX3, dfY3,
734 6.0, TRUE, poLS );
735
736 return poLS;
737 }
738
739 /* -------------------------------------------------------------------- */
740 /* Handle compound line strings and polygon rings. */
741 /* */
742 /* This is quite complicated since we need to consume several */
743 /* following elements, and merge the resulting geometries. */
744 /* -------------------------------------------------------------------- */
745 else if( nEType == 4 || nEType % 100 == 5 )
746 {
747 int nSubElementCount = nInterpretation;
748 OGRLineString *poLS;
749 int nElemCount, nTotalOrdCount;
750 OGROCISession *poSession = poDS->GetSession();
751
752 if( poSession->Failed(
753 OCICollSize( poSession->hEnv, poSession->hError,
754 (OCIColl *)(hLastGeom->sdo_elem_info), &nElemCount),
755 "OCICollSize(sdo_elem_info)" ) )
756 return nullptr;
757
758 if( poSession->Failed(
759 OCICollSize( poSession->hEnv, poSession->hError,
760 (OCIColl*)(hLastGeom->sdo_ordinates),&nTotalOrdCount),
761 "OCICollSize(sdo_ordinates)" ) )
762 return nullptr;
763
764 if( nEType == 4 )
765 poLS = new OGRLineString();
766 else
767 poLS = new OGRLinearRing();
768
769 for( *piElement += 3; nSubElementCount-- > 0; *piElement += 3 )
770 {
771 LoadElementInfo( *piElement, nElemCount, nTotalOrdCount,
772 &nEType, &nInterpretation,
773 &nStartOrdinal, &nElemOrdCount );
774
775 // Adjust for repeated end point except for last element.
776 if( nSubElementCount > 0 )
777 nElemOrdCount += nDimension;
778
779 // translate element.
780 OGRGeometry* poGeom =
781 TranslateGeometryElement( piElement, nGType, nDimension,
782 nEType, nInterpretation,
783 nStartOrdinal - 1, nElemOrdCount );
784 OGRLineString* poElemLS = dynamic_cast<OGRLineString *>(poGeom);
785
786 // Try to append to our aggregate linestring/ring
787 if( poElemLS )
788 {
789 if( poLS->getNumPoints() > 0 )
790 {
791 CPLAssert(
792 poElemLS->getX(0) == poLS->getX(poLS->getNumPoints()-1)
793 && poElemLS->getY(0) ==poLS->getY(poLS->getNumPoints()-1));
794
795 poLS->addSubLineString( poElemLS, 1 );
796 }
797 else
798 poLS->addSubLineString( poElemLS, 0 );
799 }
800 delete poGeom;
801 }
802
803 *piElement -= 3;
804 return poLS;
805 }
806
807 /* -------------------------------------------------------------------- */
808 /* Otherwise it is apparently unsupported. */
809 /* -------------------------------------------------------------------- */
810 else
811 {
812
813 CPLDebug( "OCI", "Geometry with EType=%d, Interp=%d ignored.",
814 nEType, nInterpretation );
815 }
816
817 return nullptr;
818 }
819
820 /************************************************************************/
821 /* GetOrdinalPoint() */
822 /************************************************************************/
823
GetOrdinalPoint(int iOrdinal,int nDimension,double * pdfX,double * pdfY,double * pdfZ)824 int OGROCILayer::GetOrdinalPoint( int iOrdinal, int nDimension,
825 double *pdfX, double *pdfY, double *pdfZ )
826
827 {
828 OGROCISession *poSession = poDS->GetSession();
829 boolean bExists;
830 OCINumber *hNumber;
831
832 OCICollGetElem( poSession->hEnv, poSession->hError,
833 (OCIColl *)(hLastGeom->sdo_ordinates),
834 (sb4)iOrdinal+0, (boolean *)&bExists,
835 (dvoid **)&hNumber, nullptr );
836 OCINumberToReal(poSession->hError, hNumber,
837 (uword)sizeof(double), (dvoid *)pdfX);
838 OCICollGetElem( poSession->hEnv, poSession->hError,
839 (OCIColl *)(hLastGeom->sdo_ordinates),
840 (sb4)iOrdinal + 1, (boolean *)&bExists,
841 (dvoid **)&hNumber, nullptr );
842 OCINumberToReal(poSession->hError, hNumber,
843 (uword)sizeof(double), (dvoid *)pdfY);
844 if( nDimension == 3 )
845 {
846 OCICollGetElem( poSession->hEnv, poSession->hError,
847 (OCIColl *)(hLastGeom->sdo_ordinates),
848 (sb4)iOrdinal + 2, (boolean *)&bExists,
849 (dvoid **)&hNumber, nullptr );
850 OCINumberToReal(poSession->hError, hNumber,
851 (uword)sizeof(double), (dvoid *)pdfZ);
852 }
853
854 return TRUE;
855 }
856
857 /************************************************************************/
858 /* TestCapability() */
859 /************************************************************************/
860
TestCapability(const char * pszCap)861 int OGROCILayer::TestCapability( const char * pszCap )
862
863 {
864 if( EQUAL(pszCap,OLCRandomRead) )
865 return TRUE;
866
867 else if( EQUAL(pszCap,OLCFastFeatureCount) )
868 return m_poFilterGeom == nullptr;
869
870 else if( EQUAL(pszCap,OLCFastSpatialFilter) )
871 return TRUE;
872
873 else if( EQUAL(pszCap,OLCTransactions) )
874 return TRUE;
875
876 else
877 return FALSE;
878 }
879
880 /************************************************************************/
881 /* LookupTableSRID() */
882 /* */
883 /* Note that the table name may also be prefixed by the owner */
884 /* with a dot separator. */
885 /************************************************************************/
886
LookupTableSRID()887 int OGROCILayer::LookupTableSRID()
888
889 {
890 /* -------------------------------------------------------------------- */
891 /* If we don't have a geometry column, there isn't much point */
892 /* in trying. */
893 /* -------------------------------------------------------------------- */
894 if( pszGeomName == nullptr )
895 return -1;
896
897 /* -------------------------------------------------------------------- */
898 /* Split out the owner if available. */
899 /* -------------------------------------------------------------------- */
900 const char *pszTableName = GetLayerDefn()->GetName();
901 char *pszOwner = nullptr;
902
903 if( strstr(pszTableName,".") != nullptr )
904 {
905 pszOwner = CPLStrdup(pszTableName);
906 pszTableName = strstr(pszTableName,".") + 1;
907
908 *(strstr(pszOwner,".")) = '\0';
909 }
910
911 /* -------------------------------------------------------------------- */
912 /* Build our query command. */
913 /* -------------------------------------------------------------------- */
914 OGROCIStringBuf oCommand;
915
916 oCommand.Append( "SELECT SRID FROM ALL_SDO_GEOM_METADATA "
917 "WHERE TABLE_NAME = UPPER(:table_name) AND COLUMN_NAME = UPPER(:geometry_name)" );
918
919 if( pszOwner != nullptr )
920 {
921 oCommand.Append( " AND OWNER = :owner");
922 }
923
924 /* -------------------------------------------------------------------- */
925 /* Execute query command. */
926 /* -------------------------------------------------------------------- */
927 OGROCIStatement oGetTables( poDS->GetSession() );
928 int nSRID = -1;
929
930 if( oGetTables.Prepare( oCommand.GetString() ) != CE_None )
931 return nSRID;
932
933 oGetTables.BindString(":table_name", pszTableName);
934 oGetTables.BindString(":geometry_name", pszGeomName);
935 if( pszOwner != nullptr )
936 {
937 oGetTables.BindString(":owner", pszOwner);
938 CPLFree( pszOwner );
939 }
940
941 if( oGetTables.Execute( nullptr ) == CE_None )
942 {
943 char **papszRow = oGetTables.SimpleFetchRow();
944
945 if( papszRow != nullptr && papszRow[0] != nullptr )
946 nSRID = atoi( papszRow[0] );
947 }
948
949 return nSRID;
950 }
951
952 /************************************************************************/
953 /* GetFIDColumn() */
954 /************************************************************************/
955
GetFIDColumn()956 const char *OGROCILayer::GetFIDColumn()
957
958 {
959 if( pszFIDName != nullptr )
960 return pszFIDName;
961 else
962 return "";
963 }
964
965 /************************************************************************/
966 /* GetGeometryColumn() */
967 /************************************************************************/
968
GetGeometryColumn()969 const char *OGROCILayer::GetGeometryColumn()
970
971 {
972 if( pszGeomName != nullptr )
973 return pszGeomName;
974 else
975 return "";
976 }
977