/src/gdal/ogr/ogrsf_frmts/osm/ogrosmlayer.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: Implements OGROSMLayer class |
5 | | * Author: Even Rouault, <even dot rouault at spatialys.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2012-2014, Even Rouault <even dot rouault at spatialys.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "cpl_port.h" |
14 | | |
15 | | #include <cinttypes> |
16 | | #include <cstddef> |
17 | | #include <cstdio> |
18 | | #include <cstdlib> |
19 | | #include <cstring> |
20 | | #include <time.h> |
21 | | #include <map> |
22 | | #include <memory> |
23 | | #include <set> |
24 | | #include <string> |
25 | | #include <utility> |
26 | | #include <vector> |
27 | | |
28 | | #include "cpl_conv.h" |
29 | | #include "cpl_error.h" |
30 | | #include "cpl_progress.h" |
31 | | #include "cpl_string.h" |
32 | | #include "cpl_time.h" |
33 | | #include "cpl_vsi.h" |
34 | | #include "ogr_core.h" |
35 | | #include "ogr_feature.h" |
36 | | #include "ogr_geometry.h" |
37 | | #include "ogr_p.h" |
38 | | #include "ogr_spatialref.h" |
39 | | #include "ogrsf_frmts.h" |
40 | | #include "ogr_osm.h" |
41 | | #include "osm_parser.h" |
42 | | #include "sqlite3.h" |
43 | | |
44 | | #undef SQLITE_TRANSIENT |
45 | 0 | #define SQLITE_TRANSIENT reinterpret_cast<sqlite3_destructor_type>(-1) |
46 | | |
47 | | constexpr size_t SWITCH_THRESHOLD = 10000; |
48 | | constexpr size_t MAX_THRESHOLD = 100000; |
49 | | |
50 | | /************************************************************************/ |
51 | | /* OGROSMLayer() */ |
52 | | /************************************************************************/ |
53 | | |
54 | | OGROSMLayer::OGROSMLayer(OGROSMDataSource *poDSIn, int nIdxLayerIn, |
55 | | const char *pszName) |
56 | 4.38k | : m_poDS(poDSIn), m_nIdxLayer(nIdxLayerIn), |
57 | 4.38k | m_poFeatureDefn(new OGRFeatureDefn(pszName)), |
58 | 4.38k | m_poSRS(new OGRSpatialReference()) |
59 | 4.38k | { |
60 | 4.38k | SetDescription(m_poFeatureDefn->GetName()); |
61 | 4.38k | m_poFeatureDefn->Reference(); |
62 | | |
63 | 4.38k | m_poSRS->SetWellKnownGeogCS("WGS84"); |
64 | 4.38k | m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
65 | | |
66 | 4.38k | if (m_poFeatureDefn->GetGeomFieldCount() != 0) |
67 | 4.38k | m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poSRS); |
68 | 4.38k | } |
69 | | |
70 | | /************************************************************************/ |
71 | | /* ~OGROSMLayer() */ |
72 | | /************************************************************************/ |
73 | | |
74 | | OGROSMLayer::~OGROSMLayer() |
75 | 4.38k | { |
76 | 4.38k | m_poFeatureDefn->Release(); |
77 | | |
78 | 4.38k | if (m_poSRS) |
79 | 4.38k | m_poSRS->Release(); |
80 | | |
81 | 49.9k | for (int i = 0; i < static_cast<int>(m_apszNames.size()); i++) |
82 | 45.6k | CPLFree(m_apszNames[i]); |
83 | | |
84 | 9.64k | for (int i = 0; i < static_cast<int>(apszInsignificantKeys.size()); i++) |
85 | 5.26k | CPLFree(apszInsignificantKeys[i]); |
86 | | |
87 | 50.8k | for (int i = 0; i < static_cast<int>(apszIgnoreKeys.size()); i++) |
88 | 46.4k | CPLFree(apszIgnoreKeys[i]); |
89 | | |
90 | 5.26k | for (int i = 0; i < static_cast<int>(m_oComputedAttributes.size()); i++) |
91 | 877 | { |
92 | 877 | sqlite3_finalize(m_oComputedAttributes[i].hStmt); |
93 | 877 | } |
94 | 4.38k | } |
95 | | |
96 | | /************************************************************************/ |
97 | | /* ResetReading() */ |
98 | | /************************************************************************/ |
99 | | |
100 | | void OGROSMLayer::ResetReading() |
101 | 0 | { |
102 | 0 | if (!m_bResetReadingAllowed || m_poDS->IsInterleavedReading()) |
103 | 0 | return; |
104 | | |
105 | 0 | m_poDS->MyResetReading(); |
106 | 0 | } |
107 | | |
108 | | /************************************************************************/ |
109 | | /* ForceResetReading() */ |
110 | | /************************************************************************/ |
111 | | |
112 | | void OGROSMLayer::ForceResetReading() |
113 | 0 | { |
114 | 0 | m_apoFeatures.clear(); |
115 | 0 | m_nFeatureArrayIndex = 0; |
116 | 0 | m_bResetReadingAllowed = false; |
117 | 0 | } |
118 | | |
119 | | /************************************************************************/ |
120 | | /* SetAttributeFilter() */ |
121 | | /************************************************************************/ |
122 | | |
123 | | OGRErr OGROSMLayer::SetAttributeFilter(const char *pszAttrQuery) |
124 | 0 | { |
125 | 0 | if (pszAttrQuery == nullptr && m_pszAttrQueryString == nullptr) |
126 | 0 | return OGRERR_NONE; |
127 | 0 | if (pszAttrQuery != nullptr && m_pszAttrQueryString != nullptr && |
128 | 0 | strcmp(pszAttrQuery, m_pszAttrQueryString) == 0) |
129 | 0 | return OGRERR_NONE; |
130 | | |
131 | 0 | OGRErr eErr = OGRLayer::SetAttributeFilter(pszAttrQuery); |
132 | 0 | if (eErr != OGRERR_NONE) |
133 | 0 | return eErr; |
134 | | |
135 | 0 | if (m_nFeatureArrayIndex == 0) |
136 | 0 | { |
137 | 0 | if (!m_poDS->IsInterleavedReading()) |
138 | 0 | { |
139 | 0 | m_poDS->MyResetReading(); |
140 | 0 | } |
141 | 0 | } |
142 | 0 | else |
143 | 0 | { |
144 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
145 | 0 | "The new attribute filter will " |
146 | 0 | "not be taken into account immediately. It is advised to " |
147 | 0 | "set attribute filters for all needed layers, before " |
148 | 0 | "reading *any* layer"); |
149 | 0 | } |
150 | |
|
151 | 0 | return OGRERR_NONE; |
152 | 0 | } |
153 | | |
154 | | /************************************************************************/ |
155 | | /* GetFeatureCount() */ |
156 | | /************************************************************************/ |
157 | | |
158 | | GIntBig OGROSMLayer::GetFeatureCount(int bForce) |
159 | 0 | { |
160 | 0 | if (m_poDS->IsFeatureCountEnabled()) |
161 | 0 | return OGRLayer::GetFeatureCount(bForce); |
162 | | |
163 | 0 | return -1; |
164 | 0 | } |
165 | | |
166 | | /************************************************************************/ |
167 | | /* GetNextFeature() */ |
168 | | /************************************************************************/ |
169 | | |
170 | | OGRFeature *OGROSMLayer::GetNextFeature() |
171 | 3.17k | { |
172 | 3.17k | OGROSMLayer *poNewCurLayer = nullptr; |
173 | 3.17k | OGRFeature *poFeature = MyGetNextFeature(&poNewCurLayer, nullptr, nullptr); |
174 | 3.17k | m_poDS->SetCurrentLayer(poNewCurLayer); |
175 | 3.17k | return poFeature; |
176 | 3.17k | } |
177 | | |
178 | | OGRFeature *OGROSMLayer::MyGetNextFeature(OGROSMLayer **ppoNewCurLayer, |
179 | | GDALProgressFunc pfnProgress, |
180 | | void *pProgressData) |
181 | 3.17k | { |
182 | 3.17k | *ppoNewCurLayer = m_poDS->GetCurrentLayer(); |
183 | 3.17k | m_bResetReadingAllowed = true; |
184 | | |
185 | 3.17k | if (m_apoFeatures.empty()) |
186 | 2.87k | { |
187 | 2.87k | if (m_poDS->IsInterleavedReading()) |
188 | 0 | { |
189 | 0 | if (*ppoNewCurLayer == nullptr) |
190 | 0 | { |
191 | 0 | *ppoNewCurLayer = this; |
192 | 0 | } |
193 | 0 | else if (*ppoNewCurLayer != this) |
194 | 0 | { |
195 | 0 | return nullptr; |
196 | 0 | } |
197 | | |
198 | | // If too many features have been accumulated in another layer, we |
199 | | // force a switch to that layer, so that it gets emptied. |
200 | 0 | for (int i = 0; i < m_poDS->GetLayerCount(); i++) |
201 | 0 | { |
202 | 0 | if (m_poDS->m_apoLayers[i].get() != this && |
203 | 0 | m_poDS->m_apoLayers[i]->m_apoFeatures.size() > |
204 | 0 | SWITCH_THRESHOLD) |
205 | 0 | { |
206 | 0 | *ppoNewCurLayer = m_poDS->m_apoLayers[i].get(); |
207 | 0 | CPLDebug("OSM", |
208 | 0 | "Switching to '%s' as they are too many " |
209 | 0 | "features in '%s'", |
210 | 0 | m_poDS->m_apoLayers[i]->GetName(), GetName()); |
211 | 0 | return nullptr; |
212 | 0 | } |
213 | 0 | } |
214 | | |
215 | | // Read some more data and accumulate features. |
216 | 0 | m_poDS->ParseNextChunk(m_nIdxLayer, pfnProgress, pProgressData); |
217 | |
|
218 | 0 | if (m_apoFeatures.empty()) |
219 | 0 | { |
220 | | // If there are really no more features to read in the |
221 | | // current layer, force a switch to another non-empty layer. |
222 | |
|
223 | 0 | for (int i = 0; i < m_poDS->GetLayerCount(); i++) |
224 | 0 | { |
225 | 0 | if (m_poDS->m_apoLayers[i].get() != this && |
226 | 0 | !m_poDS->m_apoLayers[i]->m_apoFeatures.empty()) |
227 | 0 | { |
228 | 0 | *ppoNewCurLayer = m_poDS->m_apoLayers[i].get(); |
229 | 0 | CPLDebug("OSM", |
230 | 0 | "Switching to '%s' as they are " |
231 | 0 | "no more feature in '%s'", |
232 | 0 | m_poDS->m_apoLayers[i]->GetName(), GetName()); |
233 | 0 | return nullptr; |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | | /* Game over : no more data to read from the stream */ |
238 | 0 | *ppoNewCurLayer = nullptr; |
239 | 0 | return nullptr; |
240 | 0 | } |
241 | 0 | } |
242 | 2.87k | else |
243 | 2.87k | { |
244 | 2.87k | while (true) |
245 | 2.87k | { |
246 | 2.87k | int bRet = |
247 | 2.87k | m_poDS->ParseNextChunk(m_nIdxLayer, nullptr, nullptr); |
248 | | // cppcheck-suppress knownConditionTrueFalse |
249 | 2.87k | if (!m_apoFeatures.empty()) |
250 | 57 | break; |
251 | 2.81k | if (bRet == FALSE) |
252 | 2.81k | return nullptr; |
253 | 2.81k | } |
254 | 2.87k | } |
255 | 2.87k | } |
256 | | |
257 | 358 | auto poFeature = std::move(m_apoFeatures[m_nFeatureArrayIndex]); |
258 | 358 | m_nFeatureArrayIndex++; |
259 | | |
260 | 358 | if (m_nFeatureArrayIndex == m_apoFeatures.size()) |
261 | 95 | { |
262 | 95 | m_nFeatureArrayIndex = 0; |
263 | 95 | m_apoFeatures.clear(); |
264 | 95 | } |
265 | | |
266 | 358 | return poFeature.release(); |
267 | 3.17k | } |
268 | | |
269 | | /************************************************************************/ |
270 | | /* TestCapability() */ |
271 | | /************************************************************************/ |
272 | | |
273 | | int OGROSMLayer::TestCapability(const char *pszCap) const |
274 | 0 | { |
275 | 0 | if (EQUAL(pszCap, OLCFastGetExtent)) |
276 | 0 | { |
277 | 0 | OGREnvelope sExtent; |
278 | 0 | if (m_poDS->GetNativeExtent(&sExtent) == OGRERR_NONE) |
279 | 0 | return TRUE; |
280 | 0 | } |
281 | | |
282 | 0 | return FALSE; |
283 | 0 | } |
284 | | |
285 | | /************************************************************************/ |
286 | | /* AddToArray() */ |
287 | | /************************************************************************/ |
288 | | |
289 | | bool OGROSMLayer::AddToArray(std::unique_ptr<OGRFeature> poFeature, |
290 | | bool bCheckFeatureThreshold) |
291 | 358 | { |
292 | 358 | if (bCheckFeatureThreshold && m_apoFeatures.size() > MAX_THRESHOLD) |
293 | 0 | { |
294 | 0 | if (!m_bHasWarnedTooManyFeatures) |
295 | 0 | { |
296 | 0 | CPLError( |
297 | 0 | CE_Failure, CPLE_AppDefined, |
298 | 0 | "Too many features have accumulated in %s layer. " |
299 | 0 | "Use the OGR_INTERLEAVED_READING=YES configuration option, " |
300 | 0 | "or the INTERLEAVED_READING=YES open option, or the " |
301 | 0 | "GDALDataset::GetNextFeature() / GDALDatasetGetNextFeature() " |
302 | 0 | "API.", |
303 | 0 | GetName()); |
304 | 0 | } |
305 | 0 | m_bHasWarnedTooManyFeatures = true; |
306 | 0 | return false; |
307 | 0 | } |
308 | | |
309 | 358 | try |
310 | 358 | { |
311 | 358 | m_apoFeatures.push_back(std::move(poFeature)); |
312 | 358 | } |
313 | 358 | catch (const std::exception &) |
314 | 358 | { |
315 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, |
316 | 0 | "For layer %s, cannot resize feature array to %" PRIu64 |
317 | 0 | " features", |
318 | 0 | GetName(), static_cast<uint64_t>(m_apoFeatures.size()) + 1); |
319 | 0 | return false; |
320 | 0 | } |
321 | | |
322 | 358 | return true; |
323 | 358 | } |
324 | | |
325 | | /************************************************************************/ |
326 | | /* EvaluateAttributeFilter() */ |
327 | | /************************************************************************/ |
328 | | |
329 | | int OGROSMLayer::EvaluateAttributeFilter(OGRFeature *poFeature) |
330 | 0 | { |
331 | 0 | return (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)); |
332 | 0 | } |
333 | | |
334 | | /************************************************************************/ |
335 | | /* AddFeature() */ |
336 | | /************************************************************************/ |
337 | | |
338 | | bool OGROSMLayer::AddFeature(std::unique_ptr<OGRFeature> poFeature, |
339 | | bool bAttrFilterAlreadyEvaluated, |
340 | | bool *pbFilteredOut, bool bCheckFeatureThreshold) |
341 | 358 | { |
342 | 358 | if (!m_bUserInterested) |
343 | 0 | { |
344 | 0 | if (pbFilteredOut) |
345 | 0 | *pbFilteredOut = true; |
346 | 0 | return true; |
347 | 0 | } |
348 | | |
349 | 358 | OGRGeometry *poGeom = poFeature->GetGeometryRef(); |
350 | 358 | if (poGeom) |
351 | 358 | poGeom->assignSpatialReference(m_poSRS); |
352 | | |
353 | 358 | if ((m_poFilterGeom == nullptr || FilterGeometry(poGeom)) && |
354 | 358 | (m_poAttrQuery == nullptr || bAttrFilterAlreadyEvaluated || |
355 | 0 | m_poAttrQuery->Evaluate(poFeature.get()))) |
356 | 358 | { |
357 | 358 | if (!AddToArray(std::move(poFeature), bCheckFeatureThreshold)) |
358 | 0 | { |
359 | 0 | return false; |
360 | 0 | } |
361 | 358 | } |
362 | 0 | else |
363 | 0 | { |
364 | 0 | if (pbFilteredOut) |
365 | 0 | *pbFilteredOut = true; |
366 | 0 | return true; |
367 | 0 | } |
368 | | |
369 | 358 | if (pbFilteredOut) |
370 | 358 | *pbFilteredOut = false; |
371 | 358 | return true; |
372 | 358 | } |
373 | | |
374 | | /************************************************************************/ |
375 | | /* IGetExtent() */ |
376 | | /************************************************************************/ |
377 | | |
378 | | OGRErr OGROSMLayer::IGetExtent(int /* iGeomField */, OGREnvelope *psExtent, |
379 | | bool /* bForce */) |
380 | 0 | { |
381 | 0 | if (m_poDS->GetNativeExtent(psExtent) == OGRERR_NONE) |
382 | 0 | return OGRERR_NONE; |
383 | | |
384 | 0 | return OGRERR_FAILURE; |
385 | 0 | } |
386 | | |
387 | | /************************************************************************/ |
388 | | /* GetLaunderedFieldName() */ |
389 | | /************************************************************************/ |
390 | | |
391 | | const char *OGROSMLayer::GetLaunderedFieldName(const char *pszName) |
392 | 45.6k | { |
393 | 45.6k | if (m_poDS->DoesAttributeNameLaundering() && |
394 | 45.6k | strchr(pszName, ':') != nullptr) |
395 | 0 | { |
396 | 0 | size_t i = 0; |
397 | 0 | for (; i < sizeof(szLaunderedFieldName) - 1 && pszName[i] != '\0'; i++) |
398 | 0 | { |
399 | 0 | if (pszName[i] == ':') |
400 | 0 | szLaunderedFieldName[i] = '_'; |
401 | 0 | else |
402 | 0 | szLaunderedFieldName[i] = pszName[i]; |
403 | 0 | } |
404 | 0 | szLaunderedFieldName[i] = '\0'; |
405 | 0 | return szLaunderedFieldName; |
406 | 0 | } |
407 | | |
408 | 45.6k | return pszName; |
409 | 45.6k | } |
410 | | |
411 | | /************************************************************************/ |
412 | | /* AddField() */ |
413 | | /************************************************************************/ |
414 | | |
415 | | void OGROSMLayer::AddField(const char *pszName, OGRFieldType eFieldType, |
416 | | OGRFieldSubType eSubType) |
417 | 45.6k | { |
418 | 45.6k | const char *pszLaunderedName = GetLaunderedFieldName(pszName); |
419 | 45.6k | OGRFieldDefn oField(pszLaunderedName, eFieldType); |
420 | 45.6k | oField.SetSubType(eSubType); |
421 | 45.6k | m_poFeatureDefn->AddFieldDefn(&oField); |
422 | | |
423 | 45.6k | int nIndex = m_poFeatureDefn->GetFieldCount() - 1; |
424 | 45.6k | char *pszDupName = CPLStrdup(pszName); |
425 | 45.6k | m_apszNames.push_back(pszDupName); |
426 | 45.6k | m_oMapFieldNameToIndex[pszDupName] = nIndex; |
427 | | |
428 | 45.6k | if (strcmp(pszName, "osm_id") == 0) |
429 | 4.38k | m_nIndexOSMId = nIndex; |
430 | | |
431 | 41.2k | else if (strcmp(pszName, "osm_way_id") == 0) |
432 | 877 | m_nIndexOSMWayId = nIndex; |
433 | | |
434 | 40.3k | else if (strcmp(pszName, "other_tags") == 0) |
435 | 4.38k | m_nIndexOtherTags = nIndex; |
436 | | |
437 | 35.9k | else if (strcmp(pszName, "all_tags") == 0) |
438 | 0 | m_nIndexAllTags = nIndex; |
439 | 45.6k | } |
440 | | |
441 | | /************************************************************************/ |
442 | | /* GetFieldIndex() */ |
443 | | /************************************************************************/ |
444 | | |
445 | | int OGROSMLayer::GetFieldIndex(const char *pszName) |
446 | 31.9k | { |
447 | 31.9k | const auto oIter = m_oMapFieldNameToIndex.find(pszName); |
448 | 31.9k | if (oIter != m_oMapFieldNameToIndex.end()) |
449 | 468 | return oIter->second; |
450 | | |
451 | 31.5k | return -1; |
452 | 31.9k | } |
453 | | |
454 | | /************************************************************************/ |
455 | | /* AddInOtherOrAllTags() */ |
456 | | /************************************************************************/ |
457 | | |
458 | | int OGROSMLayer::AddInOtherOrAllTags(const char *pszK) |
459 | 31.5k | { |
460 | 31.5k | bool bAddToOtherTags = false; |
461 | | |
462 | 31.5k | if (aoSetIgnoreKeys.find(pszK) == aoSetIgnoreKeys.end()) |
463 | 31.4k | { |
464 | 31.4k | char *pszColon = strchr(const_cast<char *>(pszK), ':'); |
465 | 31.4k | if (pszColon) |
466 | 0 | { |
467 | 0 | char chBackup = pszColon[1]; |
468 | 0 | pszColon[1] = '\0'; /* Evil but OK */ |
469 | 0 | bAddToOtherTags = |
470 | 0 | (aoSetIgnoreKeys.find(pszK) == aoSetIgnoreKeys.end()); |
471 | | // cppcheck-suppress redundantAssignment |
472 | 0 | pszColon[1] = chBackup; |
473 | 0 | } |
474 | 31.4k | else |
475 | 31.4k | bAddToOtherTags = true; |
476 | 31.4k | } |
477 | | |
478 | 31.5k | return bAddToOtherTags; |
479 | 31.5k | } |
480 | | |
481 | | /************************************************************************/ |
482 | | /* OGROSMEscapeStringHSTORE() */ |
483 | | /************************************************************************/ |
484 | | |
485 | | static void OGROSMEscapeStringHSTORE(const char *pszV, std::string &sOut) |
486 | 62.8k | { |
487 | 62.8k | sOut += '"'; |
488 | | |
489 | 559k | for (int k = 0; pszV[k] != '\0'; k++) |
490 | 496k | { |
491 | 496k | if (pszV[k] == '"' || pszV[k] == '\\') |
492 | 1 | sOut += '\\'; |
493 | 496k | sOut += pszV[k]; |
494 | 496k | } |
495 | | |
496 | 62.8k | sOut += '"'; |
497 | 62.8k | } |
498 | | |
499 | | /************************************************************************/ |
500 | | /* OGROSMEscapeStringJSON() */ |
501 | | /************************************************************************/ |
502 | | |
503 | | static void OGROSMEscapeStringJSON(const char *pszV, std::string &sOut) |
504 | 0 | { |
505 | 0 | sOut += '"'; |
506 | |
|
507 | 0 | for (int k = 0; pszV[k] != '\0'; k++) |
508 | 0 | { |
509 | 0 | const char ch = pszV[k]; |
510 | 0 | switch (ch) |
511 | 0 | { |
512 | 0 | case '"': |
513 | 0 | sOut += "\\\""; |
514 | 0 | break; |
515 | 0 | case '\\': |
516 | 0 | sOut += "\\\\"; |
517 | 0 | break; |
518 | 0 | case '\n': |
519 | 0 | sOut += "\\n"; |
520 | 0 | break; |
521 | 0 | case '\r': |
522 | 0 | sOut += "\\r"; |
523 | 0 | break; |
524 | 0 | case '\t': |
525 | 0 | sOut += "\\t"; |
526 | 0 | break; |
527 | 0 | default: |
528 | 0 | if (static_cast<unsigned char>(ch) < ' ') |
529 | 0 | sOut += CPLSPrintf("\\u%04X", ch); |
530 | 0 | else |
531 | 0 | sOut += ch; |
532 | 0 | break; |
533 | 0 | } |
534 | 0 | } |
535 | | |
536 | 0 | sOut += '"'; |
537 | 0 | } |
538 | | |
539 | | /************************************************************************/ |
540 | | /* GetValueOfTag() */ |
541 | | /************************************************************************/ |
542 | | |
543 | | static const char *GetValueOfTag(const char *pszKeyToSearch, unsigned int nTags, |
544 | | const OSMTag *pasTags) |
545 | 936 | { |
546 | 96.1k | for (unsigned int k = 0; k < nTags; k++) |
547 | 95.1k | { |
548 | 95.1k | const char *pszK = pasTags[k].pszK; |
549 | 95.1k | if (strcmp(pszK, pszKeyToSearch) == 0) |
550 | 2 | { |
551 | 2 | return pasTags[k].pszV; |
552 | 2 | } |
553 | 95.1k | } |
554 | 934 | return nullptr; |
555 | 936 | } |
556 | | |
557 | | /************************************************************************/ |
558 | | /* SetFieldsFromTags() */ |
559 | | /************************************************************************/ |
560 | | |
561 | | void OGROSMLayer::SetFieldsFromTags(OGRFeature *poFeature, GIntBig nID, |
562 | | bool bIsWayID, unsigned int nTags, |
563 | | const OSMTag *pasTags, |
564 | | const OSMInfo *psInfo) |
565 | 470 | { |
566 | 470 | if (!bIsWayID) |
567 | 407 | { |
568 | 407 | poFeature->SetFID(nID); |
569 | | |
570 | 407 | if (m_bHasOSMId) |
571 | 407 | { |
572 | 407 | char szID[32]; |
573 | 407 | snprintf(szID, sizeof(szID), CPL_FRMT_GIB, nID); |
574 | 407 | poFeature->SetField(m_nIndexOSMId, szID); |
575 | 407 | } |
576 | 407 | } |
577 | 63 | else |
578 | 63 | { |
579 | 63 | poFeature->SetFID(nID); |
580 | | |
581 | 63 | if (m_nIndexOSMWayId >= 0) |
582 | 63 | { |
583 | 63 | char szID[32]; |
584 | 63 | snprintf(szID, sizeof(szID), CPL_FRMT_GIB, nID); |
585 | 63 | poFeature->SetField(m_nIndexOSMWayId, szID); |
586 | 63 | } |
587 | 63 | } |
588 | | |
589 | 470 | if (m_bHasVersion) |
590 | 0 | { |
591 | 0 | poFeature->SetField("osm_version", psInfo->nVersion); |
592 | 0 | } |
593 | 470 | if (m_bHasTimestamp) |
594 | 0 | { |
595 | 0 | if (psInfo->bTimeStampIsStr) |
596 | 0 | { |
597 | 0 | OGRField sField; |
598 | 0 | if (OGRParseXMLDateTime(psInfo->ts.pszTimeStamp, &sField)) |
599 | 0 | { |
600 | 0 | poFeature->SetField("osm_timestamp", &sField); |
601 | 0 | } |
602 | 0 | } |
603 | 0 | else |
604 | 0 | { |
605 | 0 | struct tm brokendown; |
606 | 0 | CPLUnixTimeToYMDHMS(psInfo->ts.nTimeStamp, &brokendown); |
607 | 0 | poFeature->SetField("osm_timestamp", brokendown.tm_year + 1900, |
608 | 0 | brokendown.tm_mon + 1, brokendown.tm_mday, |
609 | 0 | brokendown.tm_hour, brokendown.tm_min, |
610 | 0 | static_cast<float>(brokendown.tm_sec), 0); |
611 | 0 | } |
612 | 0 | } |
613 | 470 | if (m_bHasUID) |
614 | 0 | { |
615 | 0 | poFeature->SetField("osm_uid", psInfo->nUID); |
616 | 0 | } |
617 | 470 | if (m_bHasUser) |
618 | 0 | { |
619 | 0 | poFeature->SetField("osm_user", psInfo->pszUserSID); |
620 | 0 | } |
621 | 470 | if (m_bHasChangeset) |
622 | 0 | { |
623 | 0 | poFeature->SetField("osm_changeset", psInfo->nChangeset); |
624 | 0 | } |
625 | | |
626 | 470 | m_osAllTagsBuffer.clear(); |
627 | 32.4k | for (unsigned int j = 0; j < nTags; j++) |
628 | 31.9k | { |
629 | 31.9k | const char *pszK = pasTags[j].pszK; |
630 | 31.9k | const char *pszV = pasTags[j].pszV; |
631 | 31.9k | int nIndex = GetFieldIndex(pszK); |
632 | 31.9k | if (nIndex >= 0 && nIndex != m_nIndexOSMId) |
633 | 468 | { |
634 | 468 | poFeature->SetField(nIndex, pszV); |
635 | 468 | if (m_nIndexAllTags < 0) |
636 | 468 | continue; |
637 | 468 | } |
638 | 31.5k | if (m_nIndexAllTags >= 0 || m_nIndexOtherTags >= 0) |
639 | 31.5k | { |
640 | 31.5k | if (AddInOtherOrAllTags(pszK)) |
641 | 31.4k | { |
642 | 31.4k | if (m_poDS->m_bTagsAsHSTORE) |
643 | 31.4k | { |
644 | 31.4k | if (!m_osAllTagsBuffer.empty()) |
645 | 31.2k | m_osAllTagsBuffer += ','; |
646 | | |
647 | 31.4k | OGROSMEscapeStringHSTORE(pszK, m_osAllTagsBuffer); |
648 | | |
649 | 31.4k | m_osAllTagsBuffer += '='; |
650 | 31.4k | m_osAllTagsBuffer += '>'; |
651 | | |
652 | 31.4k | OGROSMEscapeStringHSTORE(pszV, m_osAllTagsBuffer); |
653 | 31.4k | } |
654 | 0 | else |
655 | 0 | { |
656 | 0 | if (!m_osAllTagsBuffer.empty()) |
657 | 0 | m_osAllTagsBuffer += ','; |
658 | 0 | else |
659 | 0 | m_osAllTagsBuffer = '{'; |
660 | 0 | OGROSMEscapeStringJSON(pszK, m_osAllTagsBuffer); |
661 | 0 | m_osAllTagsBuffer += ':'; |
662 | 0 | OGROSMEscapeStringJSON(pszV, m_osAllTagsBuffer); |
663 | 0 | } |
664 | 31.4k | } |
665 | | |
666 | | #ifdef notdef |
667 | | if (aoSetWarnKeys.find(pszK) == aoSetWarnKeys.end()) |
668 | | { |
669 | | aoSetWarnKeys.insert(pszK); |
670 | | CPLDebug("OSM_KEY", "Ignored key : %s", pszK); |
671 | | } |
672 | | #endif |
673 | 31.5k | } |
674 | 31.5k | } |
675 | | |
676 | 470 | if (!m_osAllTagsBuffer.empty()) |
677 | 170 | { |
678 | 170 | if (!m_poDS->m_bTagsAsHSTORE) |
679 | 0 | { |
680 | 0 | m_osAllTagsBuffer += '}'; |
681 | 0 | } |
682 | 170 | if (m_nIndexAllTags >= 0) |
683 | 0 | poFeature->SetField(m_nIndexAllTags, m_osAllTagsBuffer.c_str()); |
684 | 170 | else |
685 | 170 | poFeature->SetField(m_nIndexOtherTags, m_osAllTagsBuffer.c_str()); |
686 | 170 | } |
687 | | |
688 | 782 | for (size_t i = 0; i < m_oComputedAttributes.size(); i++) |
689 | 312 | { |
690 | 312 | const OGROSMComputedAttribute &oAttr = m_oComputedAttributes[i]; |
691 | 312 | if (oAttr.bHardcodedZOrder) |
692 | 312 | { |
693 | 312 | const int nHighwayIdx = oAttr.anIndexToBind[0]; |
694 | 312 | const int nBridgeIdx = oAttr.anIndexToBind[1]; |
695 | 312 | const int nTunnelIdx = oAttr.anIndexToBind[2]; |
696 | 312 | const int nRailwayIdx = oAttr.anIndexToBind[3]; |
697 | 312 | const int nLayerIdx = oAttr.anIndexToBind[4]; |
698 | | |
699 | 312 | int nZOrder = 0; |
700 | | /* |
701 | | "SELECT (CASE [highway] WHEN 'minor' THEN 3 WHEN 'road' THEN 3 " |
702 | | "WHEN 'unclassified' THEN 3 WHEN 'residential' THEN 3 WHEN " |
703 | | "'tertiary_link' THEN 4 WHEN 'tertiary' THEN 4 WHEN |
704 | | 'secondary_link' " "THEN 6 WHEN 'secondary' THEN 6 WHEN |
705 | | 'primary_link' THEN 7 WHEN " |
706 | | "'primary' THEN 7 WHEN 'trunk_link' THEN 8 WHEN 'trunk' THEN 8 " |
707 | | "WHEN 'motorway_link' THEN 9 WHEN 'motorway' THEN 9 ELSE 0 END) |
708 | | + " |
709 | | "(CASE WHEN [bridge] IN ('yes', 'true', '1') THEN 10 ELSE 0 END) |
710 | | + " |
711 | | "(CASE WHEN [tunnel] IN ('yes', 'true', '1') THEN -10 ELSE 0 |
712 | | END) + " |
713 | | "(CASE WHEN [railway] IS NOT NULL THEN 5 ELSE 0 END) + " |
714 | | "(CASE WHEN [layer] IS NOT NULL THEN 10 * CAST([layer] AS |
715 | | INTEGER) " */ |
716 | | |
717 | 312 | const char *pszHighway = nullptr; |
718 | 312 | if (nHighwayIdx >= 0) |
719 | 312 | { |
720 | 312 | if (poFeature->IsFieldSetAndNotNull(nHighwayIdx)) |
721 | 209 | { |
722 | 209 | pszHighway = poFeature->GetFieldAsString(nHighwayIdx); |
723 | 209 | } |
724 | 312 | } |
725 | 0 | else |
726 | 0 | pszHighway = GetValueOfTag("highway", nTags, pasTags); |
727 | 312 | if (pszHighway) |
728 | 209 | { |
729 | 209 | if (strcmp(pszHighway, "minor") == 0 || |
730 | 209 | strcmp(pszHighway, "road") == 0 || |
731 | 205 | strcmp(pszHighway, "unclassified") == 0 || |
732 | 179 | strcmp(pszHighway, "residential") == 0) |
733 | 114 | { |
734 | 114 | nZOrder += 3; |
735 | 114 | } |
736 | 95 | else if (strcmp(pszHighway, "tertiary_link") == 0 || |
737 | 95 | strcmp(pszHighway, "tertiary") == 0) |
738 | 9 | { |
739 | 9 | nZOrder += 4; |
740 | 9 | } |
741 | 86 | else if (strcmp(pszHighway, "secondary_link") == 0 || |
742 | 86 | strcmp(pszHighway, "secondary") == 0) |
743 | 1 | { |
744 | 1 | nZOrder += 6; |
745 | 1 | } |
746 | 85 | else if (strcmp(pszHighway, "primary_link") == 0 || |
747 | 85 | strcmp(pszHighway, "primary") == 0) |
748 | 2 | { |
749 | 2 | nZOrder += 7; |
750 | 2 | } |
751 | 83 | else if (strcmp(pszHighway, "trunk_link") == 0 || |
752 | 83 | strcmp(pszHighway, "trunk") == 0) |
753 | 0 | { |
754 | 0 | nZOrder += 8; |
755 | 0 | } |
756 | 83 | else if (strcmp(pszHighway, "motorway_link") == 0 || |
757 | 83 | strcmp(pszHighway, "motorway") == 0) |
758 | 38 | { |
759 | 38 | nZOrder += 9; |
760 | 38 | } |
761 | 209 | } |
762 | | |
763 | 312 | const char *pszBridge = nullptr; |
764 | 312 | if (nBridgeIdx >= 0) |
765 | 0 | { |
766 | 0 | if (poFeature->IsFieldSetAndNotNull(nBridgeIdx)) |
767 | 0 | { |
768 | 0 | pszBridge = poFeature->GetFieldAsString(nBridgeIdx); |
769 | 0 | } |
770 | 0 | } |
771 | 312 | else |
772 | 312 | pszBridge = GetValueOfTag("bridge", nTags, pasTags); |
773 | 312 | if (pszBridge) |
774 | 0 | { |
775 | 0 | if (strcmp(pszBridge, "yes") == 0 || |
776 | 0 | strcmp(pszBridge, "true") == 0 || |
777 | 0 | strcmp(pszBridge, "1") == 0) |
778 | 0 | { |
779 | 0 | nZOrder += 10; |
780 | 0 | } |
781 | 0 | } |
782 | | |
783 | 312 | const char *pszTunnel = nullptr; |
784 | 312 | if (nTunnelIdx >= 0) |
785 | 0 | { |
786 | 0 | if (poFeature->IsFieldSetAndNotNull(nTunnelIdx)) |
787 | 0 | { |
788 | 0 | pszTunnel = poFeature->GetFieldAsString(nTunnelIdx); |
789 | 0 | } |
790 | 0 | } |
791 | 312 | else |
792 | 312 | pszTunnel = GetValueOfTag("tunnel", nTags, pasTags); |
793 | 312 | if (pszTunnel) |
794 | 0 | { |
795 | 0 | if (strcmp(pszTunnel, "yes") == 0 || |
796 | 0 | strcmp(pszTunnel, "true") == 0 || |
797 | 0 | strcmp(pszTunnel, "1") == 0) |
798 | 0 | { |
799 | 0 | nZOrder -= 10; |
800 | 0 | } |
801 | 0 | } |
802 | | |
803 | 312 | const char *pszRailway = nullptr; |
804 | 312 | if (nRailwayIdx >= 0) |
805 | 312 | { |
806 | 312 | if (poFeature->IsFieldSetAndNotNull(nRailwayIdx)) |
807 | 2 | { |
808 | 2 | pszRailway = poFeature->GetFieldAsString(nRailwayIdx); |
809 | 2 | } |
810 | 312 | } |
811 | 0 | else |
812 | 0 | pszRailway = GetValueOfTag("railway", nTags, pasTags); |
813 | 312 | if (pszRailway) |
814 | 2 | { |
815 | 2 | nZOrder += 5; |
816 | 2 | } |
817 | | |
818 | 312 | const char *pszLayer = nullptr; |
819 | 312 | if (nLayerIdx >= 0) |
820 | 0 | { |
821 | 0 | if (poFeature->IsFieldSetAndNotNull(nLayerIdx)) |
822 | 0 | { |
823 | 0 | pszLayer = poFeature->GetFieldAsString(nLayerIdx); |
824 | 0 | } |
825 | 0 | } |
826 | 312 | else |
827 | 312 | pszLayer = GetValueOfTag("layer", nTags, pasTags); |
828 | 312 | if (pszLayer) |
829 | 2 | { |
830 | 2 | nZOrder += 10 * atoi(pszLayer); |
831 | 2 | } |
832 | | |
833 | 312 | poFeature->SetField(oAttr.nIndex, nZOrder); |
834 | | |
835 | 312 | continue; |
836 | 312 | } |
837 | | |
838 | 0 | for (int j = 0; j < static_cast<int>(oAttr.anIndexToBind.size()); j++) |
839 | 0 | { |
840 | 0 | if (oAttr.anIndexToBind[j] >= 0) |
841 | 0 | { |
842 | 0 | if (!poFeature->IsFieldSetAndNotNull(oAttr.anIndexToBind[j])) |
843 | 0 | { |
844 | 0 | sqlite3_bind_null(oAttr.hStmt, j + 1); |
845 | 0 | } |
846 | 0 | else |
847 | 0 | { |
848 | 0 | OGRFieldType eType = |
849 | 0 | m_poFeatureDefn->GetFieldDefn(oAttr.anIndexToBind[j]) |
850 | 0 | ->GetType(); |
851 | 0 | if (eType == OFTInteger) |
852 | 0 | sqlite3_bind_int(oAttr.hStmt, j + 1, |
853 | 0 | poFeature->GetFieldAsInteger( |
854 | 0 | oAttr.anIndexToBind[j])); |
855 | 0 | else if (eType == OFTInteger64) |
856 | 0 | sqlite3_bind_int64(oAttr.hStmt, j + 1, |
857 | 0 | poFeature->GetFieldAsInteger64( |
858 | 0 | oAttr.anIndexToBind[j])); |
859 | 0 | else if (eType == OFTReal) |
860 | 0 | sqlite3_bind_double(oAttr.hStmt, j + 1, |
861 | 0 | poFeature->GetFieldAsDouble( |
862 | 0 | oAttr.anIndexToBind[j])); |
863 | 0 | else |
864 | 0 | sqlite3_bind_text( |
865 | 0 | oAttr.hStmt, j + 1, |
866 | 0 | poFeature->GetFieldAsString(oAttr.anIndexToBind[j]), |
867 | 0 | -1, SQLITE_TRANSIENT); |
868 | 0 | } |
869 | 0 | } |
870 | 0 | else |
871 | 0 | { |
872 | 0 | bool bTagFound = false; |
873 | 0 | for (unsigned int k = 0; k < nTags; k++) |
874 | 0 | { |
875 | 0 | const char *pszK = pasTags[k].pszK; |
876 | 0 | const char *pszV = pasTags[k].pszV; |
877 | 0 | if (strcmp(pszK, oAttr.aosAttrToBind[j]) == 0) |
878 | 0 | { |
879 | 0 | sqlite3_bind_text(oAttr.hStmt, j + 1, pszV, -1, |
880 | 0 | SQLITE_TRANSIENT); |
881 | 0 | bTagFound = true; |
882 | 0 | break; |
883 | 0 | } |
884 | 0 | } |
885 | 0 | if (!bTagFound) |
886 | 0 | sqlite3_bind_null(oAttr.hStmt, j + 1); |
887 | 0 | } |
888 | 0 | } |
889 | |
|
890 | 0 | if (sqlite3_step(oAttr.hStmt) == SQLITE_ROW && |
891 | 0 | sqlite3_column_count(oAttr.hStmt) == 1) |
892 | 0 | { |
893 | 0 | switch (sqlite3_column_type(oAttr.hStmt, 0)) |
894 | 0 | { |
895 | 0 | case SQLITE_INTEGER: |
896 | 0 | poFeature->SetField( |
897 | 0 | oAttr.nIndex, static_cast<GIntBig>(sqlite3_column_int64( |
898 | 0 | oAttr.hStmt, 0))); |
899 | 0 | break; |
900 | 0 | case SQLITE_FLOAT: |
901 | 0 | poFeature->SetField(oAttr.nIndex, |
902 | 0 | sqlite3_column_double(oAttr.hStmt, 0)); |
903 | 0 | break; |
904 | 0 | case SQLITE_TEXT: |
905 | 0 | poFeature->SetField( |
906 | 0 | oAttr.nIndex, reinterpret_cast<const char *>( |
907 | 0 | sqlite3_column_text(oAttr.hStmt, 0))); |
908 | 0 | break; |
909 | 0 | default: |
910 | 0 | break; |
911 | 0 | } |
912 | 0 | } |
913 | | |
914 | 0 | sqlite3_reset(oAttr.hStmt); |
915 | 0 | } |
916 | 470 | } |
917 | | |
918 | | /************************************************************************/ |
919 | | /* GetSpatialFilterEnvelope() */ |
920 | | /************************************************************************/ |
921 | | |
922 | | const OGREnvelope *OGROSMLayer::GetSpatialFilterEnvelope() |
923 | 323 | { |
924 | 323 | if (m_poFilterGeom != nullptr) |
925 | 0 | return &m_sFilterEnvelope; |
926 | 323 | else |
927 | 323 | return nullptr; |
928 | 323 | } |
929 | | |
930 | | /************************************************************************/ |
931 | | /* AddInsignificantKey() */ |
932 | | /************************************************************************/ |
933 | | |
934 | | void OGROSMLayer::AddInsignificantKey(const char *pszK) |
935 | 5.26k | { |
936 | 5.26k | char *pszKDup = CPLStrdup(pszK); |
937 | 5.26k | apszInsignificantKeys.push_back(pszKDup); |
938 | 5.26k | aoSetInsignificantKeys[pszKDup] = 1; |
939 | 5.26k | } |
940 | | |
941 | | /************************************************************************/ |
942 | | /* AddIgnoreKey() */ |
943 | | /************************************************************************/ |
944 | | |
945 | | void OGROSMLayer::AddIgnoreKey(const char *pszK) |
946 | 46.4k | { |
947 | 46.4k | char *pszKDup = CPLStrdup(pszK); |
948 | 46.4k | apszIgnoreKeys.push_back(pszKDup); |
949 | 46.4k | aoSetIgnoreKeys[pszKDup] = 1; |
950 | 46.4k | } |
951 | | |
952 | | /************************************************************************/ |
953 | | /* AddWarnKey() */ |
954 | | /************************************************************************/ |
955 | | |
956 | | void OGROSMLayer::AddWarnKey(const char *pszK) |
957 | 46.4k | { |
958 | 46.4k | aoSetWarnKeys.insert(pszK); |
959 | 46.4k | } |
960 | | |
961 | | /************************************************************************/ |
962 | | /* AddWarnKey() */ |
963 | | /************************************************************************/ |
964 | | |
965 | | void OGROSMLayer::AddComputedAttribute(const char *pszName, OGRFieldType eType, |
966 | | const char *pszSQL) |
967 | 877 | { |
968 | 877 | if (m_poDS->m_hDBForComputedAttributes == nullptr) |
969 | 877 | { |
970 | 877 | const int rc = sqlite3_open_v2( |
971 | 877 | ":memory:", &(m_poDS->m_hDBForComputedAttributes), |
972 | 877 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX, |
973 | 877 | nullptr); |
974 | 877 | if (rc != SQLITE_OK) |
975 | 0 | { |
976 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
977 | 0 | "Cannot open temporary sqlite DB"); |
978 | 0 | return; |
979 | 0 | } |
980 | 877 | } |
981 | | |
982 | 877 | if (m_poFeatureDefn->GetFieldIndex(pszName) >= 0) |
983 | 0 | { |
984 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
985 | 0 | "A field with same name %s already exists", pszName); |
986 | 0 | return; |
987 | 0 | } |
988 | | |
989 | 877 | CPLString osSQL(pszSQL); |
990 | 877 | const bool bHardcodedZOrder = |
991 | 877 | (eType == OFTInteger) && |
992 | 877 | strcmp( |
993 | 877 | pszSQL, |
994 | 877 | "SELECT (CASE [highway] WHEN 'minor' THEN 3 WHEN 'road' THEN 3 " |
995 | 877 | "WHEN 'unclassified' THEN 3 WHEN 'residential' THEN 3 WHEN " |
996 | 877 | "'tertiary_link' THEN 4 WHEN 'tertiary' THEN 4 WHEN " |
997 | 877 | "'secondary_link' " |
998 | 877 | "THEN 6 WHEN 'secondary' THEN 6 WHEN 'primary_link' THEN 7 WHEN " |
999 | 877 | "'primary' THEN 7 WHEN 'trunk_link' THEN 8 WHEN 'trunk' THEN 8 " |
1000 | 877 | "WHEN 'motorway_link' THEN 9 WHEN 'motorway' THEN 9 ELSE 0 END) + " |
1001 | 877 | "(CASE WHEN [bridge] IN ('yes', 'true', '1') THEN 10 ELSE 0 END) + " |
1002 | 877 | "(CASE WHEN [tunnel] IN ('yes', 'true', '1') THEN -10 ELSE 0 END) " |
1003 | 877 | "+ " |
1004 | 877 | "(CASE WHEN [railway] IS NOT NULL THEN 5 ELSE 0 END) + " |
1005 | 877 | "(CASE WHEN [layer] IS NOT NULL THEN 10 * CAST([layer] AS INTEGER) " |
1006 | 877 | "ELSE 0 END)") == 0; |
1007 | 877 | std::vector<CPLString> aosAttrToBind; |
1008 | 877 | std::vector<int> anIndexToBind; |
1009 | 877 | size_t nStartSearch = 0; |
1010 | 6.13k | while (true) |
1011 | 6.13k | { |
1012 | 6.13k | size_t nPos = osSQL.find("[", nStartSearch); |
1013 | 6.13k | if (nPos == std::string::npos) |
1014 | 877 | break; |
1015 | 5.26k | nStartSearch = nPos + 1; |
1016 | 5.26k | if (nPos > 0 && osSQL[nPos - 1] != '\\') |
1017 | 5.26k | { |
1018 | 5.26k | CPLString osAttr = osSQL.substr(nPos + 1); |
1019 | 5.26k | size_t nPos2 = osAttr.find("]"); |
1020 | 5.26k | if (nPos2 == std::string::npos) |
1021 | 0 | break; |
1022 | 5.26k | osAttr.resize(nPos2); |
1023 | | |
1024 | 5.26k | osSQL = osSQL.substr(0, nPos) + "?" + |
1025 | 5.26k | osSQL.substr(nPos + 1 + nPos2 + 1); |
1026 | | |
1027 | 5.26k | aosAttrToBind.push_back(osAttr); |
1028 | 5.26k | anIndexToBind.push_back(m_poFeatureDefn->GetFieldIndex(osAttr)); |
1029 | 5.26k | } |
1030 | 5.26k | } |
1031 | 877 | while (true) |
1032 | 877 | { |
1033 | 877 | size_t nPos = osSQL.find("\\"); |
1034 | 877 | if (nPos == std::string::npos || nPos == osSQL.size() - 1) |
1035 | 877 | break; |
1036 | 0 | osSQL = osSQL.substr(0, nPos) + osSQL.substr(nPos + 1); |
1037 | 0 | } |
1038 | | |
1039 | 877 | CPLDebug("OSM", "SQL : \"%s\"", osSQL.c_str()); |
1040 | | |
1041 | 877 | sqlite3_stmt *hStmt = nullptr; |
1042 | 877 | int rc = sqlite3_prepare_v2(m_poDS->m_hDBForComputedAttributes, osSQL, -1, |
1043 | 877 | &hStmt, nullptr); |
1044 | 877 | if (rc != SQLITE_OK) |
1045 | 0 | { |
1046 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1047 | 0 | "sqlite3_prepare_v2() failed : %s", |
1048 | 0 | sqlite3_errmsg(m_poDS->m_hDBForComputedAttributes)); |
1049 | 0 | return; |
1050 | 0 | } |
1051 | | |
1052 | 877 | OGRFieldDefn oField(pszName, eType); |
1053 | 877 | m_poFeatureDefn->AddFieldDefn(&oField); |
1054 | 877 | m_oComputedAttributes.push_back(OGROSMComputedAttribute(pszName)); |
1055 | 877 | OGROSMComputedAttribute &oComputedAttribute = m_oComputedAttributes.back(); |
1056 | 877 | oComputedAttribute.eType = eType; |
1057 | 877 | oComputedAttribute.nIndex = m_poFeatureDefn->GetFieldCount() - 1; |
1058 | 877 | oComputedAttribute.osSQL = pszSQL; |
1059 | 877 | oComputedAttribute.hStmt = hStmt; |
1060 | 877 | oComputedAttribute.aosAttrToBind = std::move(aosAttrToBind); |
1061 | 877 | oComputedAttribute.anIndexToBind = std::move(anIndexToBind); |
1062 | 877 | oComputedAttribute.bHardcodedZOrder = bHardcodedZOrder; |
1063 | 877 | } |