LCOV - code coverage report
Current view: top level - ogr - ogr_schema_override.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 315 385 81.8 %
Date: 2026-04-26 09:06:16 Functions: 25 27 92.6 %

          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

Generated by: LCOV version 1.14