LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/adbc - ogradbcbigquerylayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 562 0.0 %
Date: 2025-09-10 17:48:50 Functions: 0 16 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Arrow Database Connectivity driver
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
       9             :   *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogr_adbc.h"
      14             : #include "ogr_p.h"
      15             : 
      16             : #include <algorithm>
      17             : 
      18             : /************************************************************************/
      19             : /*                      OGRADBCBigQueryLayer()                          */
      20             : /************************************************************************/
      21             : 
      22           0 : OGRADBCBigQueryLayer::OGRADBCBigQueryLayer(OGRADBCDataset *poDS,
      23             :                                            const char *pszName,
      24             :                                            const std::string &osStatement,
      25           0 :                                            bool bInternalUse)
      26           0 :     : OGRADBCLayer(poDS, pszName, osStatement, bInternalUse)
      27             : {
      28           0 : }
      29             : 
      30             : /************************************************************************/
      31             : /*                     GetBigQueryDatasetAndTableId()                   */
      32             : /************************************************************************/
      33             : 
      34           0 : bool OGRADBCBigQueryLayer::GetBigQueryDatasetAndTableId(
      35             :     std::string &osDatasetId, std::string &osTableId) const
      36             : {
      37           0 :     auto nPos = CPLString(m_osBaseStatement).ifind(" FROM ");
      38           0 :     if (nPos != std::string::npos)
      39             :     {
      40           0 :         nPos += strlen(" FROM ");
      41           0 :         const auto nPos2 = m_osBaseStatement.find(' ', nPos);
      42             :         const std::string osTableName =
      43             :             (nPos2 != std::string::npos)
      44             :                 ? m_osBaseStatement.substr(nPos, nPos2 - nPos)
      45           0 :                 : m_osBaseStatement.substr(nPos);
      46             : 
      47           0 :         const auto nPosDot = osTableName.find('.');
      48           0 :         if (nPosDot != std::string::npos)
      49             :         {
      50           0 :             osDatasetId = osTableName.substr(0, nPosDot);
      51           0 :             osTableId = osTableName.substr(nPosDot + 1);
      52           0 :             if (osDatasetId.size() > 2 && osDatasetId[0] == '`' &&
      53           0 :                 osDatasetId.back() == '`')
      54           0 :                 osDatasetId = osDatasetId.substr(1, osDatasetId.size() - 2);
      55           0 :             if (osTableId.size() > 2 && osTableId[0] == '`' &&
      56           0 :                 osTableId.back() == '`')
      57           0 :                 osTableId = osTableId.substr(1, osTableId.size() - 2);
      58           0 :             return true;
      59             :         }
      60             :     }
      61           0 :     return false;
      62             : }
      63             : 
      64             : /************************************************************************/
      65             : /*                           BuildLayerDefn()                           */
      66             : /************************************************************************/
      67             : 
      68           0 : void OGRADBCBigQueryLayer::BuildLayerDefn()
      69             : {
      70           0 :     if (!BuildLayerDefnInit())
      71           0 :         return;
      72             : 
      73           0 :     std::map<std::string, std::unique_ptr<OGRSpatialReference>> oMapGeomColumns;
      74           0 :     std::map<std::string, bool> oMapIsNullable;
      75             : 
      76             :     const bool bIsLikelyTableExtract =
      77           0 :         !m_bInternalUse &&
      78           0 :         STARTS_WITH_CI(m_osBaseStatement.c_str(), "SELECT ") &&
      79           0 :         !STARTS_WITH_CI(m_osBaseStatement.c_str(), "SELECT COUNT(");
      80           0 :     if (bIsLikelyTableExtract)
      81             :     {
      82           0 :         std::string osDatasetId;
      83           0 :         std::string osTableId;
      84           0 :         if (GetBigQueryDatasetAndTableId(osDatasetId, osTableId))
      85             :         {
      86           0 :             auto poColumnList = m_poDS->CreateInternalLayer(CPLSPrintf(
      87             :                 "SELECT c.column_name, c.data_type, c.is_nullable, "
      88             :                 "keys.ordinal_position AS key_ordinal_position, "
      89             :                 "keys.position_in_unique_constraint FROM "
      90             :                 "`%s`.INFORMATION_SCHEMA.COLUMNS c "
      91             :                 "LEFT JOIN `%s`.INFORMATION_SCHEMA.KEY_COLUMN_USAGE keys ON "
      92             :                 "c.table_schema = keys.table_schema AND "
      93             :                 "c.table_name = keys.table_name AND "
      94             :                 "c.column_name = keys.column_name "
      95             :                 "WHERE c.table_name='%s' AND c.is_hidden = 'NO' "
      96             :                 "ORDER BY c.ordinal_position",
      97           0 :                 OGRDuplicateCharacter(osDatasetId.c_str(), '`').c_str(),
      98           0 :                 OGRDuplicateCharacter(osDatasetId.c_str(), '`').c_str(),
      99           0 :                 OGRDuplicateCharacter(osTableId.c_str(), '\'').c_str()));
     100           0 :             if (poColumnList->GetLayerDefn()->GetFieldCount() == 5)
     101             :             {
     102           0 :                 for (auto &&f : *poColumnList)
     103             :                 {
     104           0 :                     constexpr int IDX_COL_NAME = 0;
     105           0 :                     constexpr int IDX_DATA_TYPE = 1;
     106           0 :                     constexpr int IDX_IS_NULLABLE = 2;
     107           0 :                     constexpr int IDX_KEY_ORDINAL_POSITION = 3;
     108           0 :                     constexpr int IDX_POSITION_IN_UNIQUE_CONSTRAINT = 4;
     109           0 :                     const char *pszColName = f->GetFieldAsString(IDX_COL_NAME);
     110           0 :                     const char *pszColType = f->GetFieldAsString(IDX_DATA_TYPE);
     111           0 :                     if (EQUAL(pszColType, "GEOGRAPHY"))
     112             :                     {
     113           0 :                         auto poSRS = std::make_unique<OGRSpatialReference>();
     114           0 :                         poSRS->SetAxisMappingStrategy(
     115             :                             OAMS_TRADITIONAL_GIS_ORDER);
     116           0 :                         poSRS->importFromEPSG(4326);
     117           0 :                         oMapGeomColumns[pszColName] = std::move(poSRS);
     118             :                     }
     119           0 :                     oMapIsNullable[pszColName] =
     120           0 :                         EQUAL(f->GetFieldAsString(IDX_IS_NULLABLE), "YES");
     121           0 :                     if (f->IsFieldNull(IDX_POSITION_IN_UNIQUE_CONSTRAINT) &&
     122           0 :                         !f->IsFieldNull(IDX_KEY_ORDINAL_POSITION))
     123             :                     {
     124           0 :                         if (EQUAL(pszColType, "INT64") &&
     125           0 :                             f->GetFieldAsInteger64(IDX_KEY_ORDINAL_POSITION) ==
     126           0 :                                 1 &&
     127           0 :                             m_osFIDColName.empty())
     128             :                         {
     129           0 :                             m_osFIDColName = pszColName;
     130             :                         }
     131             :                         else
     132             :                         {
     133           0 :                             m_osFIDColName.clear();
     134             :                         }
     135             :                     }
     136             :                 }
     137             : 
     138           0 :                 if (!oMapGeomColumns.empty())
     139             :                 {
     140           0 :                     std::string osNewStatement = "SELECT ";
     141           0 :                     for (int i = 0; i < m_schema.n_children; ++i)
     142             :                     {
     143           0 :                         if (i > 0)
     144           0 :                             osNewStatement += ", ";
     145           0 :                         const char *pszColName = m_schema.children[i]->name;
     146           0 :                         auto oIter = oMapGeomColumns.find(pszColName);
     147           0 :                         if (oIter != oMapGeomColumns.end())
     148             :                         {
     149           0 :                             osNewStatement += "ST_AsBinary(`";
     150             :                             osNewStatement +=
     151           0 :                                 OGRDuplicateCharacter(pszColName, '`');
     152           0 :                             osNewStatement += "`) AS ";
     153             :                         }
     154           0 :                         osNewStatement += '`';
     155             :                         osNewStatement +=
     156           0 :                             OGRDuplicateCharacter(pszColName, '`');
     157           0 :                         osNewStatement += '`';
     158             :                     }
     159           0 :                     m_osModifiedSelect = osNewStatement;
     160           0 :                     osNewStatement += " FROM (";
     161           0 :                     osNewStatement += m_osBaseStatement;
     162           0 :                     osNewStatement += " )";
     163             : 
     164             : #ifdef DEBUG_VEBOSE
     165             :                     CPLDebug("ADBC", "%s -> %s", m_osBaseStatement.c_str(),
     166             :                              osNewStatement.c_str());
     167             : #endif
     168             : 
     169           0 :                     CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     170           0 :                     if (ReplaceStatement(osNewStatement.c_str()))
     171             :                     {
     172           0 :                         m_osModifiedBaseStatement = std::move(osNewStatement);
     173             :                     }
     174             :                     else
     175             :                     {
     176           0 :                         m_osModifiedSelect.clear();
     177           0 :                         oMapGeomColumns.clear();
     178             :                     }
     179             :                 }
     180             :             }
     181             :         }
     182             :     }
     183             : 
     184           0 :     auto poLayerDefn = m_poAdapterLayer->GetLayerDefn();
     185             : 
     186           0 :     for (int i = 0; i < m_schema.n_children; ++i)
     187             :     {
     188           0 :         const char *pszColName = m_schema.children[i]->name;
     189           0 :         auto oIter = oMapGeomColumns.find(pszColName);
     190           0 :         if (oIter != oMapGeomColumns.end())
     191             :         {
     192           0 :             OGRGeomFieldDefn oGeomFieldDefn(pszColName, wkbUnknown);
     193           0 :             auto poSRS = std::move(oIter->second).release();
     194           0 :             if (poSRS)
     195             :             {
     196           0 :                 oGeomFieldDefn.SetSpatialRef(poSRS);
     197           0 :                 poSRS->Release();
     198             :             }
     199           0 :             poLayerDefn->AddGeomFieldDefn(&oGeomFieldDefn);
     200             :         }
     201             :         else
     202             :         {
     203           0 :             m_poAdapterLayer->CreateFieldFromArrowSchema(m_schema.children[i]);
     204             :         }
     205             :     }
     206             : 
     207           0 :     if (bIsLikelyTableExtract)
     208             :     {
     209           0 :         for (int i = 0; i < poLayerDefn->GetFieldCount(); ++i)
     210             :         {
     211           0 :             auto poFldDefn = poLayerDefn->GetFieldDefn(i);
     212           0 :             auto oIter = oMapIsNullable.find(poFldDefn->GetNameRef());
     213           0 :             if (oIter != oMapIsNullable.end())
     214           0 :                 poFldDefn->SetNullable(oIter->second);
     215             :         }
     216           0 :         for (int i = 0; i < poLayerDefn->GetGeomFieldCount(); ++i)
     217             :         {
     218           0 :             auto poGFldDefn = poLayerDefn->GetGeomFieldDefn(i);
     219           0 :             std::string osSQL = "SELECT DISTINCT ST_GeometryType(`";
     220           0 :             osSQL += OGRDuplicateCharacter(poGFldDefn->GetNameRef(), '`');
     221           0 :             osSQL += "`) FROM (";
     222           0 :             osSQL += m_osBaseStatement;
     223           0 :             osSQL += ')';
     224           0 :             auto poGeomTypeList = m_poDS->CreateInternalLayer(osSQL.c_str());
     225           0 :             if (poGeomTypeList->GetLayerDefn()->GetFieldCount() == 1)
     226             :             {
     227           0 :                 std::string osType;
     228           0 :                 for (auto &&f : *poGeomTypeList)
     229             :                 {
     230           0 :                     if (osType.empty())
     231             :                     {
     232           0 :                         osType = f->GetFieldAsString(0);
     233             :                     }
     234             :                     else
     235             :                     {
     236           0 :                         osType.clear();
     237           0 :                         break;
     238             :                     }
     239             :                 }
     240           0 :                 if (STARTS_WITH_CI(osType.c_str(), "ST_"))
     241             :                 {
     242           0 :                     poGFldDefn->SetType(
     243           0 :                         OGRFromOGCGeomType(osType.c_str() + strlen("ST_")));
     244             :                 }
     245             :             }
     246           0 :             auto oIter = oMapIsNullable.find(poGFldDefn->GetNameRef());
     247           0 :             if (oIter != oMapIsNullable.end())
     248           0 :                 poGFldDefn->SetNullable(oIter->second);
     249             :         }
     250             :     }
     251             : }
     252             : 
     253             : /***********************************************************************/
     254             : /*                         SetAttributeFilter()                        */
     255             : /***********************************************************************/
     256             : 
     257           0 : OGRErr OGRADBCBigQueryLayer::SetAttributeFilter(const char *pszFilter)
     258             : {
     259           0 :     if (!m_osModifiedSelect.empty())
     260             :     {
     261           0 :         m_osAttributeFilter = pszFilter ? pszFilter : "";
     262           0 :         return UpdateStatement() ? OGRERR_NONE : OGRERR_FAILURE;
     263             :     }
     264             :     else
     265             :     {
     266           0 :         return OGRLayer::SetAttributeFilter(pszFilter);
     267             :     }
     268             : }
     269             : 
     270             : /************************************************************************/
     271             : /*                           GetFeatureCount()                          */
     272             : /************************************************************************/
     273             : 
     274           0 : GIntBig OGRADBCBigQueryLayer::GetFeatureCount(int /*bForce*/)
     275             : {
     276           0 :     if (!m_poAdapterLayer)
     277           0 :         BuildLayerDefn();
     278           0 :     if (m_bLayerDefinitionError)
     279           0 :         return 0;
     280             : 
     281           0 :     auto nCount = GetFeatureCountSelectCountStar();
     282           0 :     if (nCount >= 0)
     283           0 :         return nCount;
     284             : 
     285           0 :     return GetFeatureCountArrow();
     286             : }
     287             : 
     288             : /************************************************************************/
     289             : /*                          TestCapability()                            */
     290             : /************************************************************************/
     291             : 
     292           0 : int OGRADBCBigQueryLayer::TestCapability(const char *pszCap) const
     293             : {
     294           0 :     if (!m_poAdapterLayer)
     295           0 :         const_cast<OGRADBCBigQueryLayer *>(this)->BuildLayerDefn();
     296             : 
     297           0 :     if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCCreateField))
     298           0 :         return m_poDS->GetAccess() == GA_Update;
     299             : 
     300           0 :     if (EQUAL(pszCap, OLCRandomWrite) || EQUAL(pszCap, OLCDeleteFeature))
     301           0 :         return m_poDS->GetAccess() == GA_Update && !m_osFIDColName.empty();
     302             : 
     303           0 :     return OGRADBCLayer::TestCapability(pszCap);
     304             : }
     305             : 
     306             : /************************************************************************/
     307             : /*                           IGetExtent()                               */
     308             : /************************************************************************/
     309             : 
     310           0 : OGRErr OGRADBCBigQueryLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
     311             :                                         bool bForce)
     312             : {
     313           0 :     if (!m_poAdapterLayer)
     314           0 :         BuildLayerDefn();
     315             : 
     316             :     const char *pszGeomColName =
     317           0 :         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetNameRef();
     318           0 :     std::string osSQL = "SELECT ST_Extent(`";
     319           0 :     osSQL += OGRDuplicateCharacter(pszGeomColName, '`');
     320           0 :     osSQL += "`) FROM (";
     321           0 :     osSQL += m_osBaseStatement;
     322           0 :     osSQL += ")";
     323           0 :     auto poExtentLayer = m_poDS->CreateInternalLayer(osSQL.c_str());
     324           0 :     if (poExtentLayer->GetLayerDefn()->GetFieldCount() == 4)
     325             :     {
     326           0 :         auto f = std::unique_ptr<OGRFeature>(poExtentLayer->GetNextFeature());
     327           0 :         if (f && f->IsFieldSetAndNotNull(0))
     328             :         {
     329           0 :             psExtent->MinX = f->GetFieldAsDouble(0);
     330           0 :             psExtent->MinY = f->GetFieldAsDouble(1);
     331           0 :             psExtent->MaxX = f->GetFieldAsDouble(2);
     332           0 :             psExtent->MaxY = f->GetFieldAsDouble(3);
     333           0 :             return OGRERR_NONE;
     334             :         }
     335             :         else
     336           0 :             return OGRERR_FAILURE;
     337             :     }
     338             : 
     339           0 :     return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
     340             : }
     341             : 
     342             : /************************************************************************/
     343             : /*                      GetCurrentStatement()                           */
     344             : /************************************************************************/
     345             : 
     346           0 : std::string OGRADBCBigQueryLayer::GetCurrentStatement() const
     347             : {
     348           0 :     if (!m_osAttributeFilter.empty() || m_poFilterGeom)
     349             :     {
     350           0 :         std::string osStatement(m_osModifiedSelect);
     351           0 :         osStatement.append(" FROM (")
     352           0 :             .append(m_osBaseStatement)
     353           0 :             .append(") WHERE ");
     354           0 :         if (m_poFilterGeom)
     355             :         {
     356           0 :             if (m_sFilterEnvelope.MinX > 180 || m_sFilterEnvelope.MinY > 90 ||
     357           0 :                 m_sFilterEnvelope.MaxX < -180 || m_sFilterEnvelope.MaxY < -90)
     358             :             {
     359           0 :                 osStatement.append(" FALSE");
     360           0 :                 return osStatement;
     361             :             }
     362           0 :             constexpr double EPSILON = 1e-8;
     363             :             const double dfMinX =
     364           0 :                 std::max(-180.0, m_sFilterEnvelope.MinX - EPSILON);
     365             :             const double dfMinY =
     366           0 :                 std::max(-90.0, m_sFilterEnvelope.MinY - EPSILON);
     367             :             const double dfMaxX =
     368           0 :                 std::min(180.0, m_sFilterEnvelope.MaxX + EPSILON);
     369             :             const double dfMaxY =
     370           0 :                 std::min(90.0, m_sFilterEnvelope.MaxY + EPSILON);
     371             :             const char *pszGeomColName =
     372           0 :                 m_poAdapterLayer->GetLayerDefn()
     373           0 :                     ->GetGeomFieldDefn(m_iGeomFieldFilter)
     374           0 :                     ->GetNameRef();
     375             :             osStatement +=
     376             :                 CPLSPrintf("ST_IntersectsBox(`%s`,%.17g,%.17g,%.17g,%.17g)",
     377           0 :                            OGRDuplicateCharacter(pszGeomColName, '`').c_str(),
     378           0 :                            dfMinX, dfMinY, dfMaxX, dfMaxY);
     379             :         }
     380           0 :         if (!m_osAttributeFilter.empty())
     381             :         {
     382           0 :             if (m_poFilterGeom)
     383           0 :                 osStatement.append(" AND ");
     384           0 :             osStatement.append("(");
     385           0 :             osStatement.append(m_osAttributeFilter);
     386           0 :             osStatement.append(")");
     387             :         }
     388             : 
     389             : #ifdef DEBUG_VEBOSE
     390             :         CPLDebug("ADBC", "%s", osStatement.c_str());
     391             : #endif
     392             : 
     393           0 :         return osStatement;
     394             :     }
     395             :     else
     396             :     {
     397           0 :         return m_osModifiedBaseStatement;
     398             :     }
     399             : }
     400             : 
     401             : /************************************************************************/
     402             : /*                           GetSQLType()                               */
     403             : /************************************************************************/
     404             : 
     405           0 : static std::string GetSQLType(const OGRFieldDefn *poField)
     406             : {
     407           0 :     switch (poField->GetType())
     408             :     {
     409           0 :         case OFTInteger:
     410           0 :             return poField->GetSubType() == OFSTBoolean ? "BOOLEAN" : "INTEGER";
     411           0 :         case OFTInteger64:
     412           0 :             return "INT64";
     413           0 :         case OFTReal:
     414           0 :             return "FLOAT64";
     415           0 :         case OFTDate:
     416           0 :             return "DATE";
     417           0 :         case OFTTime:
     418           0 :             return "TIME";
     419           0 :         case OFTDateTime:
     420           0 :             return "TIMESTAMP";
     421           0 :         case OFTString:
     422           0 :             return poField->GetSubType() == OFSTJSON ? "JSON" : "STRING";
     423           0 :         case OFTBinary:
     424           0 :             return "BYTES";
     425           0 :         case OFTStringList:
     426           0 :             return "ARRAY<STRING>";
     427           0 :         case OFTRealList:
     428           0 :             return "ARRAY<FLOAT64>";
     429           0 :         case OFTIntegerList:
     430           0 :             return "ARRAY<INTEGER>";
     431           0 :         case OFTInteger64List:
     432           0 :             return "ARRAY<INT64>";
     433           0 :         case OFTWideString:
     434             :         case OFTWideStringList:
     435           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Unsupported type");
     436           0 :             break;
     437             :     }
     438           0 :     return std::string();
     439             : }
     440             : 
     441             : /************************************************************************/
     442             : /*                           CreateField()                              */
     443             : /************************************************************************/
     444             : 
     445           0 : OGRErr OGRADBCBigQueryLayer::CreateField(const OGRFieldDefn *poField,
     446             :                                          int /*bApproxOK*/)
     447             : {
     448           0 :     if (m_poDS->GetAccess() != GA_Update)
     449             :     {
     450           0 :         CPLError(
     451             :             CE_Failure, CPLE_NotSupported,
     452             :             "CreateField() only supported on datasets opened in update mode");
     453           0 :         return OGRERR_FAILURE;
     454             :     }
     455           0 :     if (!m_poAdapterLayer)
     456           0 :         BuildLayerDefn();
     457           0 :     if (m_bLayerDefinitionError)
     458           0 :         return OGRERR_FAILURE;
     459             : 
     460           0 :     if (GetLayerDefn()->GetFieldIndex(poField->GetNameRef()) >= 0)
     461             :     {
     462           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Field '%s' already exists.",
     463             :                  poField->GetNameRef());
     464           0 :         return OGRERR_FAILURE;
     465             :     }
     466             : 
     467           0 :     const auto osSQLType = GetSQLType(poField);
     468           0 :     if (osSQLType.empty())
     469           0 :         return OGRERR_FAILURE;
     470             : 
     471           0 :     if (!m_bDeferredCreation)
     472             :     {
     473           0 :         std::string osDatasetId, osTableId;
     474           0 :         if (!GetBigQueryDatasetAndTableId(osDatasetId, osTableId))
     475             :         {
     476           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     477             :                      "CreateField(): cannot get dataset and table ID");
     478           0 :             return OGRERR_FAILURE;
     479             :         }
     480             : 
     481           0 :         std::string osSQL = "ALTER TABLE `";
     482           0 :         osSQL += OGRDuplicateCharacter(osDatasetId.c_str(), '`');
     483           0 :         osSQL += "`.`";
     484           0 :         osSQL += OGRDuplicateCharacter(osTableId.c_str(), '`');
     485           0 :         osSQL += "` ADD COLUMN `";
     486           0 :         osSQL += OGRDuplicateCharacter(poField->GetNameRef(), '`');
     487           0 :         osSQL += "` ";
     488           0 :         osSQL += osSQLType;
     489           0 :         if (m_poDS->CreateInternalLayer(osSQL.c_str())->GotError())
     490           0 :             return OGRERR_FAILURE;
     491             :     }
     492             : 
     493           0 :     return m_poAdapterLayer->CreateField(poField, false);
     494             : }
     495             : 
     496             : /************************************************************************/
     497             : /*                          GetFieldValue()                             */
     498             : /************************************************************************/
     499             : 
     500           0 : static std::string GetFieldValue(const OGRFieldDefn *poFldDefn,
     501             :                                  OGRFeature *poFeature, int iField)
     502             : {
     503           0 :     std::string osVal;
     504             : 
     505           0 :     if (poFeature->IsFieldNull(iField))
     506           0 :         osVal = "NULL";
     507             : 
     508           0 :     else if (poFldDefn->GetType() == OFTInteger ||
     509           0 :              poFldDefn->GetType() == OFTInteger64)
     510             :     {
     511           0 :         const auto nVal = poFeature->GetFieldAsInteger64(iField);
     512           0 :         if (poFldDefn->GetSubType() == OFSTBoolean)
     513           0 :             osVal = nVal ? "TRUE" : "FALSE";
     514             :         else
     515           0 :             osVal = std::to_string(nVal);
     516             :     }
     517           0 :     else if (poFldDefn->GetType() == OFTReal)
     518             :     {
     519           0 :         osVal = CPLSPrintf("%.17g", poFeature->GetFieldAsDouble(iField));
     520             :     }
     521           0 :     else if (poFldDefn->GetType() == OFTDate)
     522             :     {
     523             :         char szTmpFieldValue[OGR_SIZEOF_ISO8601_DATETIME_BUFFER];
     524           0 :         constexpr bool bAlwaysMillisecond = false;
     525           0 :         OGRGetISO8601DateTime(poFeature->GetRawFieldRef(iField),
     526             :                               bAlwaysMillisecond, szTmpFieldValue);
     527           0 :         szTmpFieldValue[strlen("YYYY-MM-DD")] = 0;
     528           0 :         osVal += "DATE \'";
     529           0 :         osVal += szTmpFieldValue;
     530           0 :         osVal += '\'';
     531             :     }
     532           0 :     else if (poFldDefn->GetType() == OFTDateTime)
     533             :     {
     534           0 :         osVal += '\'';
     535           0 :         osVal += poFeature->GetFieldAsISO8601DateTime(iField, nullptr);
     536           0 :         osVal += '\'';
     537             :     }
     538           0 :     else if (poFldDefn->GetType() == OFTBinary)
     539             :     {
     540           0 :         osVal += "b'";
     541           0 :         int nCount = 0;
     542           0 :         GByte *pabyVal = poFeature->GetFieldAsBinary(iField, &nCount);
     543           0 :         osVal.reserve(nCount * 4 + 4);
     544           0 :         for (int i = 0; i < nCount; ++i)
     545             :         {
     546           0 :             osVal += CPLSPrintf("\\x%02X", pabyVal[i]);
     547             :         }
     548           0 :         osVal += '\'';
     549             :     }
     550           0 :     else if (poFldDefn->GetType() == OFTStringList)
     551             :     {
     552           0 :         CSLConstList papszStr = poFeature->GetFieldAsStringList(iField);
     553           0 :         osVal += '[';
     554           0 :         for (int i = 0; papszStr && papszStr[i]; ++i)
     555             :         {
     556           0 :             if (i > 0)
     557           0 :                 osVal += ',';
     558           0 :             osVal += '\'';
     559           0 :             osVal += OGRDuplicateCharacter(papszStr[i], '\'');
     560           0 :             osVal += '\'';
     561             :         }
     562           0 :         osVal += ']';
     563             :     }
     564           0 :     else if (poFldDefn->GetType() == OFTIntegerList)
     565             :     {
     566           0 :         int nCount = 0;
     567           0 :         const int *panVals = poFeature->GetFieldAsIntegerList(iField, &nCount);
     568           0 :         osVal += '[';
     569           0 :         for (int i = 0; i < nCount; ++i)
     570             :         {
     571           0 :             if (i > 0)
     572           0 :                 osVal += ',';
     573           0 :             osVal += std::to_string(panVals[i]);
     574             :         }
     575           0 :         osVal += ']';
     576             :     }
     577           0 :     else if (poFldDefn->GetType() == OFTInteger64List)
     578             :     {
     579           0 :         int nCount = 0;
     580             :         const auto *panVals =
     581           0 :             poFeature->GetFieldAsInteger64List(iField, &nCount);
     582           0 :         osVal += '[';
     583           0 :         for (int i = 0; i < nCount; ++i)
     584             :         {
     585           0 :             if (i > 0)
     586           0 :                 osVal += ',';
     587           0 :             osVal += std::to_string(panVals[i]);
     588             :         }
     589           0 :         osVal += ']';
     590             :     }
     591           0 :     else if (poFldDefn->GetType() == OFTRealList)
     592             :     {
     593           0 :         int nCount = 0;
     594             :         const double *padfVals =
     595           0 :             poFeature->GetFieldAsDoubleList(iField, &nCount);
     596           0 :         osVal += '[';
     597           0 :         for (int i = 0; i < nCount; ++i)
     598             :         {
     599           0 :             if (i > 0)
     600           0 :                 osVal += ',';
     601           0 :             osVal += CPLSPrintf("%.17g", padfVals[i]);
     602             :         }
     603           0 :         osVal += ']';
     604             :     }
     605             :     else
     606             :     {
     607             :         // Cf https://cloud.google.com/bigquery/docs/json-data?hl=en#create_a_json_value
     608           0 :         if (poFldDefn->GetSubType() == OFSTJSON)
     609           0 :             osVal += "JSON ";
     610           0 :         osVal += '\'';
     611             :         osVal +=
     612           0 :             OGRDuplicateCharacter(poFeature->GetFieldAsString(iField), '\'');
     613           0 :         osVal += '\'';
     614             :     }
     615           0 :     return osVal;
     616             : }
     617             : 
     618             : /************************************************************************/
     619             : /*                          ICreateFeature()                            */
     620             : /************************************************************************/
     621             : 
     622           0 : OGRErr OGRADBCBigQueryLayer::ICreateFeature(OGRFeature *poFeature)
     623             : {
     624           0 :     if (m_poDS->GetAccess() != GA_Update)
     625             :     {
     626           0 :         CPLError(
     627             :             CE_Failure, CPLE_NotSupported,
     628             :             "CreateFeature() only supported on datasets opened in update mode");
     629           0 :         return OGRERR_FAILURE;
     630             :     }
     631           0 :     if (!m_poAdapterLayer)
     632           0 :         BuildLayerDefn();
     633           0 :     if (m_bDeferredCreation)
     634           0 :         RunDeferredCreation();
     635           0 :     if (m_bLayerDefinitionError)
     636           0 :         return OGRERR_FAILURE;
     637             : 
     638           0 :     std::string osDatasetId;
     639           0 :     std::string osTableId;
     640           0 :     if (!STARTS_WITH_CI(m_osBaseStatement.c_str(), "SELECT * FROM ") ||
     641           0 :         CPLString(m_osBaseStatement).ifind(" WHERE ") != std::string::npos ||
     642           0 :         !GetBigQueryDatasetAndTableId(osDatasetId, osTableId))
     643             :     {
     644           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     645             :                  "CreateFeature(): cannot get dataset and table ID");
     646           0 :         return OGRERR_FAILURE;
     647             :     }
     648             : 
     649           0 :     std::string osFieldNames;
     650           0 :     std::string osFieldValues;
     651             : 
     652           0 :     if (!m_osFIDColName.empty())
     653             :     {
     654           0 :         if (poFeature->GetFID() < 0)
     655             :         {
     656           0 :             if (m_nMaxFeatureID < 0)
     657             :             {
     658           0 :                 std::string osSQL = "SELECT MAX(`";
     659           0 :                 osSQL += OGRDuplicateCharacter(m_osFIDColName.c_str(), '`');
     660           0 :                 osSQL += "`) FROM (";
     661           0 :                 osSQL += m_osBaseStatement;
     662           0 :                 osSQL += ')';
     663             : 
     664           0 :                 auto poMaxFIDLayer = m_poDS->CreateInternalLayer(osSQL.c_str());
     665           0 :                 if (poMaxFIDLayer->GetLayerDefn()->GetFieldCount() != 1)
     666           0 :                     return OGRERR_FAILURE;
     667             :                 auto f = std::unique_ptr<OGRFeature>(
     668           0 :                     poMaxFIDLayer->GetNextFeature());
     669           0 :                 if (f)
     670           0 :                     m_nMaxFeatureID = f->GetFieldAsInteger64(0);
     671             :                 else
     672           0 :                     m_nMaxFeatureID = 0;
     673             :             }
     674           0 :             poFeature->SetFID(++m_nMaxFeatureID);
     675             :         }
     676           0 :         osFieldNames = m_osFIDColName;
     677           0 :         osFieldValues = std::to_string(poFeature->GetFID());
     678             :     }
     679             : 
     680           0 :     auto poFeatureDefn = GetLayerDefn();
     681           0 :     for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); ++i)
     682             :     {
     683           0 :         const char *pszName = poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef();
     684           0 :         if (!osFieldNames.empty())
     685           0 :             osFieldNames += ", ";
     686           0 :         osFieldNames += '`';
     687           0 :         osFieldNames += OGRDuplicateCharacter(pszName, '`');
     688           0 :         osFieldNames += '`';
     689             : 
     690           0 :         if (!osFieldValues.empty())
     691           0 :             osFieldValues += ", ";
     692             : 
     693           0 :         const auto poGeom = poFeature->GetGeomFieldRef(i);
     694           0 :         if (poGeom)
     695             :         {
     696           0 :             osFieldValues += "ST_GeogFromText('";
     697           0 :             char *pszWKT = nullptr;
     698           0 :             poGeom->exportToWkt(&pszWKT, wkbVariantIso);
     699           0 :             osFieldValues += pszWKT;
     700           0 :             CPLFree(pszWKT);
     701           0 :             osFieldValues += "')";
     702             :         }
     703             :         else
     704             :         {
     705           0 :             osFieldValues += "NULL";
     706             :         }
     707             :     }
     708           0 :     for (int i = 0; i < poFeatureDefn->GetFieldCount(); ++i)
     709             :     {
     710           0 :         const auto poFieldDefn = poFeatureDefn->GetFieldDefn(i);
     711           0 :         const char *pszName = poFieldDefn->GetNameRef();
     712           0 :         if (!EQUAL(pszName, m_osFIDColName.c_str()) && poFeature->IsFieldSet(i))
     713             :         {
     714           0 :             if (!osFieldNames.empty())
     715           0 :                 osFieldNames += ", ";
     716           0 :             osFieldNames += '`';
     717           0 :             osFieldNames += OGRDuplicateCharacter(pszName, '`');
     718           0 :             osFieldNames += '`';
     719             : 
     720           0 :             if (!osFieldValues.empty())
     721           0 :                 osFieldValues += ", ";
     722             : 
     723           0 :             osFieldValues += GetFieldValue(poFieldDefn, poFeature, i);
     724             :         }
     725             :     }
     726             : 
     727           0 :     std::string osSQL = "INSERT INTO `";
     728           0 :     osSQL += OGRDuplicateCharacter(osDatasetId, '`');
     729           0 :     osSQL += "`.`";
     730           0 :     osSQL += OGRDuplicateCharacter(osTableId, '`');
     731           0 :     osSQL += "` ";
     732           0 :     if (osFieldNames.empty())
     733             :     {
     734           0 :         osSQL += "DEFAULT VALUES";
     735             :     }
     736             :     else
     737             :     {
     738           0 :         osSQL += '(';
     739           0 :         osSQL += osFieldNames;
     740           0 :         osSQL += ") VALUES (";
     741           0 :         osSQL += osFieldValues;
     742           0 :         osSQL += ')';
     743             :     }
     744           0 :     return m_poDS->CreateInternalLayer(osSQL.c_str())->GotError()
     745           0 :                ? OGRERR_FAILURE
     746           0 :                : OGRERR_NONE;
     747             : }
     748             : 
     749             : /************************************************************************/
     750             : /*                           ISetFeature()                              */
     751             : /************************************************************************/
     752             : 
     753           0 : OGRErr OGRADBCBigQueryLayer::ISetFeature(OGRFeature *poFeature)
     754             : {
     755           0 :     if (m_poDS->GetAccess() != GA_Update)
     756             :     {
     757           0 :         CPLError(
     758             :             CE_Failure, CPLE_NotSupported,
     759             :             "SetFeature() only supported on datasets opened in update mode");
     760           0 :         return OGRERR_FAILURE;
     761             :     }
     762           0 :     if (m_osFIDColName.empty())
     763             :     {
     764           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     765             :                  "SetFeature() only supported on tables with a INT64 single "
     766             :                  "column primary key");
     767           0 :         return OGRERR_FAILURE;
     768             :     }
     769           0 :     if (poFeature->GetFID() < 0)
     770             :     {
     771           0 :         return OGRERR_NON_EXISTING_FEATURE;
     772             :     }
     773             : 
     774           0 :     if (!m_poAdapterLayer)
     775           0 :         BuildLayerDefn();
     776           0 :     if (m_bDeferredCreation)
     777           0 :         RunDeferredCreation();
     778           0 :     if (m_bLayerDefinitionError)
     779           0 :         return OGRERR_FAILURE;
     780             : 
     781           0 :     std::string osDatasetId;
     782           0 :     std::string osTableId;
     783           0 :     if (!STARTS_WITH_CI(m_osBaseStatement.c_str(), "SELECT * FROM ") ||
     784           0 :         CPLString(m_osBaseStatement).ifind(" WHERE ") != std::string::npos ||
     785           0 :         !GetBigQueryDatasetAndTableId(osDatasetId, osTableId))
     786             :     {
     787           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     788             :                  "SetFeature(): cannot get dataset and table ID");
     789           0 :         return OGRERR_FAILURE;
     790             :     }
     791             : 
     792           0 :     std::string osSQL = "UPDATE `";
     793           0 :     osSQL += OGRDuplicateCharacter(osDatasetId, '`');
     794           0 :     osSQL += "`.`";
     795           0 :     osSQL += OGRDuplicateCharacter(osTableId, '`');
     796           0 :     osSQL += "` SET ";
     797             : 
     798           0 :     bool bAddComma = false;
     799           0 :     const auto poFeatureDefn = GetLayerDefn();
     800             : 
     801           0 :     for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); ++i)
     802             :     {
     803           0 :         const char *pszName = poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef();
     804           0 :         if (bAddComma)
     805           0 :             osSQL += ", ";
     806           0 :         bAddComma = true;
     807           0 :         osSQL += '`';
     808           0 :         osSQL += OGRDuplicateCharacter(pszName, '`');
     809           0 :         osSQL += "` = ";
     810           0 :         const auto poGeom = poFeature->GetGeomFieldRef(i);
     811           0 :         if (poGeom)
     812             :         {
     813           0 :             osSQL += "ST_GeogFromText('";
     814           0 :             char *pszWKT = nullptr;
     815           0 :             poGeom->exportToWkt(&pszWKT, wkbVariantIso);
     816           0 :             osSQL += pszWKT;
     817           0 :             CPLFree(pszWKT);
     818           0 :             osSQL += "')";
     819             :         }
     820             :         else
     821             :         {
     822           0 :             osSQL += "NULL";
     823             :         }
     824             :     }
     825             : 
     826           0 :     for (int i = 0; i < poFeatureDefn->GetFieldCount(); ++i)
     827             :     {
     828           0 :         const auto poFieldDefn = poFeatureDefn->GetFieldDefn(i);
     829           0 :         const char *pszName = poFieldDefn->GetNameRef();
     830           0 :         if (!EQUAL(pszName, m_osFIDColName.c_str()) && poFeature->IsFieldSet(i))
     831             :         {
     832           0 :             if (bAddComma)
     833           0 :                 osSQL += ", ";
     834           0 :             bAddComma = true;
     835           0 :             osSQL += '`';
     836           0 :             osSQL += OGRDuplicateCharacter(pszName, '`');
     837           0 :             osSQL += "` = ";
     838           0 :             osSQL += GetFieldValue(poFieldDefn, poFeature, i);
     839             :         }
     840             :     }
     841             : 
     842           0 :     osSQL += " WHERE `";
     843           0 :     osSQL += OGRDuplicateCharacter(m_osFIDColName, '`');
     844           0 :     osSQL += "` = ";
     845           0 :     osSQL += std::to_string(poFeature->GetFID());
     846             : 
     847           0 :     return bAddComma && m_poDS->CreateInternalLayer(osSQL.c_str())->GotError()
     848           0 :                ? OGRERR_FAILURE
     849           0 :                : OGRERR_NONE;
     850             : }
     851             : 
     852             : /************************************************************************/
     853             : /*                           DeleteFeature()                            */
     854             : /************************************************************************/
     855             : 
     856           0 : OGRErr OGRADBCBigQueryLayer::DeleteFeature(GIntBig nFID)
     857             : {
     858           0 :     if (m_poDS->GetAccess() != GA_Update)
     859             :     {
     860           0 :         CPLError(
     861             :             CE_Failure, CPLE_NotSupported,
     862             :             "DeleteFeature() only supported on datasets opened in update mode");
     863           0 :         return OGRERR_FAILURE;
     864             :     }
     865           0 :     if (m_osFIDColName.empty())
     866             :     {
     867           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     868             :                  "DeleteFeature() only supported on tables with a INT64 single "
     869             :                  "column primary key");
     870           0 :         return OGRERR_FAILURE;
     871             :     }
     872           0 :     if (!m_poAdapterLayer)
     873           0 :         BuildLayerDefn();
     874           0 :     if (m_bDeferredCreation)
     875           0 :         RunDeferredCreation();
     876           0 :     if (m_bLayerDefinitionError)
     877           0 :         return OGRERR_FAILURE;
     878           0 :     if (nFID < 0)
     879           0 :         return OGRERR_NON_EXISTING_FEATURE;
     880             : 
     881           0 :     std::string osDatasetId;
     882           0 :     std::string osTableId;
     883           0 :     if (!GetBigQueryDatasetAndTableId(osDatasetId, osTableId))
     884             :     {
     885           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     886             :                  "DeleteFeature(): cannot get dataset and table ID");
     887           0 :         return OGRERR_FAILURE;
     888             :     }
     889             : 
     890           0 :     std::string osSQL = "DELETE FROM `";
     891           0 :     osSQL += OGRDuplicateCharacter(osDatasetId, '`');
     892           0 :     osSQL += "`.`";
     893           0 :     osSQL += OGRDuplicateCharacter(osTableId, '`');
     894           0 :     osSQL += "` WHERE `";
     895           0 :     osSQL += OGRDuplicateCharacter(m_osFIDColName, '`');
     896           0 :     osSQL += "` = ";
     897           0 :     osSQL += std::to_string(nFID);
     898             : 
     899           0 :     return m_poDS->CreateInternalLayer(osSQL.c_str())->GotError()
     900           0 :                ? OGRERR_FAILURE
     901           0 :                : OGRERR_NONE;
     902             : }
     903             : 
     904             : /************************************************************************/
     905             : /*                        SetDeferredCreation()                         */
     906             : /************************************************************************/
     907             : 
     908           0 : void OGRADBCBigQueryLayer::SetDeferredCreation(
     909             :     const char *pszFIDColName, const OGRGeomFieldDefn *poGeomFieldDefn)
     910             : {
     911           0 :     m_bDeferredCreation = true;
     912           0 :     m_osFIDColName = pszFIDColName;
     913           0 :     m_poAdapterLayer = std::make_unique<OGRArrowArrayToOGRFeatureAdapterLayer>(
     914           0 :         GetDescription());
     915           0 :     if (poGeomFieldDefn && poGeomFieldDefn->GetType() != wkbNone)
     916             :     {
     917           0 :         OGRGeomFieldDefn oFieldDefn(poGeomFieldDefn);
     918           0 :         if (oFieldDefn.GetNameRef()[0] == '\0')
     919           0 :             oFieldDefn.SetName("geog");
     920           0 :         m_poAdapterLayer->CreateGeomField(&oFieldDefn, false);
     921             :     }
     922           0 : }
     923             : 
     924             : /************************************************************************/
     925             : /*                        RunDeferredCreation()                         */
     926             : /************************************************************************/
     927             : 
     928           0 : bool OGRADBCBigQueryLayer::RunDeferredCreation()
     929             : {
     930           0 :     if (m_bDeferredCreation)
     931             :     {
     932           0 :         m_bDeferredCreation = false;
     933             : 
     934           0 :         auto poFeatureDefn = m_poAdapterLayer->GetLayerDefn();
     935           0 :         std::string osDatasetId;
     936           0 :         std::string osTableId;
     937           0 :         CPL_IGNORE_RET_VAL(
     938           0 :             GetBigQueryDatasetAndTableId(osDatasetId, osTableId));
     939             : 
     940           0 :         std::string osSQL = "CREATE TABLE `";
     941           0 :         osSQL += OGRDuplicateCharacter(osDatasetId.c_str(), '`');
     942           0 :         osSQL += "`.`";
     943           0 :         osSQL += OGRDuplicateCharacter(osTableId.c_str(), '`');
     944           0 :         osSQL += "` (";
     945           0 :         bool bAddComma = false;
     946           0 :         if (!m_osFIDColName.empty())
     947             :         {
     948           0 :             osSQL += '`';
     949           0 :             osSQL += OGRDuplicateCharacter(m_osFIDColName.c_str(), '`');
     950           0 :             osSQL += "` INT64 PRIMARY KEY NOT ENFORCED";
     951           0 :             bAddComma = true;
     952             :         }
     953           0 :         for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); ++i)
     954             :         {
     955           0 :             const auto poFieldDefn = poFeatureDefn->GetGeomFieldDefn(i);
     956           0 :             if (bAddComma)
     957           0 :                 osSQL += ", ";
     958           0 :             bAddComma = true;
     959           0 :             osSQL += '`';
     960           0 :             osSQL += OGRDuplicateCharacter(poFieldDefn->GetNameRef(), '`');
     961           0 :             osSQL += "` GEOGRAPHY";
     962           0 :             if (!poFieldDefn->IsNullable())
     963           0 :                 osSQL += " NOT NULL";
     964             :         }
     965           0 :         for (int i = 0; i < poFeatureDefn->GetFieldCount(); ++i)
     966             :         {
     967           0 :             const auto poFieldDefn = poFeatureDefn->GetFieldDefn(i);
     968           0 :             if (bAddComma)
     969           0 :                 osSQL += ", ";
     970           0 :             bAddComma = true;
     971           0 :             osSQL += '`';
     972           0 :             osSQL += OGRDuplicateCharacter(poFieldDefn->GetNameRef(), '`');
     973           0 :             osSQL += "` ";
     974           0 :             osSQL += GetSQLType(poFieldDefn);
     975           0 :             if (!poFieldDefn->IsNullable())
     976           0 :                 osSQL += " NOT NULL";
     977             :         }
     978           0 :         osSQL += ')';
     979             : 
     980           0 :         m_bLayerDefinitionError =
     981           0 :             m_poDS->CreateInternalLayer(osSQL.c_str())->GotError();
     982             :     }
     983           0 :     return !m_bLayerDefinitionError;
     984             : }

Generated by: LCOV version 1.14