/src/gdal/ogr/ogr_schema_override.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * Project: OGR_SCHEMA open options handling |
3 | | * Purpose: Class for representing a layer schema override. |
4 | | * Author: Alessandro Pasotti, elpaso@itopen.it |
5 | | * |
6 | | ****************************************************************************** |
7 | | * Copyright (c) 2024, Alessandro Pasotti <elpaso at itopen dot it> |
8 | | * |
9 | | * SPDX-License-Identifier: MIT |
10 | | ****************************************************************************/ |
11 | | |
12 | | //! @cond Doxygen_Suppress |
13 | | |
14 | | #include "ogr_schema_override.h" |
15 | | #include "ogrsf_frmts.h" |
16 | | #include "ogr_p.h" |
17 | | |
18 | | constexpr char OGR_SCHEMA_UNDEFINED_VALUE[] = "ogr_schema_undefined_value"; |
19 | | |
20 | | void OGRSchemaOverride::AddLayerOverride( |
21 | | const OGRLayerSchemaOverride &oLayerOverride) |
22 | 0 | { |
23 | 0 | m_aoLayerOverrides.push_back(oLayerOverride); |
24 | 0 | } |
25 | | |
26 | | bool OGRSchemaOverride::LoadFromJSON(const std::string &osJSON, |
27 | | bool bAllowGeometryFields) |
28 | 0 | { |
29 | 0 | std::string osFieldsSchemaOverride; |
30 | 0 | bool bFieldsSchemaOverrideIsFilePath{false}; |
31 | | |
32 | | // Try to load the content of the file |
33 | 0 | GByte *pabyRet = nullptr; |
34 | 0 | if (VSIIngestFile(nullptr, osJSON.c_str(), &pabyRet, nullptr, -1) == TRUE) |
35 | 0 | { |
36 | 0 | bFieldsSchemaOverrideIsFilePath = true; |
37 | 0 | osFieldsSchemaOverride = std::string(reinterpret_cast<char *>(pabyRet)); |
38 | 0 | VSIFree(pabyRet); |
39 | 0 | } |
40 | |
|
41 | 0 | if (!bFieldsSchemaOverrideIsFilePath) |
42 | 0 | { |
43 | 0 | osFieldsSchemaOverride = osJSON; |
44 | 0 | } |
45 | |
|
46 | 0 | CPLJSONDocument oSchemaDoc; |
47 | 0 | if (oSchemaDoc.LoadMemory(osFieldsSchemaOverride)) |
48 | 0 | { |
49 | 0 | const CPLJSONObject oRoot = oSchemaDoc.GetRoot(); |
50 | 0 | if (oRoot.IsValid()) |
51 | 0 | { |
52 | 0 | const auto aoLayers = oRoot.GetArray("layers"); |
53 | | // Loop through layer names and get the field details for each field. |
54 | 0 | for (const auto &oLayer : aoLayers) |
55 | 0 | { |
56 | 0 | if (oLayer.IsValid()) |
57 | 0 | { |
58 | 0 | const auto oLayerFields = oLayer.GetArray("fields"); |
59 | | // Parse fields |
60 | 0 | const auto osLayerName = oLayer.GetString("name"); |
61 | 0 | const auto osSchemaType = oLayer.GetString("schemaType"); |
62 | | // Default schemaType is "Patch" |
63 | 0 | const auto bSchemaFullOverride = |
64 | 0 | CPLString(osSchemaType).tolower() == "full"; |
65 | 0 | OGRLayerSchemaOverride oLayerOverride; |
66 | 0 | oLayerOverride.SetLayerName(osLayerName); |
67 | 0 | oLayerOverride.SetFullOverride(bSchemaFullOverride); |
68 | |
|
69 | 0 | if (oLayerFields.Size() > 0 && !osLayerName.empty()) |
70 | 0 | { |
71 | 0 | for (const auto &oField : oLayerFields) |
72 | 0 | { |
73 | 0 | const auto osFieldName = oField.GetString("name"); |
74 | 0 | OGRFieldDefnOverride oFieldOverride; |
75 | |
|
76 | 0 | const CPLString oSrcType( |
77 | 0 | CPLString(oField.GetString("srcType")) |
78 | 0 | .tolower()); |
79 | 0 | const CPLString oSrcSubType( |
80 | 0 | CPLString(oField.GetString("srcSubType")) |
81 | 0 | .tolower()); |
82 | 0 | const CPLString oType( |
83 | 0 | CPLString(oField.GetString("type")).tolower()); |
84 | 0 | const CPLString oSubType( |
85 | 0 | CPLString(oField.GetString("subType")) |
86 | 0 | .tolower()); |
87 | 0 | const CPLString osNewName( |
88 | 0 | CPLString(oField.GetString("newName")) |
89 | 0 | .tolower()); |
90 | 0 | const CPLString osNullable( |
91 | 0 | CPLString( |
92 | 0 | oField.GetString( |
93 | 0 | "nullable", OGR_SCHEMA_UNDEFINED_VALUE)) |
94 | 0 | .tolower()); |
95 | 0 | const CPLString osUnique( |
96 | 0 | CPLString(oField.GetString( |
97 | 0 | "uniqueConstraint", |
98 | 0 | OGR_SCHEMA_UNDEFINED_VALUE)) |
99 | 0 | .tolower()); |
100 | 0 | const CPLString osDefaultValue(CPLString( |
101 | 0 | oField.GetString("defaultValue", |
102 | 0 | OGR_SCHEMA_UNDEFINED_VALUE))); |
103 | 0 | const CPLString osAlias(CPLString(oField.GetString( |
104 | 0 | "alias", OGR_SCHEMA_UNDEFINED_VALUE))); |
105 | 0 | const CPLString osComment( |
106 | 0 | CPLString(oField.GetString( |
107 | 0 | "comment", OGR_SCHEMA_UNDEFINED_VALUE))); |
108 | 0 | const CPLString osDomain(CPLString(oField.GetString( |
109 | 0 | "domainName", OGR_SCHEMA_UNDEFINED_VALUE))); |
110 | 0 | const CPLString osTimeZone( |
111 | 0 | CPLString(oField.GetString( |
112 | 0 | "timezone", OGR_SCHEMA_UNDEFINED_VALUE))); |
113 | 0 | const auto nWidth = oField.GetInteger("width", 0); |
114 | 0 | const auto nPrecision = |
115 | 0 | oField.GetInteger("precision", 0); |
116 | |
|
117 | 0 | if (!osNewName.empty()) |
118 | 0 | { |
119 | 0 | oFieldOverride.SetFieldName(osNewName); |
120 | 0 | } |
121 | |
|
122 | 0 | if (!oSrcType.empty()) |
123 | 0 | { |
124 | 0 | if (bSchemaFullOverride) |
125 | 0 | { |
126 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
127 | 0 | "Non-patch OGR_SCHEMA definition " |
128 | 0 | "is not allowed with specifying " |
129 | 0 | "source field type"); |
130 | 0 | return false; |
131 | 0 | } |
132 | 0 | if (!osFieldName.empty() || !osNewName.empty()) |
133 | 0 | { |
134 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
135 | 0 | "Field name and source field type " |
136 | 0 | "are mutually exclusive"); |
137 | 0 | return false; |
138 | 0 | } |
139 | 0 | const OGRFieldType eType = |
140 | 0 | OGRFieldDefn::GetFieldTypeByName( |
141 | 0 | oSrcType.c_str()); |
142 | | // Check if the field type is valid |
143 | 0 | if (eType == OFTString && oSrcType != "string") |
144 | 0 | { |
145 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
146 | 0 | "Unsupported source field type: " |
147 | 0 | "%s", |
148 | 0 | oSrcType.c_str()); |
149 | 0 | return false; |
150 | 0 | } |
151 | 0 | oFieldOverride.SetSrcFieldType(eType); |
152 | 0 | } |
153 | | |
154 | 0 | if (!oSrcSubType.empty()) |
155 | 0 | { |
156 | 0 | if (bSchemaFullOverride) |
157 | 0 | { |
158 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
159 | 0 | "Non-patch OGR_SCHEMA definition " |
160 | 0 | "is not allowed with specifying " |
161 | 0 | "source field subtype"); |
162 | 0 | return false; |
163 | 0 | } |
164 | 0 | if (!osFieldName.empty() || !osNewName.empty()) |
165 | 0 | { |
166 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
167 | 0 | "Field name and source field " |
168 | 0 | "subtype are mutually exclusive"); |
169 | 0 | return false; |
170 | 0 | } |
171 | 0 | const OGRFieldSubType eSubType = |
172 | 0 | OGRFieldDefn::GetFieldSubTypeByName( |
173 | 0 | oSubType.c_str()); |
174 | | // Check if the field subType is valid |
175 | 0 | if (eSubType == OFSTNone && |
176 | 0 | oSrcSubType != "none") |
177 | 0 | { |
178 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
179 | 0 | "Unsupported source field subType:" |
180 | 0 | " %s", |
181 | 0 | oSubType.c_str()); |
182 | 0 | return false; |
183 | 0 | } |
184 | 0 | oFieldOverride.SetSrcFieldSubType(eSubType); |
185 | 0 | } |
186 | | |
187 | 0 | if (oSrcType.empty() && oSrcSubType.empty() && |
188 | 0 | osFieldName.empty()) |
189 | 0 | { |
190 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
191 | 0 | "Field name is missing"); |
192 | 0 | return false; |
193 | 0 | } |
194 | | |
195 | 0 | if (!oType.empty()) |
196 | 0 | { |
197 | 0 | const OGRFieldType eType = |
198 | 0 | OGRFieldDefn::GetFieldTypeByName( |
199 | 0 | oType.c_str()); |
200 | | // Check if the field type is valid |
201 | 0 | if (eType == OFTString && oType != "string") |
202 | 0 | { |
203 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
204 | 0 | "Unsupported field type: %s " |
205 | 0 | "for field %s", |
206 | 0 | oType.c_str(), |
207 | 0 | osFieldName.c_str()); |
208 | 0 | return false; |
209 | 0 | } |
210 | 0 | oFieldOverride.SetFieldType(eType); |
211 | 0 | } |
212 | | |
213 | 0 | if (!oSubType.empty()) |
214 | 0 | { |
215 | 0 | const OGRFieldSubType eSubType = |
216 | 0 | OGRFieldDefn::GetFieldSubTypeByName( |
217 | 0 | oSubType.c_str()); |
218 | | // Check if the field subType is valid |
219 | 0 | if (eSubType == OFSTNone && oSubType != "none") |
220 | 0 | { |
221 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
222 | 0 | "Unsupported field subType: " |
223 | 0 | "%s for field %s", |
224 | 0 | oSubType.c_str(), |
225 | 0 | osFieldName.c_str()); |
226 | 0 | return false; |
227 | 0 | } |
228 | 0 | oFieldOverride.SetFieldSubType(eSubType); |
229 | 0 | } |
230 | | |
231 | 0 | if (nWidth != 0) |
232 | 0 | { |
233 | 0 | oFieldOverride.SetFieldWidth(nWidth); |
234 | 0 | } |
235 | |
|
236 | 0 | if (nPrecision != 0) |
237 | 0 | { |
238 | 0 | oFieldOverride.SetFieldPrecision(nPrecision); |
239 | 0 | } |
240 | |
|
241 | 0 | if (!EQUAL(osAlias, OGR_SCHEMA_UNDEFINED_VALUE)) |
242 | 0 | { |
243 | 0 | oFieldOverride.SetAlias(osAlias); |
244 | 0 | } |
245 | |
|
246 | 0 | if (!EQUAL(osComment, OGR_SCHEMA_UNDEFINED_VALUE)) |
247 | 0 | { |
248 | 0 | oFieldOverride.SetComment(osComment); |
249 | 0 | } |
250 | |
|
251 | 0 | if (!EQUAL(osDomain, OGR_SCHEMA_UNDEFINED_VALUE)) |
252 | 0 | { |
253 | 0 | oFieldOverride.SetDomainName(osDomain); |
254 | 0 | } |
255 | |
|
256 | 0 | if (!EQUAL(osTimeZone, OGR_SCHEMA_UNDEFINED_VALUE)) |
257 | 0 | { |
258 | 0 | oFieldOverride.SetTimezone(osTimeZone); |
259 | 0 | } |
260 | |
|
261 | 0 | if (!EQUAL(osDefaultValue, |
262 | 0 | OGR_SCHEMA_UNDEFINED_VALUE)) |
263 | 0 | { |
264 | 0 | oFieldOverride.SetDefaultValue(osDefaultValue); |
265 | 0 | } |
266 | |
|
267 | 0 | if (!EQUAL(osNullable, OGR_SCHEMA_UNDEFINED_VALUE)) |
268 | 0 | { |
269 | 0 | if (osNullable == "true") |
270 | 0 | { |
271 | 0 | oFieldOverride.SetNullable(true); |
272 | 0 | } |
273 | 0 | else if (osNullable == "false") |
274 | 0 | { |
275 | 0 | oFieldOverride.SetNullable(false); |
276 | 0 | } |
277 | 0 | else |
278 | 0 | { |
279 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
280 | 0 | "Invalid value for nullable " |
281 | 0 | "attribute for field %s: %s", |
282 | 0 | osFieldName.c_str(), |
283 | 0 | osNullable.c_str()); |
284 | 0 | return false; |
285 | 0 | } |
286 | 0 | } |
287 | | |
288 | 0 | if (!EQUAL(osUnique, OGR_SCHEMA_UNDEFINED_VALUE)) |
289 | 0 | { |
290 | 0 | if (osUnique == "true") |
291 | 0 | { |
292 | 0 | oFieldOverride.SetUnique(true); |
293 | 0 | } |
294 | 0 | else if (osUnique == "false") |
295 | 0 | { |
296 | 0 | oFieldOverride.SetUnique(false); |
297 | 0 | } |
298 | 0 | else |
299 | 0 | { |
300 | 0 | CPLError( |
301 | 0 | CE_Failure, CPLE_AppDefined, |
302 | 0 | "Invalid value for uniqueConstraint " |
303 | 0 | "attribute for field %s: %s", |
304 | 0 | osFieldName.c_str(), osUnique.c_str()); |
305 | 0 | return false; |
306 | 0 | } |
307 | 0 | } |
308 | | |
309 | 0 | if (bSchemaFullOverride || oFieldOverride.IsValid()) |
310 | 0 | { |
311 | 0 | if (osFieldName.empty()) |
312 | 0 | { |
313 | 0 | oLayerOverride.AddUnnamedFieldOverride( |
314 | 0 | oFieldOverride); |
315 | 0 | } |
316 | 0 | else |
317 | 0 | { |
318 | 0 | oLayerOverride.AddNamedFieldOverride( |
319 | 0 | osFieldName, oFieldOverride); |
320 | 0 | } |
321 | 0 | } |
322 | 0 | else |
323 | 0 | { |
324 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
325 | 0 | "Field %s has no valid overrides " |
326 | 0 | "and schemaType is not \"Full\"", |
327 | 0 | osFieldName.c_str()); |
328 | 0 | return false; |
329 | 0 | } |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | 0 | const auto oGeometryLayerFields = |
334 | 0 | oLayer.GetArray("geometryFields"); |
335 | 0 | if (oGeometryLayerFields.Size() > 0 && |
336 | 0 | !bAllowGeometryFields) |
337 | 0 | { |
338 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
339 | 0 | "Geometry fields are not allowed in " |
340 | 0 | "OGR_SCHEMA overrides"); |
341 | 0 | return false; |
342 | 0 | } |
343 | 0 | else if (oGeometryLayerFields.Size() > 0) |
344 | 0 | { |
345 | 0 | for (const auto &oGeometryField : oGeometryLayerFields) |
346 | 0 | { |
347 | 0 | OGRGeomFieldDefnOverride oGeomFieldOverride; |
348 | 0 | const auto osGeomFieldName = |
349 | 0 | oGeometryField.GetString("name"); |
350 | 0 | oGeomFieldOverride.SetFieldName(osGeomFieldName); |
351 | 0 | const CPLString oGeometryType( |
352 | 0 | CPLString(oGeometryField.GetString("type")) |
353 | 0 | .tolower()); |
354 | 0 | if (!oGeometryType.empty()) |
355 | 0 | { |
356 | 0 | const OGRwkbGeometryType eType = |
357 | 0 | OGRFromOGCGeomType(oGeometryType.c_str()); |
358 | 0 | if (eType == wkbUnknown) |
359 | 0 | { |
360 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
361 | 0 | "Unsupported geometry field type: " |
362 | 0 | "%s for geometry field %s", |
363 | 0 | oGeometryType.c_str(), |
364 | 0 | osGeomFieldName.c_str()); |
365 | 0 | return false; |
366 | 0 | } |
367 | 0 | oGeomFieldOverride.SetGeometryType(eType); |
368 | | |
369 | | // SRS |
370 | 0 | const auto osSRS = |
371 | 0 | oGeometryField.GetObj("coordinateSystem"); |
372 | 0 | if (!osSRS.GetString("wkt").empty() || |
373 | 0 | !osSRS.GetString("projjson").empty()) |
374 | 0 | { |
375 | 0 | OGRSpatialReference oSRS; |
376 | 0 | oSRS.SetAxisMappingStrategy( |
377 | 0 | OAMS_TRADITIONAL_GIS_ORDER); |
378 | 0 | std::string srs; |
379 | 0 | if (const auto wkt = osSRS.GetString("wkt"); |
380 | 0 | !wkt.empty()) |
381 | 0 | { |
382 | 0 | srs = wkt; |
383 | 0 | } |
384 | 0 | else if (const auto projjson = |
385 | 0 | osSRS.GetString("projjson"); |
386 | 0 | !projjson.empty()) |
387 | 0 | { |
388 | 0 | srs = projjson; |
389 | 0 | } |
390 | |
|
391 | 0 | if (!srs.empty()) |
392 | 0 | { |
393 | 0 | if (oSRS.SetFromUserInput( |
394 | 0 | srs.c_str()) != OGRERR_NONE) |
395 | 0 | { |
396 | 0 | CPLError(CE_Failure, |
397 | 0 | CPLE_AppDefined, |
398 | 0 | "Failed to parse SRS " |
399 | 0 | "definition for geometry " |
400 | 0 | "field %s.", |
401 | 0 | osGeomFieldName.c_str()); |
402 | 0 | return false; |
403 | 0 | } |
404 | 0 | oGeomFieldOverride.SetSRS(oSRS); |
405 | 0 | } |
406 | 0 | else |
407 | 0 | { |
408 | | // No SRS, assuming it's ok, just issue a warning |
409 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
410 | 0 | "CRS definition is missing " |
411 | 0 | "for geometry field %s.", |
412 | 0 | osGeomFieldName.c_str()); |
413 | 0 | } |
414 | 0 | } |
415 | | |
416 | 0 | oLayerOverride.AddGeometryFieldOverride( |
417 | 0 | oGeomFieldOverride); |
418 | 0 | } |
419 | 0 | else |
420 | 0 | { |
421 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
422 | 0 | "Geometry field %s has no type", |
423 | 0 | osGeomFieldName.c_str()); |
424 | 0 | return false; |
425 | 0 | } |
426 | 0 | } |
427 | 0 | } |
428 | | |
429 | 0 | if (oLayerOverride.IsValid()) |
430 | 0 | { |
431 | 0 | AddLayerOverride(oLayerOverride); |
432 | 0 | } |
433 | 0 | else |
434 | 0 | { |
435 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
436 | 0 | "Layer %s has no valid overrides", |
437 | 0 | osLayerName.c_str()); |
438 | 0 | return false; |
439 | 0 | } |
440 | 0 | } |
441 | 0 | else |
442 | 0 | { |
443 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
444 | 0 | "SCHEMA info is invalid JSON"); |
445 | 0 | return false; |
446 | 0 | } |
447 | 0 | } |
448 | 0 | return true; |
449 | 0 | } |
450 | 0 | else |
451 | 0 | { |
452 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
453 | 0 | "SCHEMA info is invalid JSON"); |
454 | 0 | return false; |
455 | 0 | } |
456 | 0 | } |
457 | 0 | else |
458 | 0 | { |
459 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "SCHEMA info is invalid JSON"); |
460 | 0 | return false; |
461 | 0 | } |
462 | 0 | } |
463 | | |
464 | | const std::vector<OGRLayerSchemaOverride> & |
465 | | OGRSchemaOverride::GetLayerOverrides() const |
466 | 0 | { |
467 | 0 | return m_aoLayerOverrides; |
468 | 0 | } |
469 | | |
470 | | bool OGRSchemaOverride::IsValid() const |
471 | 0 | { |
472 | 0 | bool isValid = !m_aoLayerOverrides.empty(); |
473 | 0 | for (const auto &oLayerOverride : m_aoLayerOverrides) |
474 | 0 | { |
475 | 0 | isValid &= oLayerOverride.IsValid(); |
476 | 0 | } |
477 | 0 | return isValid; |
478 | 0 | } |
479 | | |
480 | | bool OGRSchemaOverride::DefaultApply( |
481 | | GDALDataset *poDS, const char *pszDebugKey, |
482 | | std::function<void(OGRLayer *, int)> callbackWhenRemovingField) const |
483 | 0 | { |
484 | 0 | const auto &oLayerOverrides = GetLayerOverrides(); |
485 | 0 | for (const auto &oLayerFieldOverride : oLayerOverrides) |
486 | 0 | { |
487 | 0 | const auto &osLayerName = oLayerFieldOverride.GetLayerName(); |
488 | 0 | const bool bIsFullOverride{oLayerFieldOverride.IsFullOverride()}; |
489 | 0 | auto oNamedFieldOverrides = |
490 | 0 | oLayerFieldOverride.GetNamedFieldOverrides(); |
491 | 0 | const auto &oUnnamedFieldOverrides = |
492 | 0 | oLayerFieldOverride.GetUnnamedFieldOverrides(); |
493 | |
|
494 | 0 | const auto ProcessLayer = |
495 | 0 | [&callbackWhenRemovingField, &osLayerName, &oNamedFieldOverrides, |
496 | 0 | &oUnnamedFieldOverrides, bIsFullOverride](OGRLayer *poLayer) |
497 | 0 | { |
498 | 0 | std::vector<OGRFieldDefn *> aoFields; |
499 | | // Patch field definitions |
500 | 0 | auto poLayerDefn = poLayer->GetLayerDefn(); |
501 | 0 | for (int i = 0; i < poLayerDefn->GetFieldCount(); i++) |
502 | 0 | { |
503 | 0 | auto poFieldDefn = poLayerDefn->GetFieldDefn(i); |
504 | |
|
505 | 0 | const auto PatchFieldDefn = |
506 | 0 | [poFieldDefn](const OGRFieldDefnOverride &oFieldOverride) |
507 | 0 | { |
508 | 0 | if (oFieldOverride.GetFieldType().has_value()) |
509 | 0 | whileUnsealing(poFieldDefn) |
510 | 0 | ->SetType(oFieldOverride.GetFieldType().value()); |
511 | 0 | if (oFieldOverride.GetFieldWidth().has_value()) |
512 | 0 | whileUnsealing(poFieldDefn) |
513 | 0 | ->SetWidth(oFieldOverride.GetFieldWidth().value()); |
514 | 0 | if (oFieldOverride.GetFieldPrecision().has_value()) |
515 | 0 | whileUnsealing(poFieldDefn) |
516 | 0 | ->SetPrecision( |
517 | 0 | oFieldOverride.GetFieldPrecision().value()); |
518 | 0 | if (oFieldOverride.GetFieldSubType().has_value()) |
519 | 0 | whileUnsealing(poFieldDefn) |
520 | 0 | ->SetSubType( |
521 | 0 | oFieldOverride.GetFieldSubType().value()); |
522 | 0 | if (oFieldOverride.GetFieldName().has_value()) |
523 | 0 | whileUnsealing(poFieldDefn) |
524 | 0 | ->SetName( |
525 | 0 | oFieldOverride.GetFieldName().value().c_str()); |
526 | 0 | }; |
527 | |
|
528 | 0 | auto oFieldOverrideIter = |
529 | 0 | oNamedFieldOverrides.find(poFieldDefn->GetNameRef()); |
530 | 0 | if (oFieldOverrideIter != oNamedFieldOverrides.cend()) |
531 | 0 | { |
532 | 0 | const auto &oFieldOverride = oFieldOverrideIter->second; |
533 | 0 | PatchFieldDefn(oFieldOverride); |
534 | |
|
535 | 0 | if (bIsFullOverride) |
536 | 0 | { |
537 | 0 | aoFields.push_back(poFieldDefn); |
538 | 0 | } |
539 | 0 | oNamedFieldOverrides.erase(oFieldOverrideIter); |
540 | 0 | } |
541 | 0 | else |
542 | 0 | { |
543 | 0 | for (const auto &oFieldOverride : oUnnamedFieldOverrides) |
544 | 0 | { |
545 | 0 | if ((!oFieldOverride.GetSrcFieldType().has_value() || |
546 | 0 | oFieldOverride.GetSrcFieldType().value() == |
547 | 0 | poFieldDefn->GetType()) && |
548 | 0 | (!oFieldOverride.GetSrcFieldSubType().has_value() || |
549 | 0 | oFieldOverride.GetSrcFieldSubType().value() == |
550 | 0 | poFieldDefn->GetSubType())) |
551 | 0 | { |
552 | 0 | PatchFieldDefn(oFieldOverride); |
553 | 0 | break; |
554 | 0 | } |
555 | 0 | } |
556 | 0 | } |
557 | 0 | } |
558 | | |
559 | | // Error if any field override is not found |
560 | 0 | if (!oNamedFieldOverrides.empty()) |
561 | 0 | { |
562 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
563 | 0 | "Field %s not found in layer %s", |
564 | 0 | oNamedFieldOverrides.cbegin()->first.c_str(), |
565 | 0 | osLayerName.c_str()); |
566 | 0 | return false; |
567 | 0 | } |
568 | | |
569 | | // Remove fields not in the override |
570 | 0 | if (bIsFullOverride) |
571 | 0 | { |
572 | 0 | for (int i = poLayerDefn->GetFieldCount() - 1; i >= 0; i--) |
573 | 0 | { |
574 | 0 | auto poFieldDefn = poLayerDefn->GetFieldDefn(i); |
575 | 0 | if (std::find(aoFields.begin(), aoFields.end(), |
576 | 0 | poFieldDefn) == aoFields.end()) |
577 | 0 | { |
578 | 0 | callbackWhenRemovingField(poLayer, i); |
579 | 0 | whileUnsealing(poLayerDefn)->DeleteFieldDefn(i); |
580 | 0 | } |
581 | 0 | } |
582 | 0 | } |
583 | |
|
584 | 0 | return true; |
585 | 0 | }; |
586 | |
|
587 | 0 | CPLDebug(pszDebugKey, "Applying schema override for layer %s", |
588 | 0 | osLayerName.c_str()); |
589 | |
|
590 | 0 | if (osLayerName == "*") |
591 | 0 | { |
592 | 0 | for (auto *poLayer : poDS->GetLayers()) |
593 | 0 | { |
594 | 0 | if (!ProcessLayer(poLayer)) |
595 | 0 | return false; |
596 | 0 | } |
597 | 0 | } |
598 | 0 | else |
599 | 0 | { |
600 | | // Fail if the layer name does not exist |
601 | 0 | auto poLayer = poDS->GetLayerByName(osLayerName.c_str()); |
602 | 0 | if (poLayer == nullptr) |
603 | 0 | { |
604 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Layer %s not found", |
605 | 0 | osLayerName.c_str()); |
606 | 0 | return false; |
607 | 0 | } |
608 | 0 | if (!ProcessLayer(poLayer)) |
609 | 0 | return false; |
610 | 0 | } |
611 | 0 | } |
612 | | |
613 | 0 | return true; |
614 | 0 | } |
615 | | |
616 | | const OGRLayerSchemaOverride & |
617 | | OGRSchemaOverride::GetLayerOverride(const std::string &osLayerName) const |
618 | 0 | { |
619 | 0 | for (const auto &oLayerOverride : m_aoLayerOverrides) |
620 | 0 | { |
621 | 0 | if (oLayerOverride.GetLayerName() == osLayerName) |
622 | 0 | { |
623 | 0 | return oLayerOverride; |
624 | 0 | } |
625 | 0 | } |
626 | 0 | static const OGRLayerSchemaOverride emptyOverride{}; |
627 | 0 | return emptyOverride; |
628 | 0 | } |
629 | | |
630 | | void OGRLayerSchemaOverride::SetLayerName(const std::string &osLayerName) |
631 | 0 | { |
632 | 0 | m_osLayerName = osLayerName; |
633 | 0 | } |
634 | | |
635 | | void OGRLayerSchemaOverride::AddNamedFieldOverride( |
636 | | const std::string &osFieldName, const OGRFieldDefnOverride &oFieldOverride) |
637 | 0 | { |
638 | 0 | m_oNamedFieldOverrides[osFieldName] = oFieldOverride; |
639 | 0 | } |
640 | | |
641 | | void OGRLayerSchemaOverride::AddUnnamedFieldOverride( |
642 | | const OGRFieldDefnOverride &oFieldOverride) |
643 | 0 | { |
644 | 0 | m_aoUnnamedFieldOverrides.push_back(oFieldOverride); |
645 | 0 | } |
646 | | |
647 | | const std::string &OGRLayerSchemaOverride::GetLayerName() const |
648 | 0 | { |
649 | 0 | return m_osLayerName; |
650 | 0 | } |
651 | | |
652 | | const std::map<std::string, OGRFieldDefnOverride> & |
653 | | OGRLayerSchemaOverride::GetNamedFieldOverrides() const |
654 | 0 | { |
655 | 0 | return m_oNamedFieldOverrides; |
656 | 0 | } |
657 | | |
658 | | const std::vector<OGRFieldDefnOverride> & |
659 | | OGRLayerSchemaOverride::GetUnnamedFieldOverrides() const |
660 | 0 | { |
661 | 0 | return m_aoUnnamedFieldOverrides; |
662 | 0 | } |
663 | | |
664 | | void OGRLayerSchemaOverride::AddGeometryFieldOverride( |
665 | | const OGRGeomFieldDefnOverride &oGeomFieldOverride) |
666 | 0 | { |
667 | 0 | m_aoGeomFieldOverrides.push_back(oGeomFieldOverride); |
668 | 0 | } |
669 | | |
670 | | const std::vector<OGRGeomFieldDefnOverride> & |
671 | | OGRLayerSchemaOverride::GetGeometryFieldOverrides() const |
672 | 0 | { |
673 | 0 | return m_aoGeomFieldOverrides; |
674 | 0 | } |
675 | | |
676 | | std::vector<OGRFieldDefn> OGRLayerSchemaOverride::GetFieldDefinitions() const |
677 | 0 | { |
678 | 0 | std::vector<OGRFieldDefn> ret; |
679 | 0 | for (const auto &kv : m_oNamedFieldOverrides) |
680 | 0 | { |
681 | 0 | ret.push_back(kv.second.ToFieldDefn(kv.first)); |
682 | 0 | } |
683 | 0 | return ret; |
684 | 0 | } |
685 | | |
686 | | std::vector<OGRGeomFieldDefn> |
687 | | OGRLayerSchemaOverride::GetGeomFieldDefinitions() const |
688 | 0 | { |
689 | 0 | std::vector<OGRGeomFieldDefn> ret; |
690 | 0 | for (const auto &oGeomFieldOverride : m_aoGeomFieldOverrides) |
691 | 0 | { |
692 | 0 | ret.push_back(oGeomFieldOverride.ToGeometryFieldDefn("geom")); |
693 | 0 | } |
694 | 0 | return ret; |
695 | 0 | } |
696 | | |
697 | | bool OGRLayerSchemaOverride::IsFullOverride() const |
698 | 0 | { |
699 | 0 | return m_bIsFullOverride; |
700 | 0 | } |
701 | | |
702 | | void OGRLayerSchemaOverride::SetFullOverride(bool bIsFullOverride) |
703 | 0 | { |
704 | 0 | m_bIsFullOverride = bIsFullOverride; |
705 | 0 | } |
706 | | |
707 | | bool OGRLayerSchemaOverride::IsValid() const |
708 | 0 | { |
709 | 0 | bool isValid = |
710 | 0 | !m_osLayerName.empty() && |
711 | 0 | (!m_oNamedFieldOverrides.empty() || !m_aoUnnamedFieldOverrides.empty()); |
712 | 0 | for (const auto &oFieldOverrideIter : m_oNamedFieldOverrides) |
713 | 0 | { |
714 | 0 | isValid &= !oFieldOverrideIter.first.empty(); |
715 | | // When schemaType is "full" override we don't need to check if the field |
716 | | // overrides are valid: a list of fields to keep is enough. |
717 | 0 | if (!m_bIsFullOverride) |
718 | 0 | { |
719 | 0 | isValid &= oFieldOverrideIter.second.IsValid(); |
720 | 0 | } |
721 | 0 | } |
722 | 0 | return isValid; |
723 | 0 | } |
724 | | |
725 | | bool OGRLayerSchemaOverride::empty() const |
726 | 0 | { |
727 | 0 | return m_osLayerName.empty() && m_oNamedFieldOverrides.empty() && |
728 | 0 | m_aoUnnamedFieldOverrides.empty() && !m_bIsFullOverride; |
729 | 0 | } |
730 | | |
731 | | bool OGRFieldDefnOverride::IsValid() const |
732 | 0 | { |
733 | 0 | return m_osName.has_value() || m_eType.has_value() || |
734 | 0 | m_eSubType.has_value() || m_eSrcType.has_value() || |
735 | 0 | m_eSrcSubType.has_value() || m_nWidth.has_value() || |
736 | 0 | m_nPrecision.has_value(); |
737 | 0 | } |
738 | | |
739 | | OGRFieldDefn |
740 | | OGRFieldDefnOverride::ToFieldDefn(const std::string &osDefaultName) const |
741 | 0 | { |
742 | |
|
743 | 0 | OGRFieldDefn oFieldDefn(m_osName.value_or(osDefaultName).c_str(), |
744 | 0 | m_eType.value_or(OFTString)); |
745 | |
|
746 | 0 | oFieldDefn.SetName(m_osName.value_or(osDefaultName).c_str()); |
747 | |
|
748 | 0 | if (m_eSubType.has_value()) |
749 | 0 | oFieldDefn.SetSubType(m_eSubType.value()); |
750 | 0 | if (m_nWidth.has_value()) |
751 | 0 | oFieldDefn.SetWidth(m_nWidth.value()); |
752 | 0 | if (m_nPrecision.has_value()) |
753 | 0 | oFieldDefn.SetPrecision(m_nPrecision.value()); |
754 | 0 | if (m_osName.has_value()) |
755 | 0 | oFieldDefn.SetName(m_osName.value().c_str()); |
756 | 0 | if (m_bNullable.has_value()) |
757 | 0 | oFieldDefn.SetNullable(m_bNullable.value()); |
758 | 0 | if (m_bUnique.has_value()) |
759 | 0 | oFieldDefn.SetUnique(m_bUnique.value()); |
760 | 0 | if (m_osComment.has_value()) |
761 | 0 | oFieldDefn.SetComment(m_osComment.value().c_str()); |
762 | 0 | if (m_osAlias.has_value()) |
763 | 0 | oFieldDefn.SetAlternativeName(m_osAlias.value().c_str()); |
764 | 0 | if (m_osTimezone.has_value()) |
765 | 0 | { |
766 | 0 | const auto tzValue{m_osTimezone.value().c_str()}; |
767 | 0 | if (EQUAL(tzValue, "UTC")) |
768 | 0 | { |
769 | 0 | oFieldDefn.SetTZFlag(OGR_TZFLAG_UTC); |
770 | 0 | } |
771 | 0 | else if (EQUAL(tzValue, "localtime")) |
772 | 0 | { |
773 | 0 | oFieldDefn.SetTZFlag(OGR_TZFLAG_LOCALTIME); |
774 | 0 | } |
775 | 0 | else if (EQUAL(tzValue, "mixed timezones")) |
776 | 0 | { |
777 | 0 | oFieldDefn.SetTZFlag(OGR_TZFLAG_MIXED_TZ); |
778 | 0 | } |
779 | 0 | else |
780 | 0 | { |
781 | 0 | const auto tzFlag{OGRTimezoneToTZFlag( |
782 | 0 | tzValue, /* bEmitErrorIfUnhandledFormat */ false)}; |
783 | 0 | oFieldDefn.SetTZFlag(tzFlag); |
784 | 0 | if (tzFlag == OGR_TZFLAG_UNKNOWN) |
785 | 0 | { |
786 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
787 | 0 | "Invalid timezone value: %s. Ignoring it.", tzValue); |
788 | 0 | } |
789 | 0 | } |
790 | 0 | } |
791 | 0 | if (m_osDomainName.has_value()) |
792 | 0 | oFieldDefn.SetDomainName(m_osDomainName.value().c_str()); |
793 | 0 | if (m_osDefaultValue.has_value()) |
794 | 0 | oFieldDefn.SetDefault(m_osDefaultValue.value().c_str()); |
795 | 0 | return oFieldDefn; |
796 | 0 | } |
797 | | |
798 | | OGRGeomFieldDefn OGRGeomFieldDefnOverride::ToGeometryFieldDefn( |
799 | | const std::string &osDefaultName) const |
800 | 0 | { |
801 | |
|
802 | 0 | OGRGeomFieldDefn oGeomFieldDefn{m_osName.value_or(osDefaultName).c_str(), |
803 | 0 | m_eType.value_or(wkbUnknown)}; |
804 | |
|
805 | 0 | if (m_bNullable.has_value()) |
806 | 0 | { |
807 | 0 | oGeomFieldDefn.SetNullable(m_bNullable.value()); |
808 | 0 | } |
809 | |
|
810 | 0 | if (m_oSRS.has_value()) |
811 | 0 | { |
812 | 0 | std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser> poSRS; |
813 | 0 | poSRS.reset( |
814 | 0 | std::make_unique<OGRSpatialReference>(m_oSRS.value()).release()); |
815 | 0 | oGeomFieldDefn.SetSpatialRef(poSRS.get()); |
816 | 0 | } |
817 | |
|
818 | 0 | return oGeomFieldDefn; |
819 | 0 | } |
820 | | |
821 | | //! @endcond |