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