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