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

Generated by: LCOV version 1.14