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 "gdal_frmts.h" 14 : 15 : #ifdef PLUGIN_FILENAME 16 : #include "gdalplugindriverproxy.h" 17 : #endif 18 : 19 : #include "ogrsf_frmts.h" 20 : #include "gdal_priv.h" 21 : 22 : #include "ogrparquetdrivercore.h" 23 : 24 : /************************************************************************/ 25 : /* Identify() */ 26 : /************************************************************************/ 27 : 28 : template <size_t N> constexpr int constexpr_length(const char (&)[N]) 29 : { 30 : return static_cast<int>(N - 1); 31 : } 32 : 33 54826 : int OGRParquetDriverIdentify(GDALOpenInfo *poOpenInfo) 34 : { 35 : #if defined(GDAL_USE_ARROWDATASET) || defined(PLUGIN_FILENAME) 36 54826 : if (poOpenInfo->bIsDirectory) 37 : { 38 : // Might be a ParquetDataset 39 1239 : return -1; 40 : } 41 : #endif 42 53587 : if (STARTS_WITH(poOpenInfo->pszFilename, "PARQUET:")) 43 346 : return TRUE; 44 : 45 : // See https://github.com/apache/parquet-format#file-format 46 53241 : bool bRet = false; 47 53241 : constexpr const char SIGNATURE[] = "PAR1"; 48 53241 : constexpr int SIGNATURE_SIZE = constexpr_length(SIGNATURE); 49 : static_assert(SIGNATURE_SIZE == 4, "SIGNATURE_SIZE == 4"); 50 53241 : constexpr int METADATASIZE_SIZE = 4; 51 53241 : if (poOpenInfo->fpL != nullptr && 52 4078 : poOpenInfo->nHeaderBytes >= 53 3942 : SIGNATURE_SIZE + METADATASIZE_SIZE + SIGNATURE_SIZE && 54 3942 : memcmp(poOpenInfo->pabyHeader, SIGNATURE, SIGNATURE_SIZE) == 0) 55 : { 56 2086 : VSIFSeekL(poOpenInfo->fpL, 0, SEEK_END); 57 2086 : const auto nFileSize = VSIFTellL(poOpenInfo->fpL); 58 2086 : VSIFSeekL(poOpenInfo->fpL, 59 : nFileSize - (METADATASIZE_SIZE + SIGNATURE_SIZE), SEEK_SET); 60 2086 : uint32_t nMetadataSize = 0; 61 : static_assert(sizeof(nMetadataSize) == METADATASIZE_SIZE, 62 : "sizeof(nMetadataSize) == METADATASIZE_SIZE"); 63 2086 : VSIFReadL(&nMetadataSize, 1, sizeof(nMetadataSize), poOpenInfo->fpL); 64 2086 : CPL_LSBPTR32(&nMetadataSize); 65 2086 : unsigned char abyTrailingBytes[SIGNATURE_SIZE] = {0}; 66 2086 : VSIFReadL(&abyTrailingBytes[0], 1, SIGNATURE_SIZE, poOpenInfo->fpL); 67 4172 : bRet = memcmp(abyTrailingBytes, SIGNATURE, SIGNATURE_SIZE) == 0 && 68 2086 : nMetadataSize < nFileSize; 69 2086 : VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET); 70 : } 71 53241 : return bRet; 72 : } 73 : 74 : /************************************************************************/ 75 : /* OGRParquetDriverSetCommonMetadata() */ 76 : /************************************************************************/ 77 : 78 1808 : void OGRParquetDriverSetCommonMetadata(GDALDriver *poDriver) 79 : { 80 1808 : poDriver->SetDescription(DRIVER_NAME); 81 1808 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 82 1808 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 83 1808 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "(Geo)Parquet"); 84 1808 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "parquet"); 85 1808 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, 86 1808 : "drivers/vector/parquet.html"); 87 1808 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 88 1808 : poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES"); 89 1808 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); 90 1808 : poDriver->SetMetadataItem(GDAL_DCAP_REOPEN_AFTER_WRITE_REQUIRED, "YES"); 91 1808 : poDriver->SetMetadataItem(GDAL_DCAP_CAN_READ_AFTER_DELETE, "YES"); 92 : 93 1808 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); 94 1808 : poDriver->SetMetadataItem( 95 : GDAL_DMD_CREATIONFIELDDATATYPES, 96 : "Integer Integer64 Real String Date Time DateTime " 97 1808 : "Binary IntegerList Integer64List RealList StringList"); 98 1808 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, 99 1808 : "Boolean Int16 Float32 JSON UUID"); 100 1808 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS, 101 : "WidthPrecision Nullable Comment " 102 1808 : "AlternativeName Domain"); 103 1808 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 104 : 105 1808 : poDriver->SetMetadataItem( 106 : GDAL_DMD_OPENOPTIONLIST, 107 : "<OpenOptionList>" 108 : " <Option name='GEOM_POSSIBLE_NAMES' type='string' description='Comma " 109 : "separated list of possible names for geometry column(s).' " 110 : "default='geometry,wkb_geometry,wkt_geometry'/>" 111 : " <Option name='CRS' type='string' " 112 : "description='Set/override CRS, typically defined as AUTH:CODE " 113 : "(e.g EPSG:4326), of geometry column(s)'/>" 114 : " <Option name='LISTS_AS_STRING_JSON' type='boolean' description='" 115 : "Whether lists of strings/integers/reals should be reported as " 116 : "String(JSON) fields rather than String/Integer[64]/RealList. Useful " 117 : "when null values in such lists must be exactly mapped as such.' " 118 : "default='NO'/>" 119 1808 : "</OpenOptionList>"); 120 : 121 1808 : poDriver->pfnIdentify = OGRParquetDriverIdentify; 122 1808 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 123 1808 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES"); 124 : 125 1808 : poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES"); 126 1808 : poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS, "Features"); 127 : 128 1808 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES"); 129 1808 : poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES"); 130 1808 : poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS, 131 1808 : "Name Type WidthPrecision"); 132 1808 : } 133 : 134 : /************************************************************************/ 135 : /* DeclareDeferredOGRParquetPlugin() */ 136 : /************************************************************************/ 137 : 138 : #ifdef PLUGIN_FILENAME 139 2054 : void DeclareDeferredOGRParquetPlugin() 140 : { 141 2054 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 142 : { 143 283 : return; 144 : } 145 1771 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); 146 : #ifdef PLUGIN_INSTALLATION_MESSAGE 147 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, 148 : PLUGIN_INSTALLATION_MESSAGE); 149 : #endif 150 1771 : OGRParquetDriverSetCommonMetadata(poDriver); 151 1771 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 152 : } 153 : #endif