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