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 :
17 53 : bool OGRSchemaOverride::LoadFromJSON(const std::string &osJSON)
18 : {
19 106 : std::string osFieldsSchemaOverride;
20 53 : bool bFieldsSchemaOverrideIsFilePath{false};
21 :
22 : // Try to load the content of the file
23 53 : GByte *pabyRet = nullptr;
24 53 : if (VSIIngestFile(nullptr, osJSON.c_str(), &pabyRet, nullptr, -1) == TRUE)
25 : {
26 14 : bFieldsSchemaOverrideIsFilePath = true;
27 14 : osFieldsSchemaOverride = std::string(reinterpret_cast<char *>(pabyRet));
28 14 : VSIFree(pabyRet);
29 : }
30 :
31 53 : if (!bFieldsSchemaOverrideIsFilePath)
32 : {
33 39 : osFieldsSchemaOverride = osJSON;
34 : }
35 :
36 106 : CPLJSONDocument oSchemaDoc;
37 53 : if (oSchemaDoc.LoadMemory(osFieldsSchemaOverride))
38 : {
39 106 : const CPLJSONObject oRoot = oSchemaDoc.GetRoot();
40 53 : if (oRoot.IsValid())
41 : {
42 159 : const auto aoLayers = oRoot.GetArray("layers");
43 : // Loop through layer names and get the field details for each field.
44 104 : for (const auto &oLayer : aoLayers)
45 : {
46 56 : if (oLayer.IsValid())
47 : {
48 112 : const auto oLayerFields = oLayer.GetArray("fields");
49 : // Parse fields
50 112 : const auto osLayerName = oLayer.GetString("name");
51 112 : const auto osSchemaType = oLayer.GetString("schemaType");
52 : // Default schemaType is "Patch"
53 : const auto bSchemaFullOverride =
54 56 : CPLString(osSchemaType).tolower() == "full";
55 56 : OGRLayerSchemaOverride oLayerOverride;
56 56 : oLayerOverride.SetLayerName(osLayerName);
57 56 : oLayerOverride.SetFullOverride(bSchemaFullOverride);
58 :
59 56 : if (oLayerFields.Size() > 0 && !osLayerName.empty())
60 : {
61 119 : for (const auto &oField : oLayerFields)
62 : {
63 136 : const auto osFieldName = oField.GetString("name");
64 68 : OGRFieldDefnOverride oFieldOverride;
65 :
66 : const CPLString oSrcType(
67 136 : CPLString(oField.GetString("srcType"))
68 68 : .tolower());
69 : const CPLString oSrcSubType(
70 136 : CPLString(oField.GetString("srcSubType"))
71 68 : .tolower());
72 : const CPLString oType(
73 136 : CPLString(oField.GetString("type")).tolower());
74 : const CPLString oSubType(
75 136 : CPLString(oField.GetString("subType"))
76 68 : .tolower());
77 : const CPLString osNewName(
78 136 : CPLString(oField.GetString("newName"))
79 68 : .tolower());
80 68 : const auto nWidth = oField.GetInteger("width", 0);
81 : const auto nPrecision =
82 68 : oField.GetInteger("precision", 0);
83 :
84 68 : if (!osNewName.empty())
85 : {
86 9 : oFieldOverride.SetFieldName(osNewName);
87 : }
88 :
89 68 : if (!oSrcType.empty())
90 : {
91 2 : if (bSchemaFullOverride)
92 : {
93 0 : CPLError(CE_Failure, CPLE_AppDefined,
94 : "Non-patch OGR_SCHEMA definition "
95 : "is not allowed with specifying "
96 : "source field type");
97 0 : return false;
98 : }
99 2 : if (!osFieldName.empty() || !osNewName.empty())
100 : {
101 0 : CPLError(CE_Warning, CPLE_AppDefined,
102 : "Field name and source field type "
103 : "are mutually exclusive");
104 0 : return false;
105 : }
106 : const OGRFieldType eType =
107 2 : OGRFieldDefn::GetFieldTypeByName(
108 : oSrcType.c_str());
109 : // Check if the field type is valid
110 2 : if (eType == OFTString && oSrcType != "string")
111 : {
112 0 : CPLError(CE_Failure, CPLE_AppDefined,
113 : "Unsupported source field type: "
114 : "%s",
115 : oSrcType.c_str());
116 0 : return false;
117 : }
118 2 : oFieldOverride.SetSrcFieldType(eType);
119 : }
120 :
121 68 : if (!oSrcSubType.empty())
122 : {
123 1 : if (bSchemaFullOverride)
124 : {
125 0 : CPLError(CE_Failure, CPLE_AppDefined,
126 : "Non-patch OGR_SCHEMA definition "
127 : "is not allowed with specifying "
128 : "source field subtype");
129 0 : return false;
130 : }
131 1 : if (!osFieldName.empty() || !osNewName.empty())
132 : {
133 0 : CPLError(CE_Warning, CPLE_AppDefined,
134 : "Field name and source field "
135 : "subtype are mutually exclusive");
136 0 : return false;
137 : }
138 : const OGRFieldSubType eSubType =
139 1 : OGRFieldDefn::GetFieldSubTypeByName(
140 : oSubType.c_str());
141 : // Check if the field subType is valid
142 2 : if (eSubType == OFSTNone &&
143 1 : oSrcSubType != "none")
144 : {
145 0 : CPLError(CE_Failure, CPLE_AppDefined,
146 : "Unsupported source field subType:"
147 : " %s",
148 : oSubType.c_str());
149 0 : return false;
150 : }
151 1 : oFieldOverride.SetSrcFieldSubType(eSubType);
152 : }
153 :
154 134 : if (oSrcType.empty() && oSrcSubType.empty() &&
155 66 : osFieldName.empty())
156 : {
157 0 : CPLError(CE_Warning, CPLE_AppDefined,
158 : "Field name is missing");
159 0 : return false;
160 : }
161 :
162 68 : if (!oType.empty())
163 : {
164 : const OGRFieldType eType =
165 44 : OGRFieldDefn::GetFieldTypeByName(
166 : oType.c_str());
167 : // Check if the field type is valid
168 44 : if (eType == OFTString && oType != "string")
169 : {
170 5 : CPLError(CE_Failure, CPLE_AppDefined,
171 : "Unsupported field type: %s "
172 : "for field %s",
173 : oType.c_str(),
174 : osFieldName.c_str());
175 5 : return false;
176 : }
177 39 : oFieldOverride.SetFieldType(eType);
178 : }
179 :
180 63 : if (!oSubType.empty())
181 : {
182 : const OGRFieldSubType eSubType =
183 21 : OGRFieldDefn::GetFieldSubTypeByName(
184 : oSubType.c_str());
185 : // Check if the field subType is valid
186 21 : if (eSubType == OFSTNone && oSubType != "none")
187 : {
188 0 : CPLError(CE_Failure, CPLE_AppDefined,
189 : "Unsupported field subType: "
190 : "%s for field %s",
191 : oSubType.c_str(),
192 : osFieldName.c_str());
193 0 : return false;
194 : }
195 21 : oFieldOverride.SetFieldSubType(eSubType);
196 : }
197 :
198 63 : if (nWidth != 0)
199 : {
200 5 : oFieldOverride.SetFieldWidth(nWidth);
201 : }
202 :
203 63 : if (nPrecision != 0)
204 : {
205 5 : oFieldOverride.SetFieldPrecision(nPrecision);
206 : }
207 :
208 63 : if (bSchemaFullOverride || oFieldOverride.IsValid())
209 : {
210 63 : if (osFieldName.empty())
211 : {
212 2 : oLayerOverride.AddUnnamedFieldOverride(
213 : oFieldOverride);
214 : }
215 : else
216 : {
217 61 : oLayerOverride.AddNamedFieldOverride(
218 : osFieldName, oFieldOverride);
219 : }
220 : }
221 : else
222 : {
223 0 : CPLError(CE_Failure, CPLE_AppDefined,
224 : "Field %s has no valid overrides "
225 : "and schemaType is not \"Full\"",
226 : osFieldName.c_str());
227 0 : return false;
228 : }
229 : }
230 : }
231 :
232 51 : if (oLayerOverride.IsValid())
233 : {
234 51 : AddLayerOverride(oLayerOverride);
235 : }
236 : else
237 : {
238 0 : CPLError(CE_Failure, CPLE_AppDefined,
239 : "Layer %s has no valid overrides",
240 : osLayerName.c_str());
241 0 : return false;
242 : }
243 : }
244 : else
245 : {
246 0 : CPLError(CE_Failure, CPLE_AppDefined,
247 : "SCHEMA info is invalid JSON");
248 0 : return false;
249 : }
250 : }
251 48 : return true;
252 : }
253 : else
254 : {
255 0 : CPLError(CE_Failure, CPLE_AppDefined,
256 : "SCHEMA info is invalid JSON");
257 0 : return false;
258 : }
259 : }
260 : else
261 : {
262 0 : CPLError(CE_Failure, CPLE_AppDefined, "SCHEMA info is invalid JSON");
263 0 : return false;
264 : }
265 : }
266 :
267 48 : bool OGRSchemaOverride::IsValid() const
268 : {
269 48 : bool isValid = !m_aoLayerOverrides.empty();
270 99 : for (const auto &oLayerOverride : m_aoLayerOverrides)
271 : {
272 51 : isValid &= oLayerOverride.IsValid();
273 : }
274 48 : return isValid;
275 : }
276 :
277 24 : bool OGRSchemaOverride::DefaultApply(
278 : GDALDataset *poDS, const char *pszDebugKey,
279 : std::function<void(OGRLayer *, int)> callbackWhenRemovingField) const
280 : {
281 24 : const auto &oLayerOverrides = GetLayerOverrides();
282 44 : for (const auto &oLayerFieldOverride : oLayerOverrides)
283 : {
284 25 : const auto &osLayerName = oLayerFieldOverride.GetLayerName();
285 25 : const bool bIsFullOverride{oLayerFieldOverride.IsFullOverride()};
286 : auto oNamedFieldOverrides =
287 25 : oLayerFieldOverride.GetNamedFieldOverrides();
288 : const auto &oUnnamedFieldOverrides =
289 25 : oLayerFieldOverride.GetUnnamedFieldOverrides();
290 :
291 : const auto ProcessLayer =
292 23 : [&callbackWhenRemovingField, &osLayerName, &oNamedFieldOverrides,
293 425 : &oUnnamedFieldOverrides, bIsFullOverride](OGRLayer *poLayer)
294 : {
295 46 : std::vector<OGRFieldDefn *> aoFields;
296 : // Patch field definitions
297 23 : auto poLayerDefn = poLayer->GetLayerDefn();
298 174 : for (int i = 0; i < poLayerDefn->GetFieldCount(); i++)
299 : {
300 151 : auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
301 :
302 : const auto PatchFieldDefn =
303 72 : [poFieldDefn](const OGRFieldDefnOverride &oFieldOverride)
304 : {
305 32 : if (oFieldOverride.GetFieldType().has_value())
306 36 : whileUnsealing(poFieldDefn)
307 18 : ->SetType(oFieldOverride.GetFieldType().value());
308 32 : if (oFieldOverride.GetFieldWidth().has_value())
309 6 : whileUnsealing(poFieldDefn)
310 3 : ->SetWidth(oFieldOverride.GetFieldWidth().value());
311 32 : if (oFieldOverride.GetFieldPrecision().has_value())
312 6 : whileUnsealing(poFieldDefn)
313 3 : ->SetPrecision(
314 3 : oFieldOverride.GetFieldPrecision().value());
315 32 : if (oFieldOverride.GetFieldSubType().has_value())
316 26 : whileUnsealing(poFieldDefn)
317 13 : ->SetSubType(
318 13 : oFieldOverride.GetFieldSubType().value());
319 32 : if (oFieldOverride.GetFieldName().has_value())
320 6 : whileUnsealing(poFieldDefn)
321 6 : ->SetName(
322 6 : oFieldOverride.GetFieldName().value().c_str());
323 32 : };
324 :
325 : auto oFieldOverrideIter =
326 151 : oNamedFieldOverrides.find(poFieldDefn->GetNameRef());
327 151 : if (oFieldOverrideIter != oNamedFieldOverrides.cend())
328 : {
329 26 : const auto &oFieldOverride = oFieldOverrideIter->second;
330 26 : PatchFieldDefn(oFieldOverride);
331 :
332 26 : if (bIsFullOverride)
333 : {
334 8 : aoFields.push_back(poFieldDefn);
335 : }
336 26 : oNamedFieldOverrides.erase(oFieldOverrideIter);
337 : }
338 : else
339 : {
340 130 : for (const auto &oFieldOverride : oUnnamedFieldOverrides)
341 : {
342 11 : if ((!oFieldOverride.GetSrcFieldType().has_value() ||
343 11 : oFieldOverride.GetSrcFieldType().value() ==
344 28 : poFieldDefn->GetType()) &&
345 6 : (!oFieldOverride.GetSrcFieldSubType().has_value() ||
346 12 : oFieldOverride.GetSrcFieldSubType().value() ==
347 1 : poFieldDefn->GetSubType()))
348 : {
349 6 : PatchFieldDefn(oFieldOverride);
350 6 : break;
351 : }
352 : }
353 : }
354 : }
355 :
356 : // Error if any field override is not found
357 23 : if (!oNamedFieldOverrides.empty())
358 : {
359 6 : CPLError(CE_Failure, CPLE_AppDefined,
360 : "Field %s not found in layer %s",
361 3 : oNamedFieldOverrides.cbegin()->first.c_str(),
362 : osLayerName.c_str());
363 3 : return false;
364 : }
365 :
366 : // Remove fields not in the override
367 20 : if (bIsFullOverride)
368 : {
369 35 : for (int i = poLayerDefn->GetFieldCount() - 1; i >= 0; i--)
370 : {
371 30 : auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
372 30 : if (std::find(aoFields.begin(), aoFields.end(),
373 30 : poFieldDefn) == aoFields.end())
374 : {
375 22 : callbackWhenRemovingField(poLayer, i);
376 22 : whileUnsealing(poLayerDefn)->DeleteFieldDefn(i);
377 : }
378 : }
379 : }
380 :
381 20 : return true;
382 25 : };
383 :
384 25 : CPLDebug(pszDebugKey, "Applying schema override for layer %s",
385 : osLayerName.c_str());
386 :
387 25 : if (osLayerName == "*")
388 : {
389 6 : for (auto *poLayer : poDS->GetLayers())
390 : {
391 3 : if (!ProcessLayer(poLayer))
392 0 : return false;
393 : }
394 : }
395 : else
396 : {
397 : // Fail if the layer name does not exist
398 22 : auto poLayer = poDS->GetLayerByName(osLayerName.c_str());
399 22 : if (poLayer == nullptr)
400 : {
401 2 : CPLError(CE_Failure, CPLE_AppDefined, "Layer %s not found",
402 : osLayerName.c_str());
403 2 : return false;
404 : }
405 20 : if (!ProcessLayer(poLayer))
406 3 : return false;
407 : }
408 : }
409 :
410 19 : return true;
411 : }
412 :
413 102 : bool OGRLayerSchemaOverride::IsValid() const
414 : {
415 : bool isValid =
416 204 : !m_osLayerName.empty() &&
417 102 : (!m_oNamedFieldOverrides.empty() || !m_aoUnnamedFieldOverrides.empty());
418 224 : for (const auto &oFieldOverrideIter : m_oNamedFieldOverrides)
419 : {
420 122 : isValid &= !oFieldOverrideIter.first.empty();
421 : // When schemaType is "full" override we don't need to check if the field
422 : // overrides are valid: a list of fields to keep is enough.
423 122 : if (!m_bIsFullOverride)
424 : {
425 98 : isValid &= oFieldOverrideIter.second.IsValid();
426 : }
427 : }
428 102 : return isValid;
429 : }
430 :
431 149 : bool OGRFieldDefnOverride::IsValid() const
432 : {
433 322 : return m_osName.has_value() || m_eType.has_value() ||
434 66 : m_eSubType.has_value() || m_eSrcType.has_value() ||
435 301 : m_eSrcSubType.has_value() || m_nWidth.has_value() ||
436 149 : m_nPrecision.has_value();
437 : }
438 :
439 : //! @endcond
|