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