LCOV - code coverage report
Current view: top level - frmts/tiledb - tiledbcommon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 142 190 74.7 %
Date: 2025-07-12 19:59:49 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        1863 : CPLString TileDBDataset::VSI_to_tiledb_uri(const char *pszUri)
      23             : {
      24        1863 :     CPLString osUri;
      25             : 
      26        1863 :     if (STARTS_WITH_CI(pszUri, "/VSIS3/"))
      27           3 :         osUri.Printf("s3://%s", pszUri + 7);
      28        1860 :     else if (STARTS_WITH_CI(pszUri, "/VSIGS/"))
      29           0 :         osUri.Printf("gcs://%s", pszUri + 7);
      30        1860 :     else if (STARTS_WITH_CI(pszUri, "/VSIAZ/"))
      31           0 :         osUri.Printf("azure://%s", pszUri + 7);
      32             :     else
      33             :     {
      34        1860 :         osUri = pszUri;
      35             :         // tiledb (at least at 2.4.2 on Conda) wrongly interprets relative
      36             :         // directories on Windows as absolute ones.
      37        1860 :         if (CPLIsFilenameRelative(pszUri))
      38             :         {
      39         889 :             char *pszCurDir = CPLGetCurrentDir();
      40         889 :             if (pszCurDir)
      41         889 :                 osUri = CPLFormFilenameSafe(pszCurDir, pszUri, nullptr);
      42         889 :             CPLFree(pszCurDir);
      43             :         }
      44             :     }
      45             : 
      46        1863 :     return osUri;
      47             : }
      48             : 
      49             : /************************************************************************/
      50             : /*                      TileDBObjectExists()                            */
      51             : /************************************************************************/
      52        1486 : bool TileDBDataset::TileDBObjectExists(const std::string &osArrayUri)
      53             : {
      54        1489 :     tiledb::Context ctx;
      55        1486 :     const auto eType = tiledb::Object::object(ctx, osArrayUri).type();
      56        2966 :     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       45677 : int TileDBDataset::Identify(GDALOpenInfo *poOpenInfo)
     117             : 
     118             : {
     119       45677 :     int nRet = TileDBDriverIdentifySimplified(poOpenInfo);
     120       45673 :     if (nRet == GDAL_IDENTIFY_UNKNOWN)
     121             :     {
     122             :         try
     123             :         {
     124        2318 :             tiledb::Context ctx;
     125             :             CPLString osArrayPath =
     126        2318 :                 TileDBDataset::VSI_to_tiledb_uri(poOpenInfo->pszFilename);
     127        1159 :             if (TileDBDataset::TileDBObjectExists(osArrayPath))
     128         377 :                 nRet = TRUE;
     129             :             else
     130         779 :                 nRet = FALSE;
     131             :         }
     132           3 :         catch (...)
     133             :         {
     134           3 :             nRet = FALSE;
     135             :         }
     136             :     }
     137       45674 :     return nRet;
     138             : }
     139             : 
     140             : /************************************************************************/
     141             : /*                              Delete()                                */
     142             : /************************************************************************/
     143             : 
     144          16 : CPLErr TileDBDataset::Delete(const char *pszFilename)
     145             : 
     146             : {
     147             :     try
     148             :     {
     149          32 :         tiledb::Context ctx;
     150          32 :         tiledb::VFS vfs(ctx);
     151          32 :         CPLString osArrayPath = TileDBDataset::VSI_to_tiledb_uri(pszFilename);
     152             : 
     153          16 :         if (vfs.is_dir(osArrayPath))
     154             :         {
     155           0 :             vfs.remove_dir(osArrayPath);
     156           0 :             return CE_None;
     157             :         }
     158             :         else
     159          16 :             return CE_Failure;
     160             :     }
     161           0 :     catch (const tiledb::TileDBError &e)
     162             :     {
     163           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     164           0 :         return CE_Failure;
     165             :     }
     166             : }
     167             : 
     168             : /************************************************************************/
     169             : /*                                Open()                                */
     170             : /************************************************************************/
     171             : 
     172         252 : GDALDataset *TileDBDataset::Open(GDALOpenInfo *poOpenInfo)
     173             : 
     174             : {
     175             :     try
     176             :     {
     177         252 :         const auto eIdentify = TileDBDataset::Identify(poOpenInfo);
     178         252 :         if (eIdentify == GDAL_IDENTIFY_FALSE)
     179           5 :             return nullptr;
     180             : 
     181         247 :         if (STARTS_WITH_CI(poOpenInfo->pszFilename, "TILEDB:") &&
     182           2 :             !STARTS_WITH_CI(poOpenInfo->pszFilename, "TILEDB://"))
     183             :         {
     184             :             // subdataset URI so this is a raster
     185           2 :             return TileDBRasterDataset::Open(poOpenInfo,
     186           2 :                                              tiledb::Object::Type::Invalid);
     187             :         }
     188             :         else
     189             :         {
     190             :             const std::string osPath =
     191         490 :                 TileDBDataset::VSI_to_tiledb_uri(poOpenInfo->pszFilename);
     192             : 
     193             :             // identify() identifies this as a request for a TileDB dataset but not whether it exists
     194         466 :             if ((poOpenInfo->eAccess == GA_ReadOnly) &&
     195         221 :                 (!TileDBDataset::TileDBObjectExists(osPath)))
     196             :             {
     197          55 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     198             :                          "Failed to open %s as an array or group.",
     199             :                          poOpenInfo->pszFilename);
     200          55 :                 return nullptr;
     201             :             }
     202             : 
     203         190 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0)
     204             :             {
     205          29 :                 return TileDBDataset::OpenMultiDimensional(poOpenInfo);
     206             :             }
     207             : 
     208         322 :             const char *pszConfig = CSLFetchNameValue(
     209         161 :                 poOpenInfo->papszOpenOptions, "TILEDB_CONFIG");
     210         322 :             tiledb::Context oCtx;
     211             : 
     212         161 :             if (pszConfig != nullptr)
     213             :             {
     214           0 :                 tiledb::Config cfg(pszConfig);
     215           0 :                 oCtx = tiledb::Context(cfg);
     216             :             }
     217             :             else
     218             :             {
     219         161 :                 tiledb::Config cfg;
     220         161 :                 cfg["sm.enable_signal_handlers"] = "false";
     221         161 :                 oCtx = tiledb::Context(cfg);
     222             :             }
     223             : 
     224         161 :             const auto eType = tiledb::Object::object(oCtx, osPath).type();
     225         322 :             std::string osDatasetType;
     226         161 :             if (eType == tiledb::Object::Type::Group)
     227             :             {
     228         240 :                 tiledb::Group group(oCtx, osPath, TILEDB_READ);
     229         120 :                 tiledb_datatype_t v_type = TILEDB_UINT8;
     230         120 :                 const void *v_r = nullptr;
     231         120 :                 uint32_t v_num = 0;
     232         120 :                 group.get_metadata(DATASET_TYPE_ATTRIBUTE_NAME, &v_type, &v_num,
     233             :                                    &v_r);
     234         116 :                 if (v_r && (v_type == TILEDB_UINT8 || v_type == TILEDB_CHAR ||
     235         116 :                             v_type == TILEDB_STRING_ASCII ||
     236         236 :                             v_type == TILEDB_STRING_UTF8))
     237             :                 {
     238             :                     osDatasetType =
     239         116 :                         std::string(static_cast<const char *>(v_r), v_num);
     240             :                 }
     241             :             }
     242             : 
     243          61 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
     244         245 :                 eType == tiledb::Object::Type::Group &&
     245          49 :                 (osDatasetType.empty() ||
     246          23 :                  osDatasetType == GEOMETRY_DATASET_TYPE))
     247             :             {
     248           3 :                 return OGRTileDBDataset::Open(poOpenInfo, eType);
     249             :             }
     250         452 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
     251         136 :                      (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0 &&
     252         294 :                      eType == tiledb::Object::Type::Group &&
     253          94 :                      osDatasetType == GEOMETRY_DATASET_TYPE)
     254             :             {
     255           0 :                 return nullptr;
     256             :             }
     257         136 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
     258         294 :                      eType == tiledb::Object::Type::Group &&
     259         117 :                      osDatasetType == RASTER_DATASET_TYPE)
     260             :             {
     261         116 :                 return TileDBRasterDataset::Open(poOpenInfo, eType);
     262             :             }
     263         119 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
     264          35 :                      (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
     265          77 :                      eType == tiledb::Object::Type::Group &&
     266           0 :                      osDatasetType == RASTER_DATASET_TYPE)
     267             :             {
     268           0 :                 return nullptr;
     269             :             }
     270          20 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
     271          62 :                      eType == tiledb::Object::Type::Group &&
     272           1 :                      osDatasetType.empty())
     273             :             {
     274             :                 // Compatibility with generic arrays
     275             :                 // If this is a group which has only a single 2D array and
     276             :                 // no 3D+ arrays, then return this 2D array.
     277             :                 auto poDSUnique = std::unique_ptr<GDALDataset>(
     278           2 :                     TileDBDataset::OpenMultiDimensional(poOpenInfo));
     279           1 :                 if (poDSUnique)
     280             :                 {
     281           1 :                     auto poRootGroup = poDSUnique->GetRootGroup();
     282           1 :                     if (poRootGroup && poRootGroup->GetGroupNames().empty())
     283             :                     {
     284           0 :                         std::shared_ptr<GDALMDArray> poCandidateArray;
     285           4 :                         for (const auto &osName :
     286           9 :                              poRootGroup->GetMDArrayNames())
     287             :                         {
     288           4 :                             auto poArray = poRootGroup->OpenMDArray(osName);
     289           4 :                             if (poArray && poArray->GetDimensionCount() >= 3)
     290             :                             {
     291           0 :                                 poCandidateArray.reset();
     292           0 :                                 break;
     293             :                             }
     294           8 :                             else if (poArray &&
     295           9 :                                      poArray->GetDimensionCount() == 2 &&
     296           1 :                                      poArray->GetDimensions()[0]->GetType() ==
     297           8 :                                          GDAL_DIM_TYPE_HORIZONTAL_Y &&
     298           1 :                                      poArray->GetDimensions()[1]->GetType() ==
     299             :                                          GDAL_DIM_TYPE_HORIZONTAL_X)
     300             :                             {
     301           1 :                                 if (!poCandidateArray)
     302             :                                 {
     303           1 :                                     poCandidateArray = std::move(poArray);
     304             :                                 }
     305             :                                 else
     306             :                                 {
     307           0 :                                     poCandidateArray.reset();
     308           0 :                                     break;
     309             :                                 }
     310             :                             }
     311             :                         }
     312           1 :                         if (poCandidateArray)
     313             :                         {
     314           1 :                             return poCandidateArray->AsClassicDataset(1, 0);
     315             :                         }
     316             :                     }
     317             :                 }
     318           0 :                 return nullptr;
     319             :             }
     320             : 
     321          82 :             tiledb::ArraySchema schema(oCtx, osPath);
     322             : 
     323          41 :             if (schema.array_type() == TILEDB_SPARSE)
     324          35 :                 return OGRTileDBDataset::Open(poOpenInfo, eType);
     325             :             else
     326           6 :                 return TileDBRasterDataset::Open(poOpenInfo, eType);
     327             :         }
     328             :     }
     329           0 :     catch (const tiledb::TileDBError &e)
     330             :     {
     331           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     332           0 :         return nullptr;
     333             :     }
     334             : }
     335             : 
     336             : /************************************************************************/
     337             : /*                              Create()                                */
     338             : /************************************************************************/
     339             : 
     340         114 : GDALDataset *TileDBDataset::Create(const char *pszFilename, int nXSize,
     341             :                                    int nYSize, int nBandsIn, GDALDataType eType,
     342             :                                    char **papszOptions)
     343             : 
     344             : {
     345             :     try
     346             :     {
     347         114 :         if (nBandsIn > 0)
     348          64 :             return TileDBRasterDataset::Create(pszFilename, nXSize, nYSize,
     349          64 :                                                nBandsIn, eType, papszOptions);
     350             :         else
     351          50 :             return OGRTileDBDataset::Create(pszFilename, papszOptions);
     352             :     }
     353           0 :     catch (const tiledb::TileDBError &e)
     354             :     {
     355           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     356             :     }
     357             : 
     358           0 :     return nullptr;
     359             : }
     360             : 
     361             : /************************************************************************/
     362             : /*                              CreateCopy()                            */
     363             : /************************************************************************/
     364             : 
     365          54 : GDALDataset *TileDBDataset::CreateCopy(const char *pszFilename,
     366             :                                        GDALDataset *poSrcDS, int bStrict,
     367             :                                        char **papszOptions,
     368             :                                        GDALProgressFunc pfnProgress,
     369             :                                        void *pProgressData)
     370             : 
     371             : {
     372          54 :     if (poSrcDS->GetRootGroup())
     373             :     {
     374           1 :         auto poDrv = GDALDriver::FromHandle(GDALGetDriverByName("TileDB"));
     375           1 :         if (poDrv)
     376             :         {
     377           1 :             return poDrv->DefaultCreateCopy(pszFilename, poSrcDS, bStrict,
     378             :                                             papszOptions, pfnProgress,
     379           1 :                                             pProgressData);
     380             :         }
     381             :     }
     382             : 
     383             :     try
     384             :     {
     385          55 :         if (poSrcDS->GetRasterCount() > 0 ||
     386           2 :             poSrcDS->GetMetadata("SUBDATASETS"))
     387             :         {
     388          52 :             return TileDBRasterDataset::CreateCopy(pszFilename, poSrcDS,
     389             :                                                    bStrict, papszOptions,
     390          52 :                                                    pfnProgress, pProgressData);
     391             :         }
     392             :     }
     393           0 :     catch (const tiledb::TileDBError &e)
     394             :     {
     395           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     396             :     }
     397             : 
     398           1 :     return nullptr;
     399             : }
     400             : 
     401             : /************************************************************************/
     402             : /*                         GDALRegister_TILEDB()                        */
     403             : /************************************************************************/
     404             : 
     405          28 : void GDALRegister_TileDB()
     406             : 
     407             : {
     408          28 :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
     409           0 :         return;
     410             : 
     411          28 :     GDALDriver *poDriver = new GDALDriver();
     412          28 :     TileDBDriverSetCommonMetadata(poDriver);
     413             : 
     414          28 :     poDriver->pfnIdentify = TileDBDataset::Identify;
     415          28 :     poDriver->pfnOpen = TileDBDataset::Open;
     416          28 :     poDriver->pfnCreate = TileDBDataset::Create;
     417          28 :     poDriver->pfnCreateCopy = TileDBDataset::CreateCopy;
     418          28 :     poDriver->pfnDelete = TileDBDataset::Delete;
     419          28 :     poDriver->pfnCreateMultiDimensional = TileDBDataset::CreateMultiDimensional;
     420             : 
     421          28 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     422             : }

Generated by: LCOV version 1.14