1 /**********************************************************************
2 * $Id$
3 *
4 * Project: MapServer
5 * Purpose: OGR Link
6 * Author: Daniel Morissette, DM Solutions Group (morissette@dmsolutions.ca)
7 * Frank Warmerdam (warmerdam@pobox.com)
8 *
9 **********************************************************************
10 * Copyright (c) 2000-2005, Daniel Morissette, DM Solutions Group Inc
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 in
20 * all copies of this Software or works derived from this Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * 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 <assert.h>
32 #include "mapserver.h"
33 #include "mapproject.h"
34 #include "mapthread.h"
35 #include "mapows.h"
36 #include <string>
37 #include <vector>
38
39 #include "gdal.h"
40 #include "cpl_conv.h"
41 #include "cpl_string.h"
42 #include "ogr_srs_api.h"
43
44 #define ACQUIRE_OGR_LOCK msAcquireLock( TLOCK_OGR )
45 #define RELEASE_OGR_LOCK msReleaseLock( TLOCK_OGR )
46
47 // GDAL 1.x API
48 #include "ogr_api.h"
49
50 typedef struct ms_ogr_file_info_t {
51 char *pszFname;
52 char *pszLayerDef;
53 int nLayerIndex;
54 OGRDataSourceH hDS;
55 OGRLayerH hLayer;
56 OGRFeatureH hLastFeature;
57
58 int nTileId; /* applies on the tiles themselves. */
59 projectionObj sTileProj; /* applies on the tiles themselves. */
60
61 struct ms_ogr_file_info_t *poCurTile; /* exists on tile index, -> tiles */
62 bool rect_is_defined;
63 rectObj rect; /* set by TranslateMsExpression (possibly) and WhichShapes */
64
65 int last_record_index_read;
66
67 const char* dialect; /* NULL, Spatialite or PostgreSQL */
68 char *pszSelect;
69 char *pszSpatialFilterTableName;
70 char *pszSpatialFilterGeometryColumn;
71 char *pszMainTableName;
72 char *pszRowId;
73 int bIsOKForSQLCompose;
74 bool bHasSpatialIndex; // used only for spatialite for now
75 char* pszTablePrefix; // prefix to qualify field names. used only for spatialite & gpkg for now when a join is done for spatial filtering.
76
77 int bPaging;
78
79 char* pszWHERE;
80
81 } msOGRFileInfo;
82
83 static int msOGRLayerIsOpen(layerObj *layer);
84 static int msOGRLayerInitItemInfo(layerObj *layer);
85 static int msOGRLayerGetAutoStyle(mapObj *map, layerObj *layer, classObj *c,
86 shapeObj* shape);
87 static void msOGRCloseConnection( void *conn_handle );
88
89 /* ==================================================================
90 * Geometry conversion functions
91 * ================================================================== */
92
93 /**********************************************************************
94 * ogrPointsAddPoint()
95 *
96 * NOTE: This function assumes the line->point array already has been
97 * allocated large enough for the point to be added, but that numpoints
98 * does not include this new point.
99 **********************************************************************/
ogrPointsAddPoint(lineObj * line,double dX,double dY,double dZ,int lineindex,rectObj * bounds)100 static void ogrPointsAddPoint(lineObj *line, double dX, double dY,
101 #ifdef USE_POINT_Z_M
102 double dZ,
103 #endif
104 int lineindex, rectObj *bounds)
105 {
106 /* Keep track of shape bounds */
107 if (line->numpoints == 0 && lineindex == 0) {
108 bounds->minx = bounds->maxx = dX;
109 bounds->miny = bounds->maxy = dY;
110 } else {
111 if (dX < bounds->minx) bounds->minx = dX;
112 if (dX > bounds->maxx) bounds->maxx = dX;
113 if (dY < bounds->miny) bounds->miny = dY;
114 if (dY > bounds->maxy) bounds->maxy = dY;
115 }
116
117 line->point[line->numpoints].x = dX;
118 line->point[line->numpoints].y = dY;
119 #ifdef USE_POINT_Z_M
120 line->point[line->numpoints].z = dZ;
121 line->point[line->numpoints].m = 0.0;
122 #endif
123 line->numpoints++;
124 }
125
126 /**********************************************************************
127 * ogrGeomPoints()
128 **********************************************************************/
ogrGeomPoints(OGRGeometryH hGeom,shapeObj * outshp)129 static int ogrGeomPoints(OGRGeometryH hGeom, shapeObj *outshp)
130 {
131 int i;
132 int numpoints;
133
134 if (hGeom == NULL)
135 return 0;
136
137 OGRwkbGeometryType eGType = wkbFlatten( OGR_G_GetGeometryType( hGeom ) );
138
139 /* -------------------------------------------------------------------- */
140 /* Container types result in recursive invocation on each */
141 /* subobject to add a set of points to the current list. */
142 /* -------------------------------------------------------------------- */
143 switch( eGType ) {
144 case wkbGeometryCollection:
145 case wkbMultiLineString:
146 case wkbMultiPolygon:
147 case wkbPolygon: {
148 /* Treat it as GeometryCollection */
149 for (int iGeom=0; iGeom < OGR_G_GetGeometryCount( hGeom ); iGeom++ ) {
150 if( ogrGeomPoints( OGR_G_GetGeometryRef( hGeom, iGeom ),
151 outshp ) == -1 )
152 return -1;
153 }
154
155 return 0;
156 }
157 break;
158
159 case wkbPoint:
160 case wkbMultiPoint:
161 case wkbLineString:
162 case wkbLinearRing:
163 /* We will handle these directly */
164 break;
165
166 default:
167 /* There shouldn't be any more cases should there? */
168 msSetError(MS_OGRERR,
169 "OGRGeometry type `%s' not supported yet.",
170 "ogrGeomPoints()",
171 OGR_G_GetGeometryName( hGeom ) );
172 return(-1);
173 }
174
175
176 /* ------------------------------------------------------------------
177 * Count total number of points
178 * ------------------------------------------------------------------ */
179 if ( eGType == wkbPoint ) {
180 numpoints = 1;
181 } else if ( eGType == wkbLineString
182 || eGType == wkbLinearRing ) {
183 numpoints = OGR_G_GetPointCount( hGeom );
184 } else if ( eGType == wkbMultiPoint ) {
185 numpoints = OGR_G_GetGeometryCount( hGeom );
186 } else {
187 msSetError(MS_OGRERR,
188 "OGRGeometry type `%s' not supported yet.",
189 "ogrGeomPoints()",
190 OGR_G_GetGeometryName( hGeom ) );
191 return(-1);
192 }
193
194 /* ------------------------------------------------------------------
195 * Do we need to allocate a line object to contain all our points?
196 * ------------------------------------------------------------------ */
197 if( outshp->numlines == 0 ) {
198 lineObj newline;
199
200 newline.numpoints = 0;
201 newline.point = NULL;
202 msAddLine(outshp, &newline);
203 }
204
205 /* ------------------------------------------------------------------
206 * Extend the point array for the new of points to add from the
207 * current geometry.
208 * ------------------------------------------------------------------ */
209 lineObj *line = outshp->line + outshp->numlines-1;
210
211 if( line->point == NULL )
212 line->point = (pointObj *) malloc(sizeof(pointObj) * numpoints);
213 else
214 line->point = (pointObj *)
215 realloc(line->point,sizeof(pointObj) * (numpoints+line->numpoints));
216
217 if(!line->point) {
218 msSetError(MS_MEMERR, "Unable to allocate temporary point cache.",
219 "ogrGeomPoints()");
220 return(-1);
221 }
222
223 /* ------------------------------------------------------------------
224 * alloc buffer and filter/transform points
225 * ------------------------------------------------------------------ */
226 if( eGType == wkbPoint ) {
227 ogrPointsAddPoint(line, OGR_G_GetX(hGeom, 0), OGR_G_GetY(hGeom, 0),
228 #ifdef USE_POINT_Z_M
229 OGR_G_GetZ(hGeom, 0),
230 #endif
231 outshp->numlines-1, &(outshp->bounds));
232 } else if( eGType == wkbLineString
233 || eGType == wkbLinearRing ) {
234 for(i=0; i<numpoints; i++)
235 ogrPointsAddPoint(line, OGR_G_GetX(hGeom, i), OGR_G_GetY(hGeom, i),
236 #ifdef USE_POINT_Z_M
237 OGR_G_GetZ(hGeom, i),
238 #endif
239 outshp->numlines-1, &(outshp->bounds));
240 } else if( eGType == wkbMultiPoint ) {
241 for(i=0; i<numpoints; i++) {
242 OGRGeometryH hPoint = OGR_G_GetGeometryRef( hGeom, i );
243 ogrPointsAddPoint(line, OGR_G_GetX(hPoint, 0), OGR_G_GetY(hPoint, 0),
244 #ifdef USE_POINT_Z_M
245 OGR_G_GetZ(hPoint, 0),
246 #endif
247 outshp->numlines-1, &(outshp->bounds));
248 }
249 }
250
251 outshp->type = MS_SHAPE_POINT;
252
253 return(0);
254 }
255
256
257 /**********************************************************************
258 * ogrGeomLine()
259 *
260 * Recursively convert any OGRGeometry into a shapeObj. Each part becomes
261 * a line in the overall shapeObj.
262 **********************************************************************/
ogrGeomLine(OGRGeometryH hGeom,shapeObj * outshp,int bCloseRings)263 static int ogrGeomLine(OGRGeometryH hGeom, shapeObj *outshp,
264 int bCloseRings)
265 {
266 if (hGeom == NULL)
267 return 0;
268
269 /* ------------------------------------------------------------------
270 * Use recursive calls for complex geometries
271 * ------------------------------------------------------------------ */
272 OGRwkbGeometryType eGType = wkbFlatten( OGR_G_GetGeometryType( hGeom ) );
273
274
275 if ( eGType == wkbPolygon
276 || eGType == wkbGeometryCollection
277 || eGType == wkbMultiLineString
278 || eGType == wkbMultiPolygon ) {
279 if (eGType == wkbPolygon && outshp->type == MS_SHAPE_NULL)
280 outshp->type = MS_SHAPE_POLYGON;
281
282 /* Treat it as GeometryCollection */
283 for (int iGeom=0; iGeom < OGR_G_GetGeometryCount( hGeom ); iGeom++ ) {
284 if( ogrGeomLine( OGR_G_GetGeometryRef( hGeom, iGeom ),
285 outshp, bCloseRings ) == -1 )
286 return -1;
287 }
288 }
289 /* ------------------------------------------------------------------
290 * OGRPoint and OGRMultiPoint
291 * ------------------------------------------------------------------ */
292 else if ( eGType == wkbPoint || eGType == wkbMultiPoint ) {
293 /* Hummmm a point when we're drawing lines/polygons... just drop it! */
294 }
295 /* ------------------------------------------------------------------
296 * OGRLinearRing/OGRLineString ... both are of type wkbLineString
297 * ------------------------------------------------------------------ */
298 else if ( eGType == wkbLineString ) {
299 int j, numpoints;
300 lineObj line= {0,NULL};
301 double dX, dY;
302
303 if ((numpoints = OGR_G_GetPointCount( hGeom )) < 2)
304 return 0;
305
306 if (outshp->type == MS_SHAPE_NULL)
307 outshp->type = MS_SHAPE_LINE;
308
309 line.numpoints = 0;
310 line.point = (pointObj *)malloc(sizeof(pointObj)*(numpoints+1));
311 if(!line.point) {
312 msSetError(MS_MEMERR, "Unable to allocate temporary point cache.",
313 "ogrGeomLine");
314 return(-1);
315 }
316
317 OGR_G_GetPoints(hGeom,
318 &(line.point[0].x), sizeof(pointObj),
319 &(line.point[0].y), sizeof(pointObj),
320 #ifdef USE_POINT_Z_M
321 &(line.point[0].z), sizeof(pointObj));
322 #else
323 NULL, 0);
324 #endif
325
326 for(j=0; j<numpoints; j++) {
327 dX = line.point[j].x = OGR_G_GetX( hGeom, j);
328 dY = line.point[j].y = OGR_G_GetY( hGeom, j);
329
330 /* Keep track of shape bounds */
331 if (j == 0 && outshp->numlines == 0) {
332 outshp->bounds.minx = outshp->bounds.maxx = dX;
333 outshp->bounds.miny = outshp->bounds.maxy = dY;
334 } else {
335 if (dX < outshp->bounds.minx) outshp->bounds.minx = dX;
336 if (dX > outshp->bounds.maxx) outshp->bounds.maxx = dX;
337 if (dY < outshp->bounds.miny) outshp->bounds.miny = dY;
338 if (dY > outshp->bounds.maxy) outshp->bounds.maxy = dY;
339 }
340
341 }
342 line.numpoints = numpoints;
343
344 if (bCloseRings &&
345 ( line.point[line.numpoints-1].x != line.point[0].x ||
346 line.point[line.numpoints-1].y != line.point[0].y ) ) {
347 line.point[line.numpoints].x = line.point[0].x;
348 line.point[line.numpoints].y = line.point[0].y;
349 #ifdef USE_POINT_Z_M
350 line.point[line.numpoints].z = line.point[0].z;
351 #endif
352 line.numpoints++;
353 }
354
355 msAddLineDirectly(outshp, &line);
356 } else {
357 msSetError(MS_OGRERR,
358 "OGRGeometry type `%s' not supported.",
359 "ogrGeomLine()",
360 OGR_G_GetGeometryName( hGeom ) );
361 return(-1);
362 }
363
364 return(0);
365 }
366
367 /**********************************************************************
368 * ogrGetLinearGeometry()
369 *
370 * Fetch geometry from OGR feature. If using GDAL 2.0 or later, the geometry
371 * might be of curve type, so linearize it.
372 **********************************************************************/
ogrGetLinearGeometry(OGRFeatureH hFeature)373 static OGRGeometryH ogrGetLinearGeometry(OGRFeatureH hFeature)
374 {
375 #if GDAL_VERSION_MAJOR >= 2
376 /* Convert in place and reassign to the feature */
377 OGRGeometryH hGeom = OGR_F_StealGeometry(hFeature);
378 if( hGeom != NULL )
379 {
380 hGeom = OGR_G_ForceTo(hGeom, OGR_GT_GetLinear(OGR_G_GetGeometryType(hGeom)), NULL);
381 OGR_F_SetGeometryDirectly(hFeature, hGeom);
382 }
383 return hGeom;
384 #else
385 return OGR_F_GetGeometryRef( hFeature );
386 #endif
387 }
388
389 /**********************************************************************
390 * ogrConvertGeometry()
391 *
392 * Convert OGR geometry into a shape object doing the best possible
393 * job to match OGR Geometry type and layer type.
394 *
395 * If layer type is incompatible with geometry, then shape is returned with
396 * shape->type = MS_SHAPE_NULL
397 **********************************************************************/
ogrConvertGeometry(OGRGeometryH hGeom,shapeObj * outshp,enum MS_LAYER_TYPE layertype)398 static int ogrConvertGeometry(OGRGeometryH hGeom, shapeObj *outshp,
399 enum MS_LAYER_TYPE layertype)
400 {
401 /* ------------------------------------------------------------------
402 * Process geometry according to layer type
403 * ------------------------------------------------------------------ */
404 int nStatus = MS_SUCCESS;
405
406 if (hGeom == NULL) {
407 // Empty geometry... this is not an error... we'll just skip it
408 return MS_SUCCESS;
409 }
410
411 switch(layertype) {
412 /* ------------------------------------------------------------------
413 * POINT layer - Any geometry can be converted to point/multipoint
414 * ------------------------------------------------------------------ */
415 case MS_LAYER_POINT:
416 if(ogrGeomPoints(hGeom, outshp) == -1) {
417 nStatus = MS_FAILURE; // Error message already produced.
418 }
419 break;
420 /* ------------------------------------------------------------------
421 * LINE layer
422 * ------------------------------------------------------------------ */
423 case MS_LAYER_LINE:
424 if(ogrGeomLine(hGeom, outshp, MS_FALSE) == -1) {
425 nStatus = MS_FAILURE; // Error message already produced.
426 }
427 if (outshp->type != MS_SHAPE_LINE && outshp->type != MS_SHAPE_POLYGON)
428 outshp->type = MS_SHAPE_NULL; // Incompatible type for this layer
429 break;
430 /* ------------------------------------------------------------------
431 * POLYGON layer
432 * ------------------------------------------------------------------ */
433 case MS_LAYER_POLYGON:
434 if(ogrGeomLine(hGeom, outshp, MS_TRUE) == -1) {
435 nStatus = MS_FAILURE; // Error message already produced.
436 }
437 if (outshp->type != MS_SHAPE_POLYGON)
438 outshp->type = MS_SHAPE_NULL; // Incompatible type for this layer
439 break;
440 /* ------------------------------------------------------------------
441 * Chart or Query layers - return real feature type
442 * ------------------------------------------------------------------ */
443 case MS_LAYER_CHART:
444 case MS_LAYER_QUERY:
445 switch( OGR_G_GetGeometryType( hGeom ) ) {
446 case wkbPoint:
447 case wkbPoint25D:
448 case wkbMultiPoint:
449 case wkbMultiPoint25D:
450 if(ogrGeomPoints(hGeom, outshp) == -1) {
451 nStatus = MS_FAILURE; // Error message already produced.
452 }
453 break;
454 default:
455 // Handle any non-point types as lines/polygons ... ogrGeomLine()
456 // will decide the shape type
457 if(ogrGeomLine(hGeom, outshp, MS_FALSE) == -1) {
458 nStatus = MS_FAILURE; // Error message already produced.
459 }
460 }
461 break;
462
463 default:
464 msSetError(MS_MISCERR, "Unknown or unsupported layer type.",
465 "msOGRLayerNextShape()");
466 nStatus = MS_FAILURE;
467 } /* switch layertype */
468
469 return nStatus;
470 }
471
472 /**********************************************************************
473 * msOGRGeometryToShape()
474 *
475 * Utility function to convert from OGR geometry to a mapserver shape
476 * object.
477 **********************************************************************/
msOGRGeometryToShape(OGRGeometryH hGeometry,shapeObj * psShape,OGRwkbGeometryType nType)478 int msOGRGeometryToShape(OGRGeometryH hGeometry, shapeObj *psShape,
479 OGRwkbGeometryType nType)
480 {
481 if (hGeometry && psShape && nType > 0) {
482 if (nType == wkbPoint || nType == wkbMultiPoint )
483 return ogrConvertGeometry(hGeometry, psShape, MS_LAYER_POINT);
484 else if (nType == wkbLineString || nType == wkbMultiLineString)
485 return ogrConvertGeometry(hGeometry, psShape, MS_LAYER_LINE);
486 else if (nType == wkbPolygon || nType == wkbMultiPolygon)
487 return ogrConvertGeometry(hGeometry, psShape, MS_LAYER_POLYGON);
488 else
489 return MS_FAILURE;
490 } else
491 return MS_FAILURE;
492 }
493
494
495 /* ==================================================================
496 * Attributes handling functions
497 * ================================================================== */
498
499 // Special field index codes for handling text string and angle coming from
500 // OGR style strings.
501
502 #define MSOGR_FID_INDEX -99
503
504 #define MSOGR_LABELNUMITEMS 21
505 #define MSOGR_LABELFONTNAMENAME "OGR:LabelFont"
506 #define MSOGR_LABELFONTNAMEINDEX -100
507 #define MSOGR_LABELSIZENAME "OGR:LabelSize"
508 #define MSOGR_LABELSIZEINDEX -101
509 #define MSOGR_LABELTEXTNAME "OGR:LabelText"
510 #define MSOGR_LABELTEXTINDEX -102
511 #define MSOGR_LABELANGLENAME "OGR:LabelAngle"
512 #define MSOGR_LABELANGLEINDEX -103
513 #define MSOGR_LABELFCOLORNAME "OGR:LabelFColor"
514 #define MSOGR_LABELFCOLORINDEX -104
515 #define MSOGR_LABELBCOLORNAME "OGR:LabelBColor"
516 #define MSOGR_LABELBCOLORINDEX -105
517 #define MSOGR_LABELPLACEMENTNAME "OGR:LabelPlacement"
518 #define MSOGR_LABELPLACEMENTINDEX -106
519 #define MSOGR_LABELANCHORNAME "OGR:LabelAnchor"
520 #define MSOGR_LABELANCHORINDEX -107
521 #define MSOGR_LABELDXNAME "OGR:LabelDx"
522 #define MSOGR_LABELDXINDEX -108
523 #define MSOGR_LABELDYNAME "OGR:LabelDy"
524 #define MSOGR_LABELDYINDEX -109
525 #define MSOGR_LABELPERPNAME "OGR:LabelPerp"
526 #define MSOGR_LABELPERPINDEX -110
527 #define MSOGR_LABELBOLDNAME "OGR:LabelBold"
528 #define MSOGR_LABELBOLDINDEX -111
529 #define MSOGR_LABELITALICNAME "OGR:LabelItalic"
530 #define MSOGR_LABELITALICINDEX -112
531 #define MSOGR_LABELUNDERLINENAME "OGR:LabelUnderline"
532 #define MSOGR_LABELUNDERLINEINDEX -113
533 #define MSOGR_LABELPRIORITYNAME "OGR:LabelPriority"
534 #define MSOGR_LABELPRIORITYINDEX -114
535 #define MSOGR_LABELSTRIKEOUTNAME "OGR:LabelStrikeout"
536 #define MSOGR_LABELSTRIKEOUTINDEX -115
537 #define MSOGR_LABELSTRETCHNAME "OGR:LabelStretch"
538 #define MSOGR_LABELSTRETCHINDEX -116
539 #define MSOGR_LABELADJHORNAME "OGR:LabelAdjHor"
540 #define MSOGR_LABELADJHORINDEX -117
541 #define MSOGR_LABELADJVERTNAME "OGR:LabelAdjVert"
542 #define MSOGR_LABELADJVERTINDEX -118
543 #define MSOGR_LABELHCOLORNAME "OGR:LabelHColor"
544 #define MSOGR_LABELHCOLORINDEX -119
545 #define MSOGR_LABELOCOLORNAME "OGR:LabelOColor"
546 #define MSOGR_LABELOCOLORINDEX -120
547 // Special codes for the OGR style parameters
548 #define MSOGR_LABELPARAMNAME "OGR:LabelParam"
549 #define MSOGR_LABELPARAMNAMELEN 14
550 #define MSOGR_LABELPARAMINDEX -500
551 #define MSOGR_BRUSHPARAMNAME "OGR:BrushParam"
552 #define MSOGR_BRUSHPARAMNAMELEN 14
553 #define MSOGR_BRUSHPARAMINDEX -600
554 #define MSOGR_PENPARAMNAME "OGR:PenParam"
555 #define MSOGR_PENPARAMNAMELEN 12
556 #define MSOGR_PENPARAMINDEX -700
557 #define MSOGR_SYMBOLPARAMNAME "OGR:SymbolParam"
558 #define MSOGR_SYMBOLPARAMNAMELEN 15
559 #define MSOGR_SYMBOLPARAMINDEX -800
560
561 /**********************************************************************
562 * msOGRGetValues()
563 *
564 * Load selected item (i.e. field) values into a char array
565 *
566 * Some special attribute names are used to return some OGRFeature params
567 * like for instance stuff encoded in the OGRStyleString.
568 * For now the following pseudo-attribute names are supported:
569 * "OGR:TextString" OGRFeatureStyle's text string if present
570 * "OGR:TextAngle" OGRFeatureStyle's text angle, or 0 if not set
571 **********************************************************************/
msOGRGetValues(layerObj * layer,OGRFeatureH hFeature)572 static char **msOGRGetValues(layerObj *layer, OGRFeatureH hFeature)
573 {
574 char **values;
575 const char *pszValue = NULL;
576 int i;
577
578 if(layer->numitems == 0)
579 return(NULL);
580
581 if(!layer->iteminfo) // Should not happen... but just in case!
582 if (msOGRLayerInitItemInfo(layer) != MS_SUCCESS)
583 return NULL;
584
585 if((values = (char **)malloc(sizeof(char *)*layer->numitems)) == NULL) {
586 msSetError(MS_MEMERR, NULL, "msOGRGetValues()");
587 return(NULL);
588 }
589
590 OGRStyleMgrH hStyleMgr = NULL;
591 OGRStyleToolH hLabelStyle = NULL;
592 OGRStyleToolH hPenStyle = NULL;
593 OGRStyleToolH hBrushStyle = NULL;
594 OGRStyleToolH hSymbolStyle = NULL;
595
596 int *itemindexes = (int*)layer->iteminfo;
597
598 for(i=0; i<layer->numitems; i++) {
599 if (itemindexes[i] >= 0) {
600 // Extract regular attributes
601 values[i] = msStrdup(OGR_F_GetFieldAsString( hFeature, itemindexes[i]));
602 } else if (itemindexes[i] == MSOGR_FID_INDEX ) {
603 values[i] = msStrdup(CPLSPrintf(CPL_FRMT_GIB,
604 (GIntBig) OGR_F_GetFID(hFeature)));
605 } else {
606 // Handle special OGR attributes coming from StyleString
607 if (!hStyleMgr) {
608 hStyleMgr = OGR_SM_Create(NULL);
609 OGR_SM_InitFromFeature(hStyleMgr, hFeature);
610 int numParts = OGR_SM_GetPartCount(hStyleMgr, NULL);
611 for(int i=0; i<numParts; i++) {
612 OGRStyleToolH hStylePart = OGR_SM_GetPart(hStyleMgr, i, NULL);
613 if (hStylePart) {
614 if (OGR_ST_GetType(hStylePart) == OGRSTCLabel && !hLabelStyle)
615 hLabelStyle = hStylePart;
616 else if (OGR_ST_GetType(hStylePart) == OGRSTCPen && !hPenStyle)
617 hPenStyle = hStylePart;
618 else if (OGR_ST_GetType(hStylePart) == OGRSTCBrush && !hBrushStyle)
619 hBrushStyle = hStylePart;
620 else if (OGR_ST_GetType(hStylePart) == OGRSTCSymbol && !hSymbolStyle)
621 hSymbolStyle = hStylePart;
622 else {
623 OGR_ST_Destroy(hStylePart);
624 hStylePart = NULL;
625 }
626 }
627 /* Setting up the size units according to msOGRLayerGetAutoStyle*/
628 if (hStylePart && layer->map)
629 OGR_ST_SetUnit(hStylePart, OGRSTUPixel,
630 layer->map->cellsize*layer->map->resolution/layer->map->defresolution*72.0*39.37);
631 }
632 }
633 int bDefault;
634 if (itemindexes[i] == MSOGR_LABELTEXTINDEX) {
635 if (hLabelStyle == NULL
636 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
637 OGRSTLabelTextString,
638 &bDefault)) == NULL))
639 values[i] = msStrdup("");
640 else
641 values[i] = msStrdup(pszValue);
642
643 if (layer->debug >= MS_DEBUGLEVEL_VVV)
644 msDebug(MSOGR_LABELTEXTNAME " = \"%s\"\n", values[i]);
645 } else if (itemindexes[i] == MSOGR_LABELANGLEINDEX) {
646 if (hLabelStyle == NULL
647 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
648 OGRSTLabelAngle,
649 &bDefault)) == NULL))
650 values[i] = msStrdup("0");
651 else
652 values[i] = msStrdup(pszValue);
653
654 if (layer->debug >= MS_DEBUGLEVEL_VVV)
655 msDebug(MSOGR_LABELANGLENAME " = \"%s\"\n", values[i]);
656 } else if (itemindexes[i] == MSOGR_LABELSIZEINDEX) {
657 if (hLabelStyle == NULL
658 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
659 OGRSTLabelSize,
660 &bDefault)) == NULL))
661 values[i] = msStrdup("0");
662 else
663 values[i] = msStrdup(pszValue);
664
665 if (layer->debug >= MS_DEBUGLEVEL_VVV)
666 msDebug(MSOGR_LABELSIZENAME " = \"%s\"\n", values[i]);
667 } else if (itemindexes[i] == MSOGR_LABELFCOLORINDEX) {
668 if (hLabelStyle == NULL
669 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
670 OGRSTLabelFColor,
671 &bDefault)) == NULL))
672 values[i] = msStrdup("#000000");
673 else
674 values[i] = msStrdup(pszValue);
675
676 if (layer->debug >= MS_DEBUGLEVEL_VVV)
677 msDebug(MSOGR_LABELFCOLORNAME " = \"%s\"\n", values[i]);
678 } else if (itemindexes[i] == MSOGR_LABELFONTNAMEINDEX ) {
679 if (hLabelStyle == NULL
680 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
681 OGRSTLabelFontName,
682 &bDefault)) == NULL))
683 values[i] = msStrdup("Arial");
684 else
685 values[i] = msStrdup(pszValue);
686
687 if (layer->debug >= MS_DEBUGLEVEL_VVV)
688 msDebug(MSOGR_LABELFONTNAMENAME " = \"%s\"\n", values[i]);
689 } else if (itemindexes[i] == MSOGR_LABELBCOLORINDEX) {
690 if (hLabelStyle == NULL
691 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
692 OGRSTLabelBColor,
693 &bDefault)) == NULL))
694 values[i] = msStrdup("#000000");
695 else
696 values[i] = msStrdup(pszValue);
697
698 if (layer->debug >= MS_DEBUGLEVEL_VVV)
699 msDebug(MSOGR_LABELBCOLORNAME " = \"%s\"\n", values[i]);
700 } else if (itemindexes[i] == MSOGR_LABELPLACEMENTINDEX) {
701 if (hLabelStyle == NULL
702 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
703 OGRSTLabelPlacement,
704 &bDefault)) == NULL))
705 values[i] = msStrdup("");
706 else
707 values[i] = msStrdup(pszValue);
708
709 if (layer->debug >= MS_DEBUGLEVEL_VVV)
710 msDebug(MSOGR_LABELPLACEMENTNAME " = \"%s\"\n", values[i]);
711 } else if (itemindexes[i] == MSOGR_LABELANCHORINDEX) {
712 if (hLabelStyle == NULL
713 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
714 OGRSTLabelAnchor,
715 &bDefault)) == NULL))
716 values[i] = msStrdup("0");
717 else
718 values[i] = msStrdup(pszValue);
719
720 if (layer->debug >= MS_DEBUGLEVEL_VVV)
721 msDebug(MSOGR_LABELANCHORNAME " = \"%s\"\n", values[i]);
722 } else if (itemindexes[i] == MSOGR_LABELDXINDEX) {
723 if (hLabelStyle == NULL
724 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
725 OGRSTLabelDx,
726 &bDefault)) == NULL))
727 values[i] = msStrdup("0");
728 else
729 values[i] = msStrdup(pszValue);
730
731 if (layer->debug >= MS_DEBUGLEVEL_VVV)
732 msDebug(MSOGR_LABELDXNAME " = \"%s\"\n", values[i]);
733 } else if (itemindexes[i] == MSOGR_LABELDYINDEX) {
734 if (hLabelStyle == NULL
735 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
736 OGRSTLabelDy,
737 &bDefault)) == NULL))
738 values[i] = msStrdup("0");
739 else
740 values[i] = msStrdup(pszValue);
741
742 if (layer->debug >= MS_DEBUGLEVEL_VVV)
743 msDebug(MSOGR_LABELDYNAME " = \"%s\"\n", values[i]);
744 } else if (itemindexes[i] == MSOGR_LABELPERPINDEX) {
745 if (hLabelStyle == NULL
746 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
747 OGRSTLabelPerp,
748 &bDefault)) == NULL))
749 values[i] = msStrdup("0");
750 else
751 values[i] = msStrdup(pszValue);
752
753 if (layer->debug >= MS_DEBUGLEVEL_VVV)
754 msDebug(MSOGR_LABELPERPNAME " = \"%s\"\n", values[i]);
755 } else if (itemindexes[i] == MSOGR_LABELBOLDINDEX) {
756 if (hLabelStyle == NULL
757 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
758 OGRSTLabelBold,
759 &bDefault)) == NULL))
760 values[i] = msStrdup("0");
761 else
762 values[i] = msStrdup(pszValue);
763
764 if (layer->debug >= MS_DEBUGLEVEL_VVV)
765 msDebug(MSOGR_LABELBOLDNAME " = \"%s\"\n", values[i]);
766 } else if (itemindexes[i] == MSOGR_LABELITALICINDEX) {
767 if (hLabelStyle == NULL
768 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
769 OGRSTLabelItalic,
770 &bDefault)) == NULL))
771 values[i] = msStrdup("0");
772 else
773 values[i] = msStrdup(pszValue);
774
775 if (layer->debug >= MS_DEBUGLEVEL_VVV)
776 msDebug(MSOGR_LABELITALICNAME " = \"%s\"\n", values[i]);
777 } else if (itemindexes[i] == MSOGR_LABELUNDERLINEINDEX) {
778 if (hLabelStyle == NULL
779 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
780 OGRSTLabelUnderline,
781 &bDefault)) == NULL))
782 values[i] = msStrdup("0");
783 else
784 values[i] = msStrdup(pszValue);
785
786 if (layer->debug >= MS_DEBUGLEVEL_VVV)
787 msDebug(MSOGR_LABELUNDERLINENAME " = \"%s\"\n", values[i]);
788 } else if (itemindexes[i] == MSOGR_LABELPRIORITYINDEX) {
789 if (hLabelStyle == NULL
790 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
791 OGRSTLabelPriority,
792 &bDefault)) == NULL))
793 values[i] = msStrdup("0");
794 else
795 values[i] = msStrdup(pszValue);
796
797 if (layer->debug >= MS_DEBUGLEVEL_VVV)
798 msDebug(MSOGR_LABELPRIORITYNAME " = \"%s\"\n", values[i]);
799 } else if (itemindexes[i] == MSOGR_LABELSTRIKEOUTINDEX) {
800 if (hLabelStyle == NULL
801 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
802 OGRSTLabelStrikeout,
803 &bDefault)) == NULL))
804 values[i] = msStrdup("0");
805 else
806 values[i] = msStrdup(pszValue);
807
808 if (layer->debug >= MS_DEBUGLEVEL_VVV)
809 msDebug(MSOGR_LABELSTRIKEOUTNAME " = \"%s\"\n", values[i]);
810 } else if (itemindexes[i] == MSOGR_LABELSTRETCHINDEX) {
811 if (hLabelStyle == NULL
812 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
813 OGRSTLabelStretch,
814 &bDefault)) == NULL))
815 values[i] = msStrdup("0");
816 else
817 values[i] = msStrdup(pszValue);
818
819 if (layer->debug >= MS_DEBUGLEVEL_VVV)
820 msDebug(MSOGR_LABELSTRETCHNAME " = \"%s\"\n", values[i]);
821 } else if (itemindexes[i] == MSOGR_LABELADJHORINDEX) {
822 if (hLabelStyle == NULL
823 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
824 OGRSTLabelAdjHor,
825 &bDefault)) == NULL))
826 values[i] = msStrdup("");
827 else
828 values[i] = msStrdup(pszValue);
829
830 if (layer->debug >= MS_DEBUGLEVEL_VVV)
831 msDebug(MSOGR_LABELADJHORNAME " = \"%s\"\n", values[i]);
832 } else if (itemindexes[i] == MSOGR_LABELADJVERTINDEX) {
833 if (hLabelStyle == NULL
834 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
835 OGRSTLabelAdjVert,
836 &bDefault)) == NULL))
837 values[i] = msStrdup("");
838 else
839 values[i] = msStrdup(pszValue);
840
841 if (layer->debug >= MS_DEBUGLEVEL_VVV)
842 msDebug(MSOGR_LABELADJVERTNAME " = \"%s\"\n", values[i]);
843 } else if (itemindexes[i] == MSOGR_LABELHCOLORINDEX) {
844 if (hLabelStyle == NULL
845 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
846 OGRSTLabelHColor,
847 &bDefault)) == NULL))
848 values[i] = msStrdup("");
849 else
850 values[i] = msStrdup(pszValue);
851
852 if (layer->debug >= MS_DEBUGLEVEL_VVV)
853 msDebug(MSOGR_LABELHCOLORNAME " = \"%s\"\n", values[i]);
854 }
855 else if (itemindexes[i] == MSOGR_LABELOCOLORINDEX) {
856 if (hLabelStyle == NULL
857 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
858 OGRSTLabelOColor,
859 &bDefault)) == NULL))
860 values[i] = msStrdup("");
861 else
862 values[i] = msStrdup(pszValue);
863
864 if (layer->debug >= MS_DEBUGLEVEL_VVV)
865 msDebug(MSOGR_LABELOCOLORNAME " = \"%s\"\n", values[i]);
866 }
867 else if (itemindexes[i] >= MSOGR_LABELPARAMINDEX) {
868 if (hLabelStyle == NULL
869 || ((pszValue = OGR_ST_GetParamStr(hLabelStyle,
870 itemindexes[i] - MSOGR_LABELPARAMINDEX,
871 &bDefault)) == NULL))
872 values[i] = msStrdup("");
873 else
874 values[i] = msStrdup(pszValue);
875
876 if (layer->debug >= MS_DEBUGLEVEL_VVV)
877 msDebug(MSOGR_LABELPARAMNAME " = \"%s\"\n", values[i]);
878 }
879 else if (itemindexes[i] >= MSOGR_BRUSHPARAMINDEX) {
880 if (hBrushStyle == NULL
881 || ((pszValue = OGR_ST_GetParamStr(hBrushStyle,
882 itemindexes[i] - MSOGR_BRUSHPARAMINDEX,
883 &bDefault)) == NULL))
884 values[i] = msStrdup("");
885 else
886 values[i] = msStrdup(pszValue);
887
888 if (layer->debug >= MS_DEBUGLEVEL_VVV)
889 msDebug(MSOGR_BRUSHPARAMNAME " = \"%s\"\n", values[i]);
890 }
891 else if (itemindexes[i] >= MSOGR_PENPARAMINDEX) {
892 if (hPenStyle == NULL
893 || ((pszValue = OGR_ST_GetParamStr(hPenStyle,
894 itemindexes[i] - MSOGR_PENPARAMINDEX,
895 &bDefault)) == NULL))
896 values[i] = msStrdup("");
897 else
898 values[i] = msStrdup(pszValue);
899
900 if (layer->debug >= MS_DEBUGLEVEL_VVV)
901 msDebug(MSOGR_PENPARAMNAME " = \"%s\"\n", values[i]);
902 }
903 else if (itemindexes[i] >= MSOGR_SYMBOLPARAMINDEX) {
904 if (hSymbolStyle == NULL
905 || ((pszValue = OGR_ST_GetParamStr(hSymbolStyle,
906 itemindexes[i] - MSOGR_SYMBOLPARAMINDEX,
907 &bDefault)) == NULL))
908 values[i] = msStrdup("");
909 else
910 values[i] = msStrdup(pszValue);
911
912 if (layer->debug >= MS_DEBUGLEVEL_VVV)
913 msDebug(MSOGR_SYMBOLPARAMNAME " = \"%s\"\n", values[i]);
914 }
915 else {
916 msFreeCharArray(values,i);
917
918 OGR_SM_Destroy(hStyleMgr);
919 OGR_ST_Destroy(hLabelStyle);
920 OGR_ST_Destroy(hPenStyle);
921 OGR_ST_Destroy(hBrushStyle);
922 OGR_ST_Destroy(hSymbolStyle);
923
924 msSetError(MS_OGRERR,"Invalid field index!?!","msOGRGetValues()");
925 return(NULL);
926 }
927 }
928 }
929
930 OGR_SM_Destroy(hStyleMgr);
931 OGR_ST_Destroy(hLabelStyle);
932 OGR_ST_Destroy(hPenStyle);
933 OGR_ST_Destroy(hBrushStyle);
934 OGR_ST_Destroy(hSymbolStyle);
935
936 return(values);
937 }
938
939 /**********************************************************************
940 * msOGRSpatialRef2ProjectionObj()
941 *
942 * Init a MapServer projectionObj using an OGRSpatialRef
943 * Works only with PROJECTION AUTO
944 *
945 * Returns MS_SUCCESS/MS_FAILURE
946 **********************************************************************/
msOGRSpatialRef2ProjectionObj(OGRSpatialReferenceH hSRS,projectionObj * proj,int debug_flag)947 static int msOGRSpatialRef2ProjectionObj(OGRSpatialReferenceH hSRS,
948 projectionObj *proj, int debug_flag )
949 {
950 // First flush the "auto" name from the projargs[]...
951 msFreeProjectionExceptContext( proj );
952
953 if (hSRS == NULL || OSRIsLocal( hSRS ) ) {
954 // Dataset had no set projection or is NonEarth (LOCAL_CS)...
955 // Nothing else to do. Leave proj empty and no reprojection will happen!
956 return MS_SUCCESS;
957 }
958
959 #if PROJ_VERSION_MAJOR >= 6
960 // This could be done also in the < 6 case, but would be useless.
961 // Here this helps avoiding going through potentially lossy PROJ4 strings
962 const char* pszAuthName = OSRGetAuthorityName(hSRS, NULL);
963 if( pszAuthName && EQUAL(pszAuthName, "EPSG") )
964 {
965 const char* pszAuthCode = OSRGetAuthorityCode(hSRS, NULL);
966 if( pszAuthCode )
967 {
968 char szInitStr[32];
969 sprintf(szInitStr, "init=epsg:%d", atoi(pszAuthCode));
970
971 if( debug_flag )
972 msDebug( "AUTO = %s\n", szInitStr );
973
974 return msLoadProjectionString(proj, szInitStr) == 0 ? MS_SUCCESS : MS_FAILURE;
975 }
976 }
977 #endif
978
979 // Export OGR SRS to a PROJ4 string
980 char *pszProj = NULL;
981
982 if (OSRExportToProj4( hSRS, &pszProj ) != OGRERR_NONE ||
983 pszProj == NULL || strlen(pszProj) == 0) {
984 msSetError(MS_OGRERR, "Conversion from OGR SRS to PROJ4 failed.",
985 "msOGRSpatialRef2ProjectionObj()");
986 CPLFree(pszProj);
987 return(MS_FAILURE);
988 }
989
990 if( debug_flag )
991 msDebug( "AUTO = %s\n", pszProj );
992
993 if( msLoadProjectionString( proj, pszProj ) != 0 )
994 return MS_FAILURE;
995
996 CPLFree(pszProj);
997
998 return MS_SUCCESS;
999 }
1000
1001 /**********************************************************************
1002 * msOGCWKT2ProjectionObj()
1003 *
1004 * Init a MapServer projectionObj using an OGC WKT definition.
1005 * Works only with PROJECTION AUTO
1006 *
1007 * Returns MS_SUCCESS/MS_FAILURE
1008 **********************************************************************/
1009
msOGCWKT2ProjectionObj(const char * pszWKT,projectionObj * proj,int debug_flag)1010 int msOGCWKT2ProjectionObj( const char *pszWKT,
1011 projectionObj *proj,
1012 int debug_flag )
1013
1014 {
1015 OGRSpatialReferenceH hSRS;
1016 char *pszAltWKT = (char *) pszWKT;
1017 OGRErr eErr;
1018 int ms_result;
1019
1020 hSRS = OSRNewSpatialReference( NULL );
1021
1022 if( !EQUALN(pszWKT,"GEOGCS",6)
1023 && !EQUALN(pszWKT,"PROJCS",6)
1024 && !EQUALN(pszWKT,"LOCAL_CS",8) )
1025 eErr = OSRSetFromUserInput( hSRS, pszWKT );
1026 else
1027 eErr = OSRImportFromWkt( hSRS, &pszAltWKT );
1028
1029 if( eErr != OGRERR_NONE ) {
1030 OSRDestroySpatialReference( hSRS );
1031 msSetError(MS_OGRERR,
1032 "Ingestion of WKT string '%s' failed.",
1033 "msOGCWKT2ProjectionObj()",
1034 pszWKT );
1035 return MS_FAILURE;
1036 }
1037
1038 ms_result = msOGRSpatialRef2ProjectionObj( hSRS, proj, debug_flag );
1039
1040 OSRDestroySpatialReference( hSRS );
1041 return ms_result;
1042 }
1043
1044 /**********************************************************************
1045 * msOGRFileOpen()
1046 *
1047 * Open an OGR connection, and initialize a msOGRFileInfo.
1048 **********************************************************************/
1049
1050 static int bOGRDriversRegistered = MS_FALSE;
1051
msOGRInitialize(void)1052 void msOGRInitialize(void)
1053
1054 {
1055 /* ------------------------------------------------------------------
1056 * Register OGR Drivers, only once per execution
1057 * ------------------------------------------------------------------ */
1058 if (!bOGRDriversRegistered) {
1059 ACQUIRE_OGR_LOCK;
1060
1061 OGRRegisterAll();
1062 CPLPushErrorHandler( CPLQuietErrorHandler );
1063
1064 /* ------------------------------------------------------------------
1065 * Pass config option GML_FIELDTYPES=ALWAYS_STRING to OGR so that all
1066 * GML attributes are returned as strings to MapServer. This is most efficient
1067 * and prevents problems with autodetection of some attribute types.
1068 * ------------------------------------------------------------------ */
1069 CPLSetConfigOption("GML_FIELDTYPES","ALWAYS_STRING");
1070
1071 bOGRDriversRegistered = MS_TRUE;
1072
1073 RELEASE_OGR_LOCK;
1074 }
1075 }
1076
1077 /* ==================================================================
1078 * The following functions closely relate to the API called from
1079 * maplayer.c, but are intended to be used for the tileindex or direct
1080 * layer access.
1081 * ================================================================== */
1082
1083 static void msOGRFileOpenSpatialite( layerObj *layer,
1084 const char *pszLayerDef,
1085 msOGRFileInfo *psInfo );
1086
1087 /**********************************************************************
1088 * msOGRFileOpen()
1089 *
1090 * Open an OGR connection, and initialize a msOGRFileInfo.
1091 **********************************************************************/
1092
1093 static msOGRFileInfo *
msOGRFileOpen(layerObj * layer,const char * connection)1094 msOGRFileOpen(layerObj *layer, const char *connection )
1095
1096 {
1097 char *conn_decrypted = NULL;
1098
1099 msOGRInitialize();
1100
1101 /* ------------------------------------------------------------------
1102 * Make sure any encrypted token in the connection string are decrypted
1103 * ------------------------------------------------------------------ */
1104 if (connection) {
1105 conn_decrypted = msDecryptStringTokens(layer->map, connection);
1106 if (conn_decrypted == NULL)
1107 return NULL; /* An error should already have been reported */
1108 }
1109
1110 /* ------------------------------------------------------------------
1111 * Parse connection string into dataset name, and layer name.
1112 * ------------------------------------------------------------------ */
1113 char *pszDSName = NULL, *pszLayerDef = NULL;
1114
1115 if( conn_decrypted == NULL ) {
1116 /* we don't have anything */
1117 } else if( layer->data != NULL ) {
1118 pszDSName = CPLStrdup(conn_decrypted);
1119 pszLayerDef = CPLStrdup(layer->data);
1120 } else {
1121 char **papszTokens = NULL;
1122
1123 papszTokens = CSLTokenizeStringComplex( conn_decrypted, ",", TRUE, FALSE );
1124
1125 if( CSLCount(papszTokens) > 0 )
1126 pszDSName = CPLStrdup( papszTokens[0] );
1127 if( CSLCount(papszTokens) > 1 )
1128 pszLayerDef = CPLStrdup( papszTokens[1] );
1129
1130 CSLDestroy(papszTokens);
1131 }
1132
1133 /* Get rid of decrypted connection string. We'll use the original (not
1134 * decrypted) string for debug and error messages in the rest of the code.
1135 */
1136 msFree(conn_decrypted);
1137 conn_decrypted = NULL;
1138
1139 if( pszDSName == NULL ) {
1140 msSetError(MS_OGRERR,
1141 "Error parsing OGR connection information in layer `%s'",
1142 "msOGRFileOpen()",
1143 layer->name?layer->name:"(null)" );
1144 return NULL;
1145 }
1146
1147 if( pszLayerDef == NULL )
1148 pszLayerDef = CPLStrdup("0");
1149
1150 /* -------------------------------------------------------------------- */
1151 /* Can we get an existing connection for this layer? */
1152 /* -------------------------------------------------------------------- */
1153 OGRDataSourceH hDS;
1154
1155 hDS = (OGRDataSourceH) msConnPoolRequest( layer );
1156
1157 /* -------------------------------------------------------------------- */
1158 /* If not, open now, and register this connection with the */
1159 /* pool. */
1160 /* -------------------------------------------------------------------- */
1161 if( hDS == NULL ) {
1162 char szPath[MS_MAXPATHLEN] = "";
1163 const char *pszDSSelectedName = pszDSName;
1164
1165 if( layer->debug )
1166 msDebug("msOGRFileOpen(%s)...\n", connection);
1167
1168 CPLErrorReset();
1169 if (msTryBuildPath3(szPath, layer->map->mappath,
1170 layer->map->shapepath, pszDSName) != NULL ||
1171 msTryBuildPath(szPath, layer->map->mappath, pszDSName) != NULL) {
1172 /* Use relative path */
1173 pszDSSelectedName = szPath;
1174 }
1175
1176 if( layer->debug )
1177 msDebug("OGROPen(%s)\n", pszDSSelectedName);
1178
1179 ACQUIRE_OGR_LOCK;
1180 char** connectionoptions = msGetStringListFromHashTable(&(layer->connectionoptions));
1181 hDS = (OGRDataSourceH) GDALOpenEx(pszDSSelectedName,
1182 GDAL_OF_VECTOR,
1183 NULL,
1184 (const char* const*)connectionoptions,
1185 NULL);
1186 CSLDestroy(connectionoptions);
1187 RELEASE_OGR_LOCK;
1188
1189 if( hDS == NULL ) {
1190 msSetError(MS_OGRERR,
1191 "Open failed for OGR connection in layer `%s'. "
1192 "File not found or unsupported format. Check server logs.",
1193 "msOGRFileOpen()",
1194 layer->name?layer->name:"(null)" );
1195 if( strlen(CPLGetLastErrorMsg()) == 0 )
1196 msDebug("Open failed for OGR connection in layer `%s'.\n%s\n",
1197 layer->name?layer->name:"(null)",
1198 CPLGetLastErrorMsg() );
1199 CPLFree( pszDSName );
1200 CPLFree( pszLayerDef );
1201 return NULL;
1202 }
1203
1204 msConnPoolRegister( layer, hDS, msOGRCloseConnection );
1205 }
1206
1207 CPLFree( pszDSName );
1208 pszDSName = NULL;
1209
1210 /* ------------------------------------------------------------------
1211 * Find the layer selected.
1212 * ------------------------------------------------------------------ */
1213
1214 int nLayerIndex = 0;
1215 OGRLayerH hLayer = NULL;
1216
1217 int iLayer;
1218
1219 if( EQUALN(pszLayerDef,"SELECT ",7) ) {
1220 ACQUIRE_OGR_LOCK;
1221 hLayer = OGR_DS_ExecuteSQL( hDS, pszLayerDef, NULL, NULL );
1222 if( hLayer == NULL ) {
1223 msSetError(MS_OGRERR,
1224 "ExecuteSQL() failed. Check server logs.",
1225 "msOGRFileOpen()");
1226 if( strlen(CPLGetLastErrorMsg()) == 0 )
1227 msDebug("ExecuteSQL(%s) failed.\n%s\n",
1228 pszLayerDef, CPLGetLastErrorMsg() );
1229 RELEASE_OGR_LOCK;
1230 msConnPoolRelease( layer, hDS );
1231 CPLFree( pszLayerDef );
1232 return NULL;
1233 }
1234 RELEASE_OGR_LOCK;
1235 nLayerIndex = -1;
1236 }
1237
1238 for( iLayer = 0; hLayer == NULL && iLayer < OGR_DS_GetLayerCount(hDS); iLayer++ ) {
1239 hLayer = OGR_DS_GetLayer( hDS, iLayer );
1240 if( hLayer != NULL
1241 && EQUAL(OGR_L_GetName(hLayer),pszLayerDef) )
1242 {
1243 nLayerIndex = iLayer;
1244 break;
1245 } else
1246 hLayer = NULL;
1247 }
1248
1249 if( hLayer == NULL && (atoi(pszLayerDef) > 0 || EQUAL(pszLayerDef,"0")) ) {
1250 nLayerIndex = atoi(pszLayerDef);
1251 if( nLayerIndex < OGR_DS_GetLayerCount(hDS) )
1252 hLayer = OGR_DS_GetLayer( hDS, nLayerIndex );
1253 }
1254
1255 if (hLayer == NULL) {
1256 msSetError(MS_OGRERR, "GetLayer(%s) failed for OGR connection. Check logs.",
1257 "msOGRFileOpen()",
1258 pszLayerDef);
1259 msDebug("GetLayer(%s) failed for OGR connection `%s'.\n",
1260 pszLayerDef, connection );
1261 CPLFree( pszLayerDef );
1262 msConnPoolRelease( layer, hDS );
1263 return NULL;
1264 }
1265
1266 /* ------------------------------------------------------------------
1267 * OK... open succeded... alloc and fill msOGRFileInfo inside layer obj
1268 * ------------------------------------------------------------------ */
1269 msOGRFileInfo *psInfo =(msOGRFileInfo*)CPLCalloc(1,sizeof(msOGRFileInfo));
1270
1271 psInfo->pszFname = CPLStrdup(OGR_DS_GetName( hDS ));
1272 psInfo->pszLayerDef = pszLayerDef;
1273 psInfo->nLayerIndex = nLayerIndex;
1274 psInfo->hDS = hDS;
1275 psInfo->hLayer = hLayer;
1276
1277 psInfo->nTileId = 0;
1278 msInitProjection(&(psInfo->sTileProj));
1279 msProjectionInheritContextFrom(&(psInfo->sTileProj),&(layer->projection));
1280 psInfo->poCurTile = NULL;
1281 psInfo->rect_is_defined = false;
1282 psInfo->rect.minx = psInfo->rect.maxx = 0;
1283 psInfo->rect.miny = psInfo->rect.maxy = 0;
1284 psInfo->last_record_index_read = -1;
1285 psInfo->dialect = NULL;
1286
1287 psInfo->pszSelect = NULL;
1288 psInfo->pszSpatialFilterTableName = NULL;
1289 psInfo->pszSpatialFilterGeometryColumn = NULL;
1290 psInfo->pszMainTableName = NULL;
1291 psInfo->pszRowId = NULL;
1292 psInfo->bIsOKForSQLCompose = true;
1293 psInfo->bPaging = false;
1294 psInfo->bHasSpatialIndex = false;
1295 psInfo->pszTablePrefix = NULL;
1296 psInfo->pszWHERE = NULL;
1297
1298 // GDAL 1.x API
1299 OGRSFDriverH dr = OGR_DS_GetDriver(hDS);
1300 const char *name = OGR_Dr_GetName(dr);
1301 if (strcmp(name, "SQLite") == 0) {
1302 bool have_spatialite = false;
1303
1304 CPLPushErrorHandler(CPLQuietErrorHandler);
1305
1306 // test for Spatialite support in driver
1307 const char *test_spatialite = "SELECT spatialite_version()";
1308 OGRLayerH l = OGR_DS_ExecuteSQL(hDS, test_spatialite, NULL, NULL);
1309 if (l) {
1310 OGR_DS_ReleaseResultSet(hDS, l);
1311 have_spatialite = true;
1312 }
1313
1314 // test for Spatialite enabled db
1315 if (have_spatialite) {
1316 have_spatialite = false;
1317 const char *test_sql = "select 1 from sqlite_master where name = 'geometry_columns' and sql LIKE '%spatial_index_enabled%'";
1318 OGRLayerH l = OGR_DS_ExecuteSQL(hDS, test_sql, NULL, NULL);
1319 if (l) {
1320 if (OGR_L_GetFeatureCount(l, TRUE) == 1)
1321 have_spatialite = true;
1322 OGR_DS_ReleaseResultSet(hDS, l);
1323 }
1324 }
1325
1326 CPLPopErrorHandler();
1327 CPLErrorReset();
1328
1329 if (have_spatialite)
1330 psInfo->dialect = "Spatialite";
1331 else
1332 msDebug("msOGRFileOpen: Native SQL not available, no Spatialite support and/or not a Spatialite enabled db\n");
1333 } else if (strcmp(name, "PostgreSQL") == 0) {
1334 psInfo->dialect = "PostgreSQL";
1335 // todo: PostgreSQL not yet tested
1336
1337 } else if (strcmp(name, "GPKG") == 0 && nLayerIndex >= 0 &&
1338 atoi(GDALVersionInfo("VERSION_NUM")) >= 2000000) {
1339
1340 bool has_rtree = false;
1341 const char* test_rtree =
1342 CPLSPrintf("SELECT 1 FROM sqlite_master WHERE name = 'rtree_%s_%s'",
1343 OGR_L_GetName(hLayer), OGR_L_GetGeometryColumn(hLayer));
1344 OGRLayerH l = OGR_DS_ExecuteSQL(hDS, test_rtree, NULL, NULL);
1345 if( l )
1346 {
1347 if( OGR_L_GetFeatureCount(l, TRUE) == 1 )
1348 {
1349 has_rtree = true;
1350 }
1351 OGR_DS_ReleaseResultSet(hDS, l);
1352 }
1353 if( has_rtree )
1354 {
1355 bool have_gpkg_spatialite = false;
1356
1357 CPLPushErrorHandler(CPLQuietErrorHandler);
1358
1359 // test for Spatialite >= 4.3 support in driver
1360 const char *test_spatialite = "SELECT spatialite_version()";
1361 l = OGR_DS_ExecuteSQL(hDS, test_spatialite, NULL, NULL);
1362 if (l) {
1363 OGRFeatureH hFeat = OGR_L_GetNextFeature(l);
1364 if( hFeat )
1365 {
1366 const char* pszVersion = OGR_F_GetFieldAsString(hFeat, 0);
1367 have_gpkg_spatialite = atof(pszVersion) >= 4.3;
1368 OGR_F_Destroy(hFeat);
1369 }
1370 OGR_DS_ReleaseResultSet(hDS, l);
1371 }
1372 CPLPopErrorHandler();
1373 CPLErrorReset();
1374
1375 if( have_gpkg_spatialite )
1376 {
1377 psInfo->pszMainTableName = msStrdup( OGR_L_GetName(hLayer) );
1378 psInfo->pszTablePrefix = msStrdup( psInfo->pszMainTableName );
1379 psInfo->pszSpatialFilterTableName = msStrdup( OGR_L_GetName(hLayer) );
1380 psInfo->pszSpatialFilterGeometryColumn = msStrdup( OGR_L_GetGeometryColumn(hLayer) );
1381 psInfo->dialect = "GPKG";
1382 psInfo->bPaging = true;
1383 psInfo->bHasSpatialIndex = true;
1384 }
1385 else
1386 msDebug("msOGRFileOpen: Spatialite support in GPKG not enabled\n");
1387 }
1388 else
1389 {
1390 msDebug("msOGRFileOpen: RTree index not available\n");
1391 }
1392 }
1393
1394 if( psInfo->dialect != NULL && EQUAL(psInfo->dialect, "Spatialite") )
1395 msOGRFileOpenSpatialite(layer, pszLayerDef, psInfo);
1396
1397 return psInfo;
1398 }
1399
1400 /************************************************************************/
1401 /* msOGRFileOpenSpatialite() */
1402 /************************************************************************/
1403
msOGRFileOpenSpatialite(layerObj * layer,const char * pszLayerDef,msOGRFileInfo * psInfo)1404 static void msOGRFileOpenSpatialite( layerObj *layer,
1405 const char* pszLayerDef,
1406 msOGRFileInfo *psInfo )
1407 {
1408 // In the case of a SQLite DB, check that we can identify the
1409 // underlying table
1410 if( psInfo->nLayerIndex == -1 )
1411 {
1412 psInfo->bIsOKForSQLCompose = false;
1413
1414 const char* from = strstr( psInfo->pszLayerDef, " from ");
1415 if( from == NULL )
1416 from = strstr( psInfo->pszLayerDef, " FROM ");
1417 if( from )
1418 {
1419 const char* pszBeginningOfTable = from + strlen(" FROM ");
1420 const char* pszIter = pszBeginningOfTable;
1421 while( *pszIter && *pszIter != ' ' )
1422 pszIter ++;
1423 if( strchr(pszIter, ',') == NULL &&
1424 strstr(pszIter, " where ") == NULL && strstr(pszIter, " WHERE ") == NULL &&
1425 strstr(pszIter, " join ") == NULL && strstr(pszIter, " JOIN ") == NULL &&
1426 strstr(pszIter, " order by ") == NULL && strstr(pszIter, " ORDER BY ") == NULL)
1427 {
1428 psInfo->bIsOKForSQLCompose = true;
1429 psInfo->pszMainTableName = msStrdup(pszBeginningOfTable);
1430 psInfo->pszMainTableName[pszIter - pszBeginningOfTable] = '\0';
1431 psInfo->pszSpatialFilterTableName = msStrdup(psInfo->pszMainTableName);
1432 psInfo->pszSpatialFilterGeometryColumn = msStrdup( OGR_L_GetGeometryColumn(psInfo->hLayer) );
1433
1434 char* pszRequest = NULL;
1435 pszRequest = msStringConcatenate(pszRequest,
1436 "SELECT name FROM sqlite_master WHERE type = 'table' AND name = lower('");
1437 pszRequest = msStringConcatenate(pszRequest, psInfo->pszMainTableName);
1438 pszRequest = msStringConcatenate(pszRequest, "')");
1439 OGRLayerH hLayer = OGR_DS_ExecuteSQL( psInfo->hDS, pszRequest, NULL, NULL );
1440 msFree(pszRequest);
1441
1442 if( hLayer )
1443 {
1444 OGRFeatureH hFeature = OGR_L_GetNextFeature(hLayer);
1445 psInfo->bIsOKForSQLCompose = (hFeature != NULL);
1446 if( hFeature )
1447 {
1448 msFree(psInfo->pszMainTableName);
1449 msFree(psInfo->pszSpatialFilterTableName);
1450 psInfo->pszMainTableName = msStrdup( OGR_F_GetFieldAsString( hFeature, 0) );
1451 psInfo->pszSpatialFilterTableName = msStrdup( psInfo->pszMainTableName );
1452 OGR_F_Destroy(hFeature);
1453 }
1454 OGR_DS_ReleaseResultSet( psInfo->hDS, hLayer );
1455 }
1456 if( psInfo->bIsOKForSQLCompose )
1457 {
1458 psInfo->pszSelect = msStrdup(psInfo->pszLayerDef);
1459 }
1460 else
1461 {
1462 // Test if it is a spatial view
1463 pszRequest = msStringConcatenate(NULL,
1464 "SELECT f_table_name, f_geometry_column, view_rowid FROM views_geometry_columns WHERE view_name = lower('");
1465 pszRequest = msStringConcatenate(pszRequest, psInfo->pszMainTableName);
1466 pszRequest = msStringConcatenate(pszRequest, "')");
1467 CPLPushErrorHandler(CPLQuietErrorHandler);
1468 OGRLayerH hLayer = OGR_DS_ExecuteSQL( psInfo->hDS, pszRequest, NULL, NULL );
1469 CPLPopErrorHandler();
1470 msFree(pszRequest);
1471
1472 if( hLayer )
1473 {
1474 OGRFeatureH hFeature = OGR_L_GetNextFeature(hLayer);
1475 psInfo->bIsOKForSQLCompose = (hFeature != NULL);
1476 if( hFeature )
1477 {
1478 psInfo->pszSelect = msStrdup(psInfo->pszLayerDef);
1479 msFree(psInfo->pszSpatialFilterTableName);
1480 psInfo->pszSpatialFilterTableName = msStrdup( OGR_F_GetFieldAsString( hFeature, 0 ) );
1481 CPLFree( psInfo->pszSpatialFilterGeometryColumn );
1482 psInfo->pszSpatialFilterGeometryColumn = msStrdup( OGR_F_GetFieldAsString( hFeature, 1 ) );
1483 psInfo->pszRowId = msStrdup( OGR_F_GetFieldAsString( hFeature, 2 ) );
1484 OGR_F_Destroy(hFeature);
1485 }
1486 OGR_DS_ReleaseResultSet( psInfo->hDS, hLayer );
1487 }
1488 }
1489 }
1490 }
1491 }
1492 else
1493 {
1494 psInfo->bIsOKForSQLCompose = false;
1495
1496 char* pszRequest = NULL;
1497 pszRequest = msStringConcatenate(pszRequest,
1498 "SELECT * FROM sqlite_master WHERE type = 'table' AND name = lower('");
1499 pszRequest = msStringConcatenate(pszRequest, OGR_FD_GetName(OGR_L_GetLayerDefn(psInfo->hLayer)));
1500 pszRequest = msStringConcatenate(pszRequest, "')");
1501 OGRLayerH hLayer = OGR_DS_ExecuteSQL( psInfo->hDS, pszRequest, NULL, NULL );
1502 msFree(pszRequest);
1503
1504 if( hLayer )
1505 {
1506 OGRFeatureH hFeature = OGR_L_GetNextFeature(hLayer);
1507 psInfo->bIsOKForSQLCompose = (hFeature != NULL);
1508 if( hFeature )
1509 OGR_F_Destroy(hFeature);
1510 OGR_DS_ReleaseResultSet( psInfo->hDS, hLayer );
1511 }
1512 if( psInfo->bIsOKForSQLCompose )
1513 {
1514 psInfo->pszMainTableName = msStrdup(OGR_FD_GetName(OGR_L_GetLayerDefn(psInfo->hLayer)));
1515 psInfo->pszSpatialFilterTableName = msStrdup(psInfo->pszMainTableName);
1516 psInfo->pszSpatialFilterGeometryColumn = msStrdup( OGR_L_GetGeometryColumn(psInfo->hLayer) );
1517 }
1518 else
1519 {
1520 // Test if it is a spatial view
1521 pszRequest = msStringConcatenate(NULL,
1522 "SELECT f_table_name, f_geometry_column, view_rowid FROM views_geometry_columns WHERE view_name = lower('");
1523 pszRequest = msStringConcatenate(pszRequest, OGR_FD_GetName(OGR_L_GetLayerDefn(psInfo->hLayer)));
1524 pszRequest = msStringConcatenate(pszRequest, "')");
1525 CPLPushErrorHandler(CPLQuietErrorHandler);
1526 OGRLayerH hLayer = OGR_DS_ExecuteSQL( psInfo->hDS, pszRequest, NULL, NULL );
1527 CPLPopErrorHandler();
1528 msFree(pszRequest);
1529
1530 if( hLayer )
1531 {
1532 OGRFeatureH hFeature = OGR_L_GetNextFeature(hLayer);
1533 psInfo->bIsOKForSQLCompose = (hFeature != NULL);
1534 if( hFeature )
1535 {
1536 psInfo->pszMainTableName = msStrdup(OGR_FD_GetName(OGR_L_GetLayerDefn(psInfo->hLayer)));
1537 psInfo->pszSpatialFilterTableName = msStrdup( OGR_F_GetFieldAsString( hFeature, 0 ) );
1538 psInfo->pszSpatialFilterGeometryColumn = msStrdup( OGR_F_GetFieldAsString( hFeature, 1 ) );
1539 psInfo->pszRowId = msStrdup( OGR_F_GetFieldAsString( hFeature, 2 ) );
1540 OGR_F_Destroy(hFeature);
1541 }
1542 OGR_DS_ReleaseResultSet( psInfo->hDS, hLayer );
1543 }
1544 }
1545 }
1546
1547 // in the case we cannot handle the native string, go back to the client
1548 // side evaluation by unsetting it.
1549 if( !psInfo->bIsOKForSQLCompose && psInfo->dialect != NULL )
1550 {
1551 if (layer->debug >= MS_DEBUGLEVEL_VVV)
1552 {
1553 msDebug("msOGRFileOpen(): Falling back to MapServer only evaluation\n");
1554 }
1555 psInfo->dialect = NULL;
1556 }
1557
1558 // Check if spatial index has been disabled (testing purposes)
1559 if (msLayerGetProcessingKey(layer, "USE_SPATIAL_INDEX") != NULL &&
1560 !CSLTestBoolean(msLayerGetProcessingKey(layer, "USE_SPATIAL_INDEX")) )
1561 {
1562 if (layer->debug >= MS_DEBUGLEVEL_VVV)
1563 {
1564 msDebug("msOGRFileOpen(): Layer %s has spatial index disabled by processing option\n",
1565 pszLayerDef);
1566 }
1567 }
1568 // Test if spatial index is available
1569 else if( psInfo->dialect != NULL )
1570 {
1571 char* pszRequest = NULL;
1572 pszRequest = msStringConcatenate(pszRequest,
1573 "SELECT * FROM sqlite_master WHERE type = 'table' AND name = 'idx_");
1574 pszRequest = msStringConcatenate(pszRequest,
1575 psInfo->pszSpatialFilterTableName);
1576 pszRequest = msStringConcatenate(pszRequest, "_");
1577 pszRequest = msStringConcatenate(pszRequest,
1578 OGR_L_GetGeometryColumn(psInfo->hLayer));
1579 pszRequest = msStringConcatenate(pszRequest, "'");
1580
1581 psInfo->bHasSpatialIndex = false;
1582 //msDebug("msOGRFileOpen(): %s", pszRequest);
1583
1584 OGRLayerH hLayer = OGR_DS_ExecuteSQL( psInfo->hDS, pszRequest, NULL, NULL );
1585 if( hLayer )
1586 {
1587 OGRFeatureH hFeature = OGR_L_GetNextFeature(hLayer);
1588 if( hFeature )
1589 {
1590 psInfo->bHasSpatialIndex = true;
1591 OGR_F_Destroy(hFeature);
1592 }
1593 OGR_DS_ReleaseResultSet( psInfo->hDS, hLayer );
1594 }
1595 msFree(pszRequest);
1596 pszRequest = NULL;
1597
1598 if( !psInfo->bHasSpatialIndex )
1599 {
1600 if (layer->debug >= MS_DEBUGLEVEL_VVV)
1601 {
1602 msDebug("msOGRFileOpen(): Layer %s has no spatial index table\n",
1603 pszLayerDef);
1604 }
1605 }
1606 else
1607 {
1608 pszRequest = msStringConcatenate(pszRequest,
1609 "SELECT * FROM geometry_columns WHERE f_table_name = lower('");
1610 pszRequest = msStringConcatenate(pszRequest,
1611 psInfo->pszSpatialFilterTableName);
1612 pszRequest = msStringConcatenate(pszRequest, "') AND f_geometry_column = lower('");
1613 pszRequest = msStringConcatenate(pszRequest,
1614 psInfo->pszSpatialFilterGeometryColumn);
1615 pszRequest = msStringConcatenate(pszRequest, "') AND spatial_index_enabled = 1");
1616
1617 psInfo->bHasSpatialIndex = false;
1618
1619 OGRLayerH hLayer = OGR_DS_ExecuteSQL( psInfo->hDS, pszRequest, NULL, NULL );
1620 if( hLayer )
1621 {
1622 OGRFeatureH hFeature = OGR_L_GetNextFeature(hLayer);
1623 if( hFeature )
1624 {
1625 psInfo->bHasSpatialIndex = true;
1626 OGR_F_Destroy(hFeature);
1627 }
1628 OGR_DS_ReleaseResultSet( psInfo->hDS, hLayer );
1629 }
1630 msFree(pszRequest);
1631 pszRequest = NULL;
1632
1633 if( !psInfo->bHasSpatialIndex )
1634 {
1635 if (layer->debug >= MS_DEBUGLEVEL_VVV)
1636 {
1637 msDebug("msOGRFileOpen(): Layer %s has spatial index disabled\n",
1638 pszLayerDef);
1639 }
1640 }
1641 else
1642 {
1643 if (layer->debug >= MS_DEBUGLEVEL_VVV)
1644 {
1645 msDebug("msOGRFileOpen(): Layer %s has spatial index enabled\n",
1646 pszLayerDef);
1647 }
1648
1649 psInfo->pszTablePrefix = msStrdup( psInfo->pszMainTableName );
1650 }
1651 }
1652 }
1653
1654 psInfo->bPaging = (psInfo->dialect != NULL);
1655 }
1656
1657 /************************************************************************/
1658 /* msOGRCloseConnection() */
1659 /* */
1660 /* Callback for thread pool to actually release an OGR */
1661 /* connection. */
1662 /************************************************************************/
1663
msOGRCloseConnection(void * conn_handle)1664 static void msOGRCloseConnection( void *conn_handle )
1665
1666 {
1667 OGRDataSourceH hDS = (OGRDataSourceH) conn_handle;
1668
1669 ACQUIRE_OGR_LOCK;
1670 OGR_DS_Destroy( hDS );
1671 RELEASE_OGR_LOCK;
1672 }
1673
1674 /**********************************************************************
1675 * msOGRFileClose()
1676 **********************************************************************/
msOGRFileClose(layerObj * layer,msOGRFileInfo * psInfo)1677 static int msOGRFileClose(layerObj *layer, msOGRFileInfo *psInfo )
1678 {
1679 if (!psInfo)
1680 return MS_SUCCESS;
1681
1682 if( layer->debug )
1683 msDebug("msOGRFileClose(%s,%d).\n",
1684 psInfo->pszFname, psInfo->nLayerIndex);
1685
1686 CPLFree(psInfo->pszFname);
1687 CPLFree(psInfo->pszLayerDef);
1688
1689 ACQUIRE_OGR_LOCK;
1690 if (psInfo->hLastFeature)
1691 OGR_F_Destroy( psInfo->hLastFeature );
1692
1693 /* If nLayerIndex == -1 then the layer is an SQL result ... free it */
1694 if( psInfo->nLayerIndex == -1 )
1695 OGR_DS_ReleaseResultSet( psInfo->hDS, psInfo->hLayer );
1696
1697 // Release (potentially close) the datasource connection.
1698 // Make sure we aren't holding the lock when the callback may need it.
1699 RELEASE_OGR_LOCK;
1700 msConnPoolRelease( layer, psInfo->hDS );
1701
1702 // Free current tile if there is one.
1703 if( psInfo->poCurTile != NULL )
1704 msOGRFileClose( layer, psInfo->poCurTile );
1705
1706 msFreeProjection(&(psInfo->sTileProj));
1707 msFree(psInfo->pszSelect);
1708 msFree(psInfo->pszSpatialFilterTableName);
1709 msFree(psInfo->pszSpatialFilterGeometryColumn);
1710 msFree(psInfo->pszMainTableName);
1711 msFree(psInfo->pszRowId);
1712 msFree(psInfo->pszTablePrefix);
1713 msFree(psInfo->pszWHERE);
1714
1715 CPLFree(psInfo);
1716
1717 return MS_SUCCESS;
1718 }
1719
1720 /************************************************************************/
1721 /* msOGREscapeSQLParam */
1722 /************************************************************************/
msOGREscapeSQLParam(layerObj * layer,const char * pszString)1723 static char *msOGREscapeSQLParam(layerObj *layer, const char *pszString)
1724 {
1725 char* pszEscapedStr =NULL;
1726 if(layer && pszString) {
1727 char* pszEscapedOGRStr = CPLEscapeString(pszString, strlen(pszString),
1728 CPLES_SQL );
1729 pszEscapedStr = msStrdup(pszEscapedOGRStr);
1730 CPLFree(pszEscapedOGRStr);
1731 }
1732 return pszEscapedStr;
1733 }
1734
1735 // http://www.sqlite.org/lang_expr.html
1736 // http://www.gaia-gis.it/gaia-sins/spatialite-sql-4.3.0.html
1737
msOGRGetQuotedItem(layerObj * layer,const char * pszItem)1738 static char* msOGRGetQuotedItem(layerObj* layer, const char* pszItem )
1739 {
1740 msOGRFileInfo *psInfo = (msOGRFileInfo *)layer->layerinfo;
1741 char* ret = NULL;
1742 char* escapedItem = msLayerEscapePropertyName(layer, pszItem);
1743 if( psInfo->pszTablePrefix)
1744 {
1745 char* escapedTable = msLayerEscapePropertyName(layer, psInfo->pszTablePrefix);
1746 ret = msStringConcatenate(ret, "\"");
1747 ret = msStringConcatenate(ret, escapedTable);
1748 ret = msStringConcatenate(ret, "\".\"");
1749 ret = msStringConcatenate(ret, escapedItem);
1750 ret = msStringConcatenate(ret, "\"");
1751 msFree(escapedTable);
1752 }
1753 else
1754 {
1755 ret = msStringConcatenate(ret, "\"");
1756 ret = msStringConcatenate(ret, escapedItem);
1757 ret = msStringConcatenate(ret, "\"");
1758 }
1759 msFree(escapedItem);
1760 return ret;
1761 }
1762
1763 static
msOGRGetToken(layerObj * layer,tokenListNodeObjPtr * node)1764 char *msOGRGetToken(layerObj* layer, tokenListNodeObjPtr *node) {
1765 msOGRFileInfo *info = (msOGRFileInfo *)layer->layerinfo;
1766 tokenListNodeObjPtr n = *node;
1767 if (!n) return NULL;
1768 char *out = NULL;
1769 size_t nOutSize;
1770
1771 switch(n->token) {
1772 case MS_TOKEN_LOGICAL_AND:
1773 out = msStrdup(" AND ");
1774 break;
1775 case MS_TOKEN_LOGICAL_OR:
1776 out = msStrdup(" OR ");
1777 break;
1778 case MS_TOKEN_LOGICAL_NOT:
1779 out = msStrdup(" NOT ");
1780 break;
1781 case MS_TOKEN_LITERAL_NUMBER:
1782 nOutSize = 80;
1783 out = (char *)msSmallMalloc(nOutSize);
1784 snprintf(out, nOutSize, "%lf", n->tokenval.dblval);
1785 break;
1786 case MS_TOKEN_LITERAL_STRING: {
1787 char *stresc = msOGREscapeSQLParam(layer, n->tokenval.strval);
1788 nOutSize = strlen(stresc)+3;
1789 out = (char *)msSmallMalloc(nOutSize);
1790 snprintf(out, nOutSize, "'%s'", stresc);
1791 msFree(stresc);
1792 break;
1793 }
1794 case MS_TOKEN_LITERAL_TIME:
1795 // seems to require METADATA gml_types => auto
1796 nOutSize = 80;
1797 out = (char *)msSmallMalloc(nOutSize);
1798 #if 0
1799 // FIXME? or perhaps just remove me. tm_zone is not supported on Windows, and not used anywhere else in the code base
1800 if (n->tokenval.tmval.tm_zone)
1801 snprintf(out, nOutSize, "'%d-%02d-%02dT%02d:%02d:%02d%s'",
1802 n->tokenval.tmval.tm_year+1900, n->tokenval.tmval.tm_mon+1, n->tokenval.tmval.tm_mday,
1803 n->tokenval.tmval.tm_hour, n->tokenval.tmval.tm_min, n->tokenval.tmval.tm_sec,
1804 n->tokenval.tmval.tm_zone);
1805 else
1806 #endif
1807 snprintf(out, nOutSize, "'%d-%02d-%02dT%02d:%02d:%02d'",
1808 n->tokenval.tmval.tm_year+1900, n->tokenval.tmval.tm_mon+1, n->tokenval.tmval.tm_mday,
1809 n->tokenval.tmval.tm_hour, n->tokenval.tmval.tm_min, n->tokenval.tmval.tm_sec);
1810 break;
1811 case MS_TOKEN_LITERAL_SHAPE: {
1812 // assumed to be in right srs after FLTGetSpatialComparisonCommonExpression
1813 char *wkt = msShapeToWKT(n->tokenval.shpval);
1814 char *stresc = msOGRGetQuotedItem(layer, OGR_L_GetGeometryColumn(info->hLayer)); // which geom field??
1815 nOutSize = strlen(wkt)+strlen(stresc)+35;
1816 out = (char *)msSmallMalloc(nOutSize);
1817 snprintf(out, nOutSize, "ST_GeomFromText('%s',ST_SRID(%s))", wkt, stresc);
1818 msFree(wkt);
1819 msFree(stresc);
1820 break;
1821 }
1822 case MS_TOKEN_LITERAL_BOOLEAN:
1823 out = msStrdup(n->tokenval.dblval == 0 ? "FALSE" : "TRUE");
1824 break;
1825 case MS_TOKEN_COMPARISON_EQ:
1826 if(n->next != NULL && n->next->token == MS_TOKEN_LITERAL_STRING &&
1827 strcmp(n->next->tokenval.strval, "_MAPSERVER_NULL_") == 0 )
1828 {
1829 out = msStrdup(" IS NULL");
1830 n = n->next;
1831 break;
1832 }
1833
1834 out = msStrdup(" = ");
1835 break;
1836 case MS_TOKEN_COMPARISON_NE:
1837 out = msStrdup(" != ");
1838 break;
1839 case MS_TOKEN_COMPARISON_GT:
1840 out = msStrdup(" > ");
1841 break;
1842 case MS_TOKEN_COMPARISON_LT:
1843 out = msStrdup(" < ");
1844 break;
1845 case MS_TOKEN_COMPARISON_LE:
1846 out = msStrdup(" <= ");
1847 break;
1848 case MS_TOKEN_COMPARISON_GE:
1849 out = msStrdup(" >= ");
1850 break;
1851 case MS_TOKEN_COMPARISON_IEQ:
1852 out = msStrdup(" = ");
1853 break;
1854 case MS_TOKEN_COMPARISON_IN:
1855 out = msStrdup(" IN ");
1856 break;
1857 // the origin may be mapfile (complex regexes, layer->map.query.filter.string == NULL, regex may have //) or
1858 // OGC Filter (simple patterns only, layer->map.query.filter.string != NULL)
1859 case MS_TOKEN_COMPARISON_RE:
1860 case MS_TOKEN_COMPARISON_IRE:
1861 case MS_TOKEN_COMPARISON_LIKE: {
1862 int case_sensitive = n->token == MS_TOKEN_COMPARISON_RE || n->token == MS_TOKEN_COMPARISON_LIKE;
1863 // in PostgreSQL and OGR: LIKE (case sensitive) and ILIKE (case insensitive)
1864 // in SQLite: LIKE (case insensitive) and GLOB (case sensitive)
1865 const char *op = case_sensitive ? "LIKE" : "ILIKE";
1866 char wild_any = '%';
1867 char wild_one = '_';
1868
1869 if (EQUAL(info->dialect, "Spatialite") || EQUAL(info->dialect, "GPKG")) {
1870 if (case_sensitive) {
1871 op = "GLOB";
1872 wild_any = '*';
1873 wild_one = '?';
1874 } else {
1875 op = "LIKE";
1876 }
1877 }
1878
1879 n = n->next;
1880 if (n->token != MS_TOKEN_LITERAL_STRING) return NULL;
1881
1882 char *regex = msStrdup(n->tokenval.strval);
1883 int complex_regex = *n->tokenval.strval == '/'; // could be non-complex but that is soo corner case
1884
1885 // PostgreSQL has POSIX regexes, SQLite does not by default, OGR does not
1886 if (complex_regex) {
1887 if (!EQUAL(info->dialect, "PostgreSQL")) {
1888 msFree(regex);
1889 return NULL;
1890 }
1891 // remove //
1892 regex++;
1893 regex[strlen(regex) - 1] = '\0';
1894 if (case_sensitive)
1895 op = "~";
1896 else
1897 op = "~*";
1898 }
1899
1900 char *re = (char *) msSmallMalloc(strlen(regex)+3);
1901 size_t i = 0, j = 0;
1902 re[j++] = '\'';
1903 while (i < strlen(regex)) {
1904 char c = regex[i];
1905 char c_next = regex[i+1];
1906
1907 if (c == '.' && c_next == '*') {
1908 i++;
1909 c = wild_any;
1910 }
1911 else if (c == '.')
1912 c = wild_one;
1913 else if (i == 0 && c == '^') {
1914 i++;
1915 continue;
1916 }
1917 else if( c == '$' && c_next == 0 ) {
1918 break;
1919 }
1920
1921 re[j++] = c;
1922 i++;
1923
1924 }
1925 re[j++] = '\'';
1926 re[j] = '\0';
1927
1928 nOutSize = 1 + strlen(op)+ 1 + strlen(re) + 1;
1929 out = (char *)msSmallMalloc(nOutSize);
1930 snprintf(out, nOutSize, " %s %s", op, re);
1931 msFree(re);
1932 msFree(regex);
1933 break;
1934 }
1935 case MS_TOKEN_COMPARISON_INTERSECTS:
1936 out = msStrdup("ST_Intersects");
1937 break;
1938 case MS_TOKEN_COMPARISON_DISJOINT:
1939 out = msStrdup("ST_Disjoint");
1940 break;
1941 case MS_TOKEN_COMPARISON_TOUCHES:
1942 out = msStrdup("ST_Touches");
1943 break;
1944 case MS_TOKEN_COMPARISON_OVERLAPS:
1945 out = msStrdup("ST_Overlaps");
1946 break;
1947 case MS_TOKEN_COMPARISON_CROSSES:
1948 out = msStrdup("ST_Crosses");
1949 break;
1950 case MS_TOKEN_COMPARISON_WITHIN:
1951 out = msStrdup("ST_Within");
1952 break;
1953 case MS_TOKEN_COMPARISON_DWITHIN:
1954 out = msStrdup("ST_Distance");
1955 break;
1956 case MS_TOKEN_COMPARISON_BEYOND:
1957 out = msStrdup("ST_Distance");
1958 break;
1959 case MS_TOKEN_COMPARISON_CONTAINS:
1960 out = msStrdup("ST_Contains");
1961 break;
1962 case MS_TOKEN_COMPARISON_EQUALS:
1963 out = msStrdup("ST_Equals");
1964 break;
1965 case MS_TOKEN_FUNCTION_LENGTH:
1966 out = msStrdup("ST_Length");
1967 break;
1968 case MS_TOKEN_FUNCTION_AREA:
1969 out = msStrdup("ST_Area");
1970 break;
1971 case MS_TOKEN_BINDING_DOUBLE: {
1972 char *stresc = msOGRGetQuotedItem(layer, n->tokenval.bindval.item);
1973 nOutSize = strlen(stresc)+ + 30;
1974 out = (char *)msSmallMalloc(nOutSize);
1975
1976 char md_item_name[256];
1977 snprintf( md_item_name, sizeof(md_item_name), "gml_%s_type",
1978 n->tokenval.bindval.item );
1979 const char* type = msLookupHashTable(&(layer->metadata), md_item_name);
1980 // Do not cast if the variable is of the appropriate type as it can
1981 // prevent using database indexes, such as for SQlite
1982 if( type != NULL && (EQUAL(type, "Integer") ||
1983 EQUAL(type, "Long") ||
1984 EQUAL(type, "Real")) )
1985 {
1986 snprintf(out, nOutSize, "%s", stresc);
1987 }
1988 else
1989 {
1990 const char *SQLtype = "float(16)";
1991 if (EQUAL(info->dialect, "Spatialite") || EQUAL(info->dialect, "GPKG"))
1992 SQLtype = "REAL";
1993 else if (EQUAL(info->dialect, "PostgreSQL"))
1994 SQLtype = "double precision";
1995 snprintf(out, nOutSize, "CAST(%s AS %s)", stresc, SQLtype);
1996 }
1997 msFree(stresc);
1998 break;
1999 }
2000 case MS_TOKEN_BINDING_INTEGER: {
2001 char *stresc = msOGRGetQuotedItem(layer, n->tokenval.bindval.item);
2002 nOutSize = strlen(stresc)+ 20;
2003 out = (char *)msSmallMalloc(nOutSize);
2004
2005 char md_item_name[256];
2006 snprintf( md_item_name, sizeof(md_item_name), "gml_%s_type",
2007 n->tokenval.bindval.item );
2008 const char* type = msLookupHashTable(&(layer->metadata), md_item_name);
2009 // Do not cast if the variable is of the appropriate type as it can
2010 // prevent using database indexes, such as for SQlite
2011 if( type != NULL && (EQUAL(type, "Integer") ||
2012 EQUAL(type, "Long") ||
2013 EQUAL(type, "Real")) )
2014 {
2015 snprintf(out, nOutSize, "%s", stresc);
2016 }
2017 else
2018 {
2019 snprintf(out, nOutSize, "CAST(%s AS integer)", stresc);
2020 }
2021 msFree(stresc);
2022 break;
2023 }
2024 case MS_TOKEN_BINDING_STRING: {
2025 char *stresc = msOGRGetQuotedItem(layer, n->tokenval.bindval.item);
2026 nOutSize = strlen(stresc) + 30;
2027 out = (char *)msSmallMalloc(nOutSize);
2028
2029 char md_item_name[256];
2030 snprintf( md_item_name, sizeof(md_item_name), "gml_%s_type",
2031 n->tokenval.bindval.item );
2032 const char* type = msLookupHashTable(&(layer->metadata), md_item_name);
2033 // Do not cast if the variable is of the appropriate type as it can
2034 // prevent using database indexes, such as for SQlite
2035 if( type != NULL && EQUAL(type, "Character") )
2036 {
2037 snprintf(out, nOutSize, "%s", stresc);
2038 }
2039 else
2040 {
2041 snprintf(out, nOutSize, "CAST(%s AS text)", stresc);
2042 }
2043 msFree(stresc);
2044 break;
2045 }
2046 case MS_TOKEN_BINDING_TIME: {
2047 // won't get here unless col is parsed as time and they are not
2048 char *stresc = msOGRGetQuotedItem(layer, n->tokenval.bindval.item);
2049 nOutSize = strlen(stresc)+ 10;
2050 out = (char *)msSmallMalloc(nOutSize);
2051 snprintf(out, nOutSize, "%s", stresc);
2052 msFree(stresc);
2053 break;
2054 }
2055 case MS_TOKEN_BINDING_SHAPE: {
2056 char *stresc = msOGRGetQuotedItem(layer, OGR_L_GetGeometryColumn(info->hLayer)); // which geom field??
2057 nOutSize = strlen(stresc)+ 10;
2058 out = (char *)msSmallMalloc(nOutSize);
2059 snprintf(out, nOutSize, "%s", stresc);
2060 msFree(stresc);
2061 break;
2062 }
2063
2064 // unhandled below until default
2065
2066 case MS_TOKEN_FUNCTION_TOSTRING:
2067 case MS_TOKEN_FUNCTION_COMMIFY:
2068 case MS_TOKEN_FUNCTION_ROUND:
2069 case MS_TOKEN_FUNCTION_FROMTEXT:
2070 case MS_TOKEN_FUNCTION_BUFFER:
2071 case MS_TOKEN_FUNCTION_DIFFERENCE:
2072 case MS_TOKEN_FUNCTION_SIMPLIFY:
2073 case MS_TOKEN_FUNCTION_SIMPLIFYPT:
2074 case MS_TOKEN_FUNCTION_GENERALIZE:
2075 case MS_TOKEN_FUNCTION_SMOOTHSIA:
2076 case MS_TOKEN_FUNCTION_JAVASCRIPT:
2077 case MS_TOKEN_FUNCTION_UPPER:
2078 case MS_TOKEN_FUNCTION_LOWER:
2079 case MS_TOKEN_FUNCTION_INITCAP:
2080 case MS_TOKEN_FUNCTION_FIRSTCAP:
2081 case MS_TOKEN_BINDING_MAP_CELLSIZE:
2082 case MS_TOKEN_BINDING_DATA_CELLSIZE:
2083 case MS_PARSE_TYPE_BOOLEAN:
2084 case MS_PARSE_TYPE_STRING:
2085 case MS_PARSE_TYPE_SHAPE:
2086 break;
2087
2088 default:
2089 if (n->token < 128) {
2090 char c = n->token;
2091 out = (char *)msSmallMalloc(2);
2092 sprintf(out, "%c", c);
2093 }
2094 break;
2095 }
2096
2097 n = n->next;
2098 *node = n;
2099 return out;
2100 }
2101
2102 /*
2103 * msOGRLayerBuildSQLOrderBy()
2104 *
2105 * Returns the content of a SQL ORDER BY clause from the sortBy member of
2106 * the layer. The string does not contain the "ORDER BY" keywords itself.
2107 */
msOGRLayerBuildSQLOrderBy(layerObj * layer,msOGRFileInfo * psInfo)2108 static char* msOGRLayerBuildSQLOrderBy(layerObj *layer, msOGRFileInfo *psInfo)
2109 {
2110 char* strOrderBy = NULL;
2111 if( layer->sortBy.nProperties > 0 ) {
2112 int i;
2113 for(i=0;i<layer->sortBy.nProperties;i++) {
2114 if( i > 0 )
2115 strOrderBy = msStringConcatenate(strOrderBy, ", ");
2116 char* escapedItem = msLayerEscapePropertyName(layer, layer->sortBy.properties[i].item);
2117 if( psInfo->pszTablePrefix)
2118 {
2119 char* escapedTable = msLayerEscapePropertyName(layer, psInfo->pszTablePrefix);
2120 strOrderBy = msStringConcatenate(strOrderBy, "\"");
2121 strOrderBy = msStringConcatenate(strOrderBy, escapedTable);
2122 strOrderBy = msStringConcatenate(strOrderBy, "\".\"");
2123 strOrderBy = msStringConcatenate(strOrderBy, escapedItem);
2124 strOrderBy = msStringConcatenate(strOrderBy, "\"");
2125 msFree(escapedTable);
2126 }
2127 else
2128 {
2129 #if GDAL_VERSION_MAJOR < 2
2130 // Old GDAL don't like quoted identifiers in ORDER BY
2131 strOrderBy = msStringConcatenate(strOrderBy,
2132 layer->sortBy.properties[i].item);
2133 #else
2134 strOrderBy = msStringConcatenate(strOrderBy, "\"");
2135 strOrderBy = msStringConcatenate(strOrderBy, escapedItem);
2136 strOrderBy = msStringConcatenate(strOrderBy, "\"");
2137 #endif
2138 }
2139 msFree(escapedItem);
2140 if( layer->sortBy.properties[i].sortOrder == SORT_DESC )
2141 strOrderBy = msStringConcatenate(strOrderBy, " DESC");
2142 }
2143 }
2144 return strOrderBy;
2145 }
2146
2147 /**********************************************************************
2148 * msOGRFileWhichShapes()
2149 *
2150 * Init OGR layer structs ready for calls to msOGRFileNextShape().
2151 *
2152 * Returns MS_SUCCESS/MS_FAILURE, or MS_DONE if no shape matching the
2153 * layer's FILTER overlaps the selected region.
2154 **********************************************************************/
msOGRFileWhichShapes(layerObj * layer,rectObj rect,msOGRFileInfo * psInfo)2155 static int msOGRFileWhichShapes(layerObj *layer, rectObj rect, msOGRFileInfo *psInfo)
2156 {
2157 // rect is from BBOX parameter in query (In lieu of a FEATUREID or FILTER) or mapfile somehow
2158 if (psInfo == NULL || psInfo->hLayer == NULL) {
2159 msSetError(MS_MISCERR, "Assertion failed: OGR layer not opened!!!", "msOGRFileWhichShapes()");
2160 return(MS_FAILURE);
2161 }
2162
2163 char *select = (psInfo->pszSelect) ? msStrdup(psInfo->pszSelect) : NULL;
2164 const rectObj rectInvalid = MS_INIT_INVALID_RECT;
2165 bool bIsValidRect = memcmp(&rect, &rectInvalid, sizeof(rect)) != 0;
2166
2167 // we'll go strictly two possible ways:
2168 // 1) GetLayer + SetFilter
2169 // 2) ExecuteSQL (psInfo->hLayer is an SQL result OR sortBy was requested OR have native_string
2170 // and start from the second
2171
2172 if ( psInfo->bIsOKForSQLCompose && (psInfo->nLayerIndex == -1 ||
2173 layer->sortBy.nProperties > 0 ||
2174 layer->filter.native_string ||
2175 (psInfo->bPaging && layer->maxfeatures > 0)) ) {
2176
2177 const bool bHasGeometry =
2178 OGR_L_GetGeomType( psInfo->hLayer ) != wkbNone;
2179
2180 if( psInfo->nLayerIndex == -1 && select == NULL ) {
2181 select = msStrdup(psInfo->pszLayerDef);
2182 /* If nLayerIndex == -1 then the layer is an SQL result ... free it */
2183 OGR_DS_ReleaseResultSet( psInfo->hDS, psInfo->hLayer );
2184 psInfo->hLayer = NULL;
2185 }
2186 else if( select == NULL ) {
2187 const char* pszGeometryColumn;
2188 int i;
2189 select = msStringConcatenate(select, "SELECT ");
2190 for(i = 0; i < layer->numitems; i++) {
2191 if( i > 0 )
2192 select = msStringConcatenate(select, ", ");
2193 char* escaped = msOGRGetQuotedItem(layer, layer->items[i]);
2194 select = msStringConcatenate(select, escaped);
2195 msFree(escaped);
2196 if( psInfo->pszTablePrefix )
2197 {
2198 select = msStringConcatenate(select, " AS \"");
2199 escaped = msLayerEscapePropertyName(layer, layer->items[i]);
2200 select = msStringConcatenate(select, escaped);
2201 msFree(escaped);
2202 select = msStringConcatenate(select, "\"");
2203 }
2204 }
2205 if( layer->numitems > 0 )
2206 select = msStringConcatenate(select, ", ");
2207 pszGeometryColumn = OGR_L_GetGeometryColumn(psInfo->hLayer);
2208 if( pszGeometryColumn != NULL && pszGeometryColumn[0] != '\0' ) {
2209 char* escaped = msOGRGetQuotedItem(layer, pszGeometryColumn);
2210 select = msStringConcatenate(select, escaped);
2211 msFree(escaped);
2212 if( psInfo->pszTablePrefix )
2213 {
2214 select = msStringConcatenate(select, " AS \"");
2215 escaped = msLayerEscapePropertyName(layer, pszGeometryColumn);
2216 select = msStringConcatenate(select, escaped);
2217 msFree(escaped);
2218 select = msStringConcatenate(select, "\"");
2219 }
2220 } else {
2221 /* Add ", *" so that we still have an hope to get the geometry */
2222 if( psInfo->pszTablePrefix )
2223 {
2224 select = msStringConcatenate(select, "\"");
2225 char* escaped = msLayerEscapePropertyName(layer, psInfo->pszTablePrefix);
2226 select = msStringConcatenate(select, escaped);
2227 msFree(escaped);
2228 select = msStringConcatenate(select, "\".");
2229 }
2230 select = msStringConcatenate(select, "*");
2231 }
2232 select = msStringConcatenate(select, " FROM ");
2233 if( psInfo->nLayerIndex == -1 )
2234 {
2235 select = msStringConcatenate(select, "(");
2236 select = msStringConcatenate(select, psInfo->pszLayerDef);
2237 select = msStringConcatenate(select, ") MSSUBSELECT");
2238 }
2239 else
2240 {
2241 select = msStringConcatenate(select, "\"");
2242 char* escaped = msLayerEscapePropertyName(layer, OGR_FD_GetName(OGR_L_GetLayerDefn(psInfo->hLayer)));
2243 select = msStringConcatenate(select, escaped);
2244 msFree(escaped);
2245 select = msStringConcatenate(select, "\"");
2246 }
2247 }
2248
2249 char *filter = NULL;
2250 if (msLayerGetProcessingKey(layer, "NATIVE_FILTER") != NULL) {
2251 filter = msStringConcatenate(filter, "(");
2252 filter = msStringConcatenate(filter, msLayerGetProcessingKey(layer, "NATIVE_FILTER"));
2253 filter = msStringConcatenate(filter, ")");
2254 }
2255
2256 /* ------------------------------------------------------------------
2257 * Set Spatial filter... this may result in no features being returned
2258 * if layer does not overlap current view.
2259 *
2260 * __TODO__ We should return MS_DONE if no shape overlaps the selected
2261 * region and matches the layer's FILTER expression, but there is currently
2262 * no _efficient_ way to do that with OGR.
2263 * ------------------------------------------------------------------ */
2264 if (psInfo->rect_is_defined) {
2265 rect.minx = MAX(psInfo->rect.minx, rect.minx);
2266 rect.miny = MAX(psInfo->rect.miny, rect.miny);
2267 rect.maxx = MIN(psInfo->rect.maxx, rect.maxx);
2268 rect.maxy = MIN(psInfo->rect.maxy, rect.maxy);
2269 bIsValidRect = true;
2270 }
2271 psInfo->rect = rect;
2272
2273 bool bSpatialiteOrGPKGAddOrderByFID = false;
2274
2275 const char *sql = layer->filter.native_string;
2276 if (psInfo->dialect && sql && *sql != '\0' &&
2277 (EQUAL(psInfo->dialect, "Spatialite") ||
2278 EQUAL(psInfo->dialect, "GPKG") ||
2279 EQUAL(psInfo->dialect, "PostgreSQL")) )
2280 {
2281 if (filter) filter = msStringConcatenate(filter, " AND ");
2282 filter = msStringConcatenate(filter, "(");
2283 filter = msStringConcatenate(filter, sql);
2284 filter = msStringConcatenate(filter, ")");
2285 }
2286 else if( psInfo->pszWHERE )
2287 {
2288 if (filter) filter = msStringConcatenate(filter, " AND ");
2289 filter = msStringConcatenate(filter, "(");
2290 filter = msStringConcatenate(filter, psInfo->pszWHERE);
2291 filter = msStringConcatenate(filter, ")");
2292 }
2293
2294 bool bOffsetAlreadyAdded = false;
2295 // use spatial index
2296 if (psInfo->dialect && bIsValidRect ) {
2297 if (EQUAL(psInfo->dialect, "PostgreSQL")) {
2298 if (filter) filter = msStringConcatenate(filter, " AND");
2299 const char *col = OGR_L_GetGeometryColumn(psInfo->hLayer); // which geom field??
2300 filter = msStringConcatenate(filter, " (\"");
2301 char* escaped = msLayerEscapePropertyName(layer, col);
2302 filter = msStringConcatenate(filter, escaped);
2303 msFree(escaped);
2304 filter = msStringConcatenate(filter, "\" && ST_MakeEnvelope(");
2305 char *points = (char *)msSmallMalloc(30*2*5);
2306 snprintf(points, 30*4, "%lf,%lf,%lf,%lf", rect.minx, rect.miny, rect.maxx, rect.maxy);
2307 filter = msStringConcatenate(filter, points);
2308 msFree(points);
2309 filter = msStringConcatenate(filter, "))");
2310 }
2311 else if( psInfo->dialect &&
2312 (EQUAL(psInfo->dialect, "Spatialite") ||
2313 EQUAL(psInfo->dialect, "GPKG")) &&
2314 psInfo->pszMainTableName != NULL )
2315 {
2316 if( (EQUAL(psInfo->dialect, "Spatialite") && psInfo->bHasSpatialIndex)
2317 || EQUAL(psInfo->dialect, "GPKG") )
2318 {
2319 if (filter) filter = msStringConcatenate(filter, " AND ");
2320 char* pszEscapedMainTableName = msLayerEscapePropertyName(
2321 layer, psInfo->pszMainTableName);
2322 filter = msStringConcatenate(filter, "\"");
2323 filter = msStringConcatenate(filter, pszEscapedMainTableName);
2324 msFree(pszEscapedMainTableName);
2325 filter = msStringConcatenate(filter, "\".");
2326 if( psInfo->pszRowId )
2327 {
2328 char* pszEscapedRowId = msLayerEscapePropertyName(
2329 layer, psInfo->pszRowId);
2330 filter = msStringConcatenate(filter, "\"");
2331 filter = msStringConcatenate(filter, pszEscapedRowId);
2332 filter = msStringConcatenate(filter, "\"");
2333 msFree(pszEscapedRowId);
2334 }
2335 else
2336 filter = msStringConcatenate(filter, "ROWID");
2337
2338 filter = msStringConcatenate(filter, " IN ");
2339 filter = msStringConcatenate(filter, "(");
2340 filter = msStringConcatenate(filter, "SELECT ");
2341
2342 if( EQUAL(psInfo->dialect, "Spatialite") )
2343 filter = msStringConcatenate(filter, "ms_spat_idx.pkid");
2344 else
2345 filter = msStringConcatenate(filter, "ms_spat_idx.id");
2346
2347 filter = msStringConcatenate(filter, " FROM ");
2348
2349 char szSpatialIndexName[256];
2350 snprintf( szSpatialIndexName, sizeof(szSpatialIndexName),
2351 "%s_%s_%s",
2352 EQUAL(psInfo->dialect, "Spatialite") ? "idx" : "rtree",
2353 psInfo->pszSpatialFilterTableName,
2354 psInfo->pszSpatialFilterGeometryColumn );
2355 char* pszEscapedSpatialIndexName = msLayerEscapePropertyName(
2356 layer, szSpatialIndexName);
2357
2358 filter = msStringConcatenate(filter, "\"");
2359 filter = msStringConcatenate(filter, pszEscapedSpatialIndexName);
2360 msFree(pszEscapedSpatialIndexName);
2361
2362 filter = msStringConcatenate(filter, "\" ms_spat_idx WHERE ");
2363
2364 char szCond[256];
2365 if( EQUAL(psInfo->dialect, "Spatialite") )
2366 {
2367 snprintf(szCond, sizeof(szCond),
2368 "ms_spat_idx.xmin <= %.15g AND ms_spat_idx.xmax >= %.15g AND "
2369 "ms_spat_idx.ymin <= %.15g AND ms_spat_idx.ymax >= %.15g",
2370 rect.maxx, rect.minx, rect.maxy, rect.miny);
2371 }
2372 else
2373 {
2374 snprintf(szCond, sizeof(szCond),
2375 "ms_spat_idx.minx <= %.15g AND ms_spat_idx.maxx >= %.15g AND "
2376 "ms_spat_idx.miny <= %.15g AND ms_spat_idx.maxy >= %.15g",
2377 rect.maxx, rect.minx, rect.maxy, rect.miny);
2378 }
2379 filter = msStringConcatenate(filter, szCond);
2380
2381 filter = msStringConcatenate(filter, ")");
2382
2383 bSpatialiteOrGPKGAddOrderByFID = true;
2384 }
2385
2386 const bool isGPKG = EQUAL(psInfo->dialect, "GPKG");
2387 if (filter) filter = msStringConcatenate(filter, " AND");
2388 const char *col = OGR_L_GetGeometryColumn(psInfo->hLayer); // which geom field??
2389 filter = msStringConcatenate(filter, " Intersects(");
2390 if( isGPKG )
2391 {
2392 // Casting GeoPackage geometries to spatialie ones is done
2393 // automatically normally, since GDAL enables the
2394 // "amphibious" mode, but without it
2395 // explicilty specified, spatialite 4.3.0a does an
2396 // out-of-bounds access.
2397 filter = msStringConcatenate(filter, "GeomFromGPB(");
2398 }
2399 filter = msStringConcatenate(filter, "\"");
2400 char* escaped = msLayerEscapePropertyName(layer, col);
2401 filter = msStringConcatenate(filter, escaped);
2402 msFree(escaped);
2403 filter = msStringConcatenate(filter, "\"");
2404 if( isGPKG )
2405 filter = msStringConcatenate(filter, ")");
2406 filter = msStringConcatenate(filter, ", BuildMbr(");
2407 char *points = (char *)msSmallMalloc(30*2*5);
2408 snprintf(points, 30*4, "%lf,%lf,%lf,%lf", rect.minx, rect.miny, rect.maxx, rect.maxy);
2409 filter = msStringConcatenate(filter, points);
2410 msFree(points);
2411 filter = msStringConcatenate(filter, "))");
2412 }
2413 }
2414
2415 /* get sortBy */
2416 char *sort = NULL;
2417 if( layer->sortBy.nProperties > 0) {
2418
2419 char *strOrderBy = msOGRLayerBuildSQLOrderBy(layer, psInfo);
2420 if (strOrderBy) {
2421 if( psInfo->nLayerIndex == -1 ) {
2422 if( strcasestr(psInfo->pszLayerDef, " ORDER BY ") == NULL )
2423 sort = msStringConcatenate(sort, " ORDER BY ");
2424 else
2425 sort = msStringConcatenate(sort, ", ");
2426 } else {
2427 sort = msStringConcatenate(sort, " ORDER BY ");
2428 }
2429 sort = msStringConcatenate(sort, strOrderBy);
2430 msFree(strOrderBy);
2431 }
2432 }
2433
2434 if( bSpatialiteOrGPKGAddOrderByFID )
2435 {
2436 if( sort == NULL )
2437 sort = msStringConcatenate(NULL, " ORDER BY ");
2438 else
2439 sort = msStringConcatenate(sort, ", ");
2440 char* pszEscapedMainTableName = msLayerEscapePropertyName(
2441 layer, psInfo->pszMainTableName);
2442 sort = msStringConcatenate(sort, "\"");
2443 sort = msStringConcatenate(sort, pszEscapedMainTableName);
2444 sort = msStringConcatenate(sort, "\".");
2445 msFree(pszEscapedMainTableName);
2446 if( psInfo->pszRowId )
2447 {
2448 char* pszEscapedRowId = msLayerEscapePropertyName(
2449 layer, psInfo->pszRowId);
2450 sort = msStringConcatenate(sort, "\"");
2451 sort = msStringConcatenate(sort, pszEscapedRowId);
2452 sort = msStringConcatenate(sort, "\"");
2453 msFree(pszEscapedRowId);
2454 }
2455 else
2456 sort = msStringConcatenate(sort, "ROWID");
2457 }
2458
2459 // compose SQL
2460 if (filter) {
2461 select = msStringConcatenate(select, " WHERE ");
2462 select = msStringConcatenate(select, filter);
2463 msFree(filter);
2464 }
2465 if (sort) {
2466 select = msStringConcatenate(select, " ");
2467 select = msStringConcatenate(select, sort);
2468 msFree(sort);
2469 }
2470
2471 if ( psInfo->bPaging && layer->maxfeatures >= 0 ) {
2472 char szLimit[50];
2473 snprintf(szLimit, sizeof(szLimit), " LIMIT %d", layer->maxfeatures);
2474 select = msStringConcatenate(select, szLimit);
2475 }
2476
2477 if ( !bOffsetAlreadyAdded && psInfo->bPaging && layer->startindex > 0 ) {
2478 char szOffset[50];
2479 snprintf(szOffset, sizeof(szOffset), " OFFSET %d", layer->startindex-1);
2480 select = msStringConcatenate(select, szOffset);
2481 }
2482
2483 if( layer->debug )
2484 msDebug("msOGRFileWhichShapes: SQL = %s.\n", select);
2485
2486 ACQUIRE_OGR_LOCK;
2487 if( psInfo->nLayerIndex == -1 && psInfo->hLayer != NULL )
2488 {
2489 OGR_DS_ReleaseResultSet( psInfo->hDS, psInfo->hLayer );
2490 }
2491
2492 OGRGeometryH hGeom = NULL;
2493 if( psInfo->dialect == NULL &&
2494 bHasGeometry && bIsValidRect ) {
2495 if (rect.minx == rect.maxx && rect.miny == rect.maxy) {
2496 hGeom = OGR_G_CreateGeometry( wkbPoint );
2497 OGR_G_SetPoint_2D( hGeom, 0, rect.minx, rect.miny );
2498 } else if (rect.minx == rect.maxx || rect.miny == rect.maxy) {
2499 hGeom = OGR_G_CreateGeometry( wkbLineString );
2500 OGR_G_AddPoint_2D( hGeom, rect.minx, rect.miny );
2501 OGR_G_AddPoint_2D( hGeom, rect.maxx, rect.maxy );
2502 } else {
2503 hGeom = OGR_G_CreateGeometry( wkbPolygon );
2504 OGRGeometryH hRing = OGR_G_CreateGeometry( wkbLinearRing );
2505
2506 OGR_G_AddPoint_2D( hRing, rect.minx, rect.miny);
2507 OGR_G_AddPoint_2D( hRing, rect.maxx, rect.miny);
2508 OGR_G_AddPoint_2D( hRing, rect.maxx, rect.maxy);
2509 OGR_G_AddPoint_2D( hRing, rect.minx, rect.maxy);
2510 OGR_G_AddPoint_2D( hRing, rect.minx, rect.miny);
2511 OGR_G_AddGeometryDirectly( hGeom, hRing );
2512 }
2513
2514 if (layer->debug >= MS_DEBUGLEVEL_VVV)
2515 {
2516 msDebug("msOGRFileWhichShapes: Setting spatial filter to %.15g %.15g %.15g %.15g\n",
2517 rect.minx, rect.miny, rect.maxx, rect.maxy );
2518 }
2519 }
2520
2521 psInfo->hLayer = OGR_DS_ExecuteSQL( psInfo->hDS, select, hGeom, NULL );
2522 psInfo->nLayerIndex = -1;
2523 if( hGeom != NULL )
2524 OGR_G_DestroyGeometry(hGeom);
2525
2526 if( psInfo->hLayer == NULL ) {
2527 RELEASE_OGR_LOCK;
2528 msSetError(MS_OGRERR, "ExecuteSQL() failed. Check logs.", "msOGRFileWhichShapes()");
2529 msDebug("ExecuteSQL(%s) failed.\n%s\n", select, CPLGetLastErrorMsg());
2530 msFree(select);
2531 return MS_FAILURE;
2532 }
2533
2534 // Update itemindexes / layer->iteminfo
2535 msOGRLayerInitItemInfo(layer);
2536 }
2537 else {
2538
2539 // case of 1) GetLayer + SetFilter
2540
2541 char *pszOGRFilter = NULL;
2542 if (msLayerGetProcessingKey(layer, "NATIVE_FILTER") != NULL) {
2543 pszOGRFilter = msStringConcatenate(pszOGRFilter, "(");
2544 pszOGRFilter = msStringConcatenate(pszOGRFilter, msLayerGetProcessingKey(layer, "NATIVE_FILTER"));
2545 pszOGRFilter = msStringConcatenate(pszOGRFilter, ")");
2546 }
2547
2548 if( psInfo->pszWHERE )
2549 {
2550 if( pszOGRFilter )
2551 {
2552 pszOGRFilter = msStringConcatenate(pszOGRFilter, " AND (");
2553 pszOGRFilter = msStringConcatenate(pszOGRFilter, psInfo->pszWHERE);
2554 pszOGRFilter = msStringConcatenate(pszOGRFilter, ")");
2555 }
2556 else
2557 {
2558 pszOGRFilter = msStringConcatenate(pszOGRFilter, psInfo->pszWHERE);
2559 }
2560 }
2561
2562 ACQUIRE_OGR_LOCK;
2563
2564 if( OGR_L_GetGeomType( psInfo->hLayer ) != wkbNone && bIsValidRect ) {
2565 if (rect.minx == rect.maxx && rect.miny == rect.maxy) {
2566 OGRGeometryH hSpatialFilterPoint = OGR_G_CreateGeometry( wkbPoint );
2567
2568 OGR_G_SetPoint_2D( hSpatialFilterPoint, 0, rect.minx, rect.miny );
2569 OGR_L_SetSpatialFilter( psInfo->hLayer, hSpatialFilterPoint );
2570 OGR_G_DestroyGeometry( hSpatialFilterPoint );
2571 } else if (rect.minx == rect.maxx || rect.miny == rect.maxy) {
2572 OGRGeometryH hSpatialFilterLine = OGR_G_CreateGeometry( wkbLineString );
2573
2574 OGR_G_AddPoint_2D( hSpatialFilterLine, rect.minx, rect.miny );
2575 OGR_G_AddPoint_2D( hSpatialFilterLine, rect.maxx, rect.maxy );
2576 OGR_L_SetSpatialFilter( psInfo->hLayer, hSpatialFilterLine );
2577 OGR_G_DestroyGeometry( hSpatialFilterLine );
2578 } else {
2579 OGRGeometryH hSpatialFilterPolygon = OGR_G_CreateGeometry( wkbPolygon );
2580 OGRGeometryH hRing = OGR_G_CreateGeometry( wkbLinearRing );
2581
2582 OGR_G_AddPoint_2D( hRing, rect.minx, rect.miny);
2583 OGR_G_AddPoint_2D( hRing, rect.maxx, rect.miny);
2584 OGR_G_AddPoint_2D( hRing, rect.maxx, rect.maxy);
2585 OGR_G_AddPoint_2D( hRing, rect.minx, rect.maxy);
2586 OGR_G_AddPoint_2D( hRing, rect.minx, rect.miny);
2587 OGR_G_AddGeometryDirectly( hSpatialFilterPolygon, hRing );
2588 OGR_L_SetSpatialFilter( psInfo->hLayer, hSpatialFilterPolygon );
2589 OGR_G_DestroyGeometry( hSpatialFilterPolygon );
2590 }
2591
2592 if (layer->debug >= MS_DEBUGLEVEL_VVV)
2593 {
2594 msDebug("msOGRFileWhichShapes: Setting spatial filter to %.15g %.15g %.15g %.15g\n", rect.minx, rect.miny, rect.maxx, rect.maxy );
2595 }
2596 }
2597
2598 psInfo->rect = rect;
2599
2600 /* ------------------------------------------------------------------
2601 * Apply an attribute filter if we have one prefixed with a WHERE
2602 * keyword in the filter string. Otherwise, ensure the attribute
2603 * filter is clear.
2604 * ------------------------------------------------------------------ */
2605 if( pszOGRFilter != NULL ) {
2606
2607 if (layer->debug >= MS_DEBUGLEVEL_VVV)
2608 msDebug("msOGRFileWhichShapes: Setting attribute filter to %s\n", pszOGRFilter );
2609
2610 CPLErrorReset();
2611 if( OGR_L_SetAttributeFilter( psInfo->hLayer, pszOGRFilter ) != OGRERR_NONE ) {
2612 msSetError(MS_OGRERR, "SetAttributeFilter() failed on layer %s. Check logs.", "msOGRFileWhichShapes()", layer->name?layer->name:"(null)");
2613 msDebug("SetAttributeFilter(%s) failed on layer %s.\n%s\n", pszOGRFilter, layer->name?layer->name:"(null)", CPLGetLastErrorMsg() );
2614 RELEASE_OGR_LOCK;
2615 msFree(pszOGRFilter);
2616 msFree(select);
2617 return MS_FAILURE;
2618 }
2619 msFree(pszOGRFilter);
2620 } else
2621 OGR_L_SetAttributeFilter( psInfo->hLayer, NULL );
2622
2623 }
2624
2625 msFree(select);
2626
2627 /* ------------------------------------------------------------------
2628 * Reset current feature pointer
2629 * ------------------------------------------------------------------ */
2630 OGR_L_ResetReading( psInfo->hLayer );
2631 psInfo->last_record_index_read = -1;
2632
2633 RELEASE_OGR_LOCK;
2634
2635 return MS_SUCCESS;
2636 }
2637
2638 /**********************************************************************
2639 * msOGRPassThroughFieldDefinitions()
2640 *
2641 * Pass the field definitions through to the layer metadata in the
2642 * "gml_[item]_{type,width,precision}" set of metadata items for
2643 * defining fields.
2644 **********************************************************************/
2645
2646 static void
msOGRPassThroughFieldDefinitions(layerObj * layer,msOGRFileInfo * psInfo)2647 msOGRPassThroughFieldDefinitions( layerObj *layer, msOGRFileInfo *psInfo )
2648
2649 {
2650 OGRFeatureDefnH hDefn = OGR_L_GetLayerDefn( psInfo->hLayer );
2651 int numitems, i;
2652
2653 numitems = OGR_FD_GetFieldCount( hDefn );
2654
2655 for(i=0; i<numitems; i++) {
2656 OGRFieldDefnH hField = OGR_FD_GetFieldDefn( hDefn, i );
2657 char md_item_name[256];
2658 char gml_width[32], gml_precision[32];
2659 const char *gml_type = NULL;
2660 const char *item = OGR_Fld_GetNameRef( hField );
2661
2662 gml_width[0] = '\0';
2663 gml_precision[0] = '\0';
2664
2665 switch( OGR_Fld_GetType( hField ) ) {
2666 case OFTInteger:
2667 gml_type = "Integer";
2668 if( OGR_Fld_GetWidth( hField) > 0 )
2669 sprintf( gml_width, "%d", OGR_Fld_GetWidth( hField) );
2670 break;
2671
2672 #if GDAL_VERSION_MAJOR >= 2
2673 case OFTInteger64:
2674 gml_type = "Long";
2675 if( OGR_Fld_GetWidth( hField) > 0 )
2676 sprintf( gml_width, "%d", OGR_Fld_GetWidth( hField) );
2677 break;
2678 #endif
2679
2680 case OFTReal:
2681 gml_type = "Real";
2682 if( OGR_Fld_GetWidth( hField) > 0 )
2683 sprintf( gml_width, "%d", OGR_Fld_GetWidth( hField) );
2684 if( OGR_Fld_GetPrecision( hField ) > 0 )
2685 sprintf( gml_precision, "%d", OGR_Fld_GetPrecision( hField) );
2686 break;
2687
2688 case OFTString:
2689 gml_type = "Character";
2690 if( OGR_Fld_GetWidth( hField) > 0 )
2691 sprintf( gml_width, "%d", OGR_Fld_GetWidth( hField) );
2692 break;
2693
2694 case OFTDate:
2695 gml_type = "Date";
2696 break;
2697 case OFTTime:
2698 gml_type = "Time";
2699 break;
2700 case OFTDateTime:
2701 gml_type = "DateTime";
2702 break;
2703
2704 default:
2705 gml_type = "Character";
2706 break;
2707 }
2708
2709 snprintf( md_item_name, sizeof(md_item_name), "gml_%s_type", item );
2710 if( msOWSLookupMetadata(&(layer->metadata), "G", "type") == NULL )
2711 msInsertHashTable(&(layer->metadata), md_item_name, gml_type );
2712
2713 snprintf( md_item_name, sizeof(md_item_name), "gml_%s_width", item );
2714 if( strlen(gml_width) > 0
2715 && msOWSLookupMetadata(&(layer->metadata), "G", "width") == NULL )
2716 msInsertHashTable(&(layer->metadata), md_item_name, gml_width );
2717
2718 snprintf( md_item_name, sizeof(md_item_name), "gml_%s_precision",item );
2719 if( strlen(gml_precision) > 0
2720 && msOWSLookupMetadata(&(layer->metadata), "G", "precision")==NULL )
2721 msInsertHashTable(&(layer->metadata), md_item_name, gml_precision );
2722 }
2723
2724 /* Should we try to address style items, or other special items? */
2725 }
2726
2727 /**********************************************************************
2728 * msOGRFileGetItems()
2729 *
2730 * Returns a list of field names in a NULL terminated list of strings.
2731 **********************************************************************/
msOGRFileGetItems(layerObj * layer,msOGRFileInfo * psInfo)2732 static char **msOGRFileGetItems(layerObj *layer, msOGRFileInfo *psInfo )
2733 {
2734 OGRFeatureDefnH hDefn;
2735 int i, numitems,totalnumitems;
2736 int numStyleItems = MSOGR_LABELNUMITEMS;
2737 char **items;
2738 const char *getShapeStyleItems, *value;
2739
2740 if((hDefn = OGR_L_GetLayerDefn( psInfo->hLayer )) == NULL) {
2741 msSetError(MS_OGRERR,
2742 "OGR Connection for layer `%s' contains no field definition.",
2743 "msOGRFileGetItems()",
2744 layer->name?layer->name:"(null)" );
2745 return NULL;
2746 }
2747
2748 totalnumitems = numitems = OGR_FD_GetFieldCount( hDefn );
2749
2750 getShapeStyleItems = msLayerGetProcessingKey( layer, "GETSHAPE_STYLE_ITEMS" );
2751 if (getShapeStyleItems && EQUAL(getShapeStyleItems, "all"))
2752 totalnumitems += numStyleItems;
2753
2754 if((items = (char**)malloc(sizeof(char *)*(totalnumitems+1))) == NULL) {
2755 msSetError(MS_MEMERR, NULL, "msOGRFileGetItems()");
2756 return NULL;
2757 }
2758
2759 for(i=0; i<numitems; i++) {
2760 OGRFieldDefnH hField = OGR_FD_GetFieldDefn( hDefn, i );
2761 items[i] = msStrdup( OGR_Fld_GetNameRef( hField ));
2762 }
2763
2764 if (getShapeStyleItems && EQUAL(getShapeStyleItems, "all")) {
2765 assert(numStyleItems == 21);
2766 items[i++] = msStrdup( MSOGR_LABELFONTNAMENAME );
2767 items[i++] = msStrdup( MSOGR_LABELSIZENAME );
2768 items[i++] = msStrdup( MSOGR_LABELTEXTNAME );
2769 items[i++] = msStrdup( MSOGR_LABELANGLENAME );
2770 items[i++] = msStrdup( MSOGR_LABELFCOLORNAME );
2771 items[i++] = msStrdup( MSOGR_LABELBCOLORNAME );
2772 items[i++] = msStrdup( MSOGR_LABELPLACEMENTNAME );
2773 items[i++] = msStrdup( MSOGR_LABELANCHORNAME );
2774 items[i++] = msStrdup( MSOGR_LABELDXNAME );
2775 items[i++] = msStrdup( MSOGR_LABELDYNAME );
2776 items[i++] = msStrdup( MSOGR_LABELPERPNAME );
2777 items[i++] = msStrdup( MSOGR_LABELBOLDNAME );
2778 items[i++] = msStrdup( MSOGR_LABELITALICNAME );
2779 items[i++] = msStrdup( MSOGR_LABELUNDERLINENAME );
2780 items[i++] = msStrdup( MSOGR_LABELPRIORITYNAME );
2781 items[i++] = msStrdup( MSOGR_LABELSTRIKEOUTNAME );
2782 items[i++] = msStrdup( MSOGR_LABELSTRETCHNAME );
2783 items[i++] = msStrdup( MSOGR_LABELADJHORNAME );
2784 items[i++] = msStrdup( MSOGR_LABELADJVERTNAME );
2785 items[i++] = msStrdup( MSOGR_LABELHCOLORNAME );
2786 items[i++] = msStrdup( MSOGR_LABELOCOLORNAME );
2787 }
2788 items[i++] = NULL;
2789
2790 /* -------------------------------------------------------------------- */
2791 /* consider populating the field definitions in metadata. */
2792 /* -------------------------------------------------------------------- */
2793 if((value = msOWSLookupMetadata(&(layer->metadata), "G", "types")) != NULL
2794 && strcasecmp(value,"auto") == 0 )
2795 msOGRPassThroughFieldDefinitions( layer, psInfo );
2796
2797 return items;
2798 }
2799
2800 /**********************************************************************
2801 * msOGRFileNextShape()
2802 *
2803 * Returns shape sequentially from OGR data source.
2804 * msOGRLayerWhichShape() must have been called first.
2805 *
2806 * Returns MS_SUCCESS/MS_FAILURE
2807 **********************************************************************/
2808 static int
msOGRFileNextShape(layerObj * layer,shapeObj * shape,msOGRFileInfo * psInfo)2809 msOGRFileNextShape(layerObj *layer, shapeObj *shape,
2810 msOGRFileInfo *psInfo )
2811 {
2812 OGRFeatureH hFeature = NULL;
2813
2814 if (psInfo == NULL || psInfo->hLayer == NULL) {
2815 msSetError(MS_MISCERR, "Assertion failed: OGR layer not opened!!!",
2816 "msOGRFileNextShape()");
2817 return(MS_FAILURE);
2818 }
2819
2820 /* ------------------------------------------------------------------
2821 * Read until we find a feature that matches attribute filter and
2822 * whose geometry is compatible with current layer type.
2823 * ------------------------------------------------------------------ */
2824 msFreeShape(shape);
2825 shape->type = MS_SHAPE_NULL;
2826
2827 ACQUIRE_OGR_LOCK;
2828 while (shape->type == MS_SHAPE_NULL) {
2829 if( hFeature )
2830 OGR_F_Destroy( hFeature );
2831
2832 if( (hFeature = OGR_L_GetNextFeature( psInfo->hLayer )) == NULL ) {
2833 psInfo->last_record_index_read = -1;
2834 if( CPLGetLastErrorType() == CE_Failure ) {
2835 msSetError(MS_OGRERR, "OGR GetNextFeature() error'd. Check logs.",
2836 "msOGRFileNextShape()");
2837 msDebug("msOGRFileNextShape(): %s\n",
2838 CPLGetLastErrorMsg() );
2839 RELEASE_OGR_LOCK;
2840 return MS_FAILURE;
2841 } else {
2842 RELEASE_OGR_LOCK;
2843 if (layer->debug >= MS_DEBUGLEVEL_VV)
2844 msDebug("msOGRFileNextShape: Returning MS_DONE (no more shapes)\n" );
2845 return MS_DONE; // No more features to read
2846 }
2847 }
2848
2849 psInfo->last_record_index_read++;
2850
2851 if(layer->numitems > 0) {
2852 if (shape->values) msFreeCharArray(shape->values, shape->numvalues);
2853 shape->values = msOGRGetValues(layer, hFeature);
2854 shape->numvalues = layer->numitems;
2855 if(!shape->values) {
2856 OGR_F_Destroy( hFeature );
2857 RELEASE_OGR_LOCK;
2858 return(MS_FAILURE);
2859 }
2860 }
2861
2862 // Feature matched filter expression... process geometry
2863 // shape->type will be set if geom is compatible with layer type
2864 if (ogrConvertGeometry(ogrGetLinearGeometry( hFeature ), shape,
2865 layer->type) == MS_SUCCESS) {
2866 if (shape->type != MS_SHAPE_NULL)
2867 break; // Shape is ready to be returned!
2868
2869 if (layer->debug >= MS_DEBUGLEVEL_VVV)
2870 msDebug("msOGRFileNextShape: Rejecting feature (shapeid = " CPL_FRMT_GIB ", tileid=%d) of incompatible type for this layer (feature wkbType %d, layer type %d)\n",
2871 (GIntBig)OGR_F_GetFID( hFeature ), psInfo->nTileId,
2872 OGR_F_GetGeometryRef( hFeature )==NULL ? wkbFlatten(wkbUnknown):wkbFlatten( OGR_G_GetGeometryType( OGR_F_GetGeometryRef( hFeature ) ) ),
2873 layer->type);
2874
2875 } else {
2876 msFreeShape(shape);
2877 OGR_F_Destroy( hFeature );
2878 RELEASE_OGR_LOCK;
2879 return MS_FAILURE; // Error message already produced.
2880 }
2881
2882 // Feature rejected... free shape to clear attributes values.
2883 msFreeShape(shape);
2884 shape->type = MS_SHAPE_NULL;
2885 }
2886
2887 shape->index = (int)OGR_F_GetFID( hFeature ); // FIXME? GetFID() is a 64bit integer in GDAL 2.0
2888 shape->resultindex = psInfo->last_record_index_read;
2889 shape->tileindex = psInfo->nTileId;
2890
2891 if (layer->debug >= MS_DEBUGLEVEL_VVV)
2892 msDebug("msOGRFileNextShape: Returning shape=%ld, tile=%d\n",
2893 shape->index, shape->tileindex );
2894
2895 // Keep ref. to last feature read in case we need style info.
2896 if (psInfo->hLastFeature)
2897 OGR_F_Destroy( psInfo->hLastFeature );
2898 psInfo->hLastFeature = hFeature;
2899
2900 RELEASE_OGR_LOCK;
2901
2902 return MS_SUCCESS;
2903 }
2904
2905 /**********************************************************************
2906 * msOGRFileGetShape()
2907 *
2908 * Returns shape from OGR data source by id.
2909 *
2910 * Returns MS_SUCCESS/MS_FAILURE
2911 **********************************************************************/
2912 static int
msOGRFileGetShape(layerObj * layer,shapeObj * shape,long record,msOGRFileInfo * psInfo,int record_is_fid)2913 msOGRFileGetShape(layerObj *layer, shapeObj *shape, long record,
2914 msOGRFileInfo *psInfo, int record_is_fid )
2915 {
2916 OGRFeatureH hFeature;
2917
2918 if (psInfo == NULL || psInfo->hLayer == NULL) {
2919 msSetError(MS_MISCERR, "Assertion failed: OGR layer not opened!!!",
2920 "msOGRFileNextShape()");
2921 return(MS_FAILURE);
2922 }
2923
2924 /* -------------------------------------------------------------------- */
2925 /* Clear previously loaded shape. */
2926 /* -------------------------------------------------------------------- */
2927 msFreeShape(shape);
2928 shape->type = MS_SHAPE_NULL;
2929
2930 /* -------------------------------------------------------------------- */
2931 /* Support reading feature by fid. */
2932 /* -------------------------------------------------------------------- */
2933 if( record_is_fid ) {
2934 ACQUIRE_OGR_LOCK;
2935 if( (hFeature = OGR_L_GetFeature( psInfo->hLayer, record )) == NULL ) {
2936 RELEASE_OGR_LOCK;
2937 return MS_FAILURE;
2938 }
2939 }
2940
2941 /* -------------------------------------------------------------------- */
2942 /* Support reading shape by offset within the current */
2943 /* resultset. */
2944 /* -------------------------------------------------------------------- */
2945 else {
2946 ACQUIRE_OGR_LOCK;
2947 if( record <= psInfo->last_record_index_read
2948 || psInfo->last_record_index_read == -1 ) {
2949 OGR_L_ResetReading( psInfo->hLayer );
2950 psInfo->last_record_index_read = -1;
2951 }
2952
2953 hFeature = NULL;
2954 while( psInfo->last_record_index_read < record ) {
2955 if( hFeature != NULL ) {
2956 OGR_F_Destroy( hFeature );
2957 hFeature = NULL;
2958 }
2959 if( (hFeature = OGR_L_GetNextFeature( psInfo->hLayer )) == NULL ) {
2960 RELEASE_OGR_LOCK;
2961 return MS_FAILURE;
2962 }
2963 psInfo->last_record_index_read++;
2964 }
2965 }
2966
2967 /* ------------------------------------------------------------------
2968 * Handle shape geometry...
2969 * ------------------------------------------------------------------ */
2970 // shape->type will be set if geom is compatible with layer type
2971 if (ogrConvertGeometry(ogrGetLinearGeometry( hFeature ), shape,
2972 layer->type) != MS_SUCCESS) {
2973 RELEASE_OGR_LOCK;
2974 return MS_FAILURE; // Error message already produced.
2975 }
2976
2977 if (shape->type == MS_SHAPE_NULL) {
2978 msSetError(MS_OGRERR,
2979 "Requested feature is incompatible with layer type",
2980 "msOGRLayerGetShape()");
2981 RELEASE_OGR_LOCK;
2982 return MS_FAILURE;
2983 }
2984
2985 /* ------------------------------------------------------------------
2986 * Process shape attributes
2987 * ------------------------------------------------------------------ */
2988 if(layer->numitems > 0) {
2989 shape->values = msOGRGetValues(layer, hFeature);
2990 shape->numvalues = layer->numitems;
2991 if(!shape->values) {
2992 RELEASE_OGR_LOCK;
2993 return(MS_FAILURE);
2994 }
2995
2996 }
2997
2998 if (record_is_fid) {
2999 shape->index = record;
3000 shape->resultindex = -1;
3001 } else {
3002 shape->index = (int)OGR_F_GetFID( hFeature ); // FIXME? GetFID() is a 64bit integer in GDAL 2.0
3003 shape->resultindex = record;
3004 }
3005
3006 shape->tileindex = psInfo->nTileId;
3007
3008 // Keep ref. to last feature read in case we need style info.
3009 if (psInfo->hLastFeature)
3010 OGR_F_Destroy( psInfo->hLastFeature );
3011 psInfo->hLastFeature = hFeature;
3012
3013 RELEASE_OGR_LOCK;
3014
3015 return MS_SUCCESS;
3016 }
3017
3018 /************************************************************************/
3019 /* msOGRFileReadTile() */
3020 /* */
3021 /* Advance to the next tile (or if targetTile is not -1 advance */
3022 /* to that tile), causing the tile to become the poCurTile in */
3023 /* the tileindexes psInfo structure. Returns MS_DONE if there */
3024 /* are no more available tiles. */
3025 /* */
3026 /* Newly loaded tiles are automatically "WhichShaped" based on */
3027 /* the current rectangle. */
3028 /************************************************************************/
3029
msOGRFileReadTile(layerObj * layer,msOGRFileInfo * psInfo,int targetTile=-1)3030 int msOGRFileReadTile( layerObj *layer, msOGRFileInfo *psInfo,
3031 int targetTile = -1 )
3032
3033 {
3034 int nFeatureId;
3035
3036 /* -------------------------------------------------------------------- */
3037 /* Close old tile if one is open. */
3038 /* -------------------------------------------------------------------- */
3039 if( psInfo->poCurTile != NULL ) {
3040 msOGRFileClose( layer, psInfo->poCurTile );
3041 psInfo->poCurTile = NULL;
3042 }
3043
3044 /* -------------------------------------------------------------------- */
3045 /* If -2 is passed, then seek reset reading of the tileindex. */
3046 /* We want to start from the beginning even if this file is */
3047 /* shared between layers or renders. */
3048 /* -------------------------------------------------------------------- */
3049 ACQUIRE_OGR_LOCK;
3050 if( targetTile == -2 ) {
3051 OGR_L_ResetReading( psInfo->hLayer );
3052 }
3053
3054 /* -------------------------------------------------------------------- */
3055 /* Get the name (connection string really) of the next tile. */
3056 /* -------------------------------------------------------------------- */
3057 OGRFeatureH hFeature;
3058 char *connection = NULL;
3059 msOGRFileInfo *psTileInfo = NULL;
3060 int status;
3061
3062 #ifndef IGNORE_MISSING_DATA
3063 NextFile:
3064 #endif
3065
3066 if( targetTile < 0 )
3067 hFeature = OGR_L_GetNextFeature( psInfo->hLayer );
3068
3069 else
3070 hFeature = OGR_L_GetFeature( psInfo->hLayer, targetTile );
3071
3072 if( hFeature == NULL ) {
3073 RELEASE_OGR_LOCK;
3074 if( targetTile == -1 )
3075 return MS_DONE;
3076 else
3077 return MS_FAILURE;
3078
3079 }
3080
3081 connection = msStrdup( OGR_F_GetFieldAsString( hFeature,
3082 layer->tileitemindex ));
3083
3084 char* pszSRS = NULL;
3085 if( layer->tilesrs != NULL )
3086 {
3087 int idx = OGR_F_GetFieldIndex( hFeature, layer->tilesrs);
3088 if( idx >= 0 )
3089 {
3090 pszSRS = msStrdup( OGR_F_GetFieldAsString( hFeature, idx ));
3091 }
3092 }
3093
3094 nFeatureId = (int)OGR_F_GetFID( hFeature ); // FIXME? GetFID() is a 64bit integer in GDAL 2.0
3095
3096 OGR_F_Destroy( hFeature );
3097
3098 RELEASE_OGR_LOCK;
3099
3100 /* -------------------------------------------------------------------- */
3101 /* Open the new tile file. */
3102 /* -------------------------------------------------------------------- */
3103 psTileInfo = msOGRFileOpen( layer, connection );
3104
3105 free( connection );
3106
3107 #ifndef IGNORE_MISSING_DATA
3108 if( psTileInfo == NULL && targetTile == -1 )
3109 {
3110 msFree(pszSRS);
3111 goto NextFile;
3112 }
3113 #endif
3114
3115 if( psTileInfo == NULL )
3116 {
3117 msFree(pszSRS);
3118 return MS_FAILURE;
3119 }
3120
3121 if( pszSRS != NULL )
3122 {
3123 if( msOGCWKT2ProjectionObj( pszSRS, &(psInfo->sTileProj),
3124 layer->debug ) != MS_SUCCESS )
3125 {
3126 msFree(pszSRS);
3127 return MS_FAILURE;
3128 }
3129 msFree(pszSRS);
3130 }
3131
3132 psTileInfo->nTileId = nFeatureId;
3133
3134 /* -------------------------------------------------------------------- */
3135 /* Initialize the spatial query on this file. */
3136 /* -------------------------------------------------------------------- */
3137 if( psInfo->rect.minx != 0 || psInfo->rect.maxx != 0 ) {
3138 rectObj rect = psInfo->rect;
3139
3140 if( layer->tileindex != NULL && psInfo->sTileProj.numargs > 0 )
3141 {
3142 msProjectRect(&(layer->projection), &(psInfo->sTileProj), &rect);
3143 }
3144
3145 status = msOGRFileWhichShapes( layer, rect, psTileInfo );
3146 if( status != MS_SUCCESS )
3147 return status;
3148 }
3149
3150 psInfo->poCurTile = psTileInfo;
3151
3152 /* -------------------------------------------------------------------- */
3153 /* Update the iteminfo in case this layer has a different field */
3154 /* list. */
3155 /* -------------------------------------------------------------------- */
3156 msOGRLayerInitItemInfo( layer );
3157
3158 return MS_SUCCESS;
3159 }
3160
3161 /************************************************************************/
3162 /* msExprNode */
3163 /************************************************************************/
3164
3165 class msExprNode
3166 {
3167 public:
3168 std::vector<msExprNode*> m_aoChildren;
3169 int m_nToken;
3170 std::string m_osVal;
3171 double m_dfVal;
3172 struct tm m_tmVal;
3173
msExprNode()3174 msExprNode() : m_nToken(0), m_dfVal(0.0) {}
3175 ~msExprNode();
3176 };
3177
~msExprNode()3178 msExprNode::~msExprNode()
3179 {
3180 for(size_t i=0;i<m_aoChildren.size();++i)
3181 delete m_aoChildren[i];
3182 }
3183
3184 /************************************************************************/
3185 /* exprGetPriority() */
3186 /************************************************************************/
3187
exprGetPriority(int token)3188 static int exprGetPriority(int token)
3189 {
3190 if (token == MS_TOKEN_LOGICAL_NOT)
3191 return 9;
3192 else if (token == '*' || token == '/' || token == '%' )
3193 return 8;
3194 else if (token == '+' || token == '-' )
3195 return 7;
3196 else if (token == MS_TOKEN_COMPARISON_GE ||
3197 token == MS_TOKEN_COMPARISON_GT ||
3198 token == MS_TOKEN_COMPARISON_LE ||
3199 token == MS_TOKEN_COMPARISON_LT ||
3200 token == MS_TOKEN_COMPARISON_IN)
3201 return 6;
3202 else if (token == MS_TOKEN_COMPARISON_EQ ||
3203 token == MS_TOKEN_COMPARISON_IEQ ||
3204 token == MS_TOKEN_COMPARISON_LIKE ||
3205 token == MS_TOKEN_COMPARISON_RE ||
3206 token == MS_TOKEN_COMPARISON_IRE ||
3207 token == MS_TOKEN_COMPARISON_NE)
3208 return 5;
3209 else if (token == MS_TOKEN_LOGICAL_AND)
3210 return 4;
3211 else if (token == MS_TOKEN_LOGICAL_OR)
3212 return 3;
3213 else
3214 return 0;
3215 }
3216
3217 /************************************************************************/
3218 /* BuildExprTree() */
3219 /************************************************************************/
3220
BuildExprTree(tokenListNodeObjPtr node,tokenListNodeObjPtr * pNodeNext,int nParenthesisLevel)3221 static msExprNode* BuildExprTree(tokenListNodeObjPtr node,
3222 tokenListNodeObjPtr* pNodeNext,
3223 int nParenthesisLevel)
3224 {
3225 msExprNode* poRet = NULL;
3226 std::vector<msExprNode*> aoStackOp, aoStackVal;
3227 while( node != NULL )
3228 {
3229 if( node->token == '(' )
3230 {
3231 msExprNode* subExpr = BuildExprTree(node->next, &node,
3232 nParenthesisLevel + 1);
3233 if( subExpr == NULL )
3234 {
3235 goto fail;
3236 }
3237 aoStackVal.push_back(subExpr);
3238 continue;
3239 }
3240 else if( node->token == ')' )
3241 {
3242 if( nParenthesisLevel > 0 )
3243 {
3244 break;
3245 }
3246 goto fail;
3247 }
3248 else if( node->token == '+' ||
3249 node->token == '-' ||
3250 node->token == '*' ||
3251 node->token == '/' ||
3252 node->token == '%' ||
3253 node->token == MS_TOKEN_LOGICAL_NOT ||
3254 node->token == MS_TOKEN_LOGICAL_AND ||
3255 node->token == MS_TOKEN_LOGICAL_OR ||
3256 node->token == MS_TOKEN_COMPARISON_GE ||
3257 node->token == MS_TOKEN_COMPARISON_GT ||
3258 node->token == MS_TOKEN_COMPARISON_LE ||
3259 node->token == MS_TOKEN_COMPARISON_LT ||
3260 node->token == MS_TOKEN_COMPARISON_EQ ||
3261 node->token == MS_TOKEN_COMPARISON_IEQ ||
3262 node->token == MS_TOKEN_COMPARISON_LIKE ||
3263 node->token == MS_TOKEN_COMPARISON_NE ||
3264 node->token == MS_TOKEN_COMPARISON_RE ||
3265 node->token == MS_TOKEN_COMPARISON_IRE ||
3266 node->token == MS_TOKEN_COMPARISON_IN )
3267 {
3268 while( !aoStackOp.empty() &&
3269 exprGetPriority(node->token) <=
3270 exprGetPriority(aoStackOp.back()->m_nToken))
3271 {
3272 msExprNode* val1 = NULL;
3273 msExprNode* val2 = NULL;
3274 msExprNode* newNode = NULL;
3275 if (aoStackOp.back()->m_nToken != MS_TOKEN_LOGICAL_NOT)
3276 {
3277 if( aoStackVal.empty() )
3278 goto fail;
3279 val2 = aoStackVal.back();
3280 aoStackVal.pop_back();
3281 }
3282 if( aoStackVal.empty() )
3283 goto fail;
3284 val1 = aoStackVal.back();
3285 aoStackVal.pop_back();
3286
3287 newNode = new msExprNode;
3288 newNode->m_nToken = aoStackOp.back()->m_nToken;
3289 newNode->m_aoChildren.push_back(val1);
3290 if( val2 )
3291 newNode->m_aoChildren.push_back(val2);
3292 aoStackVal.push_back(newNode);
3293 delete aoStackOp.back();
3294 aoStackOp.pop_back();
3295 }
3296
3297 msExprNode* newNode = new msExprNode;
3298 newNode->m_nToken = node->token;
3299 aoStackOp.push_back(newNode);
3300 }
3301 else if( node->token == ',' )
3302 {
3303 }
3304 else if( node->token == MS_TOKEN_COMPARISON_INTERSECTS ||
3305 node->token == MS_TOKEN_COMPARISON_DISJOINT ||
3306 node->token == MS_TOKEN_COMPARISON_TOUCHES ||
3307 node->token == MS_TOKEN_COMPARISON_OVERLAPS ||
3308 node->token == MS_TOKEN_COMPARISON_CROSSES ||
3309 node->token == MS_TOKEN_COMPARISON_DWITHIN ||
3310 node->token == MS_TOKEN_COMPARISON_BEYOND ||
3311 node->token == MS_TOKEN_COMPARISON_WITHIN ||
3312 node->token == MS_TOKEN_COMPARISON_CONTAINS ||
3313 node->token == MS_TOKEN_COMPARISON_EQUALS ||
3314 node->token == MS_TOKEN_FUNCTION_LENGTH ||
3315 node->token == MS_TOKEN_FUNCTION_TOSTRING ||
3316 node->token == MS_TOKEN_FUNCTION_COMMIFY ||
3317 node->token == MS_TOKEN_FUNCTION_AREA ||
3318 node->token == MS_TOKEN_FUNCTION_ROUND ||
3319 node->token == MS_TOKEN_FUNCTION_FROMTEXT ||
3320 node->token == MS_TOKEN_FUNCTION_BUFFER ||
3321 node->token == MS_TOKEN_FUNCTION_DIFFERENCE ||
3322 node->token == MS_TOKEN_FUNCTION_SIMPLIFY ||
3323 node->token == MS_TOKEN_FUNCTION_SIMPLIFYPT ||
3324 node->token == MS_TOKEN_FUNCTION_GENERALIZE ||
3325 node->token == MS_TOKEN_FUNCTION_SMOOTHSIA ||
3326 node->token == MS_TOKEN_FUNCTION_JAVASCRIPT ||
3327 node->token == MS_TOKEN_FUNCTION_UPPER ||
3328 node->token == MS_TOKEN_FUNCTION_LOWER ||
3329 node->token == MS_TOKEN_FUNCTION_INITCAP ||
3330 node->token == MS_TOKEN_FUNCTION_FIRSTCAP )
3331 {
3332 if( node->next && node->next->token == '(' )
3333 {
3334 int node_token = node->token;
3335 msExprNode* subExpr = BuildExprTree(node->next->next, &node,
3336 nParenthesisLevel + 1);
3337 if( subExpr == NULL )
3338 {
3339 goto fail;
3340 }
3341 msExprNode* newNode = new msExprNode;
3342 newNode->m_nToken = node_token;
3343 if( subExpr->m_nToken == 0 )
3344 {
3345 newNode->m_aoChildren = subExpr->m_aoChildren;
3346 subExpr->m_aoChildren.clear();
3347 delete subExpr;
3348 }
3349 else
3350 {
3351 newNode->m_aoChildren.push_back(subExpr);
3352 }
3353 aoStackVal.push_back(newNode);
3354 continue;
3355 }
3356 else
3357 goto fail;
3358 }
3359 else if( node->token == MS_TOKEN_LITERAL_NUMBER ||
3360 node->token == MS_TOKEN_LITERAL_BOOLEAN )
3361 {
3362 msExprNode* newNode = new msExprNode;
3363 newNode->m_nToken = node->token;
3364 newNode->m_dfVal = node->tokenval.dblval;
3365 aoStackVal.push_back(newNode);
3366 }
3367 else if( node->token == MS_TOKEN_LITERAL_STRING )
3368 {
3369 msExprNode* newNode = new msExprNode;
3370 newNode->m_nToken = node->token;
3371 newNode->m_osVal = node->tokenval.strval;
3372 aoStackVal.push_back(newNode);
3373 }
3374 else if( node->token == MS_TOKEN_LITERAL_TIME )
3375 {
3376 msExprNode* newNode = new msExprNode;
3377 newNode->m_nToken = node->token;
3378 newNode->m_tmVal = node->tokenval.tmval;
3379 aoStackVal.push_back(newNode);
3380 }
3381 else if( node->token == MS_TOKEN_LITERAL_SHAPE )
3382 {
3383 msExprNode* newNode = new msExprNode;
3384 newNode->m_nToken = node->token;
3385 char *wkt = msShapeToWKT(node->tokenval.shpval);
3386 newNode->m_osVal = wkt;
3387 msFree(wkt);
3388 aoStackVal.push_back(newNode);
3389 }
3390 else if( node->token == MS_TOKEN_BINDING_DOUBLE ||
3391 node->token == MS_TOKEN_BINDING_INTEGER ||
3392 node->token == MS_TOKEN_BINDING_STRING ||
3393 node->token == MS_TOKEN_BINDING_TIME )
3394 {
3395 msExprNode* newNode = new msExprNode;
3396 newNode->m_nToken = node->token;
3397 newNode->m_osVal = node->tokenval.bindval.item;
3398 aoStackVal.push_back(newNode);
3399 }
3400 else
3401 {
3402 msExprNode* newNode = new msExprNode;
3403 newNode->m_nToken = node->token;
3404 aoStackVal.push_back(newNode);
3405 }
3406
3407 node = node->next;
3408 }
3409
3410 while( !aoStackOp.empty() )
3411 {
3412 msExprNode* val1 = NULL;
3413 msExprNode* val2 = NULL;
3414 msExprNode* newNode = NULL;
3415 if (aoStackOp.back()->m_nToken != MS_TOKEN_LOGICAL_NOT)
3416 {
3417 if( aoStackVal.empty() )
3418 goto fail;
3419 val2 = aoStackVal.back();
3420 aoStackVal.pop_back();
3421 }
3422 if( aoStackVal.empty() )
3423 goto fail;
3424 val1 = aoStackVal.back();
3425 aoStackVal.pop_back();
3426
3427 newNode = new msExprNode;
3428 newNode->m_nToken = aoStackOp.back()->m_nToken;
3429 newNode->m_aoChildren.push_back(val1);
3430 if( val2 )
3431 newNode->m_aoChildren.push_back(val2);
3432 aoStackVal.push_back(newNode);
3433 delete aoStackOp.back();
3434 aoStackOp.pop_back();
3435 }
3436
3437 if( aoStackVal.size() == 1 )
3438 poRet = aoStackVal.back();
3439 else if( aoStackVal.size() > 1 )
3440 {
3441 poRet = new msExprNode;
3442 poRet->m_aoChildren = aoStackVal;
3443 }
3444
3445 if( pNodeNext )
3446 *pNodeNext = node ? node->next : NULL;
3447
3448 return poRet;
3449
3450 fail:
3451 for( size_t i=0; i<aoStackOp.size(); ++i )
3452 delete aoStackOp[i];
3453 for( size_t i=0; i<aoStackVal.size(); ++i )
3454 delete aoStackVal[i];
3455 return NULL;
3456 }
3457
3458 /**********************************************************************
3459 * msOGRExtractTopSpatialFilter()
3460 *
3461 * Recognize expressions like "Intersects([shape], wkt) == TRUE [AND ....]"
3462 **********************************************************************/
msOGRExtractTopSpatialFilter(msOGRFileInfo * info,const msExprNode * expr,const msExprNode ** pSpatialFilterNode)3463 static int msOGRExtractTopSpatialFilter( msOGRFileInfo *info,
3464 const msExprNode* expr,
3465 const msExprNode** pSpatialFilterNode )
3466 {
3467 if( expr == NULL )
3468 return MS_FALSE;
3469
3470 if( expr->m_nToken == MS_TOKEN_COMPARISON_EQ &&
3471 expr->m_aoChildren.size() == 2 &&
3472 expr->m_aoChildren[1]->m_nToken == MS_TOKEN_LITERAL_BOOLEAN &&
3473 expr->m_aoChildren[1]->m_dfVal == 1.0 )
3474 {
3475 return msOGRExtractTopSpatialFilter(info, expr->m_aoChildren[0],
3476 pSpatialFilterNode);
3477 }
3478
3479 if( (expr->m_nToken == MS_TOKEN_COMPARISON_INTERSECTS ||
3480 expr->m_nToken == MS_TOKEN_COMPARISON_OVERLAPS ||
3481 expr->m_nToken == MS_TOKEN_COMPARISON_CROSSES ||
3482 expr->m_nToken == MS_TOKEN_COMPARISON_WITHIN ||
3483 expr->m_nToken == MS_TOKEN_COMPARISON_CONTAINS) &&
3484 expr->m_aoChildren.size() == 2 &&
3485 expr->m_aoChildren[1]->m_nToken == MS_TOKEN_LITERAL_SHAPE )
3486 {
3487 if( info->rect_is_defined )
3488 {
3489 // Several intersects...
3490 *pSpatialFilterNode = NULL;
3491 info->rect_is_defined = MS_FALSE;
3492 return MS_FALSE;
3493 }
3494 OGRGeometryH hSpatialFilter = NULL;
3495 char* wkt = const_cast<char*>(expr->m_aoChildren[1]->m_osVal.c_str());
3496 OGRErr e = OGR_G_CreateFromWkt(&wkt, NULL, &hSpatialFilter);
3497 if (e == OGRERR_NONE) {
3498 OGREnvelope env;
3499 OGR_G_GetEnvelope(hSpatialFilter, &env);
3500 info->rect.minx = env.MinX;
3501 info->rect.miny = env.MinY;
3502 info->rect.maxx = env.MaxX;
3503 info->rect.maxy = env.MaxY;
3504 info->rect_is_defined = true;
3505 *pSpatialFilterNode = expr;
3506 OGR_G_DestroyGeometry(hSpatialFilter);
3507 return MS_TRUE;
3508 }
3509 return MS_FALSE;
3510 }
3511
3512 if( expr->m_nToken == MS_TOKEN_LOGICAL_AND &&
3513 expr->m_aoChildren.size() == 2 )
3514 {
3515 return msOGRExtractTopSpatialFilter(info, expr->m_aoChildren[0],
3516 pSpatialFilterNode) &&
3517 msOGRExtractTopSpatialFilter(info, expr->m_aoChildren[1],
3518 pSpatialFilterNode);
3519 }
3520
3521 return MS_TRUE;
3522 }
3523
3524 /**********************************************************************
3525 * msOGRTranslatePartialMSExpressionToOGRSQL()
3526 *
3527 * Tries to partially translate a mapserver expression to SQL
3528 **********************************************************************/
3529
msOGRGetTokenText(int nToken)3530 static std::string msOGRGetTokenText(int nToken)
3531 {
3532 switch( nToken )
3533 {
3534 case '*':
3535 case '+':
3536 case '-':
3537 case '/':
3538 case '%':
3539 return std::string(1, static_cast<char>(nToken));
3540
3541 case MS_TOKEN_COMPARISON_GE: return ">=";
3542 case MS_TOKEN_COMPARISON_GT: return ">";
3543 case MS_TOKEN_COMPARISON_LE: return "<=";
3544 case MS_TOKEN_COMPARISON_LT: return "<";
3545 case MS_TOKEN_COMPARISON_EQ: return "=";
3546 case MS_TOKEN_COMPARISON_NE: return "!=";
3547 case MS_TOKEN_COMPARISON_LIKE: return "LIKE";
3548
3549 default:
3550 return std::string();
3551 }
3552 }
3553
msOGRTranslatePartialInternal(layerObj * layer,const msExprNode * expr,const msExprNode * spatialFilterNode,bool & bPartialFilter)3554 static std::string msOGRTranslatePartialInternal(layerObj* layer,
3555 const msExprNode* expr,
3556 const msExprNode* spatialFilterNode,
3557 bool& bPartialFilter)
3558 {
3559 switch( expr->m_nToken )
3560 {
3561 case MS_TOKEN_LOGICAL_NOT:
3562 {
3563 std::string osTmp(msOGRTranslatePartialInternal(
3564 layer, expr->m_aoChildren[0], spatialFilterNode, bPartialFilter ));
3565 if( osTmp.empty() )
3566 return std::string();
3567 return "(NOT " + osTmp + ")";
3568 }
3569
3570 case MS_TOKEN_LOGICAL_AND:
3571 {
3572 // We can deal with partially translated children
3573 std::string osTmp1(msOGRTranslatePartialInternal(
3574 layer, expr->m_aoChildren[0], spatialFilterNode, bPartialFilter ));
3575 std::string osTmp2(msOGRTranslatePartialInternal(
3576 layer, expr->m_aoChildren[1], spatialFilterNode, bPartialFilter ));
3577 if( !osTmp1.empty() && !osTmp2.empty() )
3578 {
3579 return "(" + osTmp1 + " AND " + osTmp2 + ")";
3580 }
3581 else if( !osTmp1.empty() )
3582 return osTmp1;
3583 else
3584 return osTmp2;
3585 }
3586
3587 case MS_TOKEN_LOGICAL_OR:
3588 {
3589 // We can NOT deal with partially translated children
3590 std::string osTmp1(msOGRTranslatePartialInternal(
3591 layer, expr->m_aoChildren[0], spatialFilterNode, bPartialFilter ));
3592 std::string osTmp2(msOGRTranslatePartialInternal(
3593 layer, expr->m_aoChildren[1], spatialFilterNode, bPartialFilter ));
3594 if( !osTmp1.empty() && !osTmp2.empty() )
3595 {
3596 return "(" + osTmp1 + " OR " + osTmp2 + ")";
3597 }
3598 else
3599 return std::string();
3600 }
3601
3602 case '*':
3603 case '+':
3604 case '-':
3605 case '/':
3606 case '%':
3607 case MS_TOKEN_COMPARISON_GE:
3608 case MS_TOKEN_COMPARISON_GT:
3609 case MS_TOKEN_COMPARISON_LE:
3610 case MS_TOKEN_COMPARISON_LT:
3611 case MS_TOKEN_COMPARISON_EQ:
3612 case MS_TOKEN_COMPARISON_NE:
3613 {
3614 std::string osTmp1(msOGRTranslatePartialInternal(
3615 layer, expr->m_aoChildren[0], spatialFilterNode, bPartialFilter ));
3616 std::string osTmp2(msOGRTranslatePartialInternal(
3617 layer, expr->m_aoChildren[1], spatialFilterNode, bPartialFilter ));
3618 if( !osTmp1.empty() && !osTmp2.empty() )
3619 {
3620 if( expr->m_nToken == MS_TOKEN_COMPARISON_EQ &&
3621 osTmp2 == "'_MAPSERVER_NULL_'" )
3622 {
3623 return "(" + osTmp1 + " IS NULL )";
3624 }
3625 if( expr->m_aoChildren[1]->m_nToken == MS_TOKEN_LITERAL_STRING )
3626 {
3627 char md_item_name[256];
3628 snprintf( md_item_name, sizeof(md_item_name), "gml_%s_type",
3629 expr->m_aoChildren[0]->m_osVal.c_str() );
3630 const char* type =
3631 msLookupHashTable(&(layer->metadata), md_item_name);
3632 // Cast if needed (or unsure)
3633 if( type == NULL || !EQUAL(type, "Character") )
3634 {
3635 osTmp1 = "CAST(" + osTmp1 + " AS CHARACTER(4096))";
3636 }
3637 }
3638 return "(" + osTmp1 + " " + msOGRGetTokenText(expr->m_nToken) +
3639 " " + osTmp2 + ")";
3640 }
3641 else
3642 return std::string();
3643 }
3644
3645 case MS_TOKEN_COMPARISON_RE:
3646 {
3647 std::string osTmp1(msOGRTranslatePartialInternal(
3648 layer, expr->m_aoChildren[0], spatialFilterNode, bPartialFilter ));
3649 if( expr->m_aoChildren[1]->m_nToken != MS_TOKEN_LITERAL_STRING )
3650 {
3651 return std::string();
3652 }
3653 std::string osRE("'");
3654 const size_t nSize = expr->m_aoChildren[1]->m_osVal.size();
3655 bool bHasUsedEscape = false;
3656 for( size_t i=0; i<nSize;i++ )
3657 {
3658 if( i == 0 && expr->m_aoChildren[1]->m_osVal[i] == '^' )
3659 continue;
3660 if( i == nSize-1 && expr->m_aoChildren[1]->m_osVal[i] == '$' )
3661 break;
3662 if( expr->m_aoChildren[1]->m_osVal[i] == '.' )
3663 {
3664 if( i+1<nSize &&
3665 expr->m_aoChildren[1]->m_osVal[i+1] == '*' )
3666 {
3667 osRE += "%";
3668 i++;
3669 }
3670 else
3671 {
3672 osRE += "_";
3673 }
3674 }
3675 else if( expr->m_aoChildren[1]->m_osVal[i] == '\\' &&
3676 i+1<nSize )
3677 {
3678 bHasUsedEscape = true;
3679 osRE += 'X';
3680 osRE += expr->m_aoChildren[1]->m_osVal[i+1];
3681 i++;
3682 }
3683 else if( expr->m_aoChildren[1]->m_osVal[i] == 'X' ||
3684 expr->m_aoChildren[1]->m_osVal[i] == '%' ||
3685 expr->m_aoChildren[1]->m_osVal[i] == '_' )
3686 {
3687 bHasUsedEscape = true;
3688 osRE += 'X';
3689 osRE += expr->m_aoChildren[1]->m_osVal[i];
3690 }
3691 else
3692 {
3693 osRE += expr->m_aoChildren[1]->m_osVal[i];
3694 }
3695 }
3696 osRE += "'";
3697 char md_item_name[256];
3698 snprintf( md_item_name, sizeof(md_item_name), "gml_%s_type",
3699 expr->m_aoChildren[0]->m_osVal.c_str() );
3700 const char* type =
3701 msLookupHashTable(&(layer->metadata), md_item_name);
3702 // Cast if needed (or unsure)
3703 if( type == NULL || !EQUAL(type, "Character") )
3704 {
3705 osTmp1 = "CAST(" + osTmp1 + " AS CHARACTER(4096))";
3706 }
3707 std::string osRet( "(" + osTmp1 + " LIKE " + osRE );
3708 if( bHasUsedEscape )
3709 osRet += " ESCAPE 'X'";
3710 osRet += ")";
3711 return osRet;
3712 }
3713
3714 case MS_TOKEN_COMPARISON_IN:
3715 {
3716 std::string osTmp1(msOGRTranslatePartialInternal(
3717 layer, expr->m_aoChildren[0], spatialFilterNode, bPartialFilter ));
3718 std::string osRet = "(" + osTmp1 + " IN (";
3719 for( size_t i=0; i< expr->m_aoChildren[1]->m_aoChildren.size(); ++i )
3720 {
3721 if( i > 0 )
3722 osRet += ", ";
3723 osRet += msOGRTranslatePartialInternal(
3724 layer, expr->m_aoChildren[1]->m_aoChildren[i],
3725 spatialFilterNode, bPartialFilter );
3726 }
3727 osRet += ")";
3728 return osRet;
3729 }
3730
3731 case MS_TOKEN_LITERAL_NUMBER:
3732 case MS_TOKEN_LITERAL_BOOLEAN:
3733 {
3734 return std::string(CPLSPrintf("%.18g", expr->m_dfVal));
3735 }
3736
3737 case MS_TOKEN_LITERAL_STRING:
3738 {
3739 char *stresc = msOGREscapeSQLParam(layer, expr->m_osVal.c_str());
3740 std::string osRet("'" + std::string(stresc) + "'");
3741 msFree(stresc);
3742 return osRet;
3743 }
3744
3745 case MS_TOKEN_LITERAL_TIME:
3746 {
3747 #ifdef notdef
3748 // Breaks tests in msautotest/wxs/wfs_time_ogr.map
3749 return std::string(CPLSPrintf("'%04d/%02d/%02d %02d:%02d:%02d'",
3750 expr->m_tmVal.tm_year+1900,
3751 expr->m_tmVal.tm_mon+1,
3752 expr->m_tmVal.tm_mday,
3753 expr->m_tmVal.tm_hour,
3754 expr->m_tmVal.tm_min,
3755 expr->m_tmVal.tm_sec));
3756 #endif
3757 return std::string();
3758 }
3759
3760 case MS_TOKEN_BINDING_DOUBLE:
3761 case MS_TOKEN_BINDING_INTEGER:
3762 case MS_TOKEN_BINDING_STRING:
3763 case MS_TOKEN_BINDING_TIME:
3764 {
3765 char* pszTmp = msOGRGetQuotedItem(layer, expr->m_osVal.c_str());
3766 std::string osRet(pszTmp);
3767 msFree(pszTmp);
3768 return osRet;
3769 }
3770
3771 case MS_TOKEN_COMPARISON_INTERSECTS:
3772 {
3773 if( expr != spatialFilterNode )
3774 bPartialFilter = true;
3775 return std::string();
3776 }
3777
3778 default:
3779 {
3780 bPartialFilter = true;
3781 return std::string();
3782 }
3783 }
3784 }
3785
3786 /* ==================================================================
3787 * Here comes the REAL stuff... the functions below are called by maplayer.c
3788 * ================================================================== */
3789
3790 /**********************************************************************
3791 * msOGRTranslateMsExpressionToOGRSQL()
3792 *
3793 * Tries to translate a mapserver expression to OGR or driver native SQL
3794 **********************************************************************/
msOGRTranslateMsExpressionToOGRSQL(layerObj * layer,expressionObj * psFilter,char * filteritem)3795 static int msOGRTranslateMsExpressionToOGRSQL(layerObj* layer,
3796 expressionObj* psFilter,
3797 char *filteritem)
3798 {
3799 msOGRFileInfo *info = (msOGRFileInfo *)layer->layerinfo;
3800
3801 msFree(layer->filter.native_string);
3802 layer->filter.native_string = NULL;
3803
3804 msFree(info->pszWHERE);
3805 info->pszWHERE = NULL;
3806
3807 // reasons to not produce native string: not simple layer, or an explicit deny
3808 char *do_this = msLayerGetProcessingKey(layer, "NATIVE_SQL"); // default is YES
3809 if (do_this && strcmp(do_this, "NO") == 0) {
3810 return MS_SUCCESS;
3811 }
3812
3813 tokenListNodeObjPtr node = psFilter->tokens;
3814 msExprNode* expr = BuildExprTree(node, NULL, 0);
3815 info->rect_is_defined = MS_FALSE;
3816 const msExprNode* spatialFilterNode = NULL;
3817 if( expr )
3818 msOGRExtractTopSpatialFilter( info, expr, &spatialFilterNode );
3819
3820 // more reasons to not produce native string: not a recognized driver
3821 if (!info->dialect)
3822 {
3823 // in which case we might still want to try to get a partial WHERE clause
3824 if( filteritem == NULL && expr )
3825 {
3826 bool bPartialFilter = false;
3827 std::string osSQL( msOGRTranslatePartialInternal(layer, expr,
3828 spatialFilterNode,
3829 bPartialFilter) );
3830 if( !osSQL.empty() )
3831 {
3832 info->pszWHERE = msStrdup(osSQL.c_str());
3833 if( bPartialFilter )
3834 {
3835 msDebug("Full filter has only been partially "
3836 "translated to OGR filter %s\n",
3837 info->pszWHERE);
3838 }
3839 }
3840 else if( bPartialFilter )
3841 {
3842 msDebug("Filter could not be translated to OGR filter\n");
3843 }
3844 }
3845 delete expr;
3846 return MS_SUCCESS;
3847 }
3848
3849 char *sql = NULL;
3850
3851 // node may be NULL if layer->filter.string != NULL and filteritem != NULL
3852 // this is simple filter but string is regex
3853 if (node == NULL && filteritem != NULL && layer->filter.string != NULL) {
3854 sql = msStringConcatenate(sql, "\"");
3855 sql = msStringConcatenate(sql, filteritem);
3856 sql = msStringConcatenate(sql, "\"");
3857 if (EQUAL(info->dialect, "PostgreSQL") ) {
3858 sql = msStringConcatenate(sql, " ~ ");
3859 } else {
3860 sql = msStringConcatenate(sql, " LIKE ");
3861 }
3862 sql = msStringConcatenate(sql, "'");
3863 sql = msStringConcatenate(sql, layer->filter.string);
3864 sql = msStringConcatenate(sql, "'");
3865 }
3866
3867 while (node != NULL) {
3868
3869 if (node->next && node->next->token == MS_TOKEN_COMPARISON_IEQ) {
3870 char *left = msOGRGetToken(layer, &node);
3871 node = node->next; // skip =
3872 char *right = msOGRGetToken(layer, &node);
3873 sql = msStringConcatenate(sql, "upper(");
3874 sql = msStringConcatenate(sql, left);
3875 sql = msStringConcatenate(sql, ")");
3876 sql = msStringConcatenate(sql, "=");
3877 sql = msStringConcatenate(sql, "upper(");
3878 sql = msStringConcatenate(sql, right);
3879 sql = msStringConcatenate(sql, ")");
3880 int ok = left && right;
3881 msFree(left);
3882 msFree(right);
3883 if (!ok) {
3884 goto fail;
3885 }
3886 continue;
3887 }
3888
3889 switch(node->token) {
3890 case MS_TOKEN_COMPARISON_INTERSECTS:
3891 case MS_TOKEN_COMPARISON_DISJOINT:
3892 case MS_TOKEN_COMPARISON_TOUCHES:
3893 case MS_TOKEN_COMPARISON_OVERLAPS:
3894 case MS_TOKEN_COMPARISON_CROSSES:
3895 case MS_TOKEN_COMPARISON_DWITHIN:
3896 case MS_TOKEN_COMPARISON_BEYOND:
3897 case MS_TOKEN_COMPARISON_WITHIN:
3898 case MS_TOKEN_COMPARISON_CONTAINS:
3899 case MS_TOKEN_COMPARISON_EQUALS:{
3900 int token = node->token;
3901 char *fct = msOGRGetToken(layer, &node);
3902 node = node->next; // skip (
3903 char *a1 = msOGRGetToken(layer, &node);
3904 node = node->next; // skip ,
3905 char *a2 = msOGRGetToken(layer, &node);
3906 char *a3 = NULL;
3907 if (token == MS_TOKEN_COMPARISON_DWITHIN || token == MS_TOKEN_COMPARISON_BEYOND) {
3908 node = node->next; // skip ,
3909 a3 = msOGRGetToken(layer, &node);
3910 }
3911 node = node->next; // skip )
3912 char *eq = msOGRGetToken(layer, &node);
3913 char *rval = msOGRGetToken(layer, &node);
3914 if (strcmp(eq, " != ") == 0 || strcmp(rval, "FALSE") == 0) {
3915 sql = msStringConcatenate(sql, "NOT ");
3916 }
3917 // FIXME: case rval is more complex
3918 sql = msStringConcatenate(sql, fct);
3919 sql = msStringConcatenate(sql, "(");
3920 sql = msStringConcatenate(sql, a1);
3921 sql = msStringConcatenate(sql, ",");
3922 sql = msStringConcatenate(sql, a2);
3923 if (token == MS_TOKEN_COMPARISON_DWITHIN || token == MS_TOKEN_COMPARISON_BEYOND) {
3924 sql = msStringConcatenate(sql, ")");
3925 if (token == MS_TOKEN_COMPARISON_DWITHIN)
3926 sql = msStringConcatenate(sql, "<=");
3927 else
3928 sql = msStringConcatenate(sql, ">");
3929 sql = msStringConcatenate(sql, a3);
3930 } else {
3931 sql = msStringConcatenate(sql, ")");
3932 }
3933 int ok = fct && a1 && a2 && eq && rval;
3934 if (token == MS_TOKEN_COMPARISON_DWITHIN) {
3935 ok = ok && a3;
3936 }
3937 msFree(fct);
3938 msFree(a1);
3939 msFree(a2);
3940 msFree(a3);
3941 msFree(eq);
3942 msFree(rval);
3943 if (!ok) {
3944 goto fail;
3945 }
3946 break;
3947 }
3948 default: {
3949 char *token = msOGRGetToken(layer, &node);
3950 if (!token) {
3951 goto fail;
3952 }
3953 sql = msStringConcatenate(sql, token);
3954 msFree(token);
3955 }
3956 }
3957 }
3958
3959 layer->filter.native_string = sql;
3960 delete expr;
3961 return MS_SUCCESS;
3962 fail:
3963 // error producing native string
3964 msDebug("Note: Error parsing token list, could produce only: %s. Trying in partial mode\n", sql);
3965 msFree(sql);
3966
3967 // in which case we might still want to try to get a partial WHERE clause
3968 if( expr )
3969 {
3970 bool bPartialFilter = false;
3971 std::string osSQL( msOGRTranslatePartialInternal(layer, expr,
3972 spatialFilterNode,
3973 bPartialFilter) );
3974 if( !osSQL.empty() )
3975 {
3976 info->pszWHERE = msStrdup(osSQL.c_str());
3977 if( bPartialFilter )
3978 {
3979 msDebug("Full filter has only been partially "
3980 "translated to OGR filter %s\n",
3981 info->pszWHERE);
3982 }
3983 }
3984 else if( bPartialFilter )
3985 {
3986 msDebug("Filter could not be translated to OGR filter\n");
3987 }
3988 }
3989 delete expr;
3990
3991 return MS_SUCCESS;
3992 }
3993
3994 /**********************************************************************
3995 * msOGRLayerOpen()
3996 *
3997 * Open OGR data source for the specified map layer.
3998 *
3999 * If pszOverrideConnection != NULL then this value is used as the connection
4000 * string instead of lp->connection. This is used for instance to open
4001 * a WFS layer, in this case lp->connection is the WFS url, but we want
4002 * OGR to open the local file on disk that was previously downloaded.
4003 *
4004 * An OGR connection string is: <dataset_filename>[,<layer_index>]
4005 * <dataset_filename> is file format specific
4006 * <layer_index> (optional) is the OGR layer index
4007 * default is 0, the first layer.
4008 *
4009 * One can use the "ogrinfo" program to find out the layer indices in a dataset
4010 *
4011 * Returns MS_SUCCESS/MS_FAILURE
4012 **********************************************************************/
msOGRLayerOpen(layerObj * layer,const char * pszOverrideConnection)4013 int msOGRLayerOpen(layerObj *layer, const char *pszOverrideConnection)
4014 {
4015 msOGRFileInfo *psInfo;
4016
4017 if (layer->layerinfo != NULL) {
4018 return MS_SUCCESS; // Nothing to do... layer is already opened
4019 }
4020
4021 /* -------------------------------------------------------------------- */
4022 /* If this is not a tiled layer, just directly open the target. */
4023 /* -------------------------------------------------------------------- */
4024 if( layer->tileindex == NULL ) {
4025 psInfo = msOGRFileOpen( layer,
4026 (pszOverrideConnection ? pszOverrideConnection:
4027 layer->connection) );
4028 layer->layerinfo = psInfo;
4029 layer->tileitemindex = -1;
4030
4031 if( layer->layerinfo == NULL )
4032 return MS_FAILURE;
4033 }
4034
4035 /* -------------------------------------------------------------------- */
4036 /* Otherwise we open the tile index, identify the tile item */
4037 /* index and try to select the first file matching our query */
4038 /* region. */
4039 /* -------------------------------------------------------------------- */
4040 else {
4041 // Open tile index
4042
4043 psInfo = msOGRFileOpen( layer, layer->tileindex );
4044 layer->layerinfo = psInfo;
4045
4046 if( layer->layerinfo == NULL )
4047 return MS_FAILURE;
4048
4049 // Identify TILEITEM
4050 OGRFeatureDefnH hDefn = OGR_L_GetLayerDefn( psInfo->hLayer );
4051 layer->tileitemindex = OGR_FD_GetFieldIndex(hDefn, layer->tileitem);
4052 if( layer->tileitemindex < 0 ) {
4053 msSetError(MS_OGRERR,
4054 "Can't identify TILEITEM %s field in TILEINDEX `%s'.",
4055 "msOGRLayerOpen()",
4056 layer->tileitem, layer->tileindex );
4057 msOGRFileClose( layer, psInfo );
4058 layer->layerinfo = NULL;
4059 return MS_FAILURE;
4060 }
4061
4062 // Identify TILESRS
4063 if( layer->tilesrs != NULL &&
4064 OGR_FD_GetFieldIndex(hDefn, layer->tilesrs) < 0 ) {
4065 msSetError(MS_OGRERR,
4066 "Can't identify TILESRS %s field in TILEINDEX `%s'.",
4067 "msOGRLayerOpen()",
4068 layer->tilesrs, layer->tileindex );
4069 msOGRFileClose( layer, psInfo );
4070 layer->layerinfo = NULL;
4071 return MS_FAILURE;
4072 }
4073 if( layer->tilesrs != NULL && layer->projection.numargs == 0 )
4074 {
4075 msSetError(MS_OGRERR,
4076 "A layer with TILESRS set in TILEINDEX `%s' must have a "
4077 "projection set on itself.",
4078 "msOGRLayerOpen()",
4079 layer->tileindex );
4080 msOGRFileClose( layer, psInfo );
4081 layer->layerinfo = NULL;
4082 return MS_FAILURE;
4083 }
4084 }
4085
4086 /* ------------------------------------------------------------------
4087 * If projection was "auto" then set proj to the dataset's projection.
4088 * For a tile index, it is assume the tile index has the projection.
4089 * ------------------------------------------------------------------ */
4090 if (layer->projection.numargs > 0 &&
4091 EQUAL(layer->projection.args[0], "auto")) {
4092 ACQUIRE_OGR_LOCK;
4093 OGRSpatialReferenceH hSRS = OGR_L_GetSpatialRef( psInfo->hLayer );
4094
4095 if (msOGRSpatialRef2ProjectionObj(hSRS,
4096 &(layer->projection),
4097 layer->debug ) != MS_SUCCESS) {
4098 errorObj *ms_error = msGetErrorObj();
4099
4100 RELEASE_OGR_LOCK;
4101 msSetError(MS_OGRERR,
4102 "%s "
4103 "PROJECTION AUTO cannot be used for this "
4104 "OGR connection (in layer `%s').",
4105 "msOGRLayerOpen()",
4106 ms_error->message,
4107 layer->name?layer->name:"(null)" );
4108 msOGRFileClose( layer, psInfo );
4109 layer->layerinfo = NULL;
4110 return(MS_FAILURE);
4111 }
4112 RELEASE_OGR_LOCK;
4113 }
4114
4115 return MS_SUCCESS;
4116 }
4117
4118 /**********************************************************************
4119 * msOGRLayerOpenVT()
4120 *
4121 * Overloaded version of msOGRLayerOpen for virtual table architecture
4122 **********************************************************************/
msOGRLayerOpenVT(layerObj * layer)4123 static int msOGRLayerOpenVT(layerObj *layer)
4124 {
4125 return msOGRLayerOpen(layer, NULL);
4126 }
4127
4128 /**********************************************************************
4129 * msOGRLayerClose()
4130 **********************************************************************/
msOGRLayerClose(layerObj * layer)4131 int msOGRLayerClose(layerObj *layer)
4132 {
4133 msOGRFileInfo *psInfo =(msOGRFileInfo*)layer->layerinfo;
4134
4135 if (psInfo) {
4136 if( layer->debug )
4137 msDebug("msOGRLayerClose(%s).\n", layer->connection);
4138
4139 msOGRFileClose( layer, psInfo );
4140 layer->layerinfo = NULL;
4141 }
4142
4143 return MS_SUCCESS;
4144 }
4145
4146 /**********************************************************************
4147 * msOGRLayerIsOpen()
4148 **********************************************************************/
msOGRLayerIsOpen(layerObj * layer)4149 static int msOGRLayerIsOpen(layerObj *layer)
4150 {
4151 if (layer->layerinfo)
4152 return MS_TRUE;
4153
4154 return MS_FALSE;
4155 }
4156
msOGRIsSpatialite(layerObj * layer)4157 int msOGRIsSpatialite(layerObj* layer)
4158 {
4159 msOGRFileInfo *psInfo =(msOGRFileInfo*)layer->layerinfo;
4160 if (psInfo && psInfo->dialect &&
4161 EQUAL(psInfo->dialect, "Spatialite") )
4162 {
4163 // reasons to not produce native string: not simple layer, or an explicit deny
4164 char *do_this = msLayerGetProcessingKey(layer, "NATIVE_SQL"); // default is YES
4165 if (do_this && strcmp(do_this, "NO") == 0) {
4166 return MS_FALSE;
4167 }
4168 return MS_TRUE;
4169 }
4170
4171 return MS_FALSE;
4172 }
4173
4174
4175 /**********************************************************************
4176 * msOGRLayerWhichShapes()
4177 *
4178 * Init OGR layer structs ready for calls to msOGRLayerNextShape().
4179 *
4180 * Returns MS_SUCCESS/MS_FAILURE, or MS_DONE if no shape matching the
4181 * layer's FILTER overlaps the selected region.
4182 **********************************************************************/
msOGRLayerWhichShapes(layerObj * layer,rectObj rect,int isQuery)4183 int msOGRLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery)
4184 {
4185 msOGRFileInfo *psInfo =(msOGRFileInfo*)layer->layerinfo;
4186 int status;
4187
4188 if (psInfo == NULL || psInfo->hLayer == NULL) {
4189 msSetError(MS_MISCERR, "Assertion failed: OGR layer not opened!!!",
4190 "msOGRLayerWhichShapes()");
4191 return(MS_FAILURE);
4192 }
4193
4194 status = msOGRFileWhichShapes( layer, rect, psInfo );
4195
4196 if( status != MS_SUCCESS || layer->tileindex == NULL )
4197 return status;
4198
4199 // If we are using a tile index, we need to advance to the first
4200 // tile matching the spatial query, and load it.
4201
4202 return msOGRFileReadTile( layer, psInfo );
4203 }
4204
4205 /**********************************************************************
4206 * msOGRLayerGetItems()
4207 *
4208 * Load item (i.e. field) names in a char array. If we are working
4209 * with a tiled layer, ensure a tile is loaded and use it for the items.
4210 * It is implicitly assumed that the schemas will match on all tiles.
4211 **********************************************************************/
msOGRLayerGetItems(layerObj * layer)4212 int msOGRLayerGetItems(layerObj *layer)
4213 {
4214 msOGRFileInfo *psInfo =(msOGRFileInfo*)layer->layerinfo;
4215
4216 if (psInfo == NULL || psInfo->hLayer == NULL) {
4217 msSetError(MS_MISCERR, "Assertion failed: OGR layer not opened!!!",
4218 "msOGRLayerGetItems()");
4219 return(MS_FAILURE);
4220 }
4221
4222 if( layer->tileindex != NULL ) {
4223 if( psInfo->poCurTile == NULL
4224 && msOGRFileReadTile( layer, psInfo ) != MS_SUCCESS )
4225 return MS_FAILURE;
4226
4227 psInfo = psInfo->poCurTile;
4228 }
4229
4230 layer->numitems = 0;
4231 layer->items = msOGRFileGetItems(layer, psInfo);
4232 if( layer->items == NULL )
4233 return MS_FAILURE;
4234
4235 while( layer->items[layer->numitems] != NULL )
4236 layer->numitems++;
4237
4238 return msOGRLayerInitItemInfo(layer);
4239 }
4240
4241 /**********************************************************************
4242 * msOGRLayerInitItemInfo()
4243 *
4244 * Init the itemindexes array after items[] has been reset in a layer.
4245 **********************************************************************/
msOGRLayerInitItemInfo(layerObj * layer)4246 static int msOGRLayerInitItemInfo(layerObj *layer)
4247 {
4248 msOGRFileInfo *psInfo =(msOGRFileInfo*)layer->layerinfo;
4249 int i;
4250 OGRFeatureDefnH hDefn;
4251
4252 if (layer->numitems == 0)
4253 return MS_SUCCESS;
4254
4255 if( layer->tileindex != NULL ) {
4256 if( psInfo->poCurTile == NULL
4257 && msOGRFileReadTile( layer, psInfo, -2 ) != MS_SUCCESS )
4258 return MS_FAILURE;
4259
4260 psInfo = psInfo->poCurTile;
4261 }
4262
4263 if (psInfo == NULL || psInfo->hLayer == NULL) {
4264 msSetError(MS_MISCERR, "Assertion failed: OGR layer not opened!!!",
4265 "msOGRLayerInitItemInfo()");
4266 return(MS_FAILURE);
4267 }
4268
4269 if((hDefn = OGR_L_GetLayerDefn( psInfo->hLayer )) == NULL) {
4270 msSetError(MS_OGRERR, "Layer contains no fields.",
4271 "msOGRLayerInitItemInfo()");
4272 return(MS_FAILURE);
4273 }
4274
4275 if (layer->iteminfo)
4276 free(layer->iteminfo);
4277 if((layer->iteminfo = (int *)malloc(sizeof(int)*layer->numitems))== NULL) {
4278 msSetError(MS_MEMERR, NULL, "msOGRLayerInitItemInfo()");
4279 return(MS_FAILURE);
4280 }
4281
4282 int *itemindexes = (int*)layer->iteminfo;
4283 for(i=0; i<layer->numitems; i++) {
4284 // Special case for handling text string and angle coming from
4285 // OGR style strings. We use special attribute snames.
4286 if (EQUAL(layer->items[i], MSOGR_LABELFONTNAMENAME))
4287 itemindexes[i] = MSOGR_LABELFONTNAMEINDEX;
4288 else if (EQUAL(layer->items[i], MSOGR_LABELSIZENAME))
4289 itemindexes[i] = MSOGR_LABELSIZEINDEX;
4290 else if (EQUAL(layer->items[i], MSOGR_LABELTEXTNAME))
4291 itemindexes[i] = MSOGR_LABELTEXTINDEX;
4292 else if (EQUAL(layer->items[i], MSOGR_LABELANGLENAME))
4293 itemindexes[i] = MSOGR_LABELANGLEINDEX;
4294 else if (EQUAL(layer->items[i], MSOGR_LABELFCOLORNAME))
4295 itemindexes[i] = MSOGR_LABELFCOLORINDEX;
4296 else if (EQUAL(layer->items[i], MSOGR_LABELBCOLORNAME))
4297 itemindexes[i] = MSOGR_LABELBCOLORINDEX;
4298 else if (EQUAL(layer->items[i], MSOGR_LABELPLACEMENTNAME))
4299 itemindexes[i] = MSOGR_LABELPLACEMENTINDEX;
4300 else if (EQUAL(layer->items[i], MSOGR_LABELANCHORNAME))
4301 itemindexes[i] = MSOGR_LABELANCHORINDEX;
4302 else if (EQUAL(layer->items[i], MSOGR_LABELDXNAME))
4303 itemindexes[i] = MSOGR_LABELDXINDEX;
4304 else if (EQUAL(layer->items[i], MSOGR_LABELDYNAME))
4305 itemindexes[i] = MSOGR_LABELDYINDEX;
4306 else if (EQUAL(layer->items[i], MSOGR_LABELPERPNAME))
4307 itemindexes[i] = MSOGR_LABELPERPINDEX;
4308 else if (EQUAL(layer->items[i], MSOGR_LABELBOLDNAME))
4309 itemindexes[i] = MSOGR_LABELBOLDINDEX;
4310 else if (EQUAL(layer->items[i], MSOGR_LABELITALICNAME))
4311 itemindexes[i] = MSOGR_LABELITALICINDEX;
4312 else if (EQUAL(layer->items[i], MSOGR_LABELUNDERLINENAME))
4313 itemindexes[i] = MSOGR_LABELUNDERLINEINDEX;
4314 else if (EQUAL(layer->items[i], MSOGR_LABELPRIORITYNAME))
4315 itemindexes[i] = MSOGR_LABELPRIORITYINDEX;
4316 else if (EQUAL(layer->items[i], MSOGR_LABELSTRIKEOUTNAME))
4317 itemindexes[i] = MSOGR_LABELSTRIKEOUTINDEX;
4318 else if (EQUAL(layer->items[i], MSOGR_LABELSTRETCHNAME))
4319 itemindexes[i] = MSOGR_LABELSTRETCHINDEX;
4320 else if (EQUAL(layer->items[i], MSOGR_LABELADJHORNAME))
4321 itemindexes[i] = MSOGR_LABELADJHORINDEX;
4322 else if (EQUAL(layer->items[i], MSOGR_LABELADJVERTNAME))
4323 itemindexes[i] = MSOGR_LABELADJVERTINDEX;
4324 else if (EQUAL(layer->items[i], MSOGR_LABELHCOLORNAME))
4325 itemindexes[i] = MSOGR_LABELHCOLORINDEX;
4326 else if (EQUAL(layer->items[i], MSOGR_LABELOCOLORNAME))
4327 itemindexes[i] = MSOGR_LABELOCOLORINDEX;
4328 else if (EQUALN(layer->items[i], MSOGR_LABELPARAMNAME, MSOGR_LABELPARAMNAMELEN))
4329 itemindexes[i] = MSOGR_LABELPARAMINDEX
4330 + atoi(layer->items[i] + MSOGR_LABELPARAMNAMELEN);
4331 else if (EQUALN(layer->items[i], MSOGR_BRUSHPARAMNAME, MSOGR_BRUSHPARAMNAMELEN))
4332 itemindexes[i] = MSOGR_BRUSHPARAMINDEX
4333 + atoi(layer->items[i] + MSOGR_BRUSHPARAMNAMELEN);
4334 else if (EQUALN(layer->items[i], MSOGR_PENPARAMNAME, MSOGR_PENPARAMNAMELEN))
4335 itemindexes[i] = MSOGR_PENPARAMINDEX
4336 + atoi(layer->items[i] + MSOGR_PENPARAMNAMELEN);
4337 else if (EQUALN(layer->items[i], MSOGR_SYMBOLPARAMNAME, MSOGR_SYMBOLPARAMNAMELEN))
4338 itemindexes[i] = MSOGR_SYMBOLPARAMINDEX
4339 + atoi(layer->items[i] + MSOGR_SYMBOLPARAMNAMELEN);
4340 else
4341 {
4342 itemindexes[i] = OGR_FD_GetFieldIndex( hDefn, layer->items[i] );
4343 if( itemindexes[i] == -1 )
4344 {
4345 if( EQUAL( layer->items[i], OGR_L_GetFIDColumn( psInfo->hLayer ) ) )
4346 {
4347 itemindexes[i] = MSOGR_FID_INDEX;
4348 }
4349 }
4350 }
4351 if(itemindexes[i] == -1) {
4352 msSetError(MS_OGRERR,
4353 "Invalid Field name: %s in layer `%s'",
4354 "msOGRLayerInitItemInfo()",
4355 layer->items[i], layer->name ? layer->name : "(null)");
4356 return(MS_FAILURE);
4357 }
4358 }
4359
4360 return(MS_SUCCESS);
4361 }
4362
4363 /**********************************************************************
4364 * msOGRLayerFreeItemInfo()
4365 *
4366 * Free the itemindexes array in a layer.
4367 **********************************************************************/
msOGRLayerFreeItemInfo(layerObj * layer)4368 void msOGRLayerFreeItemInfo(layerObj *layer)
4369 {
4370
4371 if (layer->iteminfo)
4372 free(layer->iteminfo);
4373 layer->iteminfo = NULL;
4374 }
4375
4376
4377 /**********************************************************************
4378 * msOGRLayerNextShape()
4379 *
4380 * Returns shape sequentially from OGR data source.
4381 * msOGRLayerWhichShape() must have been called first.
4382 *
4383 * Returns MS_SUCCESS/MS_FAILURE
4384 **********************************************************************/
msOGRLayerNextShape(layerObj * layer,shapeObj * shape)4385 int msOGRLayerNextShape(layerObj *layer, shapeObj *shape)
4386 {
4387 msOGRFileInfo *psInfo =(msOGRFileInfo*)layer->layerinfo;
4388 int status;
4389
4390 if (psInfo == NULL || psInfo->hLayer == NULL) {
4391 msSetError(MS_MISCERR, "Assertion failed: OGR layer not opened!!!",
4392 "msOGRLayerNextShape()");
4393 return(MS_FAILURE);
4394 }
4395
4396 if( layer->tileindex == NULL )
4397 return msOGRFileNextShape( layer, shape, psInfo );
4398
4399 // Do we need to load the first tile?
4400 if( psInfo->poCurTile == NULL ) {
4401 status = msOGRFileReadTile( layer, psInfo );
4402 if( status != MS_SUCCESS )
4403 return status;
4404 }
4405
4406 do {
4407 // Try getting a shape from this tile.
4408 status = msOGRFileNextShape( layer, shape, psInfo->poCurTile );
4409 if( status != MS_DONE )
4410 {
4411 if( psInfo->sTileProj.numargs > 0 )
4412 {
4413 msProjectShape(&(psInfo->sTileProj), &(layer->projection), shape);
4414 }
4415
4416 return status;
4417 }
4418
4419 // try next tile.
4420 status = msOGRFileReadTile( layer, psInfo );
4421 if( status != MS_SUCCESS )
4422 return status;
4423 } while( status == MS_SUCCESS );
4424 return status; //make compiler happy. this is never reached however
4425 }
4426
4427 /**********************************************************************
4428 * msOGRLayerGetShape()
4429 *
4430 * Returns shape from OGR data source by fid.
4431 *
4432 * Returns MS_SUCCESS/MS_FAILURE
4433 **********************************************************************/
msOGRLayerGetShape(layerObj * layer,shapeObj * shape,resultObj * record)4434 int msOGRLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record)
4435 {
4436 msOGRFileInfo *psInfo =(msOGRFileInfo*)layer->layerinfo;
4437
4438 long shapeindex = record->shapeindex;
4439 int tileindex = record->tileindex;
4440 int resultindex = record->resultindex;
4441 int record_is_fid = TRUE;
4442
4443 /* set the resultindex as shapeindex if available */
4444 if (resultindex >= 0) {
4445 record_is_fid = FALSE;
4446 shapeindex = resultindex;
4447 }
4448
4449 if (psInfo == NULL || psInfo->hLayer == NULL) {
4450 msSetError(MS_MISCERR, "Assertion failed: OGR layer not opened!!!", "msOGRLayerGetShape()");
4451 return(MS_FAILURE);
4452 }
4453
4454 if( layer->tileindex == NULL )
4455 return msOGRFileGetShape(layer, shape, shapeindex, psInfo, record_is_fid );
4456 else {
4457 if( psInfo->poCurTile == NULL
4458 || psInfo->poCurTile->nTileId != tileindex ) {
4459 if( msOGRFileReadTile( layer, psInfo, tileindex ) != MS_SUCCESS )
4460 return MS_FAILURE;
4461 }
4462
4463 int status = msOGRFileGetShape(layer, shape, shapeindex, psInfo->poCurTile, record_is_fid );
4464 if( status == MS_SUCCESS && psInfo->sTileProj.numargs > 0 )
4465 {
4466 msProjectShape(&(psInfo->sTileProj), &(layer->projection), shape);
4467 }
4468 return status;
4469 }
4470 }
4471
4472 /**********************************************************************
4473 * msOGRLayerGetExtent()
4474 *
4475 * Returns the layer extents.
4476 *
4477 * Returns MS_SUCCESS/MS_FAILURE
4478 **********************************************************************/
msOGRLayerGetExtent(layerObj * layer,rectObj * extent)4479 int msOGRLayerGetExtent(layerObj *layer, rectObj *extent)
4480 {
4481 msOGRFileInfo *psInfo =(msOGRFileInfo*)layer->layerinfo;
4482 OGREnvelope oExtent;
4483
4484 if (psInfo == NULL || psInfo->hLayer == NULL) {
4485 msSetError(MS_MISCERR, "Assertion failed: OGR layer not opened!!!",
4486 "msOGRLayerGetExtent()");
4487 return(MS_FAILURE);
4488 }
4489
4490 /* ------------------------------------------------------------------
4491 * Call OGR's GetExtent()... note that for some formats this will
4492 * result in a scan of the whole layer and can be an expensive call.
4493 *
4494 * For tile indexes layers we assume it is sufficient to get the
4495 * extents of the tile index.
4496 * ------------------------------------------------------------------ */
4497 ACQUIRE_OGR_LOCK;
4498 if (OGR_L_GetExtent( psInfo->hLayer, &oExtent, TRUE) != OGRERR_NONE) {
4499 RELEASE_OGR_LOCK;
4500 msSetError(MS_MISCERR, "Unable to get extents for this layer.",
4501 "msOGRLayerGetExtent()");
4502 return(MS_FAILURE);
4503 }
4504 RELEASE_OGR_LOCK;
4505
4506 extent->minx = oExtent.MinX;
4507 extent->miny = oExtent.MinY;
4508 extent->maxx = oExtent.MaxX;
4509 extent->maxy = oExtent.MaxY;
4510
4511 return MS_SUCCESS;
4512 }
4513
4514 /**********************************************************************
4515 * msOGRLayerGetNumFeatures()
4516 *
4517 * Returns the layer feature count.
4518 *
4519 * Returns the number of features on success, -1 on error
4520 **********************************************************************/
msOGRLayerGetNumFeatures(layerObj * layer)4521 int msOGRLayerGetNumFeatures(layerObj *layer)
4522 {
4523 msOGRFileInfo *psInfo = (msOGRFileInfo*)layer->layerinfo;
4524 int result;
4525
4526 if (psInfo == NULL || psInfo->hLayer == NULL) {
4527 msSetError(MS_MISCERR, "Assertion failed: OGR layer not opened!!!",
4528 "msOGRLayerGetNumFeatures()");
4529 return -1;
4530 }
4531
4532 /* ------------------------------------------------------------------
4533 * Call OGR's GetFeatureCount()... note that for some formats this will
4534 * result in a scan of the whole layer and can be an expensive call.
4535 * ------------------------------------------------------------------ */
4536 ACQUIRE_OGR_LOCK;
4537 result = (int)OGR_L_GetFeatureCount(psInfo->hLayer, TRUE);
4538 RELEASE_OGR_LOCK;
4539
4540 return result;
4541 }
4542
4543 /**********************************************************************
4544 * msOGRGetSymbolId()
4545 *
4546 * Returns a MapServer symbol number matching one of the symbols from
4547 * the OGR symbol id string. If not found then try to locate the
4548 * default symbol name, and if not found return 0.
4549 **********************************************************************/
msOGRGetSymbolId(symbolSetObj * symbolset,const char * pszSymbolId,const char * pszDefaultSymbol,int try_addimage_if_notfound)4550 static int msOGRGetSymbolId(symbolSetObj *symbolset, const char *pszSymbolId,
4551 const char *pszDefaultSymbol, int try_addimage_if_notfound)
4552 {
4553 // Symbol name mapping:
4554 // First look for the native symbol name, then the ogr-...
4555 // generic name, and in last resort try pszDefaultSymbol if
4556 // provided by user.
4557 char **params;
4558 int numparams;
4559 int nSymbol = -1;
4560
4561 if (pszSymbolId && pszSymbolId[0] != '\0') {
4562 params = msStringSplit(pszSymbolId, ',', &numparams);
4563 if (params != NULL) {
4564 for(int j=0; j<numparams && nSymbol == -1; j++) {
4565 nSymbol = msGetSymbolIndex(symbolset, params[j],
4566 try_addimage_if_notfound);
4567 }
4568 msFreeCharArray(params, numparams);
4569 }
4570 }
4571 if (nSymbol == -1 && pszDefaultSymbol) {
4572 nSymbol = msGetSymbolIndex(symbolset,(char*)pszDefaultSymbol,
4573 try_addimage_if_notfound);
4574 }
4575 if (nSymbol == -1)
4576 nSymbol = 0;
4577
4578 return nSymbol;
4579 }
4580
4581 static int msOGRUpdateStyleParseLabel(mapObj *map, layerObj *layer, classObj *c,
4582 OGRStyleToolH hLabelStyle);
4583 static int msOGRUpdateStyleParsePen(mapObj *map, layerObj *layer, styleObj *s,
4584 OGRStyleToolH hPenStyle, int bIsBrush, int* pbPriority);
4585 static int msOGRUpdateStyleParseBrush(mapObj *map, layerObj *layer, styleObj *s,
4586 OGRStyleToolH hBrushStyle, int* pbIsBrush, int* pbPriority);
4587 static int msOGRUpdateStyleParseSymbol(mapObj *map, layerObj *layer, styleObj *s,
4588 OGRStyleToolH hSymbolStyle, int* pbPriority);
4589
msOGRUpdateStyleCheckPenBrushOnly(OGRStyleMgrH hStyleMgr)4590 static int msOGRUpdateStyleCheckPenBrushOnly(OGRStyleMgrH hStyleMgr)
4591 {
4592 int numParts = OGR_SM_GetPartCount(hStyleMgr, NULL);
4593 int countPen = 0, countBrush = 0;
4594 int bIsNull;
4595
4596 for(int i=0; i<numParts; i++) {
4597 OGRSTClassId eStylePartType;
4598 OGRStyleToolH hStylePart = OGR_SM_GetPart(hStyleMgr, i, NULL);
4599 if (!hStylePart)
4600 continue;
4601
4602 eStylePartType = OGR_ST_GetType(hStylePart);
4603 if (eStylePartType == OGRSTCPen) {
4604 countPen ++;
4605 OGR_ST_GetParamNum(hStylePart, OGRSTPenPriority, &bIsNull);
4606 if( !bIsNull ) {
4607 OGR_ST_Destroy(hStylePart);
4608 return MS_FALSE;
4609 }
4610 }
4611 else if (eStylePartType == OGRSTCBrush) {
4612 countBrush ++;
4613 OGR_ST_GetParamNum(hStylePart, OGRSTBrushPriority, &bIsNull);
4614 if( !bIsNull ) {
4615 OGR_ST_Destroy(hStylePart);
4616 return MS_FALSE;
4617 }
4618 }
4619 else if (eStylePartType == OGRSTCSymbol) {
4620 OGR_ST_Destroy(hStylePart);
4621 return MS_FALSE;
4622 }
4623 OGR_ST_Destroy(hStylePart);
4624 }
4625 return (countPen == 1 && countBrush == 1);
4626 }
4627
4628 /**********************************************************************
4629 * msOGRUpdateStyle()
4630 *
4631 * Update the mapserver style according to the ogr style.
4632 * The function is called by msOGRGetAutoStyle and
4633 * msOGRUpdateStyleFromString
4634 **********************************************************************/
4635
4636 typedef struct
4637 {
4638 int nPriority; /* the explicit priority as specified by the 'l' option of PEN, BRUSH and SYMBOL tools */
4639 int nApparitionIndex; /* the index of the tool as parsed from the OGR feature style string */
4640 } StyleSortStruct;
4641
msOGRUpdateStyleSortFct(const void * pA,const void * pB)4642 static int msOGRUpdateStyleSortFct(const void* pA, const void* pB)
4643 {
4644 StyleSortStruct* sssa = (StyleSortStruct*)pA;
4645 StyleSortStruct* sssb = (StyleSortStruct*)pB;
4646 if( sssa->nPriority < sssb->nPriority )
4647 return -1;
4648 else if( sssa->nPriority > sssb->nPriority )
4649 return 1;
4650 else if( sssa->nApparitionIndex < sssb->nApparitionIndex )
4651 return -1;
4652 else
4653 return 1;
4654 }
4655
msOGRUpdateStyle(OGRStyleMgrH hStyleMgr,mapObj * map,layerObj * layer,classObj * c)4656 static int msOGRUpdateStyle(OGRStyleMgrH hStyleMgr, mapObj *map, layerObj *layer, classObj *c)
4657 {
4658 GBool bIsBrush=MS_FALSE;
4659 int numParts = OGR_SM_GetPartCount(hStyleMgr, NULL);
4660 int nPriority;
4661 int bIsPenBrushOnly = msOGRUpdateStyleCheckPenBrushOnly(hStyleMgr);
4662 StyleSortStruct* pasSortStruct = (StyleSortStruct*) msSmallMalloc(sizeof(StyleSortStruct) * numParts);
4663 int iSortStruct = 0;
4664 int iBaseStyleIndex = c->numstyles;
4665 int i;
4666
4667 /* ------------------------------------------------------------------
4668 * Handle each part
4669 * ------------------------------------------------------------------ */
4670
4671 for(i=0; i<numParts; i++) {
4672 OGRSTClassId eStylePartType;
4673 OGRStyleToolH hStylePart = OGR_SM_GetPart(hStyleMgr, i, NULL);
4674 if (!hStylePart)
4675 continue;
4676 eStylePartType = OGR_ST_GetType(hStylePart);
4677 nPriority = INT_MIN;
4678
4679 // We want all size values returned in pixels.
4680 //
4681 // The scale factor that OGR expect is the ground/paper scale
4682 // e.g. if 1 ground unit = 0.01 paper unit then scale=1/0.01=100
4683 // cellsize if number of ground units/pixel, and OGR assumes that
4684 // there is 72*39.37 pixels/ground units (since meter is assumed
4685 // for ground... but what ground units we have does not matter
4686 // as long as use the same assumptions everywhere)
4687 // That gives scale = cellsize*72*39.37
4688
4689 OGR_ST_SetUnit(hStylePart, OGRSTUPixel,
4690 map->cellsize*map->resolution/map->defresolution*72.0*39.37);
4691
4692 if (eStylePartType == OGRSTCLabel) {
4693 int ret = msOGRUpdateStyleParseLabel(map, layer, c, hStylePart);
4694 if( ret != MS_SUCCESS ) {
4695 OGR_ST_Destroy(hStylePart);
4696 msFree(pasSortStruct);
4697 return ret;
4698 }
4699 } else if (eStylePartType == OGRSTCPen) {
4700 styleObj* s;
4701 int nIndex;
4702 if( bIsPenBrushOnly ) {
4703 /* Historic behaviour when there is a PEN and BRUSH only */
4704 if (bIsBrush || layer->type == MS_LAYER_POLYGON)
4705 // This is a multipart symbology, so pen defn goes in the
4706 // overlaysymbol params
4707 nIndex = 1;
4708 else
4709 nIndex = 0;
4710 }
4711 else
4712 nIndex = c->numstyles;
4713
4714 if (msMaybeAllocateClassStyle(c, nIndex)) {
4715 OGR_ST_Destroy(hStylePart);
4716 msFree(pasSortStruct);
4717 return(MS_FAILURE);
4718 }
4719 s = c->styles[nIndex];
4720
4721 msOGRUpdateStyleParsePen(map, layer, s, hStylePart, bIsBrush, &nPriority);
4722
4723 } else if (eStylePartType == OGRSTCBrush) {
4724 styleObj* s;
4725 int nIndex = ( bIsPenBrushOnly ) ? 0 : c->numstyles;
4726 /* We need 1 style */
4727 if (msMaybeAllocateClassStyle(c, nIndex)) {
4728 OGR_ST_Destroy(hStylePart);
4729 msFree(pasSortStruct);
4730 return(MS_FAILURE);
4731 }
4732 s = c->styles[nIndex];
4733
4734 msOGRUpdateStyleParseBrush(map, layer, s, hStylePart, &bIsBrush, &nPriority);
4735
4736 } else if (eStylePartType == OGRSTCSymbol) {
4737 styleObj* s;
4738 /* We need 1 style */
4739 int nIndex = c->numstyles;
4740 if (msMaybeAllocateClassStyle(c, nIndex)) {
4741 OGR_ST_Destroy(hStylePart);
4742 msFree(pasSortStruct);
4743 return(MS_FAILURE);
4744 }
4745 s = c->styles[nIndex];
4746
4747 msOGRUpdateStyleParseSymbol(map, layer, s, hStylePart, &nPriority);
4748 }
4749
4750 /* Memorize the explicit priority and apparition order of the parsed tool/style */
4751 if( !bIsPenBrushOnly &&
4752 (eStylePartType == OGRSTCPen || eStylePartType == OGRSTCBrush ||
4753 eStylePartType == OGRSTCSymbol) ) {
4754 pasSortStruct[iSortStruct].nPriority = nPriority;
4755 pasSortStruct[iSortStruct].nApparitionIndex = iSortStruct;
4756 iSortStruct++;
4757 }
4758
4759 OGR_ST_Destroy(hStylePart);
4760
4761 }
4762
4763 if( iSortStruct > 1 && !bIsPenBrushOnly ) {
4764 /* Compute style order based on their explicit priority and apparition order */
4765 qsort(pasSortStruct, iSortStruct, sizeof(StyleSortStruct), msOGRUpdateStyleSortFct);
4766
4767 /* Now reorder styles in c->styles */
4768 styleObj** ppsStyleTmp = (styleObj**)msSmallMalloc( iSortStruct * sizeof(styleObj*) );
4769 memcpy( ppsStyleTmp, c->styles + iBaseStyleIndex, iSortStruct * sizeof(styleObj*) );
4770 for( i = 0; i < iSortStruct; i++)
4771 {
4772 c->styles[iBaseStyleIndex + i] = ppsStyleTmp[pasSortStruct[i].nApparitionIndex];
4773 }
4774 msFree(ppsStyleTmp);
4775 }
4776
4777 msFree(pasSortStruct);
4778
4779 return MS_SUCCESS;
4780 }
4781
msOGRUpdateStyleParseLabel(mapObj * map,layerObj * layer,classObj * c,OGRStyleToolH hLabelStyle)4782 static int msOGRUpdateStyleParseLabel(mapObj *map, layerObj *layer, classObj *c,
4783 OGRStyleToolH hLabelStyle)
4784 {
4785 GBool bIsNull;
4786 int r=0,g=0,b=0,t=0;
4787
4788 // Enclose the text string inside quotes to make sure it is seen
4789 // as a string by the parser inside loadExpression(). (bug185)
4790 /* See bug 3481 about the isalnum hack */
4791 const char *labelTextString = OGR_ST_GetParamStr(hLabelStyle,
4792 OGRSTLabelTextString,
4793 &bIsNull);
4794
4795 if (c->numlabels == 0) {
4796 /* allocate a new label object */
4797 if(msGrowClassLabels(c) == NULL)
4798 return MS_FAILURE;
4799 c->numlabels++;
4800 initLabel(c->labels[0]);
4801 }
4802 msFreeExpression(&c->labels[0]->text);
4803 c->labels[0]->text.type = MS_STRING;
4804 c->labels[0]->text.string = msStrdup(labelTextString);
4805
4806 c->labels[0]->angle = OGR_ST_GetParamDbl(hLabelStyle,
4807 OGRSTLabelAngle, &bIsNull);
4808
4809 c->labels[0]->size = OGR_ST_GetParamDbl(hLabelStyle,
4810 OGRSTLabelSize, &bIsNull);
4811 if( c->labels[0]->size < 1 ) /* no point dropping to zero size */
4812 c->labels[0]->size = 1;
4813
4814 // OGR default is anchor point = LL, so label is at UR of anchor
4815 c->labels[0]->position = MS_UR;
4816
4817 int nPosition = OGR_ST_GetParamNum(hLabelStyle,
4818 OGRSTLabelAnchor,
4819 &bIsNull);
4820 if( !bIsNull ) {
4821 switch( nPosition ) {
4822 case 1:
4823 c->labels[0]->position = MS_UR;
4824 break;
4825 case 2:
4826 c->labels[0]->position = MS_UC;
4827 break;
4828 case 3:
4829 c->labels[0]->position = MS_UL;
4830 break;
4831 case 4:
4832 c->labels[0]->position = MS_CR;
4833 break;
4834 case 5:
4835 c->labels[0]->position = MS_CC;
4836 break;
4837 case 6:
4838 c->labels[0]->position = MS_CL;
4839 break;
4840 case 7:
4841 c->labels[0]->position = MS_LR;
4842 break;
4843 case 8:
4844 c->labels[0]->position = MS_LC;
4845 break;
4846 case 9:
4847 c->labels[0]->position = MS_LL;
4848 break;
4849 case 10:
4850 c->labels[0]->position = MS_UR;
4851 break; /*approximate*/
4852 case 11:
4853 c->labels[0]->position = MS_UC;
4854 break;
4855 case 12:
4856 c->labels[0]->position = MS_UL;
4857 break;
4858 default:
4859 break;
4860 }
4861 }
4862
4863 const char *pszColor = OGR_ST_GetParamStr(hLabelStyle,
4864 OGRSTLabelFColor,
4865 &bIsNull);
4866 if (!bIsNull && OGR_ST_GetRGBFromString(hLabelStyle, pszColor,
4867 &r, &g, &b, &t)) {
4868 MS_INIT_COLOR(c->labels[0]->color, r, g, b, t);
4869 }
4870
4871 pszColor = OGR_ST_GetParamStr(hLabelStyle,
4872 OGRSTLabelHColor,
4873 &bIsNull);
4874 if (!bIsNull && OGR_ST_GetRGBFromString(hLabelStyle, pszColor,
4875 &r, &g, &b, &t)) {
4876 MS_INIT_COLOR(c->labels[0]->shadowcolor, r, g, b, t);
4877 }
4878
4879 pszColor = OGR_ST_GetParamStr(hLabelStyle,
4880 OGRSTLabelOColor,
4881 &bIsNull);
4882 if (!bIsNull && OGR_ST_GetRGBFromString(hLabelStyle, pszColor,
4883 &r, &g, &b, &t)) {
4884 MS_INIT_COLOR(c->labels[0]->outlinecolor, r, g, b, t);
4885 }
4886
4887 const char *pszBold = OGR_ST_GetParamNum(hLabelStyle,
4888 OGRSTLabelBold,
4889 &bIsNull) ? "-bold" : "";
4890 const char *pszItalic = OGR_ST_GetParamNum(hLabelStyle,
4891 OGRSTLabelItalic,
4892 &bIsNull) ? "-italic" : "";
4893 const char *pszFontName = OGR_ST_GetParamStr(hLabelStyle,
4894 OGRSTLabelFontName,
4895 &bIsNull);
4896 /* replace spaces with hyphens to allow mapping to a valid hashtable entry*/
4897 char* pszFontNameEscaped = NULL;
4898 if (pszFontName != NULL) {
4899 pszFontNameEscaped = msStrdup(pszFontName);
4900 msReplaceChar(pszFontNameEscaped, ' ', '-');
4901 }
4902
4903 const char *pszName = CPLSPrintf("%s%s%s", pszFontNameEscaped, pszBold, pszItalic);
4904 bool bFont = true;
4905
4906 if (pszFontNameEscaped != NULL && !bIsNull && pszFontNameEscaped[0] != '\0') {
4907 if (msLookupHashTable(&(map->fontset.fonts), (char*)pszName) != NULL) {
4908 c->labels[0]->font = msStrdup(pszName);
4909 if (layer->debug >= MS_DEBUGLEVEL_VVV)
4910 msDebug("** Using '%s' TTF font **\n", pszName);
4911 } else if ( (strcmp(pszFontNameEscaped,pszName) != 0) &&
4912 msLookupHashTable(&(map->fontset.fonts), (char*)pszFontNameEscaped) != NULL) {
4913 c->labels[0]->font = msStrdup(pszFontNameEscaped);
4914 if (layer->debug >= MS_DEBUGLEVEL_VVV)
4915 msDebug("** Using '%s' TTF font **\n", pszFontNameEscaped);
4916 } else if (msLookupHashTable(&(map->fontset.fonts),"default") != NULL) {
4917 c->labels[0]->font = msStrdup("default");
4918 if (layer->debug >= MS_DEBUGLEVEL_VVV)
4919 msDebug("** Using 'default' TTF font **\n");
4920 } else
4921 bFont = false;
4922 }
4923
4924 msFree(pszFontNameEscaped);
4925
4926 if (!bFont) {
4927 c->labels[0]->size = MS_MEDIUM;
4928 }
4929
4930 return MS_SUCCESS;
4931 }
4932
msOGRUpdateStyleParsePen(mapObj * map,layerObj * layer,styleObj * s,OGRStyleToolH hPenStyle,int bIsBrush,int * pbPriority)4933 static int msOGRUpdateStyleParsePen(mapObj *map, layerObj *layer, styleObj *s,
4934 OGRStyleToolH hPenStyle, int bIsBrush,
4935 int* pbPriority)
4936 {
4937 GBool bIsNull;
4938 int r=0,g=0,b=0,t=0;
4939
4940 const char *pszPenName, *pszPattern, *pszCap, *pszJoin;
4941 colorObj oPenColor;
4942 int nPenSymbol = 0;
4943 int nPenSize = 1;
4944 t =-1;
4945 double pattern[MS_MAXPATTERNLENGTH];
4946 int patternlength = 0;
4947 int linecap = MS_CJC_DEFAULT_CAPS;
4948 int linejoin = MS_CJC_DEFAULT_JOINS;
4949 double offsetx = 0.0;
4950 double offsety = 0.0;
4951
4952 // Make sure pen is always initialized
4953 MS_INIT_COLOR(oPenColor, -1, -1, -1,255);
4954
4955 pszPenName = OGR_ST_GetParamStr(hPenStyle,
4956 OGRSTPenId,
4957 &bIsNull);
4958 if (bIsNull) pszPenName = NULL;
4959 // Check for Pen Pattern "ogr-pen-1": the invisible pen
4960 // If that's what we have then set pen color to -1
4961 if (pszPenName && strstr(pszPenName, "ogr-pen-1") != NULL) {
4962 MS_INIT_COLOR(oPenColor, -1, -1, -1,255);
4963 } else {
4964 const char *pszColor = OGR_ST_GetParamStr(hPenStyle,
4965 OGRSTPenColor,
4966 &bIsNull);
4967 if (!bIsNull && OGR_ST_GetRGBFromString(hPenStyle, pszColor,
4968 &r, &g, &b, &t)) {
4969 MS_INIT_COLOR(oPenColor, r, g, b, t);
4970 if (layer->debug >= MS_DEBUGLEVEL_VVV)
4971 msDebug("** PEN COLOR = %d %d %d **\n", r,g,b);
4972 }
4973
4974 nPenSize = OGR_ST_GetParamNum(hPenStyle,
4975 OGRSTPenWidth, &bIsNull);
4976 if (bIsNull)
4977 nPenSize = 1;
4978 if (pszPenName!=NULL) {
4979 // Try to match pen name in symbol file
4980 nPenSymbol = msOGRGetSymbolId(&(map->symbolset),
4981 pszPenName, NULL, MS_FALSE);
4982 }
4983 }
4984
4985 if (layer->debug >= MS_DEBUGLEVEL_VVV)
4986 msDebug("** PEN COLOR = %d %d %d **\n", oPenColor.red,oPenColor.green,oPenColor.blue);
4987
4988 pszPattern = OGR_ST_GetParamStr(hPenStyle, OGRSTPenPattern, &bIsNull);
4989 if (bIsNull) pszPattern = NULL;
4990 if( pszPattern != NULL )
4991 {
4992 char** papszTokens = CSLTokenizeStringComplex(pszPattern, " ", FALSE, FALSE);
4993 int nTokenCount = CSLCount(papszTokens);
4994 int bValidFormat = TRUE;
4995 if( nTokenCount >= 2 && nTokenCount <= MS_MAXPATTERNLENGTH)
4996 {
4997 for(int i=0;i<nTokenCount;i++)
4998 {
4999 if( strlen(papszTokens[i]) > 2 &&
5000 strcmp(papszTokens[i] + strlen(papszTokens[i]) - 2, "px") == 0 )
5001 {
5002 pattern[patternlength++] = CPLAtof(papszTokens[i]);
5003 }
5004 else
5005 {
5006 bValidFormat = FALSE;
5007 patternlength = 0;
5008 break;
5009 }
5010 }
5011 }
5012 else
5013 bValidFormat = FALSE;
5014 if( !bValidFormat && layer->debug >= MS_DEBUGLEVEL_VVV)
5015 msDebug("Invalid/unhandled pen pattern format = %s\n", pszPattern);
5016 CSLDestroy(papszTokens);
5017 }
5018
5019 pszCap = OGR_ST_GetParamStr(hPenStyle, OGRSTPenCap, &bIsNull);
5020 if (bIsNull) pszCap = NULL;
5021 if( pszCap != NULL )
5022 {
5023 /* Note: the default in OGR Feature style is BUTT, but the MapServer */
5024 /* default is ROUND. Currently use MapServer default. */
5025 if( strcmp(pszCap, "b") == 0 ) /* BUTT */
5026 linecap = MS_CJC_BUTT;
5027 else if( strcmp(pszCap, "r") == 0 ) /* ROUND */
5028 linecap = MS_CJC_ROUND;
5029 else if( strcmp(pszCap, "p") == 0 ) /* PROJECTING */
5030 linecap = MS_CJC_SQUARE;
5031 else if( layer->debug >= MS_DEBUGLEVEL_VVV)
5032 msDebug("Invalid/unhandled pen cap = %s\n", pszCap);
5033 }
5034
5035 pszJoin = OGR_ST_GetParamStr(hPenStyle, OGRSTPenJoin, &bIsNull);
5036 if (bIsNull) pszJoin = NULL;
5037 if( pszJoin != NULL )
5038 {
5039 /* Note: the default in OGR Feature style is MITER, but the MapServer */
5040 /* default is NONE. Currently use MapServer default. */
5041 if( strcmp(pszJoin, "m") == 0 ) /* MITTER */
5042 linejoin = MS_CJC_MITER;
5043 else if( strcmp(pszJoin, "r") == 0 ) /* ROUND */
5044 linejoin = MS_CJC_ROUND;
5045 else if( strcmp(pszJoin, "b") == 0 ) /* BEVEL */
5046 linejoin = MS_CJC_BEVEL;
5047 else if( layer->debug >= MS_DEBUGLEVEL_VVV)
5048 msDebug("Invalid/unhandled pen join = %s\n", pszJoin);
5049 }
5050
5051 offsetx = OGR_ST_GetParamDbl(hPenStyle, OGRSTPenPerOffset, &bIsNull);
5052 if( bIsNull ) offsetx = 0;
5053 if( offsetx != 0.0 )
5054 {
5055 /* OGR feature style and MapServer conventions related to offset */
5056 /* sign are the same : negative values for left of line, positive for */
5057 /* right of line */
5058 offsety = MS_STYLE_SINGLE_SIDED_OFFSET;
5059 }
5060
5061 if (bIsBrush || layer->type == MS_LAYER_POLYGON) {
5062 // This is a multipart symbology, so pen defn goes in the
5063 // overlaysymbol params
5064 s->outlinecolor = oPenColor;
5065 } else {
5066 // Single part symbology
5067 s->color = oPenColor;
5068 }
5069
5070 s->symbol = nPenSymbol;
5071 s->size = nPenSize;
5072 s->width = nPenSize;
5073 s->linecap = linecap;
5074 s->linejoin = linejoin;
5075 s->offsetx = offsetx;
5076 s->offsety = offsety;
5077 s->patternlength = patternlength;
5078 if( patternlength > 0 )
5079 memcpy(s->pattern, pattern, sizeof(double) * patternlength);
5080
5081 int nPriority = OGR_ST_GetParamNum(hPenStyle, OGRSTPenPriority, &bIsNull);
5082 if( !bIsNull )
5083 *pbPriority = nPriority;
5084
5085 return MS_SUCCESS;
5086 }
5087
msOGRUpdateStyleParseBrush(mapObj * map,layerObj * layer,styleObj * s,OGRStyleToolH hBrushStyle,int * pbIsBrush,int * pbPriority)5088 static int msOGRUpdateStyleParseBrush(mapObj *map, layerObj *layer, styleObj *s,
5089 OGRStyleToolH hBrushStyle, int* pbIsBrush,
5090 int* pbPriority)
5091 {
5092 GBool bIsNull;
5093 int r=0,g=0,b=0,t=0;
5094
5095 const char *pszBrushName = OGR_ST_GetParamStr(hBrushStyle,
5096 OGRSTBrushId,
5097 &bIsNull);
5098 if (bIsNull) pszBrushName = NULL;
5099
5100 // Check for Brush Pattern "ogr-brush-1": the invisible fill
5101 // If that's what we have then set fill color to -1
5102 if (pszBrushName && strstr(pszBrushName, "ogr-brush-1") != NULL) {
5103 MS_INIT_COLOR(s->color, -1, -1, -1, 255);
5104 } else {
5105 *pbIsBrush = TRUE;
5106 const char *pszColor = OGR_ST_GetParamStr(hBrushStyle,
5107 OGRSTBrushFColor,
5108 &bIsNull);
5109 if (!bIsNull && OGR_ST_GetRGBFromString(hBrushStyle,
5110 pszColor,
5111 &r, &g, &b, &t)) {
5112 MS_INIT_COLOR(s->color, r, g, b, t);
5113
5114 if (layer->debug >= MS_DEBUGLEVEL_VVV)
5115 msDebug("** BRUSH COLOR = %d %d %d **\n", r,g,b);
5116 }
5117
5118 pszColor = OGR_ST_GetParamStr(hBrushStyle,
5119 OGRSTBrushBColor, &bIsNull);
5120 if (!bIsNull && OGR_ST_GetRGBFromString(hBrushStyle,
5121 pszColor,
5122 &r, &g, &b, &t)) {
5123 MS_INIT_COLOR(s->backgroundcolor, r, g, b, t);
5124 }
5125
5126 // Symbol name mapping:
5127 // First look for the native symbol name, then the ogr-...
5128 // generic name.
5129 // If none provided or found then use 0: solid fill
5130
5131 const char *pszName = OGR_ST_GetParamStr(hBrushStyle,
5132 OGRSTBrushId,
5133 &bIsNull);
5134 s->symbol = msOGRGetSymbolId(&(map->symbolset),
5135 pszName, NULL, MS_FALSE);
5136
5137 double angle = OGR_ST_GetParamDbl(hBrushStyle, OGRSTBrushAngle, &bIsNull);
5138 if( !bIsNull )
5139 s->angle = angle;
5140
5141 double size = OGR_ST_GetParamDbl(hBrushStyle, OGRSTBrushSize, &bIsNull);
5142 if( !bIsNull )
5143 s->size = size;
5144
5145 double spacingx = OGR_ST_GetParamDbl(hBrushStyle, OGRSTBrushDx, &bIsNull);
5146 if( !bIsNull )
5147 {
5148 double spacingy = OGR_ST_GetParamDbl(hBrushStyle, OGRSTBrushDy, &bIsNull);
5149 if( !bIsNull )
5150 {
5151 if( spacingx == spacingy )
5152 s->gap = spacingx;
5153 else if( layer->debug >= MS_DEBUGLEVEL_VVV )
5154 msDebug("Ignoring brush dx and dy since they don't have the same value\n");
5155 }
5156 }
5157 }
5158
5159 int nPriority = OGR_ST_GetParamNum(hBrushStyle, OGRSTBrushPriority, &bIsNull);
5160 if( !bIsNull )
5161 *pbPriority = nPriority;
5162
5163 return MS_SUCCESS;
5164 }
5165
msOGRUpdateStyleParseSymbol(mapObj * map,layerObj * layer,styleObj * s,OGRStyleToolH hSymbolStyle,int * pbPriority)5166 static int msOGRUpdateStyleParseSymbol(mapObj *map, layerObj *layer, styleObj *s,
5167 OGRStyleToolH hSymbolStyle,
5168 int* pbPriority)
5169 {
5170 GBool bIsNull;
5171 int r=0,g=0,b=0,t=0;
5172
5173 const char *pszColor = OGR_ST_GetParamStr(hSymbolStyle,
5174 OGRSTSymbolColor,
5175 &bIsNull);
5176 if (!bIsNull && OGR_ST_GetRGBFromString(hSymbolStyle,
5177 pszColor,
5178 &r, &g, &b, &t)) {
5179 MS_INIT_COLOR(s->color, r, g, b, t);
5180 }
5181
5182 pszColor = OGR_ST_GetParamStr(hSymbolStyle,
5183 OGRSTSymbolOColor,
5184 &bIsNull);
5185 if (!bIsNull && OGR_ST_GetRGBFromString(hSymbolStyle,
5186 pszColor,
5187 &r, &g, &b, &t)) {
5188 MS_INIT_COLOR(s->outlinecolor, r, g, b, t);
5189 }
5190
5191 s->angle = OGR_ST_GetParamNum(hSymbolStyle,
5192 OGRSTSymbolAngle,
5193 &bIsNull);
5194 double dfTmp = OGR_ST_GetParamNum(hSymbolStyle, OGRSTSymbolSize, &bIsNull);
5195 if (!bIsNull)
5196 s->size = dfTmp;
5197
5198 // Symbol name mapping:
5199 // First look for the native symbol name, then the ogr-...
5200 // generic name, and in last resort try "default-marker" if
5201 // provided by user.
5202 const char *pszName = OGR_ST_GetParamStr(hSymbolStyle,
5203 OGRSTSymbolId,
5204 &bIsNull);
5205 if (bIsNull)
5206 pszName = NULL;
5207
5208 int try_addimage_if_notfound = MS_FALSE;
5209 #ifdef USE_CURL
5210 if (pszName && strncasecmp(pszName, "http", 4) == 0)
5211 try_addimage_if_notfound =MS_TRUE;
5212 #endif
5213 if (!s->symbolname)
5214 s->symbol = msOGRGetSymbolId(&(map->symbolset),
5215 pszName,
5216 "default-marker", try_addimage_if_notfound);
5217
5218 int nPriority = OGR_ST_GetParamNum(hSymbolStyle, OGRSTSymbolPriority, &bIsNull);
5219 if( !bIsNull )
5220 *pbPriority = nPriority;
5221
5222 return MS_SUCCESS;
5223 }
5224
5225
5226 /**********************************************************************
5227 * msOGRLayerGetAutoStyle()
5228 *
5229 * Fills a classObj with style info from the specified shape.
5230 * For optimal results, this should be called immediately after
5231 * GetNextShape() or GetShape() so that the shape doesn't have to be read
5232 * twice.
5233 *
5234 * The returned classObj is a ref. to a static structure valid only until
5235 * the next call and that shouldn't be freed by the caller.
5236 **********************************************************************/
msOGRLayerGetAutoStyle(mapObj * map,layerObj * layer,classObj * c,shapeObj * shape)5237 static int msOGRLayerGetAutoStyle(mapObj *map, layerObj *layer, classObj *c,
5238 shapeObj* shape)
5239 {
5240 msOGRFileInfo *psInfo =(msOGRFileInfo*)layer->layerinfo;
5241
5242 if (psInfo == NULL || psInfo->hLayer == NULL) {
5243 msSetError(MS_MISCERR, "Assertion failed: OGR layer not opened!!!",
5244 "msOGRLayerGetAutoStyle()");
5245 return(MS_FAILURE);
5246 }
5247
5248 if( layer->tileindex != NULL ) {
5249 if( (psInfo->poCurTile == NULL || shape->tileindex != psInfo->poCurTile->nTileId)
5250 && msOGRFileReadTile( layer, psInfo ) != MS_SUCCESS )
5251 return MS_FAILURE;
5252
5253 psInfo = psInfo->poCurTile;
5254 }
5255
5256 /* ------------------------------------------------------------------
5257 * Read shape or reuse ref. to last shape read.
5258 * ------------------------------------------------------------------ */
5259 ACQUIRE_OGR_LOCK;
5260 if (psInfo->hLastFeature == NULL ||
5261 psInfo->last_record_index_read != shape->resultindex) {
5262 RELEASE_OGR_LOCK;
5263 msSetError(MS_MISCERR,
5264 "Assertion failed: AutoStyle not requested on loaded shape.",
5265 "msOGRLayerGetAutoStyle()");
5266 return(MS_FAILURE);
5267 }
5268
5269 /* ------------------------------------------------------------------
5270 * Reset style info in the class to defaults
5271 * the only members we don't touch are name, expression, and join/query stuff
5272 * ------------------------------------------------------------------ */
5273 resetClassStyle(c);
5274 if (msMaybeAllocateClassStyle(c, 0)) {
5275 RELEASE_OGR_LOCK;
5276 return(MS_FAILURE);
5277 }
5278
5279 // __TODO__ label cache incompatible with styleitem feature.
5280 layer->labelcache = MS_OFF;
5281
5282 int nRetVal = MS_SUCCESS;
5283 if (psInfo->hLastFeature) {
5284 OGRStyleMgrH hStyleMgr = OGR_SM_Create(NULL);
5285 OGR_SM_InitFromFeature(hStyleMgr, psInfo->hLastFeature);
5286 nRetVal = msOGRUpdateStyle(hStyleMgr, map, layer, c);
5287 OGR_SM_Destroy(hStyleMgr);
5288 }
5289
5290 RELEASE_OGR_LOCK;
5291 return nRetVal;
5292 }
5293
5294
5295 /**********************************************************************
5296 * msOGRUpdateStyleFromString()
5297 *
5298 * Fills a classObj with style info from the specified style string.
5299 * For optimal results, this should be called immediately after
5300 * GetNextShape() or GetShape() so that the shape doesn't have to be read
5301 * twice.
5302 *
5303 * The returned classObj is a ref. to a static structure valid only until
5304 * the next call and that shouldn't be freed by the caller.
5305 **********************************************************************/
msOGRUpdateStyleFromString(mapObj * map,layerObj * layer,classObj * c,const char * stylestring)5306 int msOGRUpdateStyleFromString(mapObj *map, layerObj *layer, classObj *c,
5307 const char *stylestring)
5308 {
5309 /* ------------------------------------------------------------------
5310 * Reset style info in the class to defaults
5311 * the only members we don't touch are name, expression, and join/query stuff
5312 * ------------------------------------------------------------------ */
5313 resetClassStyle(c);
5314 if (msMaybeAllocateClassStyle(c, 0)) {
5315 return(MS_FAILURE);
5316 }
5317
5318 // __TODO__ label cache incompatible with styleitem feature.
5319 layer->labelcache = MS_OFF;
5320
5321 int nRetVal = MS_SUCCESS;
5322
5323 ACQUIRE_OGR_LOCK;
5324
5325 OGRStyleMgrH hStyleMgr = OGR_SM_Create(NULL);
5326 OGR_SM_InitStyleString(hStyleMgr, stylestring);
5327 nRetVal = msOGRUpdateStyle(hStyleMgr, map, layer, c);
5328 OGR_SM_Destroy(hStyleMgr);
5329
5330 RELEASE_OGR_LOCK;
5331 return nRetVal;
5332 }
5333
5334 /************************************************************************/
5335 /* msOGRLCleanup() */
5336 /************************************************************************/
5337
msOGRCleanup(void)5338 void msOGRCleanup( void )
5339
5340 {
5341 ACQUIRE_OGR_LOCK;
5342 if( bOGRDriversRegistered == MS_TRUE ) {
5343 CPLPopErrorHandler();
5344 bOGRDriversRegistered = MS_FALSE;
5345 }
5346 RELEASE_OGR_LOCK;
5347 }
5348
5349 /************************************************************************/
5350 /* msOGREscapeSQLParam */
5351 /************************************************************************/
msOGREscapePropertyName(layerObj * layer,const char * pszString)5352 char *msOGREscapePropertyName(layerObj *layer, const char *pszString)
5353 {
5354 char* pszEscapedStr =NULL;
5355 if(layer && pszString && strlen(pszString) > 0) {
5356 pszEscapedStr = (char*) msSmallMalloc( strlen(pszString) * 2 + 1 );
5357 int j = 0;
5358 for( int i = 0; pszString[i] != '\0'; ++i )
5359 {
5360 if( pszString[i] == '"' )
5361 {
5362 pszEscapedStr[j++] = '"';
5363 pszEscapedStr[j++] = '"';
5364 }
5365 else
5366 pszEscapedStr[j++] = pszString[i];
5367 }
5368 pszEscapedStr[j] = 0;
5369 }
5370 return pszEscapedStr;
5371 }
5372
msOGRLayerSupportsCommonFilters(layerObj * layer)5373 static int msOGRLayerSupportsCommonFilters(layerObj *layer)
5374 {
5375 return MS_FALSE;
5376 }
5377
msOGREnablePaging(layerObj * layer,int value)5378 static void msOGREnablePaging(layerObj *layer, int value)
5379 {
5380 msOGRFileInfo *layerinfo = NULL;
5381
5382 if (layer->debug) {
5383 msDebug("msOGREnablePaging(%d) called.\n", value);
5384 }
5385
5386 if(!msOGRLayerIsOpen(layer))
5387 msOGRLayerOpenVT(layer);
5388
5389 assert( layer->layerinfo != NULL);
5390
5391 layerinfo = (msOGRFileInfo *)layer->layerinfo;
5392 layerinfo->bPaging = value;
5393 }
5394
msOGRGetPaging(layerObj * layer)5395 static int msOGRGetPaging(layerObj *layer)
5396 {
5397 msOGRFileInfo *layerinfo = NULL;
5398
5399 if (layer->debug) {
5400 msDebug("msOGRGetPaging called.\n");
5401 }
5402
5403 if(!msOGRLayerIsOpen(layer))
5404 msOGRLayerOpenVT(layer);
5405
5406 assert( layer->layerinfo != NULL);
5407
5408 layerinfo = (msOGRFileInfo *)layer->layerinfo;
5409 return layerinfo->bPaging;
5410 }
5411
5412 /************************************************************************/
5413 /* msOGRLayerInitializeVirtualTable() */
5414 /************************************************************************/
msOGRLayerInitializeVirtualTable(layerObj * layer)5415 int msOGRLayerInitializeVirtualTable(layerObj *layer)
5416 {
5417 assert(layer != NULL);
5418 assert(layer->vtable != NULL);
5419
5420 layer->vtable->LayerTranslateFilter = msOGRTranslateMsExpressionToOGRSQL;
5421
5422 layer->vtable->LayerSupportsCommonFilters = msOGRLayerSupportsCommonFilters;
5423 layer->vtable->LayerInitItemInfo = msOGRLayerInitItemInfo;
5424 layer->vtable->LayerFreeItemInfo = msOGRLayerFreeItemInfo;
5425 layer->vtable->LayerOpen = msOGRLayerOpenVT;
5426 layer->vtable->LayerIsOpen = msOGRLayerIsOpen;
5427 layer->vtable->LayerWhichShapes = msOGRLayerWhichShapes;
5428 layer->vtable->LayerNextShape = msOGRLayerNextShape;
5429 layer->vtable->LayerGetShape = msOGRLayerGetShape;
5430 /* layer->vtable->LayerGetShapeCount, use default */
5431 layer->vtable->LayerClose = msOGRLayerClose;
5432 layer->vtable->LayerGetItems = msOGRLayerGetItems;
5433 layer->vtable->LayerGetExtent = msOGRLayerGetExtent;
5434 layer->vtable->LayerGetAutoStyle = msOGRLayerGetAutoStyle;
5435 /* layer->vtable->LayerCloseConnection, use default */
5436 layer->vtable->LayerApplyFilterToLayer = msLayerApplyCondSQLFilterToLayer;
5437 layer->vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter;
5438 /* layer->vtable->LayerCreateItems, use default */
5439 layer->vtable->LayerGetNumFeatures = msOGRLayerGetNumFeatures;
5440 /* layer->vtable->LayerGetAutoProjection, use defaut*/
5441
5442 layer->vtable->LayerEscapeSQLParam = msOGREscapeSQLParam;
5443 layer->vtable->LayerEscapePropertyName = msOGREscapePropertyName;
5444 layer->vtable->LayerEnablePaging = msOGREnablePaging;
5445 layer->vtable->LayerGetPaging = msOGRGetPaging;
5446 return MS_SUCCESS;
5447 }
5448
5449 /************************************************************************/
5450 /* msOGRShapeFromWKT() */
5451 /************************************************************************/
msOGRShapeFromWKT(const char * string)5452 shapeObj *msOGRShapeFromWKT(const char *string)
5453 {
5454
5455 OGRGeometryH hGeom = NULL;
5456 shapeObj *shape=NULL;
5457
5458 if(!string)
5459 return NULL;
5460
5461 if( OGR_G_CreateFromWkt( (char **)&string, NULL, &hGeom ) != OGRERR_NONE ) {
5462 msSetError(MS_OGRERR, "Failed to parse WKT string.",
5463 "msOGRShapeFromWKT()" );
5464 return NULL;
5465 }
5466
5467 /* Initialize a corresponding shapeObj */
5468
5469 shape = (shapeObj *) malloc(sizeof(shapeObj));
5470 msInitShape(shape);
5471
5472 /* translate WKT into an OGRGeometry. */
5473
5474 if( msOGRGeometryToShape( hGeom, shape,
5475 wkbFlatten(OGR_G_GetGeometryType(hGeom)) )
5476 == MS_FAILURE ) {
5477 free( shape );
5478 return NULL;
5479 }
5480
5481 OGR_G_DestroyGeometry( hGeom );
5482
5483 return shape;
5484 }
5485
5486 /************************************************************************/
5487 /* msOGRShapeToWKT() */
5488 /************************************************************************/
msOGRShapeToWKT(shapeObj * shape)5489 char *msOGRShapeToWKT(shapeObj *shape)
5490 {
5491 OGRGeometryH hGeom = NULL;
5492 int i;
5493 char *wkt = NULL;
5494
5495 if(!shape)
5496 return NULL;
5497
5498 if( shape->type == MS_SHAPE_POINT && shape->numlines == 1
5499 && shape->line[0].numpoints == 1 ) {
5500 hGeom = OGR_G_CreateGeometry( wkbPoint );
5501 OGR_G_SetPoint_2D( hGeom, 0,
5502 shape->line[0].point[0].x,
5503 shape->line[0].point[0].y );
5504 } else if( shape->type == MS_SHAPE_POINT && shape->numlines == 1
5505 && shape->line[0].numpoints > 1 ) {
5506 hGeom = OGR_G_CreateGeometry( wkbMultiPoint );
5507 for( i = 0; i < shape->line[0].numpoints; i++ ) {
5508 OGRGeometryH hPoint;
5509
5510 hPoint = OGR_G_CreateGeometry( wkbPoint );
5511 OGR_G_SetPoint_2D( hPoint, 0,
5512 shape->line[0].point[i].x,
5513 shape->line[0].point[i].y );
5514 OGR_G_AddGeometryDirectly( hGeom, hPoint );
5515 }
5516 } else if( shape->type == MS_SHAPE_LINE && shape->numlines == 1 ) {
5517 hGeom = OGR_G_CreateGeometry( wkbLineString );
5518 for( i = 0; i < shape->line[0].numpoints; i++ ) {
5519 OGR_G_AddPoint_2D( hGeom,
5520 shape->line[0].point[i].x,
5521 shape->line[0].point[i].y );
5522 }
5523 } else if( shape->type == MS_SHAPE_LINE && shape->numlines > 1 ) {
5524 OGRGeometryH hMultiLine = OGR_G_CreateGeometry( wkbMultiLineString );
5525 int iLine;
5526
5527 for( iLine = 0; iLine < shape->numlines; iLine++ ) {
5528 hGeom = OGR_G_CreateGeometry( wkbLineString );
5529 for( i = 0; i < shape->line[iLine].numpoints; i++ ) {
5530 OGR_G_AddPoint_2D( hGeom,
5531 shape->line[iLine].point[i].x,
5532 shape->line[iLine].point[i].y );
5533 }
5534
5535 OGR_G_AddGeometryDirectly( hMultiLine, hGeom );
5536 }
5537
5538 hGeom = hMultiLine;
5539 } else if( shape->type == MS_SHAPE_POLYGON ) {
5540 int iLine;
5541
5542 /* actually, it is pretty hard to be sure rings 1+ are interior */
5543 hGeom = OGR_G_CreateGeometry( wkbPolygon );
5544 for( iLine = 0; iLine < shape->numlines; iLine++ ) {
5545 OGRGeometryH hRing;
5546 hRing = OGR_G_CreateGeometry( wkbLinearRing );
5547
5548 for( i = 0; i < shape->line[iLine].numpoints; i++ ) {
5549 OGR_G_AddPoint_2D( hRing,
5550 shape->line[iLine].point[i].x,
5551 shape->line[iLine].point[i].y );
5552 }
5553 OGR_G_AddGeometryDirectly( hGeom, hRing );
5554 }
5555 } else {
5556 msSetError(MS_OGRERR, "OGR support is not available.", "msOGRShapeToWKT()");
5557 }
5558
5559 if( hGeom != NULL ) {
5560 char *pszOGRWkt;
5561
5562 OGR_G_ExportToWkt( hGeom, &pszOGRWkt );
5563 wkt = msStrdup( pszOGRWkt );
5564 CPLFree( pszOGRWkt );
5565 }
5566
5567 return wkt;
5568 }
5569