Coverage Report

Created: 2025-06-13 06:29

/src/gdal/ogr/ogr_schema_override.cpp
Line
Count
Source (jump to first uncovered line)
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
16
bool OGRSchemaOverride::LoadFromJSON(const std::string &osJSON)
17
0
{
18
0
    std::string osFieldsSchemaOverride;
19
0
    bool bFieldsSchemaOverrideIsFilePath{false};
20
21
    // Try to load the content of the file
22
0
    GByte *pabyRet = nullptr;
23
0
    if (VSIIngestFile(nullptr, osJSON.c_str(), &pabyRet, nullptr, -1) == TRUE)
24
0
    {
25
0
        bFieldsSchemaOverrideIsFilePath = true;
26
0
        osFieldsSchemaOverride = std::string(reinterpret_cast<char *>(pabyRet));
27
0
        VSIFree(pabyRet);
28
0
    }
29
30
0
    if (!bFieldsSchemaOverrideIsFilePath)
31
0
    {
32
0
        osFieldsSchemaOverride = osJSON;
33
0
    }
34
35
0
    CPLJSONDocument oSchemaDoc;
36
0
    if (oSchemaDoc.LoadMemory(osFieldsSchemaOverride))
37
0
    {
38
0
        const CPLJSONObject oRoot = oSchemaDoc.GetRoot();
39
0
        if (oRoot.IsValid())
40
0
        {
41
0
            const auto aoLayers = oRoot.GetArray("layers");
42
            // Loop through layer names and get the field details for each field.
43
0
            for (const auto &oLayer : aoLayers)
44
0
            {
45
0
                if (oLayer.IsValid())
46
0
                {
47
0
                    const auto oLayerFields = oLayer.GetArray("fields");
48
                    // Parse fields
49
0
                    const auto osLayerName = oLayer.GetString("name");
50
0
                    const auto osSchemaType = oLayer.GetString("schemaType");
51
                    // Default schemaType is "Patch"
52
0
                    const auto bSchemaFullOverride =
53
0
                        CPLString(osSchemaType).tolower() == "full";
54
0
                    OGRLayerSchemaOverride oLayerOverride;
55
0
                    oLayerOverride.SetLayerName(osLayerName);
56
0
                    oLayerOverride.SetFullOverride(bSchemaFullOverride);
57
58
0
                    if (oLayerFields.Size() > 0 && !osLayerName.empty())
59
0
                    {
60
0
                        for (const auto &oField : oLayerFields)
61
0
                        {
62
0
                            const auto osFieldName = oField.GetString("name");
63
0
                            if (osFieldName.empty())
64
0
                            {
65
0
                                CPLError(CE_Warning, CPLE_AppDefined,
66
0
                                         "Field name is missing");
67
0
                                return false;
68
0
                            }
69
0
                            OGRFieldDefnOverride oFieldOverride;
70
71
0
                            const CPLString oType(
72
0
                                CPLString(oField.GetString("type")).tolower());
73
0
                            const CPLString oSubType(
74
0
                                CPLString(oField.GetString("subType"))
75
0
                                    .tolower());
76
0
                            const CPLString osNewName(
77
0
                                CPLString(oField.GetString("newName"))
78
0
                                    .tolower());
79
0
                            const auto nWidth = oField.GetInteger("width", 0);
80
0
                            const auto nPrecision =
81
0
                                oField.GetInteger("precision", 0);
82
83
0
                            if (!osNewName.empty())
84
0
                            {
85
0
                                oFieldOverride.SetFieldName(osNewName);
86
0
                            }
87
88
0
                            if (!oType.empty())
89
0
                            {
90
0
                                const OGRFieldType eType =
91
0
                                    OGRFieldDefn::GetFieldTypeByName(
92
0
                                        oType.c_str());
93
                                // Check if the field type is valid
94
0
                                if (eType == OFTString && oType != "string")
95
0
                                {
96
0
                                    CPLError(CE_Failure, CPLE_AppDefined,
97
0
                                             "Unsupported field type: %s "
98
0
                                             "for field %s",
99
0
                                             oType.c_str(),
100
0
                                             osFieldName.c_str());
101
0
                                    return false;
102
0
                                }
103
0
                                oFieldOverride.SetFieldType(eType);
104
0
                            }
105
106
0
                            if (!oSubType.empty())
107
0
                            {
108
0
                                const OGRFieldSubType eSubType =
109
0
                                    OGRFieldDefn::GetFieldSubTypeByName(
110
0
                                        oSubType.c_str());
111
                                // Check if the field subType is valid
112
0
                                if (eSubType == OFSTNone && oSubType != "none")
113
0
                                {
114
0
                                    CPLError(CE_Failure, CPLE_AppDefined,
115
0
                                             "Unsupported field subType: "
116
0
                                             "%s for field %s",
117
0
                                             oSubType.c_str(),
118
0
                                             osFieldName.c_str());
119
0
                                    return false;
120
0
                                }
121
0
                                oFieldOverride.SetFieldSubType(eSubType);
122
0
                            }
123
124
0
                            if (nWidth != 0)
125
0
                            {
126
0
                                oFieldOverride.SetFieldWidth(nWidth);
127
0
                            }
128
129
0
                            if (nPrecision != 0)
130
0
                            {
131
0
                                oFieldOverride.SetFieldPrecision(nPrecision);
132
0
                            }
133
134
0
                            if (bSchemaFullOverride || oFieldOverride.IsValid())
135
0
                            {
136
0
                                oLayerOverride.AddFieldOverride(osFieldName,
137
0
                                                                oFieldOverride);
138
0
                            }
139
0
                            else
140
0
                            {
141
0
                                CPLError(CE_Failure, CPLE_AppDefined,
142
0
                                         "Field %s has no valid overrides "
143
0
                                         "and schemaType is not \"Full\"",
144
0
                                         osFieldName.c_str());
145
0
                                return false;
146
0
                            }
147
0
                        }
148
0
                    }
149
150
0
                    if (oLayerOverride.IsValid())
151
0
                    {
152
0
                        AddLayerOverride(osLayerName, oLayerOverride);
153
0
                    }
154
0
                    else
155
0
                    {
156
0
                        CPLError(CE_Failure, CPLE_AppDefined,
157
0
                                 "Layer %s has no valid overrides",
158
0
                                 osLayerName.c_str());
159
0
                        return false;
160
0
                    }
161
0
                }
162
0
                else
163
0
                {
164
0
                    CPLError(CE_Failure, CPLE_AppDefined,
165
0
                             "SCHEMA info is invalid JSON");
166
0
                    return false;
167
0
                }
168
0
            }
169
0
            return true;
170
0
        }
171
0
        else
172
0
        {
173
0
            CPLError(CE_Failure, CPLE_AppDefined,
174
0
                     "SCHEMA info is invalid JSON");
175
0
            return false;
176
0
        }
177
0
    }
178
0
    else
179
0
    {
180
0
        CPLError(CE_Failure, CPLE_AppDefined, "SCHEMA info is invalid JSON");
181
0
        return false;
182
0
    }
183
0
}
184
185
bool OGRSchemaOverride::IsValid() const
186
0
{
187
0
    bool isValid = !m_moLayerOverrides.empty();
188
0
    for (const auto &oLayerOverride : m_moLayerOverrides)
189
0
    {
190
0
        isValid &= oLayerOverride.second.IsValid();
191
0
    }
192
0
    return isValid;
193
0
}
194
195
bool OGRLayerSchemaOverride::IsValid() const
196
0
{
197
0
    bool isValid = !m_osLayerName.empty() && !m_moFieldOverrides.empty();
198
0
    for (const auto &oFieldOverride : m_moFieldOverrides)
199
0
    {
200
0
        isValid &= !oFieldOverride.first.empty();
201
        // When schemaType is "full" override we don't need to check if the field
202
        // overrides are valid: a list of fields to keep is enough.
203
0
        if (!m_bIsFullOverride)
204
0
        {
205
0
            isValid &= oFieldOverride.second.IsValid();
206
0
        }
207
0
    }
208
0
    return isValid;
209
0
}
210
211
bool OGRFieldDefnOverride::IsValid() const
212
0
{
213
0
    return m_osName.has_value() || m_eType.has_value() ||
214
0
           m_eSubType.has_value() || m_nWidth.has_value() ||
215
0
           m_nPrecision.has_value();
216
0
}
217
218
//! @endcond