Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: Parquet Translator 4 : * Purpose: Implements OGRParquetDriver. 5 : * Author: Even Rouault, <even.rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2022, Planet Labs 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "ogrsf_frmts.h" 14 : #include "gdal_priv.h" 15 : 16 : #include "ogrparquetdrivercore.h" 17 : 18 : /************************************************************************/ 19 : /* Identify() */ 20 : /************************************************************************/ 21 : 22 : template <size_t N> constexpr int constexpr_length(const char (&)[N]) 23 : { 24 : return static_cast<int>(N - 1); 25 : } 26 : 27 53127 : int OGRParquetDriverIdentify(GDALOpenInfo *poOpenInfo) 28 : { 29 : #if defined(GDAL_USE_ARROWDATASET) || defined(PLUGIN_FILENAME) 30 53127 : if (poOpenInfo->bIsDirectory) 31 : { 32 : // Might be a ParquetDataset 33 1174 : return -1; 34 : } 35 : #endif 36 51953 : if (STARTS_WITH(poOpenInfo->pszFilename, "PARQUET:")) 37 262 : return TRUE; 38 : 39 : // See https://github.com/apache/parquet-format#file-format 40 51691 : bool bRet = false; 41 51691 : constexpr const char SIGNATURE[] = "PAR1"; 42 51691 : constexpr int SIGNATURE_SIZE = constexpr_length(SIGNATURE); 43 : static_assert(SIGNATURE_SIZE == 4, "SIGNATURE_SIZE == 4"); 44 51691 : constexpr int METADATASIZE_SIZE = 4; 45 51691 : if (poOpenInfo->fpL != nullptr && 46 3663 : poOpenInfo->nHeaderBytes >= 47 3527 : SIGNATURE_SIZE + METADATASIZE_SIZE + SIGNATURE_SIZE && 48 3527 : memcmp(poOpenInfo->pabyHeader, SIGNATURE, SIGNATURE_SIZE) == 0) 49 : { 50 1750 : VSIFSeekL(poOpenInfo->fpL, 0, SEEK_END); 51 1750 : const auto nFileSize = VSIFTellL(poOpenInfo->fpL); 52 1750 : VSIFSeekL(poOpenInfo->fpL, 53 : nFileSize - (METADATASIZE_SIZE + SIGNATURE_SIZE), SEEK_SET); 54 1750 : uint32_t nMetadataSize = 0; 55 : static_assert(sizeof(nMetadataSize) == METADATASIZE_SIZE, 56 : "sizeof(nMetadataSize) == METADATASIZE_SIZE"); 57 1750 : VSIFReadL(&nMetadataSize, 1, sizeof(nMetadataSize), poOpenInfo->fpL); 58 1750 : CPL_LSBPTR32(&nMetadataSize); 59 1750 : unsigned char abyTrailingBytes[SIGNATURE_SIZE] = {0}; 60 1750 : VSIFReadL(&abyTrailingBytes[0], 1, SIGNATURE_SIZE, poOpenInfo->fpL); 61 3500 : bRet = memcmp(abyTrailingBytes, SIGNATURE, SIGNATURE_SIZE) == 0 && 62 1750 : nMetadataSize < nFileSize; 63 1750 : VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET); 64 : } 65 51691 : return bRet; 66 : } 67 : 68 : /************************************************************************/ 69 : /* OGRParquetDriverSetCommonMetadata() */ 70 : /************************************************************************/ 71 : 72 1777 : void OGRParquetDriverSetCommonMetadata(GDALDriver *poDriver) 73 : { 74 1777 : poDriver->SetDescription(DRIVER_NAME); 75 1777 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 76 1777 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 77 1777 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "(Geo)Parquet"); 78 1777 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "parquet"); 79 1777 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, 80 1777 : "drivers/vector/parquet.html"); 81 1777 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 82 1777 : poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES"); 83 1777 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); 84 1777 : poDriver->SetMetadataItem(GDAL_DCAP_REOPEN_AFTER_WRITE_REQUIRED, "YES"); 85 1777 : poDriver->SetMetadataItem(GDAL_DCAP_CAN_READ_AFTER_DELETE, "YES"); 86 : 87 1777 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); 88 1777 : poDriver->SetMetadataItem( 89 : GDAL_DMD_CREATIONFIELDDATATYPES, 90 : "Integer Integer64 Real String Date Time DateTime " 91 1777 : "Binary IntegerList Integer64List RealList StringList"); 92 1777 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, 93 1777 : "Boolean Int16 Float32 JSON UUID"); 94 1777 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS, 95 : "WidthPrecision Nullable Comment " 96 1777 : "AlternativeName Domain"); 97 1777 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 98 : 99 1777 : poDriver->SetMetadataItem( 100 : GDAL_DMD_OPENOPTIONLIST, 101 : "<OpenOptionList>" 102 : " <Option name='GEOM_POSSIBLE_NAMES' type='string' description='Comma " 103 : "separated list of possible names for geometry column(s).' " 104 : "default='geometry,wkb_geometry,wkt_geometry'/>" 105 : " <Option name='CRS' type='string' " 106 : "description='Set/override CRS, typically defined as AUTH:CODE " 107 : "(e.g EPSG:4326), of geometry column(s)'/>" 108 1777 : "</OpenOptionList>"); 109 : 110 1777 : poDriver->pfnIdentify = OGRParquetDriverIdentify; 111 1777 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 112 1777 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES"); 113 1777 : } 114 : 115 : /************************************************************************/ 116 : /* DeclareDeferredOGRParquetPlugin() */ 117 : /************************************************************************/ 118 : 119 : #ifdef PLUGIN_FILENAME 120 2024 : void DeclareDeferredOGRParquetPlugin() 121 : { 122 2024 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 123 : { 124 283 : return; 125 : } 126 1741 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); 127 : #ifdef PLUGIN_INSTALLATION_MESSAGE 128 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, 129 : PLUGIN_INSTALLATION_MESSAGE); 130 : #endif 131 1741 : OGRParquetDriverSetCommonMetadata(poDriver); 132 1741 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 133 : } 134 : #endif