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 46023 : int OGRParquetDriverIdentify(GDALOpenInfo *poOpenInfo) 28 : { 29 : #if defined(GDAL_USE_ARROWDATASET) || defined(PLUGIN_FILENAME) 30 46023 : if (poOpenInfo->bIsDirectory) 31 : { 32 : // Might be a ParquetDataset 33 942 : return -1; 34 : } 35 : #endif 36 45081 : if (STARTS_WITH(poOpenInfo->pszFilename, "PARQUET:")) 37 260 : return TRUE; 38 : 39 : // See https://github.com/apache/parquet-format#file-format 40 44821 : bool bRet = false; 41 44821 : constexpr const char SIGNATURE[] = "PAR1"; 42 44821 : constexpr int SIGNATURE_SIZE = constexpr_length(SIGNATURE); 43 : static_assert(SIGNATURE_SIZE == 4, "SIGNATURE_SIZE == 4"); 44 44821 : constexpr int METADATASIZE_SIZE = 4; 45 44821 : if (poOpenInfo->fpL != nullptr && 46 3267 : poOpenInfo->nHeaderBytes >= 47 3145 : SIGNATURE_SIZE + METADATASIZE_SIZE + SIGNATURE_SIZE && 48 3145 : memcmp(poOpenInfo->pabyHeader, SIGNATURE, SIGNATURE_SIZE) == 0) 49 : { 50 1695 : VSIFSeekL(poOpenInfo->fpL, 0, SEEK_END); 51 1695 : const auto nFileSize = VSIFTellL(poOpenInfo->fpL); 52 1695 : VSIFSeekL(poOpenInfo->fpL, 53 : nFileSize - (METADATASIZE_SIZE + SIGNATURE_SIZE), SEEK_SET); 54 1695 : uint32_t nMetadataSize = 0; 55 : static_assert(sizeof(nMetadataSize) == METADATASIZE_SIZE, 56 : "sizeof(nMetadataSize) == METADATASIZE_SIZE"); 57 1695 : VSIFReadL(&nMetadataSize, 1, sizeof(nMetadataSize), poOpenInfo->fpL); 58 1695 : CPL_LSBPTR32(&nMetadataSize); 59 1695 : unsigned char abyTrailingBytes[SIGNATURE_SIZE] = {0}; 60 1695 : VSIFReadL(&abyTrailingBytes[0], 1, SIGNATURE_SIZE, poOpenInfo->fpL); 61 3390 : bRet = memcmp(abyTrailingBytes, SIGNATURE, SIGNATURE_SIZE) == 0 && 62 1695 : nMetadataSize < nFileSize; 63 1695 : VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET); 64 : } 65 44821 : return bRet; 66 : } 67 : 68 : /************************************************************************/ 69 : /* OGRParquetDriverSetCommonMetadata() */ 70 : /************************************************************************/ 71 : 72 1323 : void OGRParquetDriverSetCommonMetadata(GDALDriver *poDriver) 73 : { 74 1323 : poDriver->SetDescription(DRIVER_NAME); 75 1323 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 76 1323 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 77 1323 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "(Geo)Parquet"); 78 1323 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "parquet"); 79 1323 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, 80 1323 : "drivers/vector/parquet.html"); 81 1323 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 82 1323 : poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES"); 83 1323 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); 84 : 85 1323 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); 86 1323 : poDriver->SetMetadataItem( 87 : GDAL_DMD_CREATIONFIELDDATATYPES, 88 : "Integer Integer64 Real String Date Time DateTime " 89 1323 : "Binary IntegerList Integer64List RealList StringList"); 90 1323 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, 91 1323 : "Boolean Int16 Float32 JSON UUID"); 92 1323 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS, 93 : "WidthPrecision Nullable Comment " 94 1323 : "AlternativeName Domain"); 95 1323 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 96 : 97 1323 : poDriver->SetMetadataItem( 98 : GDAL_DMD_OPENOPTIONLIST, 99 : "<OpenOptionList>" 100 : " <Option name='GEOM_POSSIBLE_NAMES' type='string' description='Comma " 101 : "separated list of possible names for geometry column(s).' " 102 : "default='geometry,wkb_geometry,wkt_geometry'/>" 103 : " <Option name='CRS' type='string' " 104 : "description='Set/override CRS, typically defined as AUTH:CODE " 105 : "(e.g EPSG:4326), of geometry column(s)'/>" 106 1323 : "</OpenOptionList>"); 107 : 108 1323 : poDriver->pfnIdentify = OGRParquetDriverIdentify; 109 1323 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 110 1323 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES"); 111 1323 : } 112 : 113 : /************************************************************************/ 114 : /* DeclareDeferredOGRParquetPlugin() */ 115 : /************************************************************************/ 116 : 117 : #ifdef PLUGIN_FILENAME 118 1595 : void DeclareDeferredOGRParquetPlugin() 119 : { 120 1595 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 121 : { 122 302 : return; 123 : } 124 1293 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); 125 : #ifdef PLUGIN_INSTALLATION_MESSAGE 126 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, 127 : PLUGIN_INSTALLATION_MESSAGE); 128 : #endif 129 1293 : OGRParquetDriverSetCommonMetadata(poDriver); 130 1293 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 131 : } 132 : #endif