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