1 /******************************************************************************
2  *
3  * Project:  OpenGIS Simple Features Reference Implementation
4  * Purpose:  Implements OGRIngresLayer class.
5  * Author:   Frank Warmerdam, warmerdam@pobox.com
6  *
7  ******************************************************************************
8  * Copyright (c) 2008, Frank Warmerdam <warmerdam@pobox.com>
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #include "ogr_ingres.h"
30 #include "cpl_conv.h"
31 #include "cpl_string.h"
32 
33 CPL_CVSID("$Id: ogringreslayer.cpp 8ca42e1b9c2e54b75d35e49885df9789a2643aa4 2020-05-17 21:43:40 +0200 Even Rouault $")
34 
35 /************************************************************************/
36 /*                           OGRIngresLayer()                            */
37 /************************************************************************/
~OGRIngresDriver()38 
39 OGRIngresLayer::OGRIngresLayer()
40 
41 {
42     poDS = NULL;
43 
44     iNextShapeId = 0;
45     nResultOffset = 0;
46 
47     poSRS = NULL;
48     nSRSId = -2; // we haven't even queried the database for it yet.
49 
50     poFeatureDefn = NULL;
51 
52     poResultSet = NULL;
53 }
54 
55 /************************************************************************/
56 /*                           ~OGRIngresLayer()                           */
ParseWrappedName(const char * pszEncodedName)57 /************************************************************************/
58 
59 OGRIngresLayer::~OGRIngresLayer()
60 
61 {
62     if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
63     {
64         CPLDebug( "Ingres", "%d features read on layer '%s'.",
65                   (int) m_nFeaturesRead,
66                   poFeatureDefn->GetName() );
67     }
68 
69     OGRIngresLayer::ResetReading();
70 
71     if( poSRS != NULL )
72         poSRS->Release();
73 
74     if( poFeatureDefn )
75         poFeatureDefn->Release();
76 }
77 
78 /************************************************************************/
79 /*                            ResetReading()                            */
80 /************************************************************************/
81 
82 void OGRIngresLayer::ResetReading()
83 
84 {
85     iNextShapeId = 0;
86 
87     if( poResultSet != NULL )
88     {
89         delete poResultSet;
90         poResultSet = NULL;
91     }
92 }
93 
94 /************************************************************************/
95 /*                           GetNextFeature()                           */
96 /************************************************************************/
97 
98 OGRFeature *OGRIngresLayer::GetNextFeature()
99 
100 {
101     while( true )
102     {
CreateDataSource(const char * pszName,char **)103         OGRFeature *poFeature = GetNextRawFeature();
104         if( poFeature == NULL )
105             return NULL;
106 
107         if( (m_poFilterGeom == NULL
108             || FilterGeometry( poFeature->GetGeometryRef() ) )
109             && (m_poAttrQuery == NULL
110                 || m_poAttrQuery->Evaluate( poFeature )) )
111             return poFeature;
112 
113         delete poFeature;
114     }
115 }
116 
117 /************************************************************************/
118 /*                              ParseXY()                               */
119 /************************************************************************/
120 
121 static bool ParseXY( const char **ppszNext, double *padfXY )
122 
123 {
124     const char *pszNext = *ppszNext;
125 
126     int iStartY = 0;  // Used after for.
127     for( ; ; iStartY++ )
128     {
129         if( pszNext[iStartY] == '\0' )
130             return false;
131 
132         if( pszNext[iStartY] == ',' )
133         {
134             iStartY++;
135             break;
136         }
137     }
138 
139     padfXY[0] = CPLAtof(pszNext);
TestCapability(const char * pszCap)140     padfXY[1] = CPLAtof(pszNext + iStartY);
141 
142     int iEnd = iStartY;  // Used after for.
143     for( ; pszNext[iEnd] != ')'; iEnd++ )
144     {
145         if( pszNext[iEnd] == '\0' )
146             return false;
147     }
148 
149     *ppszNext += iEnd;
150 
151     return true;
152 }
153 
154 /************************************************************************/
155 /*                         TranslateGeometry()                          */
156 /*                                                                      */
RegisterOGRIngres()157 /*      This currently only supports "old style" ingres geometry in     */
158 /*      text format.  Essentially tuple lists of vertices.              */
159 /************************************************************************/
160 
161 OGRGeometry *OGRIngresLayer::TranslateGeometry( const char *pszGeom )
162 
163 {
164     OGRGeometry *poGeom = NULL;
165 
166 /* -------------------------------------------------------------------- */
167 /*      Parse the tuple list into an array of x/y vertices.  The        */
168 /*      input may look like "(2,3)" or "((2,3),(4,5),...)".  Extra      */
169 /*      spaces may occur between tokens.                                */
170 /* -------------------------------------------------------------------- */
171     double *padfXY = NULL;
172     int nVertMax = 0;
173     int nVertCount = 0;
174     int nDepth = 0;
175     const char *pszNext = pszGeom;
176 
177     while( *pszNext != '\0' )
178     {
179         while( *pszNext == ' ' )
180             pszNext++;
181 
182         if( *pszNext == '(' )
183         {
184             pszNext++;
185             nDepth++;
186             continue;
187         }
188 
189         if( *pszNext == ')' )
190         {
191             //pszNext++;
192             CPLAssert( nDepth == 1 );
193             nDepth--;
194             break;
195         }
196 
197         if( *pszNext == ',' )
198         {
199             pszNext++;
200             CPLAssert( nDepth == 1 );
201             continue;
202         }
203 
204         if( nVertCount == nVertMax )
205         {
206             nVertMax = nVertMax * 2 + 1;
207             padfXY = (double *)
208                 CPLRealloc(padfXY, sizeof(double) * nVertMax * 2 );
209         }
210 
211         if( !ParseXY( &pszNext, padfXY + nVertCount*2 ) )
212         {
213             CPLDebug( "INGRES", "Error parsing geometry: %s",
214                       pszGeom );
215             CPLFree( padfXY );
216             return NULL;
217         }
218 
219         CPLAssert( *pszNext == ')' );
220         nVertCount++;
221         pszNext++;
222         nDepth--;
223 
224         while( *pszNext == ' ' )
225             pszNext++;
226     }
227 
228     (void)nDepth;
229     CPLAssert( nDepth == 0 );
230 
231 /* -------------------------------------------------------------------- */
232 /*      Handle Box/IBox.                                                */
233 /* -------------------------------------------------------------------- */
234     if( EQUAL(osIngresGeomType,"BOX")
235         || EQUAL(osIngresGeomType,"IBOX") )
236     {
237         CPLAssert( nVertCount == 2 );
238 
239         OGRLinearRing *poRing = new OGRLinearRing();
240         poRing->addPoint( padfXY[0], padfXY[1] );
241         poRing->addPoint( padfXY[2], padfXY[1] );
242         poRing->addPoint( padfXY[2], padfXY[3] );
243         poRing->addPoint( padfXY[0], padfXY[3] );
244         poRing->addPoint( padfXY[0], padfXY[1] );
245 
246         OGRPolygon *poPolygon = new OGRPolygon();
247         poPolygon->addRingDirectly( poRing );
248 
249         poGeom = poPolygon;
250     }
251 
252 /* -------------------------------------------------------------------- */
253 /*      Handle Point/IPoint                                             */
254 /* -------------------------------------------------------------------- */
255     else if( EQUAL(osIngresGeomType,"POINT")
256              || EQUAL(osIngresGeomType,"IPOINT") )
257     {
258         CPLAssert( nVertCount == 1 );
259 
260         poGeom = new OGRPoint( padfXY[0], padfXY[1] );
261     }
262 
263 /* -------------------------------------------------------------------- */
264 /*      Handle various linestring types.                                */
265 /* -------------------------------------------------------------------- */
266     else if( EQUAL(osIngresGeomType,"LSEG")
267              || EQUAL(osIngresGeomType,"ILSEG")
268              || EQUAL(osIngresGeomType,"LINE")
269              || EQUAL(osIngresGeomType,"LONG LINE")
270              || EQUAL(osIngresGeomType,"ILINE") )
271     {
272         OGRLineString *poLine = new OGRLineString();
273         int iVert;
274 
275         poLine->setNumPoints( nVertCount );
276         for( iVert = 0; iVert < nVertCount; iVert++ )
277             poLine->setPoint( iVert, padfXY[iVert*2+0], padfXY[iVert*2+1] );
278 
279         poGeom = poLine;
280     }
281 
282 /* -------------------------------------------------------------------- */
283 /*      Handle Polygon/IPolygon/LongPolygon.                            */
284 /* -------------------------------------------------------------------- */
285     else if( EQUAL(osIngresGeomType,"POLYGON")
286              || EQUAL(osIngresGeomType,"IPOLYGON")
287              || EQUAL(osIngresGeomType,"LONG POLYGON") )
288     {
289         OGRLinearRing *poLine = new OGRLinearRing();
290         int iVert;
291 
292         poLine->setNumPoints( nVertCount );
293         for( iVert = 0; iVert < nVertCount; iVert++ )
294             poLine->setPoint( iVert, padfXY[iVert*2+0], padfXY[iVert*2+1] );
295 
296         // INGRES polygons are implicitly closed, but OGR expects explicit
297         if( poLine->getX(nVertCount-1) != poLine->getX(0)
298             || poLine->getY(nVertCount-1) != poLine->getY(0) )
299             poLine->addPoint( poLine->getX(0), poLine->getY(0) );
300 
301         OGRPolygon *poPolygon = new OGRPolygon();
302         poPolygon->addRingDirectly( poLine );
303         poGeom = poPolygon;
304     }
305 
306     return poGeom;
307 }
308 
309 /************************************************************************/
310 /*                          RecordToFeature()                           */
311 /*                                                                      */
312 /*      Convert the indicated record of the current result set into     */
313 /*      a feature.                                                      */
314 /************************************************************************/
315 
316 OGRFeature *OGRIngresLayer::RecordToFeature( char **papszRow )
317 
318 {
319 /* -------------------------------------------------------------------- */
320 /*      Create a feature from the current result.                       */
321 /* -------------------------------------------------------------------- */
322     int         iField;
323     OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
324 
325     poFeature->SetFID( iNextShapeId );
326     m_nFeaturesRead++;
327 
328 /* ==================================================================== */
329 /*      Transfer all result fields we can.                              */
330 /* ==================================================================== */
331     for( iField = 0;
332          iField < (int) poResultSet->getDescrParm.gd_descriptorCount;
333          iField++ )
334     {
335         IIAPI_DATAVALUE *psDV =
336             poResultSet->pasDataBuffer + iField;
337         IIAPI_DESCRIPTOR *psFDesc =
338             poResultSet->getDescrParm.gd_descriptor + iField;
339         int     iOGRField;
340 
341 /* -------------------------------------------------------------------- */
342 /*      Ignore NULL fields.                                             */
343 /* -------------------------------------------------------------------- */
344         if( psDV->dv_null )
345             continue;
346 
347 /* -------------------------------------------------------------------- */
348 /*      Handle FID.                                                     */
349 /* -------------------------------------------------------------------- */
350         if( osFIDColumn.size()
351             && EQUAL(psFDesc->ds_columnName,osFIDColumn)
352             && psFDesc->ds_dataType == IIAPI_INT_TYPE
353             && psDV->dv_length == 4 )
354         {
355             if( papszRow[iField] == NULL )
356             {
357                 CPLError( CE_Failure, CPLE_AppDefined,
358                           "NULL primary key in RecordToFeature()" );
359                 return NULL;
360             }
361 
362             GInt32 nValue;
363             memcpy( &nValue, papszRow[iField], 4 );
364             poFeature->SetFID( nValue );
365         }
366 
367 /* -------------------------------------------------------------------- */
368 /*      Handle Ingres geometry                                           */
369 /* -------------------------------------------------------------------- */
370         if( osGeomColumn.size()
371             && EQUAL(psFDesc->ds_columnName,osGeomColumn))
372         {
373             if( poDS->IsNewIngres() )
374             {
375                 OGRGeometry *poGeometry = NULL;
376                 unsigned char *pszWKB = (unsigned char *) papszRow[iField];
377 
378                 // GRGeometryFactory::createFromWkt(&pszWKT, NULL, &poGeometry);
379                 OGRGeometryFactory::createFromWkb(pszWKB, NULL, &poGeometry, -1);
380 
381                 poFeature->SetGeometryDirectly(poGeometry);
382             }
383             else
384             {
385                 poFeature->SetGeometryDirectly(
386                     TranslateGeometry( papszRow[iField] ) );
387             }
388             continue;
389         }
390 
391 /* -------------------------------------------------------------------- */
392 /*      Transfer regular data fields.                                   */
393 /* -------------------------------------------------------------------- */
394         iOGRField = poFeatureDefn->GetFieldIndex(psFDesc->ds_columnName);
395         if( iOGRField < 0 )
396             continue;
397 
398         switch( psFDesc->ds_dataType )
399         {
400           case IIAPI_CHR_TYPE:
401           case IIAPI_CHA_TYPE:
402           case IIAPI_LVCH_TYPE:
403           case IIAPI_LTXT_TYPE:
404             poFeature->SetField( iOGRField, papszRow[iField] );
405             break;
406 
407           case IIAPI_VCH_TYPE:
408           case IIAPI_TXT_TYPE:
409             GUInt16 nLength;
410             memcpy( &nLength, papszRow[iField], 2 );
411             papszRow[iField][nLength+2] = '\0';
412             poFeature->SetField( iOGRField, papszRow[iField]+2 );
413             break;
414 
415           case IIAPI_INT_TYPE:
416             if( psDV->dv_length == 8 )
417             {
418                 GIntBig nValue;
419                 memcpy( &nValue, papszRow[iField], 8 );
420                 poFeature->SetField( iOGRField, (int) nValue );
421             }
422             else if( psDV->dv_length == 4 )
423             {
424                 GInt32 nValue;
425                 memcpy( &nValue, papszRow[iField], 4 );
426                 poFeature->SetField( iOGRField, nValue );
427             }
428             else if( psDV->dv_length == 2 )
429             {
430                 GInt16 nValue;
431                 memcpy( &nValue, papszRow[iField], 2 );
432                 poFeature->SetField( iOGRField, nValue );
433             }
434             else if( psDV->dv_length == 1 )
435             {
436                 GByte nValue;
437                 memcpy( &nValue, papszRow[iField], 1 );
438                 poFeature->SetField( iOGRField, nValue );
439             }
440             break;
441 
442           case IIAPI_FLT_TYPE:
443             if( psDV->dv_length == 4 )
444             {
445                 float fValue;
446                 memcpy( &fValue, papszRow[iField], 4 );
447                 poFeature->SetField( iOGRField, fValue );
448             }
449             else if( psDV->dv_length == 8 )
450             {
451                 double dfValue;
452                 memcpy( &dfValue, papszRow[iField], 8 );
453                 poFeature->SetField( iOGRField, dfValue );
454             }
455             break;
456 
457           case IIAPI_DEC_TYPE:
458           {
459               IIAPI_CONVERTPARM sCParm;
460               char szFormatBuf[30];
461 
462               memset( &sCParm, 0, sizeof(sCParm) );
463 
464               memcpy( &(sCParm.cv_srcDesc), psFDesc,
465                       sizeof(IIAPI_DESCRIPTOR) );
466               memcpy( &(sCParm.cv_srcValue), psDV,
467                       sizeof(IIAPI_DATAVALUE) );
468 
469               sCParm.cv_dstDesc.ds_dataType = IIAPI_CHA_TYPE;
470               sCParm.cv_dstDesc.ds_nullable = FALSE;
471               sCParm.cv_dstDesc.ds_length = sizeof(szFormatBuf);
472 
473               sCParm.cv_dstValue.dv_value = szFormatBuf;
474 
475               IIapi_convertData( &sCParm );
476 
477               poFeature->SetField( iOGRField, szFormatBuf );
478               break;
479           }
480         }
481     }
482 
483     return poFeature;
484 }
485 
486 /************************************************************************/
487 /*                         GetNextRawFeature()                          */
488 /************************************************************************/
489 
490 OGRFeature *OGRIngresLayer::GetNextRawFeature()
491 
492 {
493 /* -------------------------------------------------------------------- */
494 /*      Do we need to establish an initial query?                       */
495 /* -------------------------------------------------------------------- */
496     if( iNextShapeId == 0 && poResultSet == NULL )
497     {
498         CPLAssert( !osQueryStatement.empty() );
499 
500         poDS->EstablishActiveLayer( this );
501 
502         poResultSet = new OGRIngresStatement( poDS->GetConn() );
503 
504         if( !poResultSet->ExecuteSQL( osQueryStatement ) )
505             return NULL;
506     }
507 
508 /* -------------------------------------------------------------------- */
509 /*      Fetch next record.                                              */
510 /* -------------------------------------------------------------------- */
511     char **papszRow = poResultSet->GetRow();
512     if( papszRow == NULL )
513     {
514         ResetReading();
515         return NULL;
516     }
517 
518 /* -------------------------------------------------------------------- */
519 /*      Process record.                                                 */
520 /* -------------------------------------------------------------------- */
521     OGRFeature *poFeature = RecordToFeature( papszRow );
522 
523     iNextShapeId++;
524 
525     return poFeature;
526 }
527 
528 /************************************************************************/
529 /*                             GetFeature()                             */
530 /*                                                                      */
531 /*      Note that we actually override this in OGRIngresTableLayer.      */
532 /************************************************************************/
533 
534 OGRFeature *OGRIngresLayer::GetFeature( GIntBig nFeatureId )
535 
536 {
537     return OGRLayer::GetFeature( nFeatureId );
538 }
539 
540 /************************************************************************/
541 /*                           TestCapability()                           */
542 /************************************************************************/
543 
544 int OGRIngresLayer::TestCapability( const char * pszCap )
545 
546 {
547     return FALSE;
548 
549 #if 0
550     if( EQUAL(pszCap, OLCRandomRead) )
551         return FALSE;
552 
553     else if( EQUAL(pszCap, OLCFastFeatureCount) )
554         return FALSE;
555 
556     else if( EQUAL(pszCap, OLCFastSpatialFilter) )
557         return FALSE;
558 
559     else if( EQUAL(pszCap, OLCTransactions) )
560         return FALSE;
561 
562     else if( EQUAL(pszCap, OLCFastGetExtent) )
563         return FALSE;
564 
565     return FALSE;
566 #endif
567 }
568 
569 /************************************************************************/
570 /*                            GetFIDColumn()                            */
571 /************************************************************************/
572 
573 const char *OGRIngresLayer::GetFIDColumn()
574 
575 {
576     return osFIDColumn;
577 }
578 
579 /************************************************************************/
580 /*                         GetGeometryColumn()                          */
581 /************************************************************************/
582 
583 const char *OGRIngresLayer::GetGeometryColumn()
584 
585 {
586     return osGeomColumn;
587 }
588 
589 /************************************************************************/
590 /*                         FetchSRSId()                                 */
591 /************************************************************************/
592 
593 int OGRIngresLayer::FetchSRSId(OGRFeatureDefn *poDefn)
594 {
595 /* -------------------------------------------------------------------- */
596 /*      We only support srses in the new ingres geospatial implementation.*/
597 /* -------------------------------------------------------------------- */
598     if( !poDS->IsNewIngres() )
599     {
600         nSRSId = -1;
601     }
602 
603 /* -------------------------------------------------------------------- */
604 /*      If we haven't queried for the srs id yet, do so now.            */
605 /* -------------------------------------------------------------------- */
606     if( nSRSId == -2 )
607     {
608         OGRIngresStatement oStatement(poDS->GetConn());
609 
610         char szCommand[1024] = {};
611         sprintf( szCommand,
612                  "SELECT srid FROM geometry_columns "
613                  "WHERE f_table_name = '%s' AND f_geometry_column = '%s'",
614                  poDefn->GetName(),
615                  GetGeometryColumn());
616 
617         oStatement.ExecuteSQL(szCommand);
618 
619         char **papszRow = oStatement.GetRow();
620 
621         if( papszRow != NULL && papszRow[0] != NULL )
622         {
623             nSRSId = *((II_INT4 *) papszRow[0]);
624         }
625     }
626 
627     return nSRSId;
628 }
629 
630 /************************************************************************/
631 /*                           GetSpatialRef()                            */
632 /************************************************************************/
633 
634 OGRSpatialReference *OGRIngresLayer::GetSpatialRef()
635 
636 {
637     if( poSRS == NULL && nSRSId > -1 )
638     {
639         poSRS = poDS->FetchSRS( nSRSId );
640         if( poSRS != NULL )
641             poSRS->Reference();
642         else
643             nSRSId = -1;
644     }
645 
646     return poSRS;
647 }
648