Coverage Report

Created: 2026-07-25 06:50

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