LCOV - code coverage report
Current view: top level - frmts/tiledb - tiledbcommon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 144 197 73.1 %
Date: 2026-07-24 18:27:47 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL TileDB Driver
       4             :  * Purpose:  Implement GDAL TileDB Support based on https://www.tiledb.io
       5             :  * Author:   TileDB, Inc
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2023, TileDB, Inc
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "tiledbheaders.h"
      14             : #include "tiledbdrivercore.h"
      15             : 
      16             : TileDBDataset::~TileDBDataset() = default;
      17             : 
      18             : /************************************************************************/
      19             : /*                         VSI_to_tiledb_uri()                          */
      20             : /************************************************************************/
      21             : 
      22        1957 : CPLString TileDBDataset::VSI_to_tiledb_uri(const char *pszUri)
      23             : {
      24        1957 :     CPLString osUri;
      25             : 
      26        1957 :     if (STARTS_WITH_CI(pszUri, "/VSIS3/"))
      27           0 :         osUri.Printf("s3://%s", pszUri + 7);
      28        1957 :     else if (STARTS_WITH_CI(pszUri, "/VSIGS/"))
      29           0 :         osUri.Printf("gcs://%s", pszUri + 7);
      30        1957 :     else if (STARTS_WITH_CI(pszUri, "/VSIAZ/"))
      31           0 :         osUri.Printf("azure://%s", pszUri + 7);
      32             :     else
      33             :     {
      34        1957 :         osUri = pszUri;
      35             :         // tiledb (at least at 2.4.2 on Conda) wrongly interprets relative
      36             :         // directories on Windows as absolute ones.
      37        1957 :         if (CPLIsFilenameRelative(pszUri))
      38             :         {
      39         940 :             char *pszCurDir = CPLGetCurrentDir();
      40         940 :             if (pszCurDir)
      41         940 :                 osUri = CPLFormFilenameSafe(pszCurDir, pszUri, nullptr);
      42         940 :             CPLFree(pszCurDir);
      43             :         }
      44             :     }
      45             : 
      46        1957 :     return osUri;
      47             : }
      48             : 
      49             : /************************************************************************/
      50             : /*                         TileDBObjectExists()                         */
      51             : /************************************************************************/
      52        1580 : bool TileDBDataset::TileDBObjectExists(tiledb::Context &ctx,
      53             :                                        const std::string &osArrayUri)
      54             : {
      55        1580 :     const auto eType = tiledb::Object::object(ctx, osArrayUri).type();
      56        1580 :     return eType != tiledb::Object::Type::Invalid;
      57             : }
      58             : 
      59             : /************************************************************************/
      60             : /*                             AddFilter()                              */
      61             : /************************************************************************/
      62             : 
      63           2 : CPLErr TileDBDataset::AddFilter(tiledb::Context &ctx,
      64             :                                 tiledb::FilterList &filterList,
      65             :                                 const char *pszFilterName, const int level)
      66             : 
      67             : {
      68             :     try
      69             :     {
      70           2 :         if (pszFilterName == nullptr)
      71             :             filterList.add_filter(
      72           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_NONE)
      73           0 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      74           2 :         else if EQUAL (pszFilterName, "GZIP")
      75             :             filterList.add_filter(
      76           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_GZIP)
      77           0 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      78           2 :         else if EQUAL (pszFilterName, "ZSTD")
      79             :             filterList.add_filter(
      80           4 :                 tiledb::Filter(ctx, TILEDB_FILTER_ZSTD)
      81           2 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      82           0 :         else if EQUAL (pszFilterName, "LZ4")
      83             :             filterList.add_filter(
      84           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_LZ4)
      85           0 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      86           0 :         else if EQUAL (pszFilterName, "RLE")
      87             :             filterList.add_filter(
      88           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_RLE)
      89           0 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      90           0 :         else if EQUAL (pszFilterName, "BZIP2")
      91             :             filterList.add_filter(
      92           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_BZIP2)
      93           0 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      94           0 :         else if EQUAL (pszFilterName, "DOUBLE-DELTA")
      95             :             filterList.add_filter(
      96           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_DOUBLE_DELTA));
      97           0 :         else if EQUAL (pszFilterName, "POSITIVE-DELTA")
      98             :             filterList.add_filter(
      99           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_POSITIVE_DELTA));
     100             :         else
     101           0 :             return CE_Failure;
     102             : 
     103           2 :         return CE_None;
     104             :     }
     105           0 :     catch (const tiledb::TileDBError &e)
     106             :     {
     107           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     108           0 :         return CE_Failure;
     109             :     }
     110             : }
     111             : 
     112             : /************************************************************************/
     113             : /*                              Identify()                              */
     114             : /************************************************************************/
     115             : 
     116       51964 : int TileDBDataset::Identify(GDALOpenInfo *poOpenInfo)
     117             : 
     118             : {
     119       51964 :     int nRet = TileDBDriverIdentifySimplified(poOpenInfo);
     120       51964 :     if (nRet == GDAL_IDENTIFY_UNKNOWN)
     121             :     {
     122             :         try
     123             :         {
     124        2506 :             const char *pszConfig = CSLFetchNameValue(
     125        1253 :                 poOpenInfo->papszOpenOptions, "TILEDB_CONFIG");
     126        2506 :             tiledb::Context oCtx;
     127             : 
     128        1253 :             if (pszConfig != nullptr)
     129             :             {
     130           0 :                 tiledb::Config cfg(pszConfig);
     131           0 :                 oCtx = tiledb::Context(cfg);
     132             :             }
     133             :             else
     134             :             {
     135        1253 :                 tiledb::Config cfg;
     136        1253 :                 cfg["sm.enable_signal_handlers"] = "false";
     137        1253 :                 oCtx = tiledb::Context(cfg);
     138             :             }
     139             : 
     140             :             CPLString osArrayPath =
     141        2506 :                 TileDBDataset::VSI_to_tiledb_uri(poOpenInfo->pszFilename);
     142        1253 :             if (TileDBDataset::TileDBObjectExists(oCtx, osArrayPath))
     143         377 :                 nRet = TRUE;
     144             :             else
     145         876 :                 nRet = FALSE;
     146             :         }
     147           0 :         catch (...)
     148             :         {
     149           0 :             nRet = FALSE;
     150             :         }
     151             :     }
     152       51964 :     return nRet;
     153             : }
     154             : 
     155             : /************************************************************************/
     156             : /*                               Delete()                               */
     157             : /************************************************************************/
     158             : 
     159          16 : CPLErr TileDBDataset::Delete(const char *pszFilename)
     160             : 
     161             : {
     162             :     try
     163             :     {
     164          32 :         tiledb::Context ctx;
     165          32 :         tiledb::VFS vfs(ctx);
     166          32 :         CPLString osArrayPath = TileDBDataset::VSI_to_tiledb_uri(pszFilename);
     167             : 
     168          16 :         if (vfs.is_dir(osArrayPath))
     169             :         {
     170           0 :             vfs.remove_dir(osArrayPath);
     171           0 :             return CE_None;
     172             :         }
     173             :         else
     174          16 :             return CE_Failure;
     175             :     }
     176           0 :     catch (const tiledb::TileDBError &e)
     177             :     {
     178           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     179           0 :         return CE_Failure;
     180             :     }
     181             : }
     182             : 
     183             : /************************************************************************/
     184             : /*                                Open()                                */
     185             : /************************************************************************/
     186             : 
     187         252 : GDALDataset *TileDBDataset::Open(GDALOpenInfo *poOpenInfo)
     188             : 
     189             : {
     190             :     try
     191             :     {
     192         252 :         const auto eIdentify = TileDBDataset::Identify(poOpenInfo);
     193         252 :         if (eIdentify == GDAL_IDENTIFY_FALSE)
     194           5 :             return nullptr;
     195             : 
     196         247 :         if (STARTS_WITH_CI(poOpenInfo->pszFilename, "TILEDB:") &&
     197           2 :             !STARTS_WITH_CI(poOpenInfo->pszFilename, "TILEDB://"))
     198             :         {
     199             :             // subdataset URI so this is a raster
     200           2 :             return TileDBRasterDataset::Open(poOpenInfo,
     201           2 :                                              tiledb::Object::Type::Invalid);
     202             :         }
     203             :         else
     204             :         {
     205             :             const std::string osPath =
     206         490 :                 TileDBDataset::VSI_to_tiledb_uri(poOpenInfo->pszFilename);
     207             : 
     208         490 :             const char *pszConfig = CSLFetchNameValue(
     209         245 :                 poOpenInfo->papszOpenOptions, "TILEDB_CONFIG");
     210         490 :             tiledb::Context oCtx;
     211             : 
     212         245 :             if (pszConfig != nullptr)
     213             :             {
     214           0 :                 tiledb::Config cfg(pszConfig);
     215           0 :                 oCtx = tiledb::Context(cfg);
     216             :             }
     217             :             else
     218             :             {
     219         245 :                 tiledb::Config cfg;
     220         245 :                 cfg["sm.enable_signal_handlers"] = "false";
     221         245 :                 oCtx = tiledb::Context(cfg);
     222             :             }
     223             : 
     224             :             // identify() identifies this as a request for a TileDB dataset but not whether it exists
     225         466 :             if ((poOpenInfo->eAccess == GA_ReadOnly) &&
     226         221 :                 (!TileDBDataset::TileDBObjectExists(oCtx, osPath)))
     227             :             {
     228          55 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     229             :                          "Failed to open %s as an array or group.",
     230             :                          poOpenInfo->pszFilename);
     231          55 :                 return nullptr;
     232             :             }
     233             : 
     234         190 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0)
     235             :             {
     236          29 :                 return TileDBDataset::OpenMultiDimensional(poOpenInfo);
     237             :             }
     238             : 
     239         161 :             const auto eType = tiledb::Object::object(oCtx, osPath).type();
     240         322 :             std::string osDatasetType;
     241         161 :             if (eType == tiledb::Object::Type::Group)
     242             :             {
     243         240 :                 tiledb::Group group(oCtx, osPath, TILEDB_READ);
     244         120 :                 tiledb_datatype_t v_type = TILEDB_UINT8;
     245         120 :                 const void *v_r = nullptr;
     246         120 :                 uint32_t v_num = 0;
     247         120 :                 group.get_metadata(DATASET_TYPE_ATTRIBUTE_NAME, &v_type, &v_num,
     248             :                                    &v_r);
     249         116 :                 if (v_r && (v_type == TILEDB_UINT8 || v_type == TILEDB_CHAR ||
     250         116 :                             v_type == TILEDB_STRING_ASCII ||
     251         236 :                             v_type == TILEDB_STRING_UTF8))
     252             :                 {
     253             :                     osDatasetType =
     254         116 :                         std::string(static_cast<const char *>(v_r), v_num);
     255             :                 }
     256             :             }
     257             : 
     258         159 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
     259         436 :                 eType == tiledb::Object::Type::Group &&
     260         235 :                 (osDatasetType.empty() ||
     261         116 :                  osDatasetType == GEOMETRY_DATASET_TYPE))
     262             :             {
     263           3 :                 return OGRTileDBDataset::Open(poOpenInfo, eType);
     264             :             }
     265         452 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
     266         136 :                      (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0 &&
     267         294 :                      eType == tiledb::Object::Type::Group &&
     268           1 :                      osDatasetType == GEOMETRY_DATASET_TYPE)
     269             :             {
     270           0 :                 return nullptr;
     271             :             }
     272         136 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
     273         294 :                      eType == tiledb::Object::Type::Group &&
     274         117 :                      osDatasetType == RASTER_DATASET_TYPE)
     275             :             {
     276         116 :                 return TileDBRasterDataset::Open(poOpenInfo, eType);
     277             :             }
     278         124 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
     279          40 :                      (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
     280          82 :                      eType == tiledb::Object::Type::Group &&
     281           0 :                      osDatasetType == RASTER_DATASET_TYPE)
     282             :             {
     283           0 :                 return nullptr;
     284             :             }
     285          20 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
     286          62 :                      eType == tiledb::Object::Type::Group &&
     287           1 :                      osDatasetType.empty())
     288             :             {
     289             :                 // Compatibility with generic arrays
     290             :                 // If this is a group which has only a single 2D array and
     291             :                 // no 3D+ arrays, then return this 2D array.
     292             :                 auto poDSUnique = std::unique_ptr<GDALDataset>(
     293           2 :                     TileDBDataset::OpenMultiDimensional(poOpenInfo));
     294           1 :                 if (poDSUnique)
     295             :                 {
     296           1 :                     auto poRootGroup = poDSUnique->GetRootGroup();
     297           1 :                     if (poRootGroup && poRootGroup->GetGroupNames().empty())
     298             :                     {
     299           0 :                         std::shared_ptr<GDALMDArray> poCandidateArray;
     300           4 :                         for (const auto &osName :
     301           9 :                              poRootGroup->GetMDArrayNames())
     302             :                         {
     303           4 :                             auto poArray = poRootGroup->OpenMDArray(osName);
     304           4 :                             if (poArray && poArray->GetDimensionCount() >= 3)
     305             :                             {
     306           0 :                                 poCandidateArray.reset();
     307           0 :                                 break;
     308             :                             }
     309           8 :                             else if (poArray &&
     310           9 :                                      poArray->GetDimensionCount() == 2 &&
     311           1 :                                      poArray->GetDimensions()[0]->GetType() ==
     312           8 :                                          GDAL_DIM_TYPE_HORIZONTAL_Y &&
     313           1 :                                      poArray->GetDimensions()[1]->GetType() ==
     314             :                                          GDAL_DIM_TYPE_HORIZONTAL_X)
     315             :                             {
     316           1 :                                 if (!poCandidateArray)
     317             :                                 {
     318           1 :                                     poCandidateArray = std::move(poArray);
     319             :                                 }
     320             :                                 else
     321             :                                 {
     322           0 :                                     poCandidateArray.reset();
     323           0 :                                     break;
     324             :                                 }
     325             :                             }
     326             :                         }
     327           1 :                         if (poCandidateArray)
     328             :                         {
     329           1 :                             return poCandidateArray->AsClassicDataset(1, 0);
     330             :                         }
     331             :                     }
     332             :                 }
     333           0 :                 return nullptr;
     334             :             }
     335             : 
     336          82 :             tiledb::ArraySchema schema(oCtx, osPath);
     337             : 
     338          41 :             if (schema.array_type() == TILEDB_SPARSE)
     339          35 :                 return OGRTileDBDataset::Open(poOpenInfo, eType);
     340             :             else
     341           6 :                 return TileDBRasterDataset::Open(poOpenInfo, eType);
     342             :         }
     343             :     }
     344           0 :     catch (const tiledb::TileDBError &e)
     345             :     {
     346           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     347           0 :         return nullptr;
     348             :     }
     349             : }
     350             : 
     351             : /************************************************************************/
     352             : /*                               Create()                               */
     353             : /************************************************************************/
     354             : 
     355         114 : GDALDataset *TileDBDataset::Create(const char *pszFilename, int nXSize,
     356             :                                    int nYSize, int nBandsIn, GDALDataType eType,
     357             :                                    CSLConstList papszOptions)
     358             : 
     359             : {
     360             :     try
     361             :     {
     362         114 :         if (nBandsIn > 0)
     363          64 :             return TileDBRasterDataset::Create(pszFilename, nXSize, nYSize,
     364          64 :                                                nBandsIn, eType, papszOptions);
     365             :         else
     366          50 :             return OGRTileDBDataset::Create(pszFilename, papszOptions);
     367             :     }
     368           0 :     catch (const tiledb::TileDBError &e)
     369             :     {
     370           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     371             :     }
     372             : 
     373           0 :     return nullptr;
     374             : }
     375             : 
     376             : /************************************************************************/
     377             : /*                             CreateCopy()                             */
     378             : /************************************************************************/
     379             : 
     380          54 : GDALDataset *TileDBDataset::CreateCopy(const char *pszFilename,
     381             :                                        GDALDataset *poSrcDS, int bStrict,
     382             :                                        CSLConstList papszOptions,
     383             :                                        GDALProgressFunc pfnProgress,
     384             :                                        void *pProgressData)
     385             : 
     386             : {
     387          54 :     if (poSrcDS->GetRootGroup())
     388             :     {
     389           1 :         auto poDrv = GDALDriver::FromHandle(GDALGetDriverByName("TileDB"));
     390           1 :         if (poDrv)
     391             :         {
     392           1 :             return poDrv->DefaultCreateCopy(pszFilename, poSrcDS, bStrict,
     393             :                                             papszOptions, pfnProgress,
     394           1 :                                             pProgressData);
     395             :         }
     396             :     }
     397             : 
     398             :     try
     399             :     {
     400          55 :         if (poSrcDS->GetRasterCount() > 0 ||
     401           2 :             poSrcDS->GetMetadata(GDAL_MDD_SUBDATASETS))
     402             :         {
     403          52 :             return TileDBRasterDataset::CreateCopy(pszFilename, poSrcDS,
     404             :                                                    bStrict, papszOptions,
     405          52 :                                                    pfnProgress, pProgressData);
     406             :         }
     407             :     }
     408           0 :     catch (const tiledb::TileDBError &e)
     409             :     {
     410           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     411             :     }
     412             : 
     413           1 :     return nullptr;
     414             : }
     415             : 
     416             : /************************************************************************/
     417             : /*                        GDALRegister_TILEDB()                         */
     418             : /************************************************************************/
     419             : 
     420          27 : void GDALRegister_TileDB()
     421             : 
     422             : {
     423          27 :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
     424           0 :         return;
     425             : 
     426          27 :     GDALDriver *poDriver = new GDALDriver();
     427          27 :     TileDBDriverSetCommonMetadata(poDriver);
     428             : 
     429          27 :     poDriver->pfnIdentify = TileDBDataset::Identify;
     430          27 :     poDriver->pfnOpen = TileDBDataset::Open;
     431          27 :     poDriver->pfnCreate = TileDBDataset::Create;
     432          27 :     poDriver->pfnCreateCopy = TileDBDataset::CreateCopy;
     433          27 :     poDriver->pfnDelete = TileDBDataset::Delete;
     434          27 :     poDriver->pfnCreateMultiDimensional = TileDBDataset::CreateMultiDimensional;
     435             : 
     436          27 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     437             : }

Generated by: LCOV version 1.14