Coverage Report

Created: 2025-08-28 06:57

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