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) 2024, Even Rouault <even dot rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "ogrsf_frmts.h" 14 : #include "ogradbcdrivercore.h" 15 : #include "gdal_adbc.h" 16 : 17 : /************************************************************************/ 18 : /* IsDuckDB() */ 19 : /************************************************************************/ 20 : 21 18031 : bool OGRADBCDriverIsDuckDB(const GDALOpenInfo *poOpenInfo) 22 : { 23 18528 : return poOpenInfo->nHeaderBytes >= 20 && 24 497 : memcmp(poOpenInfo->pabyHeader + 8, "DUCK\x40\0\0\0\0\0\0\0", 25 18031 : 4 + 8) == 0; 26 : } 27 : 28 : /************************************************************************/ 29 : /* IsSQLite3() */ 30 : /************************************************************************/ 31 : 32 18024 : bool OGRADBCDriverIsSQLite3(const GDALOpenInfo *poOpenInfo) 33 : { 34 18024 : constexpr const char *SQLITE3_SIGNATURE = "SQLite format 3"; 35 18385 : return poOpenInfo->nHeaderBytes >= 512 && 36 361 : memcmp(poOpenInfo->pabyHeader, SQLITE3_SIGNATURE, 37 18024 : strlen(SQLITE3_SIGNATURE)) == 0; 38 : } 39 : 40 : /************************************************************************/ 41 : /* IsParquet() */ 42 : /************************************************************************/ 43 : 44 18031 : bool OGRADBCDriverIsParquet(const GDALOpenInfo *poOpenInfo) 45 : { 46 18031 : constexpr const char *PARQUET_SIGNATURE = "PAR1"; 47 18031 : return poOpenInfo->nHeaderBytes >= 48 18553 : static_cast<int>(strlen(PARQUET_SIGNATURE)) && 49 522 : memcmp(poOpenInfo->pabyHeader, PARQUET_SIGNATURE, 50 18031 : strlen(PARQUET_SIGNATURE)) == 0; 51 : } 52 : 53 : /************************************************************************/ 54 : /* OGRADBCDriverIdentify() */ 55 : /************************************************************************/ 56 : 57 49750 : int OGRADBCDriverIdentify(GDALOpenInfo *poOpenInfo) 58 : { 59 49750 : if (STARTS_WITH(poOpenInfo->pszFilename, "ADBC:")) 60 2 : return true; 61 : 62 49748 : if (STARTS_WITH(poOpenInfo->pszFilename, "/vsi")) 63 31718 : return false; 64 : 65 18030 : if (OGRADBCDriverIsDuckDB(poOpenInfo) || OGRADBCDriverIsParquet(poOpenInfo)) 66 : { 67 : #ifdef OGR_ADBC_HAS_DRIVER_MANAGER 68 : return true; 69 : #else 70 0 : const char *pszADBCDriverName = 71 : #ifdef _WIN32 72 : "duckdb.dll" 73 : #elif defined(__MACH__) && defined(__APPLE__) 74 : "libduckdb.dylib" 75 : #else 76 : "libduckdb.so" 77 : #endif 78 : ; 79 0 : return (GDALGetAdbcLoadDriverOverride() != nullptr || 80 0 : CPLGetSymbol(pszADBCDriverName, "duckdb_adbc_init") != nullptr); 81 : #endif 82 : } 83 : else 84 : { 85 36053 : return !poOpenInfo->IsExtensionEqualToCI("mbtiles") && 86 18023 : (OGRADBCDriverIsSQLite3(poOpenInfo) && 87 1 : ((!poOpenInfo->IsExtensionEqualToCI("gpkg") && 88 0 : (GDALGetDriverByName("SQLite") == nullptr || 89 1 : poOpenInfo->IsSingleAllowedDriver("ADBC"))) || 90 1 : (poOpenInfo->IsExtensionEqualToCI("gpkg") && 91 1 : (GDALGetDriverByName("GPKG") == nullptr || 92 1 : poOpenInfo->IsSingleAllowedDriver("ADBC"))))) 93 : #ifndef OGR_ADBC_HAS_DRIVER_MANAGER 94 36053 : && GDALGetAdbcLoadDriverOverride() != nullptr 95 : #endif 96 : ; 97 : } 98 : } 99 : 100 : /************************************************************************/ 101 : /* OGRADBCDriverSetCommonMetadata() */ 102 : /************************************************************************/ 103 : 104 2095 : void OGRADBCDriverSetCommonMetadata(GDALDriver *poDriver) 105 : { 106 2095 : poDriver->SetDescription(DRIVER_NAME); 107 2095 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 108 2095 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Arrow Database Connectivity"); 109 2095 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/adbc.html"); 110 : 111 2095 : poDriver->SetMetadataItem(GDAL_DMD_CONNECTION_PREFIX, "ADBC:"); 112 : 113 2095 : poDriver->SetMetadataItem( 114 : GDAL_DMD_OPENOPTIONLIST, 115 : "<OpenOptionList>" 116 : " <Option name='ADBC_DRIVER' type='string' description='ADBC driver " 117 : "name'/>" 118 : " <Option name='SQL' type='string' " 119 : "description='SQL statement from which to build layer'/>" 120 : " <Option name='ADBC_OPTION_*' type='string' " 121 : "description='Option to pass to AdbcDatabaseSetOption()'/>" 122 : " <Option name='PRELUDE_STATEMENTS' type='string' description='SQL " 123 : "statement(s) to send on the database connection before any other " 124 : "ones'/>" 125 : #ifdef OGR_ADBC_HAS_DRIVER_MANAGER 126 : " <Option name='BIGQUERY_PROJECT_ID' type='string' " 127 : "description='Google Project ID'/>" 128 : " <Option name='BIGQUERY_DATASET_ID' type='string' " 129 : "description='Google BigQuery dataset ID'/>" 130 : " <Option name='BIGQUERY_JSON_CREDENTIAL_STRING' type='string' " 131 : "description='JSON string containing Google credentials'/>" 132 : " <Option name='BIGQUERY_JSON_CREDENTIAL_FILE' type='string' " 133 : "description='Filename containing Google credentials'/>" 134 : #endif 135 2095 : "</OpenOptionList>"); 136 2095 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, 137 2095 : "NATIVE OGRSQL SQLITE"); 138 : #ifdef OGR_ADBC_HAS_DRIVER_MANAGER 139 : poDriver->SetMetadataItem("HAS_ADBC_DRIVER_MANAGER", "YES"); 140 : 141 : // For BigQuery 142 : poDriver->SetMetadataItem( 143 : GDAL_DS_LAYER_CREATIONOPTIONLIST, 144 : "<LayerCreationOptionList>" 145 : "<Option name='FID' type='string' " 146 : "description='Name of the FID column to create' default='ogc_fid'/>" 147 : "</LayerCreationOptionList>"); 148 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 149 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_LAYER, "YES"); 150 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); 151 : poDriver->SetMetadataItem( 152 : GDAL_DMD_CREATIONFIELDDATATYPES, 153 : "Integer Integer64 Real String Date Time DateTime Binary StringList " 154 : "IntegerList Integer64List RealList"); 155 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, 156 : "Boolean JSON"); 157 : poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES"); 158 : poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS, "Features"); 159 : #endif 160 : 161 2095 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 162 2095 : poDriver->pfnIdentify = OGRADBCDriverIdentify; 163 2095 : } 164 : 165 : /************************************************************************/ 166 : /* DeclareDeferredOGRADBCPlugin() */ 167 : /************************************************************************/ 168 : 169 : #ifdef PLUGIN_FILENAME 170 2024 : void DeclareDeferredOGRADBCPlugin() 171 : { 172 2024 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 173 : { 174 283 : return; 175 : } 176 1741 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); 177 : #ifdef PLUGIN_INSTALLATION_MESSAGE 178 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, 179 : PLUGIN_INSTALLATION_MESSAGE); 180 : #endif 181 1741 : OGRADBCDriverSetCommonMetadata(poDriver); 182 1741 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 183 : } 184 : #endif