Coverage Report

Created: 2026-04-01 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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