Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL TileDB Driver
4 : * Purpose: Implement GDAL TileDB Support based on https://www.tiledb.io
5 : * Author: TileDB, Inc
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2023, TileDB, Inc
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "tiledbheaders.h"
14 :
15 : #include "cpl_float.h"
16 : #include "cpl_json.h"
17 : #include "cpl_time.h"
18 : #include "ogr_p.h"
19 : #include "ogr_recordbatch.h"
20 : #include "ogr_swq.h"
21 :
22 : #include <algorithm>
23 : #include <limits>
24 :
25 : constexpr int SECONDS_PER_DAY = 3600 * 24;
26 :
27 : /************************************************************************/
28 : /* ==================================================================== */
29 : /* ProcessField */
30 : /* ==================================================================== */
31 : /************************************************************************/
32 :
33 : namespace
34 : {
35 :
36 : template <tiledb_datatype_t> struct GetType
37 : {
38 : };
39 :
40 : template <> struct GetType<TILEDB_INT32>
41 : {
42 : using EltType = std::vector<int32_t>;
43 : };
44 :
45 : template <> struct GetType<TILEDB_INT16>
46 : {
47 : using EltType = std::vector<int16_t>;
48 : };
49 :
50 : template <> struct GetType<TILEDB_UINT8>
51 : {
52 : using EltType = std::vector<uint8_t>;
53 : };
54 :
55 : template <> struct GetType<TILEDB_UINT16>
56 : {
57 : using EltType = std::vector<uint16_t>;
58 : };
59 :
60 : template <> struct GetType<TILEDB_BOOL>
61 : {
62 : using EltType = VECTOR_OF_BOOL;
63 : };
64 :
65 : template <> struct GetType<TILEDB_INT64>
66 : {
67 : using EltType = std::vector<int64_t>;
68 : };
69 :
70 : template <> struct GetType<TILEDB_FLOAT64>
71 : {
72 : using EltType = std::vector<double>;
73 : };
74 :
75 : template <> struct GetType<TILEDB_FLOAT32>
76 : {
77 : using EltType = std::vector<float>;
78 : };
79 :
80 : template <> struct GetType<TILEDB_STRING_ASCII>
81 : {
82 : using EltType = std::string;
83 : };
84 :
85 : template <> struct GetType<TILEDB_STRING_UTF8>
86 : {
87 : using EltType = std::string;
88 : };
89 :
90 : template <> struct GetType<TILEDB_BLOB>
91 : {
92 : using EltType = std::vector<uint8_t>;
93 : };
94 :
95 : template <> struct GetType<TILEDB_DATETIME_DAY>
96 : {
97 : using EltType = std::vector<int64_t>;
98 : };
99 :
100 : template <> struct GetType<TILEDB_DATETIME_MS>
101 : {
102 : using EltType = std::vector<int64_t>;
103 : };
104 :
105 : template <> struct GetType<TILEDB_TIME_MS>
106 : {
107 : using EltType = std::vector<int64_t>;
108 : };
109 :
110 : template <template <class> class Func> struct ProcessField
111 : {
112 9428 : static void exec(tiledb_datatype_t eType, OGRTileDBLayer::ArrayType &array)
113 : {
114 9428 : switch (eType)
115 : {
116 1446 : case TILEDB_INT32:
117 1446 : Func<GetType<TILEDB_INT32>::EltType>::exec(array);
118 1446 : break;
119 958 : case TILEDB_INT16:
120 958 : Func<GetType<TILEDB_INT16>::EltType>::exec(array);
121 958 : break;
122 479 : case TILEDB_UINT8:
123 479 : Func<GetType<TILEDB_UINT8>::EltType>::exec(array);
124 479 : break;
125 479 : case TILEDB_UINT16:
126 479 : Func<GetType<TILEDB_UINT16>::EltType>::exec(array);
127 479 : break;
128 958 : case TILEDB_BOOL:
129 958 : Func<GetType<TILEDB_BOOL>::EltType>::exec(array);
130 958 : break;
131 583 : case TILEDB_INT64:
132 583 : Func<GetType<TILEDB_INT64>::EltType>::exec(array);
133 583 : break;
134 958 : case TILEDB_FLOAT32:
135 958 : Func<GetType<TILEDB_FLOAT32>::EltType>::exec(array);
136 958 : break;
137 1062 : case TILEDB_FLOAT64:
138 1062 : Func<GetType<TILEDB_FLOAT64>::EltType>::exec(array);
139 1062 : break;
140 0 : case TILEDB_STRING_ASCII:
141 0 : Func<GetType<TILEDB_STRING_ASCII>::EltType>::exec(array);
142 0 : break;
143 589 : case TILEDB_STRING_UTF8:
144 589 : Func<GetType<TILEDB_STRING_UTF8>::EltType>::exec(array);
145 589 : break;
146 479 : case TILEDB_BLOB:
147 479 : Func<GetType<TILEDB_BLOB>::EltType>::exec(array);
148 479 : break;
149 479 : case TILEDB_DATETIME_DAY:
150 479 : Func<GetType<TILEDB_DATETIME_DAY>::EltType>::exec(array);
151 479 : break;
152 479 : case TILEDB_DATETIME_MS:
153 479 : Func<GetType<TILEDB_DATETIME_MS>::EltType>::exec(array);
154 479 : break;
155 479 : case TILEDB_TIME_MS:
156 479 : Func<GetType<TILEDB_TIME_MS>::EltType>::exec(array);
157 479 : break;
158 :
159 0 : default:
160 : {
161 0 : CPLAssert(false);
162 : break;
163 : }
164 : }
165 9428 : }
166 : };
167 :
168 : } // namespace
169 :
170 : /************************************************************************/
171 : /* ==================================================================== */
172 : /* OGRTileDBDataset */
173 : /* ==================================================================== */
174 : /************************************************************************/
175 :
176 : /************************************************************************/
177 : /* OGRTileDBDataset() */
178 : /************************************************************************/
179 :
180 88 : OGRTileDBDataset::OGRTileDBDataset()
181 : {
182 88 : }
183 :
184 : /************************************************************************/
185 : /* ~OGRTileDBDataset() */
186 : /************************************************************************/
187 :
188 176 : OGRTileDBDataset::~OGRTileDBDataset()
189 : {
190 176 : }
191 :
192 : /************************************************************************/
193 : /* Open() */
194 : /************************************************************************/
195 :
196 38 : GDALDataset *OGRTileDBDataset::Open(GDALOpenInfo *poOpenInfo,
197 : tiledb::Object::Type objectType)
198 :
199 : {
200 76 : auto poDS = std::make_unique<OGRTileDBDataset>();
201 38 : poDS->eAccess = poOpenInfo->eAccess;
202 : const char *pszConfig =
203 38 : CSLFetchNameValue(poOpenInfo->papszOpenOptions, "TILEDB_CONFIG");
204 :
205 76 : const char *pszTimestamp = CSLFetchNameValueDef(
206 38 : poOpenInfo->papszOpenOptions, "TILEDB_TIMESTAMP", "0");
207 38 : const uint64_t nTimestamp = std::strtoull(pszTimestamp, nullptr, 10);
208 :
209 38 : if (pszConfig != nullptr)
210 : {
211 0 : tiledb::Config cfg(pszConfig);
212 0 : poDS->m_ctx.reset(new tiledb::Context(cfg));
213 : }
214 : else
215 : {
216 76 : tiledb::Config cfg;
217 38 : cfg["sm.enable_signal_handlers"] = "false";
218 38 : poDS->m_ctx.reset(new tiledb::Context(cfg));
219 : }
220 :
221 : std::string osFilename(
222 76 : TileDBDataset::VSI_to_tiledb_uri(poOpenInfo->pszFilename));
223 38 : if (osFilename.back() == '/')
224 0 : osFilename.pop_back();
225 :
226 42 : const auto AddLayer = [&poDS, nTimestamp, poOpenInfo](
227 : const std::string &osLayerFilename,
228 : const std::optional<std::string> &osLayerName =
229 246 : std::optional<std::string>())
230 : {
231 : auto poLayer = std::make_unique<OGRTileDBLayer>(
232 42 : poDS.get(), osLayerFilename.c_str(),
233 42 : osLayerName.has_value()
234 77 : ? (*osLayerName).c_str()
235 77 : : CPLGetBasenameSafe(osLayerFilename.c_str()).c_str(),
236 126 : wkbUnknown, nullptr);
237 42 : poLayer->m_bUpdatable = poOpenInfo->eAccess == GA_Update;
238 84 : if (!poLayer->InitFromStorage(poDS->m_ctx.get(), nTimestamp,
239 42 : poOpenInfo->papszOpenOptions))
240 : {
241 2 : poLayer->m_array.reset();
242 2 : return false;
243 : }
244 :
245 40 : int nBatchSize = atoi(CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
246 : "BATCH_SIZE", "0"));
247 40 : poLayer->m_nBatchSize =
248 40 : nBatchSize <= 0 ? DEFAULT_BATCH_SIZE : nBatchSize;
249 :
250 80 : poLayer->m_bStats =
251 40 : CPLFetchBool(poOpenInfo->papszOpenOptions, "STATS", false);
252 :
253 40 : poDS->m_apoLayers.emplace_back(std::move(poLayer));
254 40 : return true;
255 38 : };
256 :
257 38 : CPL_IGNORE_RET_VAL(objectType);
258 38 : if (objectType == tiledb::Object::Type::Group)
259 : {
260 3 : poDS->m_osGroupName = osFilename;
261 9 : tiledb::Group group(*(poDS->m_ctx), osFilename.c_str(), TILEDB_READ);
262 10 : for (uint64_t i = 0; i < group.member_count(); ++i)
263 : {
264 14 : auto obj = group.member(i);
265 7 : if (obj.type() == tiledb::Object::Type::Array)
266 : {
267 14 : tiledb::ArraySchema schema(*(poDS->m_ctx), obj.uri());
268 7 : if (schema.array_type() == TILEDB_SPARSE)
269 : {
270 7 : AddLayer(obj.uri(), obj.name());
271 : }
272 : }
273 : }
274 : }
275 : else
276 : {
277 35 : if (!AddLayer(osFilename))
278 2 : return nullptr;
279 : }
280 :
281 36 : return poDS.release();
282 : }
283 :
284 : /************************************************************************/
285 : /* TestCapability() */
286 : /************************************************************************/
287 :
288 36 : int OGRTileDBDataset::TestCapability(const char *pszCap)
289 : {
290 36 : if (EQUAL(pszCap, ODsCCreateLayer))
291 : {
292 46 : return eAccess == GA_Update &&
293 46 : (m_apoLayers.empty() || !m_osGroupName.empty());
294 : }
295 14 : if (EQUAL(pszCap, ODsCCurveGeometries) ||
296 7 : EQUAL(pszCap, ODsCMeasuredGeometries) || EQUAL(pszCap, ODsCZGeometries))
297 : {
298 10 : return TRUE;
299 : }
300 4 : return FALSE;
301 : }
302 :
303 : /***********************************************************************/
304 : /* ExecuteSQL() */
305 : /***********************************************************************/
306 :
307 6 : OGRLayer *OGRTileDBDataset::ExecuteSQL(const char *pszSQLCommand,
308 : OGRGeometry *poSpatialFilter,
309 : const char *pszDialect)
310 : {
311 6 : return GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter, pszDialect);
312 : }
313 :
314 : /***********************************************************************/
315 : /* ICreateLayer() */
316 : /***********************************************************************/
317 : OGRLayer *
318 56 : OGRTileDBDataset::ICreateLayer(const char *pszName,
319 : const OGRGeomFieldDefn *poGeomFieldDefn,
320 : CSLConstList papszOptions)
321 : {
322 56 : if (eAccess != GA_Update)
323 : {
324 1 : CPLError(CE_Failure, CPLE_NotSupported,
325 : "CreateLayer() failed: dataset in read-only mode");
326 1 : return nullptr;
327 : }
328 :
329 55 : if (!m_osGroupName.empty() && strchr(pszName, '/'))
330 : {
331 : // Otherwise a layer name wit ha slash when groups are enabled causes
332 : // a "[TileDB::Array] Error: FragmentID: input URI is invalid. Provided URI does not contain a fragment name."
333 : // exception on re-opening starting with TileDB 2.21
334 0 : CPLError(CE_Failure, CPLE_NotSupported,
335 : "Slash is not supported in layer name");
336 0 : return nullptr;
337 : }
338 :
339 55 : const auto eGType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
340 : const auto poSpatialRef =
341 55 : poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
342 :
343 55 : if (m_osGroupName.empty() && !m_apoLayers.empty())
344 : {
345 1 : CPLError(CE_Failure, CPLE_NotSupported,
346 : "CreateLayer() failed: no more than one layer per dataset "
347 : "supported on a array object. Create a dataset with the "
348 : "CREATE_GROUP=YES creation option or open such group "
349 : "to enable multiple layer creation.");
350 1 : return nullptr;
351 : }
352 :
353 54 : if (eGType == wkbNone)
354 : {
355 2 : CPLError(CE_Failure, CPLE_NotSupported,
356 : "CreateLayer() failed: non-spatial layer not supported");
357 2 : return nullptr;
358 : }
359 :
360 104 : std::string osFilename = GetDescription();
361 52 : if (!m_osGroupName.empty())
362 : {
363 : osFilename =
364 3 : CPLFormFilenameSafe(m_osGroupName.c_str(), "layers", nullptr);
365 6 : if (!STARTS_WITH(m_osGroupName.c_str(), "s3://") &&
366 3 : !STARTS_WITH(m_osGroupName.c_str(), "gcs://"))
367 : {
368 : VSIStatBufL sStat;
369 3 : if (VSIStatL(osFilename.c_str(), &sStat) != 0)
370 1 : VSIMkdir(osFilename.c_str(), 0755);
371 : }
372 3 : osFilename = CPLFormFilenameSafe(osFilename.c_str(), pszName, nullptr);
373 : }
374 : auto poLayer = std::make_unique<OGRTileDBLayer>(
375 104 : this, osFilename.c_str(), pszName, eGType, poSpatialRef);
376 52 : poLayer->m_bUpdatable = true;
377 52 : poLayer->m_ctx.reset(new tiledb::Context(*m_ctx));
378 52 : poLayer->m_osGroupName = m_osGroupName;
379 :
380 52 : const char *pszBounds = CSLFetchNameValue(papszOptions, "BOUNDS");
381 52 : if (pszBounds)
382 : {
383 25 : CPLStringList aosBounds(CSLTokenizeString2(pszBounds, ",", 0));
384 25 : if (aosBounds.Count() == 4)
385 : {
386 23 : poLayer->m_dfXStart = CPLAtof(aosBounds[0]);
387 23 : poLayer->m_dfYStart = CPLAtof(aosBounds[1]);
388 23 : poLayer->m_dfXEnd = CPLAtof(aosBounds[2]);
389 23 : poLayer->m_dfYEnd = CPLAtof(aosBounds[3]);
390 : }
391 2 : else if (aosBounds.Count() == 6)
392 : {
393 1 : poLayer->m_dfXStart = CPLAtof(aosBounds[0]);
394 1 : poLayer->m_dfYStart = CPLAtof(aosBounds[1]);
395 1 : poLayer->m_dfZStart = CPLAtof(aosBounds[2]);
396 1 : poLayer->m_dfXEnd = CPLAtof(aosBounds[3]);
397 1 : poLayer->m_dfYEnd = CPLAtof(aosBounds[4]);
398 1 : poLayer->m_dfZEnd = CPLAtof(aosBounds[5]);
399 : }
400 : else
401 : {
402 1 : CPLError(CE_Failure, CPLE_AppDefined,
403 : "Domain bounds specified as minx,miny,maxx,maxy or "
404 : "minx,miny,minx,maxx,maxy,maxz are "
405 : "required for array creation.");
406 1 : return nullptr;
407 : }
408 : }
409 27 : else if (poSpatialRef && poSpatialRef->IsGeographic())
410 : {
411 8 : poLayer->m_dfXStart = -360;
412 8 : poLayer->m_dfXEnd = 360;
413 8 : poLayer->m_dfYStart = -90;
414 8 : poLayer->m_dfYEnd = 90;
415 : }
416 19 : else if (poSpatialRef && poSpatialRef->IsProjected())
417 : {
418 : // Should hopefully be sufficiently large for most projections...
419 : // For example the eastings of Mercator go between [-PI * a, PI * a]
420 : // so we take a 2x margin here.
421 2 : const double dfBounds = 2 * M_PI * poSpatialRef->GetSemiMajor();
422 2 : poLayer->m_dfXStart = -dfBounds;
423 2 : poLayer->m_dfXEnd = dfBounds;
424 2 : poLayer->m_dfYStart = -dfBounds;
425 2 : poLayer->m_dfYEnd = dfBounds;
426 : }
427 : else
428 : {
429 17 : CPLError(CE_Failure, CPLE_AppDefined,
430 : "Domain bounds must be specified with the BOUNDS layer "
431 : "creation option.");
432 17 : return nullptr;
433 : }
434 :
435 : int nBatchSize =
436 34 : atoi(CSLFetchNameValueDef(papszOptions, "BATCH_SIZE", "0"));
437 34 : poLayer->m_nBatchSize = nBatchSize <= 0 ? DEFAULT_BATCH_SIZE : nBatchSize;
438 :
439 : int nTileCapacity =
440 34 : atoi(CSLFetchNameValueDef(papszOptions, "TILE_CAPACITY", "0"));
441 34 : poLayer->m_nTileCapacity =
442 34 : nTileCapacity <= 0 ? DEFAULT_TILE_CAPACITY : nTileCapacity;
443 :
444 34 : poLayer->m_bStats = CPLFetchBool(papszOptions, "STATS", false);
445 :
446 68 : poLayer->m_dfTileExtent =
447 34 : std::min(poLayer->m_dfYEnd - poLayer->m_dfYStart,
448 68 : poLayer->m_dfXEnd - poLayer->m_dfXStart) /
449 : 10;
450 :
451 34 : const char *pszTileExtent = CSLFetchNameValue(papszOptions, "TILE_EXTENT");
452 34 : if (pszTileExtent)
453 0 : poLayer->m_dfTileExtent = CPLAtof(pszTileExtent);
454 :
455 34 : if (wkbHasZ(eGType) || eGType == wkbUnknown)
456 : {
457 16 : poLayer->m_osZDim = "_Z";
458 32 : poLayer->m_dfZTileExtent =
459 16 : (poLayer->m_dfZEnd - poLayer->m_dfZStart) / 2;
460 :
461 : const char *pszZTileExtent =
462 16 : CSLFetchNameValue(papszOptions, "TILE_Z_EXTENT");
463 16 : if (pszZTileExtent)
464 0 : poLayer->m_dfZTileExtent = CPLAtof(pszZTileExtent);
465 : }
466 :
467 34 : const char *pszAddZDim = CSLFetchNameValue(papszOptions, "ADD_Z_DIM");
468 34 : if (pszAddZDim && !EQUAL(pszAddZDim, "AUTO") && !CPLTestBool(pszAddZDim))
469 0 : poLayer->m_osZDim.clear();
470 :
471 : const char *pszTimestamp =
472 34 : CSLFetchNameValueDef(papszOptions, "TILEDB_TIMESTAMP", "0");
473 34 : poLayer->m_nTimestamp = std::strtoull(pszTimestamp, nullptr, 10);
474 :
475 34 : const char *pszCompression = CSLFetchNameValue(papszOptions, "COMPRESSION");
476 : const char *pszCompressionLevel =
477 34 : CSLFetchNameValue(papszOptions, "COMPRESSION_LEVEL");
478 :
479 34 : poLayer->m_filterList.reset(new tiledb::FilterList(*poLayer->m_ctx));
480 34 : if (pszCompression != nullptr)
481 : {
482 1 : int nLevel = (pszCompressionLevel) ? atoi(pszCompressionLevel) : -1;
483 1 : TileDBDataset::AddFilter(*(poLayer->m_ctx.get()),
484 1 : *(poLayer->m_filterList.get()), pszCompression,
485 : nLevel);
486 : }
487 :
488 34 : poLayer->m_osFIDColumn = CSLFetchNameValueDef(papszOptions, "FID", "FID");
489 :
490 : const char *pszGeomColName =
491 34 : CSLFetchNameValueDef(papszOptions, "GEOMETRY_NAME", "wkb_geometry");
492 34 : if (EQUAL(pszGeomColName, "") && wkbFlatten(eGType) != wkbPoint)
493 : {
494 0 : CPLError(CE_Failure, CPLE_AppDefined,
495 : "GEOMETRY_NAME must be defined to a non-empty string "
496 : "for layers whose geometry type is not Point.");
497 0 : return nullptr;
498 : }
499 34 : poLayer->m_poFeatureDefn->GetGeomFieldDefn(0)->SetName(pszGeomColName);
500 :
501 34 : poLayer->m_eCurrentMode = OGRTileDBLayer::CurrentMode::WriteInProgress;
502 :
503 : const char *pszTileDBStringType =
504 34 : CSLFetchNameValue(papszOptions, "TILEDB_STRING_TYPE");
505 34 : if (pszTileDBStringType)
506 : {
507 0 : if (EQUAL(pszTileDBStringType, "ASCII"))
508 0 : poLayer->m_eTileDBStringType = TILEDB_STRING_ASCII;
509 0 : else if (EQUAL(pszTileDBStringType, "UTF8"))
510 0 : poLayer->m_eTileDBStringType = TILEDB_STRING_UTF8;
511 : }
512 :
513 34 : m_apoLayers.emplace_back(std::move(poLayer));
514 :
515 34 : return m_apoLayers.back().get();
516 : }
517 :
518 : /************************************************************************/
519 : /* Create() */
520 : /************************************************************************/
521 :
522 50 : GDALDataset *OGRTileDBDataset::Create(const char *pszFilename,
523 : CSLConstList papszOptions)
524 : {
525 100 : auto poDS = std::make_unique<OGRTileDBDataset>();
526 50 : poDS->SetDescription(TileDBDataset::VSI_to_tiledb_uri(pszFilename));
527 50 : poDS->eAccess = GA_Update;
528 :
529 50 : const char *pszConfig = CSLFetchNameValue(papszOptions, "TILEDB_CONFIG");
530 50 : if (pszConfig != nullptr)
531 : {
532 0 : tiledb::Config cfg(pszConfig);
533 0 : poDS->m_ctx.reset(new tiledb::Context(cfg));
534 : }
535 : else
536 : {
537 50 : poDS->m_ctx.reset(new tiledb::Context());
538 : }
539 :
540 50 : if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "CREATE_GROUP", "NO")))
541 : {
542 : try
543 : {
544 1 : tiledb::create_group(*(poDS->m_ctx.get()), poDS->GetDescription());
545 : }
546 0 : catch (const std::exception &e)
547 : {
548 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
549 0 : return nullptr;
550 : }
551 1 : poDS->m_osGroupName = poDS->GetDescription();
552 : }
553 :
554 50 : return poDS.release();
555 : }
556 :
557 : /************************************************************************/
558 : /* ==================================================================== */
559 : /* OGRTileDBLayer */
560 : /* ==================================================================== */
561 : /************************************************************************/
562 :
563 : /************************************************************************/
564 : /* OGRTileDBLayer() */
565 : /************************************************************************/
566 :
567 94 : OGRTileDBLayer::OGRTileDBLayer(GDALDataset *poDS, const char *pszFilename,
568 : const char *pszLayerName,
569 : const OGRwkbGeometryType eGType,
570 94 : const OGRSpatialReference *poSRS)
571 : : m_poDS(poDS), m_osFilename(pszFilename),
572 94 : m_poFeatureDefn(new OGRFeatureDefn(pszLayerName)),
573 0 : m_pbLayerStillAlive(std::make_shared<bool>(true)),
574 : m_anFIDs(std::make_shared<std::vector<int64_t>>()),
575 : m_adfXs(std::make_shared<std::vector<double>>()),
576 : m_adfYs(std::make_shared<std::vector<double>>()),
577 : m_adfZs(std::make_shared<std::vector<double>>()),
578 : m_abyGeometries(std::make_shared<std::vector<unsigned char>>()),
579 188 : m_anGeometryOffsets(std::make_shared<std::vector<uint64_t>>())
580 : {
581 94 : m_poFeatureDefn->SetGeomType(eGType);
582 :
583 94 : if (poSRS)
584 : {
585 10 : auto poSRSClone = poSRS->Clone();
586 10 : m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRSClone);
587 10 : poSRSClone->Release();
588 : }
589 :
590 94 : m_poFeatureDefn->Reference();
591 :
592 94 : SetDescription(pszLayerName);
593 94 : }
594 :
595 : /************************************************************************/
596 : /* ~OGRTileDBLayer() */
597 : /************************************************************************/
598 :
599 188 : OGRTileDBLayer::~OGRTileDBLayer()
600 : {
601 94 : *m_pbLayerStillAlive = false;
602 :
603 : try
604 : {
605 94 : if (m_bUpdatable && !m_bInitializationAttempted && m_filterList)
606 : {
607 4 : InitializeSchemaAndArray();
608 : }
609 94 : if (m_array && m_bUpdatable)
610 : {
611 38 : SwitchToWritingMode();
612 : }
613 94 : if (m_array)
614 : {
615 74 : if (m_bUpdatable)
616 : {
617 38 : if (m_bInitialized && !m_adfXs->empty())
618 : {
619 27 : FlushArrays();
620 : }
621 :
622 : // write the pad metadata
623 38 : m_array->put_metadata("PAD_X", TILEDB_FLOAT64, 1, &m_dfPadX);
624 38 : m_array->put_metadata("PAD_Y", TILEDB_FLOAT64, 1, &m_dfPadY);
625 38 : if (m_dfPadZ != 0)
626 0 : m_array->put_metadata("PAD_Z", TILEDB_FLOAT64, 1,
627 0 : &m_dfPadZ);
628 :
629 38 : if (m_nTotalFeatureCount >= 0)
630 66 : m_array->put_metadata("FEATURE_COUNT", TILEDB_INT64, 1,
631 33 : &m_nTotalFeatureCount);
632 :
633 38 : if (m_oLayerExtent.IsInit())
634 : {
635 62 : m_array->put_metadata("LAYER_EXTENT_MINX", TILEDB_FLOAT64,
636 31 : 1, &m_oLayerExtent.MinX);
637 62 : m_array->put_metadata("LAYER_EXTENT_MINY", TILEDB_FLOAT64,
638 31 : 1, &m_oLayerExtent.MinY);
639 62 : m_array->put_metadata("LAYER_EXTENT_MAXX", TILEDB_FLOAT64,
640 31 : 1, &m_oLayerExtent.MaxX);
641 62 : m_array->put_metadata("LAYER_EXTENT_MAXY", TILEDB_FLOAT64,
642 31 : 1, &m_oLayerExtent.MaxY);
643 : }
644 : }
645 :
646 74 : m_array->close();
647 : }
648 : }
649 0 : catch (const std::exception &e)
650 : {
651 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
652 : }
653 :
654 94 : if (m_poFeatureDefn)
655 94 : m_poFeatureDefn->Release();
656 188 : }
657 :
658 : /************************************************************************/
659 : /* InitFromStorage() */
660 : /************************************************************************/
661 :
662 42 : bool OGRTileDBLayer::InitFromStorage(tiledb::Context *poCtx,
663 : uint64_t nTimestamp,
664 : CSLConstList papszOpenOptions)
665 : {
666 42 : m_bInitialized = true;
667 42 : m_bInitializationAttempted = true;
668 42 : m_ctx.reset(new tiledb::Context(*poCtx));
669 42 : m_schema.reset(new tiledb::ArraySchema(*m_ctx, m_osFilename));
670 42 : m_nTimestamp = nTimestamp;
671 :
672 42 : m_filterList.reset(new tiledb::FilterList(*m_ctx));
673 :
674 84 : CPLJSONObject oJson;
675 84 : CPLJSONObject oSchema;
676 42 : oJson.Add("schema", oSchema);
677 :
678 : {
679 84 : const auto filters = m_schema->coords_filter_list();
680 42 : CPLJSONArray oCoordsFilterList;
681 43 : for (uint32_t j = 0; j < filters.nfilters(); ++j)
682 : {
683 1 : const auto filter = filters.filter(j);
684 1 : oCoordsFilterList.Add(tiledb::Filter::to_str(filter.filter_type()));
685 : }
686 42 : oSchema.Add("coords_filter_list", oCoordsFilterList);
687 : }
688 :
689 42 : if (m_nTimestamp)
690 0 : m_array.reset(new tiledb::Array(
691 0 : *m_ctx, m_osFilename, TILEDB_READ,
692 0 : tiledb::TemporalPolicy(tiledb::TimeTravel, m_nTimestamp)));
693 : else
694 42 : m_array.reset(new tiledb::Array(*m_ctx, m_osFilename, TILEDB_READ));
695 :
696 84 : const auto domain = m_schema->domain();
697 42 : if (domain.ndim() < 2)
698 : {
699 0 : CPLError(CE_Failure, CPLE_AppDefined,
700 : "Domain should have at least 2 dimensions");
701 0 : return false;
702 : }
703 :
704 181 : const auto CreateField = [this](const std::string &osName,
705 : tiledb_datatype_t type, bool bIsSingle,
706 543 : bool bIsNullable)
707 : {
708 181 : bool bOK = true;
709 181 : OGRFieldType eType = OFTString;
710 181 : OGRFieldSubType eSubType = OFSTNone;
711 181 : auto &fieldValues = m_aFieldValues;
712 181 : switch (type)
713 : {
714 8 : case TILEDB_UINT16:
715 8 : eType = bIsSingle ? OFTInteger : OFTIntegerList;
716 8 : fieldValues.push_back(
717 16 : std::make_shared<std::vector<uint16_t>>());
718 8 : break;
719 27 : case TILEDB_INT32:
720 27 : eType = bIsSingle ? OFTInteger : OFTIntegerList;
721 27 : fieldValues.push_back(std::make_shared<std::vector<int32_t>>());
722 27 : break;
723 11 : case TILEDB_INT64:
724 11 : eType = bIsSingle ? OFTInteger64 : OFTInteger64List;
725 11 : fieldValues.push_back(std::make_shared<std::vector<int64_t>>());
726 11 : break;
727 18 : case TILEDB_FLOAT32:
728 18 : eType = bIsSingle ? OFTReal : OFTRealList;
729 18 : eSubType = OFSTFloat32;
730 18 : fieldValues.push_back(std::make_shared<std::vector<float>>());
731 18 : break;
732 21 : case TILEDB_FLOAT64:
733 21 : eType = bIsSingle ? OFTReal : OFTRealList;
734 21 : fieldValues.push_back(std::make_shared<std::vector<double>>());
735 21 : break;
736 18 : case TILEDB_INT16:
737 18 : eType = bIsSingle ? OFTInteger : OFTIntegerList;
738 18 : eSubType = OFSTInt16;
739 18 : fieldValues.push_back(std::make_shared<std::vector<int16_t>>());
740 18 : break;
741 16 : case TILEDB_STRING_ASCII:
742 : case TILEDB_STRING_UTF8:
743 16 : eType = OFTString;
744 16 : fieldValues.push_back(std::make_shared<std::string>());
745 16 : break;
746 18 : case TILEDB_BOOL:
747 18 : eType = bIsSingle ? OFTInteger : OFTIntegerList;
748 18 : eSubType = OFSTBoolean;
749 18 : fieldValues.push_back(std::make_shared<VECTOR_OF_BOOL>());
750 18 : break;
751 9 : case TILEDB_DATETIME_DAY:
752 9 : eType = OFTDate;
753 9 : fieldValues.push_back(std::make_shared<std::vector<int64_t>>());
754 9 : break;
755 9 : case TILEDB_DATETIME_MS:
756 9 : eType = OFTDateTime;
757 9 : fieldValues.push_back(std::make_shared<std::vector<int64_t>>());
758 9 : break;
759 9 : case TILEDB_TIME_MS:
760 9 : eType = OFTTime;
761 9 : fieldValues.push_back(std::make_shared<std::vector<int64_t>>());
762 9 : break;
763 8 : case TILEDB_UINT8:
764 8 : eType = bIsSingle ? OFTInteger : OFTBinary;
765 8 : fieldValues.push_back(std::make_shared<std::vector<uint8_t>>());
766 8 : break;
767 9 : case TILEDB_BLOB:
768 : {
769 9 : if (bIsSingle)
770 : {
771 0 : bOK = false;
772 0 : const char *pszTypeName = "";
773 0 : tiledb_datatype_to_str(type, &pszTypeName);
774 0 : CPLError(
775 : CE_Warning, CPLE_AppDefined,
776 : "Ignoring attribute %s of type %s, as only "
777 : "variable length is supported, but it has a fixed size",
778 : osName.c_str(), pszTypeName);
779 : }
780 : else
781 : {
782 9 : eType = OFTBinary;
783 9 : fieldValues.push_back(
784 18 : std::make_shared<std::vector<uint8_t>>());
785 : }
786 9 : break;
787 : }
788 :
789 : #ifdef HAS_TILEDB_GEOM_WKB_WKT
790 : case TILEDB_GEOM_WKT:
791 : {
792 : eType = OFTString;
793 : fieldValues.push_back(std::make_shared<std::string>());
794 : break;
795 : }
796 :
797 : case TILEDB_GEOM_WKB:
798 : {
799 : eType = OFTBinary;
800 : fieldValues.push_back(std::make_shared<std::vector<uint8_t>>());
801 : break;
802 : }
803 : #endif
804 :
805 0 : case TILEDB_CHAR:
806 : case TILEDB_INT8:
807 : case TILEDB_UINT32:
808 : case TILEDB_UINT64:
809 : case TILEDB_STRING_UTF16:
810 : case TILEDB_STRING_UTF32:
811 : case TILEDB_STRING_UCS2:
812 : case TILEDB_STRING_UCS4:
813 : case TILEDB_DATETIME_YEAR:
814 : case TILEDB_DATETIME_MONTH:
815 : case TILEDB_DATETIME_WEEK:
816 : case TILEDB_DATETIME_HR:
817 : case TILEDB_DATETIME_MIN:
818 : case TILEDB_DATETIME_SEC:
819 : case TILEDB_DATETIME_US:
820 : case TILEDB_DATETIME_NS:
821 : case TILEDB_DATETIME_PS:
822 : case TILEDB_DATETIME_FS:
823 : case TILEDB_DATETIME_AS:
824 : case TILEDB_TIME_HR:
825 : case TILEDB_TIME_MIN:
826 : case TILEDB_TIME_SEC:
827 : case TILEDB_TIME_US:
828 : case TILEDB_TIME_NS:
829 : case TILEDB_TIME_PS:
830 : case TILEDB_TIME_FS:
831 : case TILEDB_TIME_AS:
832 : case TILEDB_ANY:
833 : {
834 : // TODO ?
835 0 : const char *pszTypeName = "";
836 0 : tiledb_datatype_to_str(type, &pszTypeName);
837 0 : CPLError(CE_Warning, CPLE_AppDefined,
838 : "Ignoring attribute %s as its type %s is unsupported",
839 : osName.c_str(), pszTypeName);
840 0 : bOK = false;
841 0 : break;
842 : }
843 : }
844 181 : if (bOK)
845 : {
846 181 : m_aeFieldTypes.push_back(type);
847 362 : OGRFieldDefn oFieldDefn(osName.c_str(), eType);
848 181 : oFieldDefn.SetSubType(eSubType);
849 181 : oFieldDefn.SetNullable(bIsNullable);
850 181 : m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
851 : }
852 181 : };
853 :
854 : // Figure out dimensions
855 42 : m_osXDim.clear();
856 42 : m_osYDim.clear();
857 :
858 : // to improve interoperability with PDAL generated datasets
859 : const bool bDefaultDimNameWithoutUnderscore =
860 123 : !CSLFetchNameValue(papszOpenOptions, "DIM_X") &&
861 39 : !CSLFetchNameValue(papszOpenOptions, "DIM_Y") &&
862 39 : !CSLFetchNameValue(papszOpenOptions, "DIM_Z") &&
863 81 : !domain.has_dimension("_X") && !domain.has_dimension("_Y") &&
864 81 : domain.has_dimension("X") && domain.has_dimension("Y");
865 :
866 : const std::string osXDim =
867 : CSLFetchNameValueDef(papszOpenOptions, "DIM_X",
868 84 : bDefaultDimNameWithoutUnderscore ? "X" : "_X");
869 : const std::string osYDim =
870 : CSLFetchNameValueDef(papszOpenOptions, "DIM_Y",
871 84 : bDefaultDimNameWithoutUnderscore ? "Y" : "_Y");
872 : const std::string osZDim =
873 : CSLFetchNameValueDef(papszOpenOptions, "DIM_Z",
874 84 : bDefaultDimNameWithoutUnderscore ? "Z" : "_Z");
875 147 : for (unsigned int i = 0; i < domain.ndim(); ++i)
876 : {
877 105 : auto dim = domain.dimension(i);
878 105 : if (dim.name() == osXDim)
879 : {
880 40 : m_osXDim = dim.name();
881 40 : if (dim.type() != TILEDB_FLOAT64)
882 : {
883 0 : const char *pszTypeName = "";
884 0 : tiledb_datatype_to_str(dim.type(), &pszTypeName);
885 0 : CPLError(CE_Failure, CPLE_AppDefined,
886 : "Did not get expected type for %s dimension of "
887 : "domain. Got %s, expected FLOAT64",
888 0 : dim.name().c_str(), pszTypeName);
889 0 : return false;
890 : }
891 40 : const auto dimdomain = dim.domain<double>();
892 40 : m_dfXStart = dimdomain.first;
893 40 : m_dfXEnd = dimdomain.second;
894 : }
895 65 : else if (dim.name() == osYDim)
896 : {
897 42 : m_osYDim = dim.name();
898 42 : if (dim.type() != TILEDB_FLOAT64)
899 : {
900 0 : const char *pszTypeName = "";
901 0 : tiledb_datatype_to_str(dim.type(), &pszTypeName);
902 0 : CPLError(CE_Failure, CPLE_AppDefined,
903 : "Did not get expected type for %s dimension of "
904 : "domain. Got %s, expected FLOAT64",
905 0 : dim.name().c_str(), pszTypeName);
906 0 : return false;
907 : }
908 42 : const auto dimdomain = dim.domain<double>();
909 42 : m_dfYStart = dimdomain.first;
910 42 : m_dfYEnd = dimdomain.second;
911 : }
912 23 : else if (dim.name() == osZDim)
913 : {
914 21 : m_osZDim = dim.name();
915 21 : if (dim.type() != TILEDB_FLOAT64)
916 : {
917 0 : const char *pszTypeName = "";
918 0 : tiledb_datatype_to_str(dim.type(), &pszTypeName);
919 0 : CPLError(CE_Failure, CPLE_AppDefined,
920 : "Did not get expected type for %s dimension of "
921 : "domain. Got %s, expected FLOAT64",
922 0 : dim.name().c_str(), pszTypeName);
923 0 : return false;
924 : }
925 21 : const auto dimdomain = dim.domain<double>();
926 21 : m_dfZStart = dimdomain.first;
927 21 : m_dfZEnd = dimdomain.second;
928 : }
929 : else
930 : {
931 2 : CreateField(dim.name(), dim.type(), /*bIsSingle=*/true,
932 : /*bIsNullable=*/false);
933 : }
934 : }
935 42 : if (m_osXDim.empty())
936 : {
937 2 : CPLError(CE_Failure, CPLE_AppDefined,
938 : "Did not get expected _X dimension of domain");
939 2 : return false;
940 : }
941 40 : if (m_osYDim.empty())
942 : {
943 0 : CPLError(CE_Failure, CPLE_AppDefined,
944 : "Did not get expected _Y dimension of domain");
945 0 : return false;
946 : }
947 :
948 40 : tiledb_datatype_t v_type = TILEDB_FLOAT64;
949 40 : const void *v_r = nullptr;
950 40 : uint32_t v_num = 0;
951 80 : std::string osFIDColumn = "FID";
952 40 : m_array->get_metadata("FID_ATTRIBUTE_NAME", &v_type, &v_num, &v_r);
953 37 : if (v_r && (v_type == TILEDB_UINT8 || v_type == TILEDB_CHAR ||
954 77 : v_type == TILEDB_STRING_ASCII || v_type == TILEDB_STRING_UTF8))
955 : {
956 37 : osFIDColumn.assign(static_cast<const char *>(v_r), v_num);
957 : }
958 :
959 80 : std::string osGeomColumn = "wkb_geometry";
960 40 : m_array->get_metadata("GEOMETRY_ATTRIBUTE_NAME", &v_type, &v_num, &v_r);
961 34 : if (v_r && (v_type == TILEDB_UINT8 || v_type == TILEDB_CHAR ||
962 74 : v_type == TILEDB_STRING_ASCII || v_type == TILEDB_STRING_UTF8))
963 : {
964 34 : osGeomColumn.assign(static_cast<const char *>(v_r), v_num);
965 : }
966 : #ifdef HAS_TILEDB_GEOM_WKB_WKT
967 : else
968 : {
969 : // If GEOMETRY_ATTRIBUTE_NAME isn't defined, identify the first attribute
970 : // of type TILEDB_GEOM_WKB
971 : osGeomColumn.clear();
972 : for (unsigned i = 0; i < m_schema->attribute_num(); ++i)
973 : {
974 : auto attr = m_schema->attribute(i);
975 : if (attr.type() == TILEDB_GEOM_WKB &&
976 : attr.cell_val_num() == TILEDB_VAR_NUM)
977 : {
978 : if (osGeomColumn.empty())
979 : osGeomColumn = attr.name();
980 : }
981 : }
982 : }
983 : #endif
984 :
985 40 : bool bFoundWkbGeometry = false;
986 80 : CPLJSONArray oAttributes;
987 40 : oSchema.Add("attributes", oAttributes);
988 290 : for (unsigned i = 0; i < m_schema->attribute_num(); ++i)
989 : {
990 250 : auto attr = m_schema->attribute(i);
991 :
992 : // Export attribute in json:TILEDB metadata domain, mostly for unit
993 : // testing purposes
994 : {
995 500 : CPLJSONObject oAttribute;
996 250 : oAttributes.Add(oAttribute);
997 250 : oAttribute.Set("name", attr.name());
998 250 : const char *pszTypeName = "";
999 250 : tiledb_datatype_to_str(attr.type(), &pszTypeName);
1000 250 : oAttribute.Set("type", pszTypeName);
1001 250 : if (attr.cell_val_num() == TILEDB_VAR_NUM)
1002 105 : oAttribute.Set("cell_val_num", "variable");
1003 : else
1004 145 : oAttribute.Set("cell_val_num",
1005 145 : static_cast<GIntBig>(attr.cell_val_num()));
1006 250 : oAttribute.Set("nullable", attr.nullable());
1007 :
1008 500 : const auto filters = attr.filter_list();
1009 250 : CPLJSONArray oFilterList;
1010 269 : for (uint32_t j = 0; j < filters.nfilters(); ++j)
1011 : {
1012 19 : const auto filter = filters.filter(j);
1013 19 : oFilterList.Add(tiledb::Filter::to_str(filter.filter_type()));
1014 : }
1015 250 : oAttribute.Add("filter_list", oFilterList);
1016 : }
1017 :
1018 250 : if (attr.name() == osFIDColumn && attr.type() == TILEDB_INT64)
1019 : {
1020 37 : m_osFIDColumn = attr.name();
1021 37 : continue;
1022 : }
1023 213 : if (attr.name() == osGeomColumn &&
1024 34 : (attr.type() == TILEDB_UINT8 || attr.type() == TILEDB_BLOB
1025 : #ifdef HAS_TILEDB_GEOM_WKB_WKT
1026 : || attr.type() == TILEDB_GEOM_WKB
1027 : #endif
1028 247 : ) &&
1029 34 : attr.cell_val_num() == TILEDB_VAR_NUM)
1030 : {
1031 34 : bFoundWkbGeometry = true;
1032 34 : continue;
1033 : }
1034 : #ifdef HAS_TILEDB_GEOM_WKB_WKT
1035 : else if (attr.type() == TILEDB_GEOM_WKB &&
1036 : attr.cell_val_num() == TILEDB_VAR_NUM)
1037 : {
1038 : CPLError(CE_Warning, CPLE_AppDefined,
1039 : "Attribute %s has type GeomWKB, but another one (%s) is "
1040 : "already used as the OGR geometry column. Dealing with %s "
1041 : "has a Binary field",
1042 : attr.name().c_str(), osGeomColumn.c_str(),
1043 : attr.name().c_str());
1044 : }
1045 : #endif
1046 :
1047 179 : const bool bIsSingle = attr.cell_val_num() == 1;
1048 179 : if (attr.cell_val_num() > 1 && attr.cell_val_num() != TILEDB_VAR_NUM)
1049 : {
1050 0 : CPLError(CE_Warning, CPLE_NotSupported,
1051 : "Ignoring attribute %s as it has a number of values per "
1052 : "cell that is not 1 neither variable size",
1053 0 : attr.name().c_str());
1054 0 : continue;
1055 : }
1056 179 : CreateField(attr.name(), attr.type(), bIsSingle, attr.nullable());
1057 : }
1058 :
1059 40 : if (bFoundWkbGeometry)
1060 34 : m_poFeatureDefn->GetGeomFieldDefn(0)->SetName(osGeomColumn.c_str());
1061 :
1062 219 : for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); ++i)
1063 179 : m_aFieldValueOffsets.push_back(
1064 358 : std::make_shared<std::vector<uint64_t>>());
1065 40 : m_aFieldValidity.resize(m_poFeatureDefn->GetFieldCount());
1066 :
1067 40 : m_array->get_metadata("PAD_X", &v_type, &v_num, &v_r);
1068 40 : if (v_r && v_type == TILEDB_FLOAT64 && v_num == 1)
1069 : {
1070 40 : m_dfPadX = *static_cast<const double *>(v_r);
1071 : }
1072 :
1073 40 : m_array->get_metadata("PAD_Y", &v_type, &v_num, &v_r);
1074 40 : if (v_r && v_type == TILEDB_FLOAT64 && v_num == 1)
1075 : {
1076 40 : m_dfPadY = *static_cast<const double *>(v_r);
1077 : }
1078 :
1079 40 : m_array->get_metadata("PAD_Z", &v_type, &v_num, &v_r);
1080 40 : if (v_r && v_type == TILEDB_FLOAT64 && v_num == 1)
1081 : {
1082 0 : m_dfPadZ = *static_cast<const double *>(v_r);
1083 : }
1084 :
1085 40 : m_array->get_metadata("FEATURE_COUNT", &v_type, &v_num, &v_r);
1086 40 : if (v_r && v_type == TILEDB_INT64 && v_num == 1)
1087 : {
1088 34 : m_nTotalFeatureCount = *static_cast<const int64_t *>(v_r);
1089 : }
1090 :
1091 40 : m_array->get_metadata("LAYER_EXTENT_MINX", &v_type, &v_num, &v_r);
1092 40 : if (v_r && v_type == TILEDB_FLOAT64 && v_num == 1)
1093 : {
1094 32 : m_oLayerExtent.MinX = *static_cast<const double *>(v_r);
1095 : }
1096 :
1097 40 : m_array->get_metadata("LAYER_EXTENT_MINY", &v_type, &v_num, &v_r);
1098 40 : if (v_r && v_type == TILEDB_FLOAT64 && v_num == 1)
1099 : {
1100 32 : m_oLayerExtent.MinY = *static_cast<const double *>(v_r);
1101 : }
1102 :
1103 40 : m_array->get_metadata("LAYER_EXTENT_MAXX", &v_type, &v_num, &v_r);
1104 40 : if (v_r && v_type == TILEDB_FLOAT64 && v_num == 1)
1105 : {
1106 32 : m_oLayerExtent.MaxX = *static_cast<const double *>(v_r);
1107 : }
1108 :
1109 40 : m_array->get_metadata("LAYER_EXTENT_MAXY", &v_type, &v_num, &v_r);
1110 40 : if (v_r && v_type == TILEDB_FLOAT64 && v_num == 1)
1111 : {
1112 32 : m_oLayerExtent.MaxY = *static_cast<const double *>(v_r);
1113 : }
1114 :
1115 40 : m_array->get_metadata("CRS", &v_type, &v_num, &v_r);
1116 12 : if (v_r && (v_type == TILEDB_UINT8 || v_type == TILEDB_CHAR ||
1117 52 : v_type == TILEDB_STRING_ASCII || v_type == TILEDB_STRING_UTF8))
1118 : {
1119 24 : std::string osStr;
1120 12 : osStr.assign(static_cast<const char *>(v_r), v_num);
1121 12 : OGRSpatialReference *poSRS = new OGRSpatialReference();
1122 12 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1123 12 : if (poSRS->SetFromUserInput(
1124 : osStr.c_str(),
1125 12 : OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()) !=
1126 : OGRERR_NONE)
1127 : {
1128 0 : poSRS->Release();
1129 0 : poSRS = nullptr;
1130 : }
1131 12 : if (poSRS)
1132 : {
1133 12 : m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
1134 12 : poSRS->Release();
1135 : }
1136 : }
1137 :
1138 40 : m_array->get_metadata("GeometryType", &v_type, &v_num, &v_r);
1139 40 : if (v_r && (v_type == TILEDB_UINT8 || v_type == TILEDB_CHAR ||
1140 80 : v_type == TILEDB_STRING_ASCII || v_type == TILEDB_STRING_UTF8))
1141 : {
1142 80 : std::string osStr;
1143 40 : osStr.assign(static_cast<const char *>(v_r), v_num);
1144 40 : OGRwkbGeometryType eGeomType = wkbUnknown;
1145 40 : OGRReadWKTGeometryType(osStr.c_str(), &eGeomType);
1146 80 : m_poFeatureDefn->GetGeomFieldDefn(0)->SetType(eGeomType);
1147 : }
1148 0 : else if (!bFoundWkbGeometry)
1149 : {
1150 0 : m_poFeatureDefn->GetGeomFieldDefn(0)->SetType(
1151 0 : m_osZDim.empty() ? wkbPoint : wkbPoint25D);
1152 : }
1153 :
1154 : // Export array metadata in json:TILEDB metadata domain, mostly for
1155 : // unit testing purposes
1156 80 : CPLJSONObject oArray;
1157 40 : oJson.Add("array", oArray);
1158 80 : CPLJSONObject oMetadata;
1159 40 : oArray.Add("metadata", oMetadata);
1160 445 : for (uint64_t i = 0; i < m_array->metadata_num(); ++i)
1161 : {
1162 810 : std::string osKey;
1163 405 : m_array->get_metadata_from_index(i, &osKey, &v_type, &v_num, &v_r);
1164 810 : CPLJSONObject oMDItem;
1165 405 : oMetadata.Add(osKey, oMDItem);
1166 :
1167 405 : const char *pszTypeName = "";
1168 405 : tiledb_datatype_to_str(v_type, &pszTypeName);
1169 405 : oMDItem.Set("type", pszTypeName);
1170 :
1171 405 : switch (v_type)
1172 : {
1173 0 : case TILEDB_INT32:
1174 0 : if (v_num == 1)
1175 0 : oMDItem.Set("value", *static_cast<const int32_t *>(v_r));
1176 0 : break;
1177 34 : case TILEDB_INT64:
1178 34 : if (v_num == 1)
1179 34 : oMDItem.Set("value",
1180 : static_cast<GIntBig>(
1181 34 : *static_cast<const int64_t *>(v_r)));
1182 34 : break;
1183 208 : case TILEDB_FLOAT64:
1184 208 : if (v_num == 1)
1185 208 : oMDItem.Set("value", *static_cast<const double *>(v_r));
1186 208 : break;
1187 163 : case TILEDB_STRING_ASCII:
1188 : case TILEDB_STRING_UTF8:
1189 : {
1190 326 : std::string osStr;
1191 163 : osStr.append(static_cast<const char *>(v_r), v_num);
1192 163 : if (osStr.find("$schema") != std::string::npos)
1193 : {
1194 : // PROJJSON typically
1195 24 : CPLJSONDocument oDoc;
1196 12 : if (oDoc.LoadMemory(osStr))
1197 : {
1198 12 : oMDItem.Add("value", oDoc.GetRoot());
1199 : }
1200 : else
1201 : {
1202 0 : oMDItem.Set("value", osStr);
1203 : }
1204 : }
1205 : else
1206 : {
1207 151 : oMDItem.Set("value", osStr);
1208 : }
1209 163 : break;
1210 : }
1211 0 : default:
1212 : // other types unhandled for now
1213 0 : break;
1214 : }
1215 : }
1216 :
1217 40 : char *apszMD[] = {nullptr, nullptr};
1218 40 : std::string osJsonMD = oJson.Format(CPLJSONObject::PrettyFormat::Plain);
1219 40 : apszMD[0] = osJsonMD.data();
1220 40 : SetMetadata(apszMD, "json:TILEDB");
1221 :
1222 40 : return true;
1223 : }
1224 :
1225 : /************************************************************************/
1226 : /* GetDatabaseGeomColName() */
1227 : /************************************************************************/
1228 :
1229 1282 : const char *OGRTileDBLayer::GetDatabaseGeomColName()
1230 : {
1231 1282 : const char *pszGeomColName = GetGeometryColumn();
1232 1282 : if (pszGeomColName && pszGeomColName[0] == 0)
1233 33 : pszGeomColName = nullptr;
1234 1282 : return pszGeomColName;
1235 : }
1236 :
1237 : /************************************************************************/
1238 : /* SetReadBuffers() */
1239 : /************************************************************************/
1240 :
1241 329 : void OGRTileDBLayer::SetReadBuffers(bool bGrowVariableSizeArrays)
1242 : {
1243 : const auto GetValueSize =
1244 2063 : [this, bGrowVariableSizeArrays](const std::string & /*osColName*/,
1245 4110 : size_t nCapacity, size_t nMulFactor = 1)
1246 : {
1247 2063 : if (bGrowVariableSizeArrays)
1248 : {
1249 16 : CPLAssert(nCapacity > 0);
1250 16 : return 2 * nCapacity;
1251 : }
1252 2047 : return std::max(m_nBatchSize * nMulFactor, nCapacity);
1253 329 : };
1254 :
1255 329 : m_anFIDs->resize(m_nBatchSize);
1256 329 : if (!m_osFIDColumn.empty())
1257 : {
1258 326 : m_query->set_data_buffer(m_osFIDColumn, *(m_anFIDs));
1259 : }
1260 :
1261 329 : if (!m_poFeatureDefn->GetGeomFieldDefn(0)->IsIgnored())
1262 : {
1263 326 : const char *pszGeomColName = GetDatabaseGeomColName();
1264 326 : if (pszGeomColName)
1265 : {
1266 320 : m_anGeometryOffsets->resize(m_nBatchSize);
1267 320 : m_abyGeometries->resize(GetValueSize(pszGeomColName,
1268 : m_nGeometriesCapacity,
1269 : m_nEstimatedWkbSizePerRow));
1270 320 : m_nGeometriesCapacity = m_abyGeometries->capacity();
1271 320 : const auto colType = m_schema->attribute(pszGeomColName).type();
1272 320 : if (colType == TILEDB_UINT8)
1273 : {
1274 0 : m_query->set_data_buffer(pszGeomColName, *m_abyGeometries);
1275 : m_query->set_offsets_buffer(pszGeomColName,
1276 0 : *m_anGeometryOffsets);
1277 : }
1278 320 : else if (colType == TILEDB_BLOB)
1279 : {
1280 : m_query->set_data_buffer(
1281 : pszGeomColName,
1282 320 : reinterpret_cast<std::byte *>(m_abyGeometries->data()),
1283 640 : m_abyGeometries->size());
1284 : m_query->set_offsets_buffer(pszGeomColName,
1285 320 : m_anGeometryOffsets->data(),
1286 320 : m_anGeometryOffsets->size());
1287 : }
1288 : #ifdef HAS_TILEDB_GEOM_WKB_WKT
1289 : else if (colType == TILEDB_GEOM_WKB)
1290 : {
1291 : m_query->set_offsets_buffer(pszGeomColName,
1292 : *m_anGeometryOffsets);
1293 : // We could use API expected std::byte, but this requires
1294 : // TileDB 2.22 because of https://github.com/TileDB-Inc/TileDB/pull/4826
1295 : m_query->set_data_buffer(
1296 : pszGeomColName,
1297 : static_cast<void *>(m_abyGeometries->data()),
1298 : m_abyGeometries->size());
1299 : }
1300 : #endif
1301 : else
1302 : {
1303 0 : CPLAssert(false);
1304 : }
1305 : }
1306 : else
1307 : {
1308 6 : m_adfXs->resize(m_nBatchSize);
1309 6 : m_query->set_data_buffer(m_osXDim, *m_adfXs);
1310 :
1311 6 : m_adfYs->resize(m_nBatchSize);
1312 6 : m_query->set_data_buffer(m_osYDim, *m_adfYs);
1313 :
1314 6 : if (!m_osZDim.empty())
1315 : {
1316 2 : m_adfZs->resize(m_nBatchSize);
1317 2 : m_query->set_data_buffer(m_osZDim, *m_adfZs);
1318 : }
1319 : }
1320 : }
1321 :
1322 329 : if (m_anFieldValuesCapacity.empty())
1323 46 : m_anFieldValuesCapacity.resize(m_poFeatureDefn->GetFieldCount());
1324 :
1325 5079 : for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); ++i)
1326 : {
1327 4750 : const OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
1328 4750 : if (poFieldDefn->IsIgnored())
1329 3 : continue;
1330 4747 : const char *pszFieldName = poFieldDefn->GetNameRef();
1331 4747 : auto &anOffsets = *(m_aFieldValueOffsets[i]);
1332 4747 : if (poFieldDefn->IsNullable())
1333 : {
1334 2145 : m_aFieldValidity[i].resize(m_nBatchSize);
1335 2145 : m_query->set_validity_buffer(pszFieldName, m_aFieldValidity[i]);
1336 : }
1337 4747 : auto &fieldValues = m_aFieldValues[i];
1338 4747 : switch (poFieldDefn->GetType())
1339 : {
1340 1455 : case OFTInteger:
1341 : {
1342 1455 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
1343 : {
1344 : auto &v = *(
1345 242 : std::get<std::shared_ptr<VECTOR_OF_BOOL>>(fieldValues));
1346 242 : v.resize(m_nBatchSize);
1347 : #ifdef VECTOR_OF_BOOL_IS_NOT_UINT8_T
1348 : m_query->set_data_buffer(pszFieldName, v.data(), v.size());
1349 : #else
1350 242 : m_query->set_data_buffer(pszFieldName, v);
1351 : #endif
1352 : }
1353 1213 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
1354 : {
1355 : auto &v = *(std::get<std::shared_ptr<std::vector<int16_t>>>(
1356 242 : fieldValues));
1357 242 : v.resize(m_nBatchSize);
1358 242 : m_query->set_data_buffer(pszFieldName, v);
1359 : }
1360 971 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
1361 : {
1362 : auto &v = *(std::get<std::shared_ptr<std::vector<int32_t>>>(
1363 487 : fieldValues));
1364 487 : v.resize(m_nBatchSize);
1365 487 : m_query->set_data_buffer(pszFieldName, v);
1366 : }
1367 484 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
1368 : {
1369 : auto &v = *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
1370 242 : fieldValues));
1371 242 : v.resize(m_nBatchSize);
1372 242 : m_query->set_data_buffer(pszFieldName, v);
1373 : }
1374 242 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
1375 : {
1376 : auto &v =
1377 : *(std::get<std::shared_ptr<std::vector<uint16_t>>>(
1378 242 : fieldValues));
1379 242 : v.resize(m_nBatchSize);
1380 242 : m_query->set_data_buffer(pszFieldName, v);
1381 : }
1382 : else
1383 : {
1384 0 : CPLAssert(false);
1385 : }
1386 1455 : break;
1387 : }
1388 :
1389 726 : case OFTIntegerList:
1390 : {
1391 726 : auto iter = m_oMapEstimatedSizePerRow.find(pszFieldName);
1392 : const int nMulFactor =
1393 726 : iter != m_oMapEstimatedSizePerRow.end()
1394 726 : ? static_cast<int>(
1395 726 : std::min<uint64_t>(1000, iter->second))
1396 726 : : 8;
1397 726 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
1398 : {
1399 : auto &v = *(
1400 242 : std::get<std::shared_ptr<VECTOR_OF_BOOL>>(fieldValues));
1401 242 : v.resize(GetValueSize(
1402 242 : pszFieldName, m_anFieldValuesCapacity[i], nMulFactor));
1403 242 : m_anFieldValuesCapacity[i] = v.capacity();
1404 242 : anOffsets.resize(m_nBatchSize);
1405 242 : m_query->set_offsets_buffer(pszFieldName, anOffsets);
1406 : #ifdef VECTOR_OF_BOOL_IS_NOT_UINT8_T
1407 : m_query->set_data_buffer(pszFieldName, v.data(), v.size());
1408 : #else
1409 242 : m_query->set_data_buffer(pszFieldName, v);
1410 : #endif
1411 : }
1412 484 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
1413 : {
1414 : auto &v = *(std::get<std::shared_ptr<std::vector<int16_t>>>(
1415 242 : fieldValues));
1416 242 : v.resize(GetValueSize(
1417 242 : pszFieldName, m_anFieldValuesCapacity[i], nMulFactor));
1418 242 : m_anFieldValuesCapacity[i] = v.capacity();
1419 242 : anOffsets.resize(m_nBatchSize);
1420 242 : m_query->set_data_buffer(pszFieldName, v);
1421 242 : m_query->set_offsets_buffer(pszFieldName, anOffsets);
1422 : }
1423 242 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
1424 : {
1425 : auto &v = *(std::get<std::shared_ptr<std::vector<int32_t>>>(
1426 242 : fieldValues));
1427 242 : v.resize(GetValueSize(
1428 242 : pszFieldName, m_anFieldValuesCapacity[i], nMulFactor));
1429 242 : m_anFieldValuesCapacity[i] = v.capacity();
1430 242 : anOffsets.resize(m_nBatchSize);
1431 242 : m_query->set_data_buffer(pszFieldName, v);
1432 242 : m_query->set_offsets_buffer(pszFieldName, anOffsets);
1433 : }
1434 0 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
1435 : {
1436 : auto &v = *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
1437 0 : fieldValues));
1438 0 : v.resize(GetValueSize(
1439 0 : pszFieldName, m_anFieldValuesCapacity[i], nMulFactor));
1440 0 : m_anFieldValuesCapacity[i] = v.capacity();
1441 0 : anOffsets.resize(m_nBatchSize);
1442 0 : m_query->set_data_buffer(pszFieldName, v);
1443 0 : m_query->set_offsets_buffer(pszFieldName, anOffsets);
1444 : }
1445 0 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
1446 : {
1447 : auto &v =
1448 : *(std::get<std::shared_ptr<std::vector<uint16_t>>>(
1449 0 : fieldValues));
1450 0 : v.resize(GetValueSize(
1451 0 : pszFieldName, m_anFieldValuesCapacity[i], nMulFactor));
1452 0 : m_anFieldValuesCapacity[i] = v.capacity();
1453 0 : anOffsets.resize(m_nBatchSize);
1454 0 : m_query->set_data_buffer(pszFieldName, v);
1455 0 : m_query->set_offsets_buffer(pszFieldName, anOffsets);
1456 : }
1457 : else
1458 : {
1459 0 : CPLAssert(false);
1460 : }
1461 726 : break;
1462 : }
1463 :
1464 1017 : case OFTInteger64:
1465 : case OFTDate:
1466 : case OFTDateTime:
1467 : case OFTTime:
1468 : {
1469 : auto &v = *(std::get<std::shared_ptr<std::vector<int64_t>>>(
1470 1017 : fieldValues));
1471 1017 : v.resize(m_nBatchSize);
1472 1017 : m_query->set_data_buffer(pszFieldName, v);
1473 1017 : break;
1474 : }
1475 :
1476 0 : case OFTInteger64List:
1477 : {
1478 0 : auto iter = m_oMapEstimatedSizePerRow.find(pszFieldName);
1479 : const int nMulFactor =
1480 0 : iter != m_oMapEstimatedSizePerRow.end()
1481 0 : ? static_cast<int>(
1482 0 : std::min<uint64_t>(1000, iter->second))
1483 0 : : 8;
1484 : auto &v = *(std::get<std::shared_ptr<std::vector<int64_t>>>(
1485 0 : fieldValues));
1486 0 : v.resize(GetValueSize(pszFieldName, m_anFieldValuesCapacity[i],
1487 : nMulFactor));
1488 0 : m_anFieldValuesCapacity[i] = v.capacity();
1489 0 : anOffsets.resize(m_nBatchSize);
1490 0 : m_query->set_data_buffer(pszFieldName, v);
1491 0 : m_query->set_offsets_buffer(pszFieldName, anOffsets);
1492 0 : break;
1493 : }
1494 :
1495 532 : case OFTReal:
1496 : {
1497 532 : if (poFieldDefn->GetSubType() == OFSTFloat32)
1498 : {
1499 : auto &v = *(std::get<std::shared_ptr<std::vector<float>>>(
1500 242 : fieldValues));
1501 242 : v.resize(m_nBatchSize);
1502 242 : m_query->set_data_buffer(pszFieldName, v);
1503 : }
1504 : else
1505 : {
1506 : auto &v = *(std::get<std::shared_ptr<std::vector<double>>>(
1507 290 : fieldValues));
1508 290 : v.resize(m_nBatchSize);
1509 290 : m_query->set_data_buffer(pszFieldName, v);
1510 : }
1511 532 : break;
1512 : }
1513 :
1514 484 : case OFTRealList:
1515 : {
1516 484 : auto iter = m_oMapEstimatedSizePerRow.find(pszFieldName);
1517 : const int nMulFactor =
1518 484 : iter != m_oMapEstimatedSizePerRow.end()
1519 484 : ? static_cast<int>(
1520 484 : std::min<uint64_t>(1000, iter->second))
1521 484 : : 8;
1522 484 : anOffsets.resize(m_nBatchSize);
1523 484 : if (poFieldDefn->GetSubType() == OFSTFloat32)
1524 : {
1525 : auto &v = *(std::get<std::shared_ptr<std::vector<float>>>(
1526 242 : fieldValues));
1527 242 : v.resize(GetValueSize(
1528 242 : pszFieldName, m_anFieldValuesCapacity[i], nMulFactor));
1529 242 : m_anFieldValuesCapacity[i] = v.capacity();
1530 242 : m_query->set_data_buffer(pszFieldName, v);
1531 242 : m_query->set_offsets_buffer(pszFieldName, anOffsets);
1532 : }
1533 : else
1534 : {
1535 : auto &v = *(std::get<std::shared_ptr<std::vector<double>>>(
1536 242 : fieldValues));
1537 242 : v.resize(GetValueSize(
1538 242 : pszFieldName, m_anFieldValuesCapacity[i], nMulFactor));
1539 242 : m_anFieldValuesCapacity[i] = v.capacity();
1540 242 : m_query->set_data_buffer(pszFieldName, v);
1541 242 : m_query->set_offsets_buffer(pszFieldName, anOffsets);
1542 : }
1543 484 : break;
1544 : }
1545 :
1546 291 : case OFTString:
1547 : {
1548 : auto &v =
1549 291 : *(std::get<std::shared_ptr<std::string>>(fieldValues));
1550 291 : auto iter = m_oMapEstimatedSizePerRow.find(pszFieldName);
1551 580 : v.resize(GetValueSize(pszFieldName, m_anFieldValuesCapacity[i],
1552 291 : iter != m_oMapEstimatedSizePerRow.end()
1553 289 : ? iter->second
1554 : : 8));
1555 291 : m_anFieldValuesCapacity[i] = v.capacity();
1556 291 : anOffsets.resize(m_nBatchSize);
1557 291 : m_query->set_data_buffer(pszFieldName, v);
1558 291 : m_query->set_offsets_buffer(pszFieldName, anOffsets);
1559 291 : break;
1560 : }
1561 :
1562 242 : case OFTBinary:
1563 : {
1564 242 : const auto eType = m_schema->attribute(pszFieldName).type();
1565 : auto &v = *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
1566 242 : fieldValues));
1567 242 : auto iter = m_oMapEstimatedSizePerRow.find(pszFieldName);
1568 484 : v.resize(GetValueSize(pszFieldName, m_anFieldValuesCapacity[i],
1569 242 : iter != m_oMapEstimatedSizePerRow.end()
1570 242 : ? iter->second
1571 : : 8));
1572 242 : m_anFieldValuesCapacity[i] = v.capacity();
1573 242 : anOffsets.resize(m_nBatchSize);
1574 242 : if (eType == TILEDB_UINT8)
1575 : {
1576 0 : m_query->set_data_buffer(pszFieldName, v);
1577 0 : m_query->set_offsets_buffer(pszFieldName, anOffsets);
1578 : }
1579 242 : else if (eType == TILEDB_BLOB)
1580 : {
1581 : m_query->set_data_buffer(
1582 242 : pszFieldName, reinterpret_cast<std::byte *>(v.data()),
1583 484 : v.size());
1584 : m_query->set_offsets_buffer(pszFieldName, anOffsets.data(),
1585 242 : anOffsets.size());
1586 : }
1587 : else
1588 : {
1589 0 : CPLAssert(false);
1590 : }
1591 242 : break;
1592 : }
1593 :
1594 0 : default:
1595 : {
1596 0 : CPLAssert(false);
1597 : break;
1598 : }
1599 : }
1600 : }
1601 329 : }
1602 :
1603 : /************************************************************************/
1604 : /* SetupQuery() */
1605 : /************************************************************************/
1606 :
1607 : namespace
1608 : {
1609 : template <class T> struct ResetArray
1610 : {
1611 703 : static void exec(OGRTileDBLayer::ArrayType &array)
1612 : {
1613 703 : array = std::make_shared<T>();
1614 703 : }
1615 : };
1616 : } // namespace
1617 :
1618 60 : void OGRTileDBLayer::AllocateNewBuffers()
1619 : {
1620 60 : m_anFIDs = std::make_shared<std::vector<int64_t>>();
1621 60 : m_adfXs = std::make_shared<std::vector<double>>();
1622 60 : m_adfYs = std::make_shared<std::vector<double>>();
1623 60 : m_adfZs = std::make_shared<std::vector<double>>();
1624 60 : m_abyGeometries = std::make_shared<std::vector<unsigned char>>();
1625 60 : m_anGeometryOffsets = std::make_shared<std::vector<uint64_t>>();
1626 :
1627 763 : for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
1628 : {
1629 703 : ProcessField<ResetArray>::exec(m_aeFieldTypes[i], m_aFieldValues[i]);
1630 :
1631 703 : m_aFieldValueOffsets[i] = std::make_shared<std::vector<uint64_t>>();
1632 : }
1633 60 : }
1634 :
1635 355 : bool OGRTileDBLayer::SetupQuery(tiledb::QueryCondition *queryCondition)
1636 : {
1637 355 : if (!m_bArrowBatchReleased)
1638 : {
1639 21 : AllocateNewBuffers();
1640 : }
1641 :
1642 355 : m_anFIDs->clear();
1643 355 : m_adfXs->clear();
1644 355 : m_anGeometryOffsets->clear();
1645 355 : m_nOffsetInResultSet = 0;
1646 355 : m_nRowCountInResultSet = 0;
1647 355 : if (m_bAttributeFilterAlwaysFalse)
1648 22 : return false;
1649 :
1650 333 : const char *pszGeomColName = GetDatabaseGeomColName();
1651 :
1652 : // FIXME: remove this
1653 333 : const bool bHitBug = CPLTestBool(CPLGetConfigOption("TILEDB_BUG", "NO"));
1654 333 : if (bHitBug)
1655 : {
1656 0 : m_nBatchSize = 1;
1657 0 : m_nEstimatedWkbSizePerRow = 10;
1658 : }
1659 :
1660 : try
1661 : {
1662 333 : if (!m_query)
1663 : {
1664 293 : m_query = std::make_unique<tiledb::Query>(*m_ctx, *m_array);
1665 293 : m_query->set_layout(TILEDB_UNORDERED);
1666 293 : if (queryCondition)
1667 14 : m_query->set_condition(*queryCondition);
1668 279 : else if (m_poQueryCondition)
1669 133 : m_query->set_condition(*(m_poQueryCondition.get()));
1670 :
1671 293 : if (m_nEstimatedWkbSizePerRow == 0)
1672 : {
1673 194 : for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); ++i)
1674 : {
1675 : const OGRFieldDefn *poFieldDefn =
1676 159 : m_poFeatureDefn->GetFieldDefn(i);
1677 159 : const char *pszFieldName = poFieldDefn->GetNameRef();
1678 159 : switch (poFieldDefn->GetType())
1679 : {
1680 59 : case OFTString:
1681 : case OFTBinary:
1682 : case OFTIntegerList:
1683 : case OFTInteger64List:
1684 : case OFTRealList:
1685 : {
1686 : uint64_t nEstRows;
1687 : uint64_t nEstBytes;
1688 59 : if (poFieldDefn->IsNullable())
1689 : {
1690 : const auto estimation =
1691 : m_query->est_result_size_var_nullable(
1692 31 : pszFieldName);
1693 31 : nEstRows = estimation[0] / sizeof(uint64_t);
1694 31 : nEstBytes = estimation[1];
1695 : }
1696 : else
1697 : {
1698 : const auto estimation =
1699 28 : m_query->est_result_size_var(pszFieldName);
1700 28 : nEstRows = estimation[0] / sizeof(uint64_t);
1701 28 : nEstBytes = estimation[1];
1702 : }
1703 59 : if (nEstRows)
1704 : {
1705 57 : m_oMapEstimatedSizePerRow[pszFieldName] =
1706 57 : std::max<size_t>(1,
1707 : static_cast<size_t>(
1708 57 : nEstBytes / nEstRows) *
1709 57 : 4 / 3);
1710 57 : CPLDebug("TILEDB", "Average %s size: %u bytes",
1711 : pszFieldName,
1712 : static_cast<unsigned>(
1713 : m_oMapEstimatedSizePerRow
1714 57 : [pszFieldName]));
1715 : }
1716 59 : break;
1717 : }
1718 :
1719 100 : default:
1720 100 : break;
1721 : }
1722 : }
1723 :
1724 35 : m_nEstimatedWkbSizePerRow = 9; // Size of 2D point WKB
1725 35 : if (pszGeomColName)
1726 : {
1727 : const auto estimation =
1728 29 : m_query->est_result_size_var(pszGeomColName);
1729 29 : const uint64_t nEstRows = estimation[0] / sizeof(uint64_t);
1730 29 : const uint64_t nEstBytes = estimation[1];
1731 29 : if (nEstRows)
1732 : {
1733 27 : m_nEstimatedWkbSizePerRow = std::max(
1734 27 : m_nEstimatedWkbSizePerRow,
1735 27 : static_cast<size_t>(nEstBytes / nEstRows) * 4 / 3);
1736 27 : CPLDebug(
1737 : "TILEDB", "Average WKB size: %u bytes",
1738 27 : static_cast<unsigned>(m_nEstimatedWkbSizePerRow));
1739 : }
1740 : }
1741 : }
1742 :
1743 293 : if (m_poFilterGeom && queryCondition == nullptr)
1744 : {
1745 47 : tiledb::Subarray subarray(*m_ctx, *m_array);
1746 :
1747 : const double dfMinX =
1748 47 : std::max(m_dfXStart, m_sFilterEnvelope.MinX - m_dfPadX);
1749 : const double dfMaxX =
1750 47 : std::min(m_dfXEnd, m_sFilterEnvelope.MaxX + m_dfPadX);
1751 : const double dfMinY =
1752 47 : std::max(m_dfYStart, m_sFilterEnvelope.MinY - m_dfPadY);
1753 : const double dfMaxY =
1754 47 : std::min(m_dfYEnd, m_sFilterEnvelope.MaxY + m_dfPadY);
1755 :
1756 47 : if (dfMaxX < dfMinX || dfMaxY < dfMinY)
1757 : {
1758 4 : m_bQueryComplete = true;
1759 4 : return false;
1760 : }
1761 :
1762 43 : subarray.add_range(m_osXDim, dfMinX, dfMaxX);
1763 43 : subarray.add_range(m_osYDim, dfMinY, dfMaxY);
1764 43 : m_query->set_subarray(subarray);
1765 : }
1766 : }
1767 :
1768 329 : SetReadBuffers(m_bGrowBuffers);
1769 329 : m_bGrowBuffers = false;
1770 :
1771 : // Create a loop
1772 : tiledb::Query::Status status;
1773 329 : uint64_t nRowCount = 0;
1774 : while (true)
1775 : {
1776 : // Submit query and get status
1777 329 : if (m_bStats)
1778 0 : tiledb::Stats::enable();
1779 :
1780 329 : m_query->submit();
1781 :
1782 329 : if (m_bStats)
1783 : {
1784 0 : tiledb::Stats::dump(stdout);
1785 0 : tiledb::Stats::disable();
1786 : }
1787 :
1788 329 : status = m_query->query_status();
1789 329 : if (status == tiledb::Query::Status::FAILED)
1790 : {
1791 0 : CPLError(CE_Failure, CPLE_AppDefined, "Query failed");
1792 0 : m_bQueryComplete = true;
1793 0 : return false;
1794 : }
1795 :
1796 : const auto result_buffer_elements =
1797 329 : m_query->result_buffer_elements();
1798 329 : if (m_osFIDColumn.empty())
1799 : {
1800 3 : auto oIter = result_buffer_elements.begin();
1801 3 : if (oIter != result_buffer_elements.end())
1802 3 : nRowCount = oIter->second.second;
1803 : }
1804 : else
1805 : {
1806 326 : auto oIter = result_buffer_elements.find(m_osFIDColumn);
1807 326 : if (oIter != result_buffer_elements.end())
1808 326 : nRowCount = oIter->second.second;
1809 : }
1810 329 : if (!m_poFeatureDefn->GetGeomFieldDefn(0)->IsIgnored() &&
1811 : pszGeomColName)
1812 : {
1813 320 : auto oIter = result_buffer_elements.find(pszGeomColName);
1814 320 : if (oIter != result_buffer_elements.end())
1815 : {
1816 320 : const auto &result = oIter->second;
1817 320 : nRowCount = std::min(nRowCount, result.first);
1818 : // For some reason, result.first can be 1, and result.second 0
1819 320 : if (!bHitBug && result.second == 0)
1820 46 : nRowCount = 0;
1821 : }
1822 : else
1823 : {
1824 0 : CPLAssert(false);
1825 : }
1826 : }
1827 5079 : for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); ++i)
1828 : {
1829 : const OGRFieldDefn *poFieldDefn =
1830 4750 : m_poFeatureDefn->GetFieldDefn(i);
1831 4750 : if (!poFieldDefn->IsIgnored())
1832 : {
1833 4747 : const char *pszFieldName = poFieldDefn->GetNameRef();
1834 4747 : auto oIter = result_buffer_elements.find(pszFieldName);
1835 4747 : if (oIter != result_buffer_elements.end())
1836 : {
1837 4747 : const auto &result = oIter->second;
1838 4747 : if (result.first == 0)
1839 : {
1840 3290 : nRowCount = std::min(nRowCount, result.second);
1841 : }
1842 : else
1843 1457 : nRowCount = std::min(nRowCount, result.first);
1844 : }
1845 : else
1846 : {
1847 0 : CPLAssert(false);
1848 : }
1849 : }
1850 : }
1851 :
1852 329 : if (status != tiledb::Query::Status::INCOMPLETE)
1853 289 : break;
1854 :
1855 40 : if (bHitBug)
1856 : {
1857 0 : if (nRowCount > 0)
1858 0 : break;
1859 0 : SetReadBuffers(true);
1860 : }
1861 40 : else if (nRowCount < m_nBatchSize)
1862 : {
1863 2 : if (nRowCount > 0)
1864 : {
1865 2 : m_bGrowBuffers = true;
1866 2 : break;
1867 : }
1868 0 : CPLDebug("TILEDB", "Got 0 rows. Grow buffers");
1869 0 : SetReadBuffers(true);
1870 : }
1871 : else
1872 38 : break;
1873 0 : }
1874 :
1875 329 : m_bQueryComplete = (status == tiledb::Query::Status::COMPLETE);
1876 329 : m_nRowCountInResultSet = nRowCount;
1877 :
1878 329 : if (nRowCount == 0)
1879 : {
1880 46 : m_bQueryComplete = true;
1881 46 : return false;
1882 : }
1883 : //CPLDebug("TILEDB", "Read %d rows", int(nRowCount));
1884 :
1885 566 : const auto result_buffer_elements = m_query->result_buffer_elements();
1886 283 : m_anFIDs->resize(nRowCount);
1887 283 : if (m_osFIDColumn.empty())
1888 : {
1889 7 : for (uint64_t i = 0; i < nRowCount; ++i)
1890 : {
1891 4 : (*m_anFIDs)[i] = m_nNextFID;
1892 4 : m_nNextFID++;
1893 : }
1894 : }
1895 :
1896 283 : if (!m_poFeatureDefn->GetGeomFieldDefn(0)->IsIgnored())
1897 : {
1898 280 : if (pszGeomColName)
1899 : {
1900 274 : auto oIter = result_buffer_elements.find(pszGeomColName);
1901 274 : if (oIter != result_buffer_elements.end())
1902 : {
1903 274 : const auto &result = oIter->second;
1904 274 : if (nRowCount < result.first)
1905 : {
1906 0 : m_abyGeometries->resize(
1907 0 : (*m_anGeometryOffsets)[nRowCount]);
1908 : }
1909 : else
1910 : {
1911 274 : m_abyGeometries->resize(
1912 274 : static_cast<size_t>(result.second));
1913 : }
1914 274 : m_anGeometryOffsets->resize(nRowCount);
1915 : }
1916 : }
1917 : else
1918 : {
1919 6 : m_adfXs->resize(nRowCount);
1920 6 : m_adfYs->resize(nRowCount);
1921 6 : if (!m_osZDim.empty())
1922 2 : m_adfZs->resize(nRowCount);
1923 : }
1924 : }
1925 :
1926 4259 : for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); ++i)
1927 : {
1928 3976 : const OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
1929 3976 : if (poFieldDefn->IsIgnored())
1930 3 : continue;
1931 3973 : const char *pszFieldName = poFieldDefn->GetNameRef();
1932 3973 : auto &anOffsets = *(m_aFieldValueOffsets[i]);
1933 3973 : auto oIter = result_buffer_elements.find(pszFieldName);
1934 3973 : if (oIter == result_buffer_elements.end())
1935 : {
1936 0 : CPLAssert(false);
1937 : continue;
1938 : }
1939 3973 : const auto &result = oIter->second;
1940 3973 : if (poFieldDefn->IsNullable())
1941 1751 : m_aFieldValidity[i].resize(nRowCount);
1942 3973 : auto &fieldValues = m_aFieldValues[i];
1943 3973 : switch (poFieldDefn->GetType())
1944 : {
1945 1215 : case OFTInteger:
1946 : {
1947 1215 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
1948 : {
1949 : auto &v = *(std::get<std::shared_ptr<VECTOR_OF_BOOL>>(
1950 202 : fieldValues));
1951 202 : v.resize(result.second);
1952 : }
1953 1013 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
1954 : {
1955 : auto &v =
1956 : *(std::get<std::shared_ptr<std::vector<int16_t>>>(
1957 202 : fieldValues));
1958 202 : v.resize(result.second);
1959 : }
1960 811 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
1961 : {
1962 : auto &v =
1963 : *(std::get<std::shared_ptr<std::vector<int32_t>>>(
1964 407 : fieldValues));
1965 407 : v.resize(result.second);
1966 : }
1967 404 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
1968 : {
1969 : auto &v =
1970 : *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
1971 202 : fieldValues));
1972 202 : v.resize(result.second);
1973 : }
1974 202 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
1975 : {
1976 : auto &v =
1977 : *(std::get<std::shared_ptr<std::vector<uint16_t>>>(
1978 202 : fieldValues));
1979 202 : v.resize(result.second);
1980 : }
1981 : else
1982 : {
1983 0 : CPLAssert(false);
1984 : }
1985 1215 : break;
1986 : }
1987 :
1988 606 : case OFTIntegerList:
1989 : {
1990 606 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
1991 : {
1992 : auto &v = *(std::get<std::shared_ptr<VECTOR_OF_BOOL>>(
1993 202 : fieldValues));
1994 202 : if (nRowCount < result.first)
1995 : {
1996 0 : v.resize(anOffsets[nRowCount] / sizeof(v[0]));
1997 : }
1998 : else
1999 : {
2000 202 : v.resize(static_cast<size_t>(result.second));
2001 : }
2002 : }
2003 404 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
2004 : {
2005 : auto &v =
2006 : *(std::get<std::shared_ptr<std::vector<int16_t>>>(
2007 202 : fieldValues));
2008 202 : if (nRowCount < result.first)
2009 : {
2010 0 : v.resize(anOffsets[nRowCount] / sizeof(v[0]));
2011 : }
2012 : else
2013 : {
2014 202 : v.resize(static_cast<size_t>(result.second));
2015 : }
2016 : }
2017 202 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
2018 : {
2019 : auto &v =
2020 : *(std::get<std::shared_ptr<std::vector<int32_t>>>(
2021 202 : fieldValues));
2022 202 : if (nRowCount < result.first)
2023 : {
2024 0 : v.resize(anOffsets[nRowCount] / sizeof(v[0]));
2025 : }
2026 : else
2027 : {
2028 202 : v.resize(static_cast<size_t>(result.second));
2029 : }
2030 : }
2031 0 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
2032 : {
2033 : auto &v =
2034 : *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
2035 0 : fieldValues));
2036 0 : if (nRowCount < result.first)
2037 : {
2038 0 : v.resize(anOffsets[nRowCount] / sizeof(v[0]));
2039 : }
2040 : else
2041 : {
2042 0 : v.resize(static_cast<size_t>(result.second));
2043 : }
2044 : }
2045 0 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
2046 : {
2047 : auto &v =
2048 : *(std::get<std::shared_ptr<std::vector<uint16_t>>>(
2049 0 : fieldValues));
2050 0 : if (nRowCount < result.first)
2051 : {
2052 0 : v.resize(anOffsets[nRowCount] / sizeof(v[0]));
2053 : }
2054 : else
2055 : {
2056 0 : v.resize(static_cast<size_t>(result.second));
2057 : }
2058 : }
2059 : else
2060 : {
2061 0 : CPLAssert(false);
2062 : }
2063 606 : anOffsets.resize(nRowCount);
2064 606 : break;
2065 : }
2066 :
2067 853 : case OFTInteger64:
2068 : case OFTDate:
2069 : case OFTDateTime:
2070 : case OFTTime:
2071 : {
2072 : auto &v = *(std::get<std::shared_ptr<std::vector<int64_t>>>(
2073 853 : fieldValues));
2074 853 : v.resize(result.second);
2075 853 : break;
2076 : }
2077 :
2078 0 : case OFTInteger64List:
2079 : {
2080 : auto &v = *(std::get<std::shared_ptr<std::vector<int64_t>>>(
2081 0 : fieldValues));
2082 0 : if (nRowCount < result.first)
2083 : {
2084 0 : v.resize(anOffsets[nRowCount] / sizeof(v[0]));
2085 : }
2086 : else
2087 : {
2088 0 : v.resize(static_cast<size_t>(result.second));
2089 : }
2090 0 : anOffsets.resize(nRowCount);
2091 0 : break;
2092 : }
2093 :
2094 448 : case OFTReal:
2095 : {
2096 448 : if (poFieldDefn->GetSubType() == OFSTFloat32)
2097 : {
2098 : auto &v =
2099 : *(std::get<std::shared_ptr<std::vector<float>>>(
2100 202 : fieldValues));
2101 202 : v.resize(result.second);
2102 : }
2103 : else
2104 : {
2105 : auto &v =
2106 : *(std::get<std::shared_ptr<std::vector<double>>>(
2107 246 : fieldValues));
2108 246 : v.resize(result.second);
2109 : }
2110 448 : break;
2111 : }
2112 :
2113 404 : case OFTRealList:
2114 : {
2115 404 : if (poFieldDefn->GetSubType() == OFSTFloat32)
2116 : {
2117 : auto &v =
2118 : *(std::get<std::shared_ptr<std::vector<float>>>(
2119 202 : fieldValues));
2120 202 : if (nRowCount < result.first)
2121 : {
2122 0 : v.resize(anOffsets[nRowCount] / sizeof(v[0]));
2123 : }
2124 : else
2125 : {
2126 202 : v.resize(static_cast<size_t>(result.second));
2127 : }
2128 : }
2129 : else
2130 : {
2131 : auto &v =
2132 : *(std::get<std::shared_ptr<std::vector<double>>>(
2133 202 : fieldValues));
2134 202 : if (nRowCount < result.first)
2135 : {
2136 0 : v.resize(anOffsets[nRowCount] / sizeof(v[0]));
2137 : }
2138 : else
2139 : {
2140 202 : v.resize(static_cast<size_t>(result.second));
2141 : }
2142 : }
2143 404 : anOffsets.resize(nRowCount);
2144 404 : break;
2145 : }
2146 :
2147 245 : case OFTString:
2148 : {
2149 : auto &v =
2150 245 : *(std::get<std::shared_ptr<std::string>>(fieldValues));
2151 245 : if (nRowCount < result.first)
2152 : {
2153 0 : v.resize(anOffsets[nRowCount] / sizeof(v[0]));
2154 : }
2155 : else
2156 : {
2157 245 : v.resize(static_cast<size_t>(result.second));
2158 : }
2159 245 : anOffsets.resize(nRowCount);
2160 245 : break;
2161 : }
2162 :
2163 202 : case OFTBinary:
2164 : {
2165 : auto &v = *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
2166 202 : fieldValues));
2167 202 : if (nRowCount < result.first)
2168 : {
2169 0 : v.resize(anOffsets[nRowCount] / sizeof(v[0]));
2170 : }
2171 : else
2172 : {
2173 202 : v.resize(static_cast<size_t>(result.second));
2174 : }
2175 202 : anOffsets.resize(nRowCount);
2176 202 : break;
2177 : }
2178 :
2179 0 : default:
2180 : {
2181 0 : CPLAssert(false);
2182 : break;
2183 : }
2184 : }
2185 : }
2186 : }
2187 0 : catch (const std::exception &e)
2188 : {
2189 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
2190 0 : m_bQueryComplete = true;
2191 0 : return false;
2192 : }
2193 :
2194 283 : return true;
2195 : }
2196 :
2197 : /************************************************************************/
2198 : /* SwitchToReadingMode() */
2199 : /************************************************************************/
2200 :
2201 591 : void OGRTileDBLayer::SwitchToReadingMode()
2202 : {
2203 591 : if (m_eCurrentMode == CurrentMode::WriteInProgress)
2204 : {
2205 3 : m_eCurrentMode = CurrentMode::None;
2206 : try
2207 : {
2208 3 : if (m_array)
2209 : {
2210 3 : if (!m_adfXs->empty())
2211 : {
2212 3 : FlushArrays();
2213 : }
2214 3 : m_array->close();
2215 3 : m_array.reset();
2216 : }
2217 : }
2218 0 : catch (const std::exception &e)
2219 : {
2220 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
2221 0 : m_array.reset();
2222 0 : return;
2223 : }
2224 :
2225 : try
2226 : {
2227 3 : if (m_nTimestamp)
2228 0 : m_array.reset(new tiledb::Array(
2229 0 : *m_ctx, m_osFilename, TILEDB_READ,
2230 0 : tiledb::TemporalPolicy(tiledb::TimeTravel, m_nTimestamp)));
2231 : else
2232 6 : m_array.reset(
2233 6 : new tiledb::Array(*m_ctx, m_osFilename, TILEDB_READ));
2234 : }
2235 0 : catch (const std::exception &e)
2236 : {
2237 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
2238 0 : return;
2239 : }
2240 : }
2241 591 : m_eCurrentMode = CurrentMode::ReadInProgress;
2242 : }
2243 :
2244 : /************************************************************************/
2245 : /* GetNextRawFeature() */
2246 : /************************************************************************/
2247 :
2248 723 : OGRFeature *OGRTileDBLayer::GetNextRawFeature()
2249 : {
2250 723 : if (m_eCurrentMode == CurrentMode::WriteInProgress)
2251 : {
2252 2 : ResetReading();
2253 : }
2254 723 : if (!m_array)
2255 0 : return nullptr;
2256 :
2257 723 : if (m_nOffsetInResultSet >= m_nRowCountInResultSet)
2258 : {
2259 454 : if (m_bQueryComplete)
2260 162 : return nullptr;
2261 :
2262 292 : if (!SetupQuery(nullptr))
2263 67 : return nullptr;
2264 : }
2265 :
2266 494 : return TranslateCurrentFeature();
2267 : }
2268 :
2269 : /***********************************************************************/
2270 : /* GetColumnSubNode() */
2271 : /***********************************************************************/
2272 :
2273 199 : static const swq_expr_node *GetColumnSubNode(const swq_expr_node *poNode)
2274 : {
2275 199 : if (poNode->eNodeType == SNT_OPERATION && poNode->nSubExprCount == 2)
2276 : {
2277 199 : if (poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN)
2278 158 : return poNode->papoSubExpr[0];
2279 41 : if (poNode->papoSubExpr[1]->eNodeType == SNT_COLUMN)
2280 22 : return poNode->papoSubExpr[1];
2281 : }
2282 19 : return nullptr;
2283 : }
2284 :
2285 : /***********************************************************************/
2286 : /* GetConstantSubNode() */
2287 : /***********************************************************************/
2288 :
2289 199 : static const swq_expr_node *GetConstantSubNode(const swq_expr_node *poNode)
2290 : {
2291 199 : if (poNode->eNodeType == SNT_OPERATION && poNode->nSubExprCount == 2)
2292 : {
2293 199 : if (poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT)
2294 177 : return poNode->papoSubExpr[1];
2295 22 : if (poNode->papoSubExpr[0]->eNodeType == SNT_CONSTANT)
2296 22 : return poNode->papoSubExpr[0];
2297 : }
2298 0 : return nullptr;
2299 : }
2300 :
2301 : /***********************************************************************/
2302 : /* IsComparisonOp() */
2303 : /***********************************************************************/
2304 :
2305 255 : static bool IsComparisonOp(int op)
2306 : {
2307 138 : return (op == SWQ_EQ || op == SWQ_NE || op == SWQ_LT || op == SWQ_LE ||
2308 393 : op == SWQ_GT || op == SWQ_GE);
2309 : }
2310 :
2311 : /***********************************************************************/
2312 : /* OGRFieldToTimeMS() */
2313 : /***********************************************************************/
2314 :
2315 14 : static int64_t OGRFieldToTimeMS(const OGRField &sField)
2316 : {
2317 14 : GIntBig nVal = sField.Date.Hour * 3600 + sField.Date.Minute * 60;
2318 : return static_cast<int64_t>(
2319 14 : (static_cast<double>(nVal) + sField.Date.Second) * 1000 + 0.5);
2320 : }
2321 :
2322 : /***********************************************************************/
2323 : /* OGRFieldToDateDay() */
2324 : /***********************************************************************/
2325 :
2326 16 : static int64_t OGRFieldToDateDay(const OGRField &sField)
2327 : {
2328 : struct tm brokenDown;
2329 16 : memset(&brokenDown, 0, sizeof(brokenDown));
2330 16 : brokenDown.tm_year = sField.Date.Year - 1900;
2331 16 : brokenDown.tm_mon = sField.Date.Month - 1;
2332 16 : brokenDown.tm_mday = sField.Date.Day;
2333 16 : brokenDown.tm_hour = 0;
2334 16 : brokenDown.tm_min = 0;
2335 16 : brokenDown.tm_sec = 0;
2336 16 : GIntBig nVal = CPLYMDHMSToUnixTime(&brokenDown);
2337 16 : return static_cast<int64_t>(nVal / SECONDS_PER_DAY);
2338 : }
2339 :
2340 : /***********************************************************************/
2341 : /* OGRFieldToDateTimeMS() */
2342 : /***********************************************************************/
2343 :
2344 16 : static int64_t OGRFieldToDateTimeMS(const OGRField &sField)
2345 : {
2346 : struct tm brokenDown;
2347 16 : memset(&brokenDown, 0, sizeof(brokenDown));
2348 16 : brokenDown.tm_year = sField.Date.Year - 1900;
2349 16 : brokenDown.tm_mon = sField.Date.Month - 1;
2350 16 : brokenDown.tm_mday = sField.Date.Day;
2351 16 : brokenDown.tm_hour = sField.Date.Hour;
2352 16 : brokenDown.tm_min = sField.Date.Minute;
2353 16 : brokenDown.tm_sec = 0;
2354 16 : GIntBig nVal = CPLYMDHMSToUnixTime(&brokenDown);
2355 16 : if (sField.Date.TZFlag != 0 && sField.Date.TZFlag != 1)
2356 : {
2357 16 : nVal -= (sField.Date.TZFlag - 100) * 15 * 60;
2358 : }
2359 : return static_cast<int64_t>(
2360 16 : (static_cast<double>(nVal) + sField.Date.Second) * 1000 + 0.5);
2361 : }
2362 :
2363 : /***********************************************************************/
2364 : /* CreateQueryConditionForIntType() */
2365 : /***********************************************************************/
2366 :
2367 : template <typename T>
2368 : static std::unique_ptr<tiledb::QueryCondition>
2369 30 : CreateQueryConditionForIntType(tiledb::Context &ctx,
2370 : const OGRFieldDefn *poFieldDefn, int nVal,
2371 : tiledb_query_condition_op_t tiledb_op,
2372 : bool &bAlwaysTrue, bool &bAlwaysFalse)
2373 : {
2374 48 : if (nVal >= static_cast<int>(std::numeric_limits<T>::min()) &&
2375 18 : nVal <= static_cast<int>(std::numeric_limits<T>::max()))
2376 : {
2377 : return std::make_unique<tiledb::QueryCondition>(
2378 : tiledb::QueryCondition::create(ctx, poFieldDefn->GetNameRef(),
2379 6 : static_cast<T>(nVal), tiledb_op));
2380 : }
2381 24 : else if (tiledb_op == TILEDB_EQ)
2382 : {
2383 4 : bAlwaysFalse = true;
2384 : }
2385 20 : else if (tiledb_op == TILEDB_NE)
2386 : {
2387 4 : bAlwaysTrue = true;
2388 : }
2389 16 : else if (nVal > static_cast<int>(std::numeric_limits<T>::max()))
2390 : {
2391 8 : bAlwaysTrue = (tiledb_op == TILEDB_LE || tiledb_op == TILEDB_LT);
2392 8 : bAlwaysFalse = (tiledb_op == TILEDB_GE || tiledb_op == TILEDB_GT);
2393 : }
2394 8 : else if (nVal < static_cast<int>(std::numeric_limits<T>::min()))
2395 : {
2396 8 : bAlwaysTrue = (tiledb_op == TILEDB_GE || tiledb_op == TILEDB_GT);
2397 8 : bAlwaysFalse = (tiledb_op == TILEDB_LE || tiledb_op == TILEDB_LT);
2398 : }
2399 24 : return nullptr;
2400 : }
2401 :
2402 : /***********************************************************************/
2403 : /* CreateQueryCondition() */
2404 : /***********************************************************************/
2405 :
2406 207 : std::unique_ptr<tiledb::QueryCondition> OGRTileDBLayer::CreateQueryCondition(
2407 : int nOperation, bool bColumnIsLeft, const swq_expr_node *poColumn,
2408 : const swq_expr_node *poValue, bool &bAlwaysTrue, bool &bAlwaysFalse)
2409 : {
2410 207 : bAlwaysTrue = false;
2411 207 : bAlwaysFalse = false;
2412 :
2413 395 : if (poColumn != nullptr && poValue != nullptr &&
2414 188 : poColumn->field_index < m_poFeatureDefn->GetFieldCount())
2415 : {
2416 : const OGRFieldDefn *poFieldDefn =
2417 188 : m_poFeatureDefn->GetFieldDefn(poColumn->field_index);
2418 :
2419 188 : if (!bColumnIsLeft)
2420 : {
2421 : /* If "constant op column", then we must reverse */
2422 : /* the operator for LE, LT, GE, GT */
2423 22 : switch (nOperation)
2424 : {
2425 4 : case SWQ_LE:
2426 4 : nOperation = SWQ_GE;
2427 4 : break;
2428 4 : case SWQ_LT:
2429 4 : nOperation = SWQ_GT;
2430 4 : break;
2431 2 : case SWQ_NE: /* do nothing */;
2432 2 : break;
2433 2 : case SWQ_EQ: /* do nothing */;
2434 2 : break;
2435 4 : case SWQ_GE:
2436 4 : nOperation = SWQ_LE;
2437 4 : break;
2438 6 : case SWQ_GT:
2439 6 : nOperation = SWQ_LT;
2440 6 : break;
2441 0 : default:
2442 0 : CPLAssert(false);
2443 : break;
2444 : }
2445 : }
2446 :
2447 188 : tiledb_query_condition_op_t tiledb_op = TILEDB_EQ;
2448 188 : switch (nOperation)
2449 : {
2450 12 : case SWQ_LE:
2451 12 : tiledb_op = TILEDB_LE;
2452 12 : break;
2453 14 : case SWQ_LT:
2454 14 : tiledb_op = TILEDB_LT;
2455 14 : break;
2456 30 : case SWQ_NE:
2457 30 : tiledb_op = TILEDB_NE;
2458 30 : break;
2459 106 : case SWQ_EQ:
2460 106 : tiledb_op = TILEDB_EQ;
2461 106 : break;
2462 12 : case SWQ_GE:
2463 12 : tiledb_op = TILEDB_GE;
2464 12 : break;
2465 14 : case SWQ_GT:
2466 14 : tiledb_op = TILEDB_GT;
2467 14 : break;
2468 0 : default:
2469 0 : CPLAssert(false);
2470 : break;
2471 : }
2472 :
2473 188 : switch (poFieldDefn->GetType())
2474 : {
2475 150 : case OFTInteger:
2476 : {
2477 : int nVal;
2478 150 : if (poValue->field_type == SWQ_FLOAT)
2479 2 : nVal = static_cast<int>(poValue->float_value);
2480 148 : else if (SWQ_IS_INTEGER(poValue->field_type))
2481 148 : nVal = static_cast<int>(poValue->int_value);
2482 : else
2483 : {
2484 0 : CPLDebug("TILEDB",
2485 : "Unexpected field_type in SQL expression");
2486 0 : CPLAssert(false);
2487 : return nullptr;
2488 : }
2489 :
2490 150 : if (m_aeFieldTypes[poColumn->field_index] == TILEDB_BOOL)
2491 : {
2492 8 : if (nVal == 0 || nVal == 1)
2493 : {
2494 : return std::make_unique<tiledb::QueryCondition>(
2495 12 : tiledb::QueryCondition::create(
2496 4 : *(m_ctx.get()), poFieldDefn->GetNameRef(),
2497 4 : static_cast<uint8_t>(nVal), tiledb_op));
2498 : }
2499 4 : else if (tiledb_op == TILEDB_EQ)
2500 : {
2501 2 : bAlwaysFalse = true;
2502 2 : return nullptr;
2503 : }
2504 2 : else if (tiledb_op == TILEDB_NE)
2505 : {
2506 2 : bAlwaysTrue = true;
2507 2 : return nullptr;
2508 : }
2509 : }
2510 142 : else if (m_aeFieldTypes[poColumn->field_index] == TILEDB_INT16)
2511 : {
2512 : return CreateQueryConditionForIntType<int16_t>(
2513 30 : *(m_ctx.get()), poFieldDefn, nVal, tiledb_op,
2514 30 : bAlwaysTrue, bAlwaysFalse);
2515 : }
2516 112 : else if (m_aeFieldTypes[poColumn->field_index] == TILEDB_UINT8)
2517 : {
2518 : return CreateQueryConditionForIntType<uint8_t>(
2519 0 : *(m_ctx.get()), poFieldDefn, nVal, tiledb_op,
2520 0 : bAlwaysTrue, bAlwaysFalse);
2521 : }
2522 112 : else if (m_aeFieldTypes[poColumn->field_index] == TILEDB_UINT16)
2523 : {
2524 : return CreateQueryConditionForIntType<uint16_t>(
2525 0 : *(m_ctx.get()), poFieldDefn, nVal, tiledb_op,
2526 0 : bAlwaysTrue, bAlwaysFalse);
2527 : }
2528 : else
2529 : {
2530 : return std::make_unique<tiledb::QueryCondition>(
2531 336 : tiledb::QueryCondition::create(
2532 112 : *(m_ctx.get()), poFieldDefn->GetNameRef(), nVal,
2533 112 : tiledb_op));
2534 : }
2535 0 : break;
2536 : }
2537 :
2538 6 : case OFTInteger64:
2539 : {
2540 : int64_t nVal;
2541 6 : if (poValue->field_type == SWQ_FLOAT)
2542 2 : nVal = static_cast<int64_t>(poValue->float_value);
2543 4 : else if (SWQ_IS_INTEGER(poValue->field_type))
2544 4 : nVal = static_cast<int64_t>(poValue->int_value);
2545 : else
2546 : {
2547 0 : CPLDebug("TILEDB",
2548 : "Unexpected field_type in SQL expression");
2549 0 : CPLAssert(false);
2550 : return nullptr;
2551 : }
2552 : return std::make_unique<tiledb::QueryCondition>(
2553 12 : tiledb::QueryCondition::create(*(m_ctx.get()),
2554 : poFieldDefn->GetNameRef(),
2555 6 : nVal, tiledb_op));
2556 : }
2557 :
2558 12 : case OFTReal:
2559 : {
2560 12 : if (poValue->field_type != SWQ_FLOAT)
2561 : {
2562 0 : CPLDebug("TILEDB",
2563 : "Unexpected field_type in SQL expression");
2564 0 : CPLAssert(false);
2565 : return nullptr;
2566 : }
2567 12 : if (poFieldDefn->GetSubType() == OFSTFloat32)
2568 : {
2569 : return std::make_unique<tiledb::QueryCondition>(
2570 6 : tiledb::QueryCondition::create(
2571 2 : *(m_ctx.get()), poFieldDefn->GetNameRef(),
2572 2 : static_cast<float>(poValue->float_value),
2573 2 : tiledb_op));
2574 : }
2575 : return std::make_unique<tiledb::QueryCondition>(
2576 30 : tiledb::QueryCondition::create(
2577 10 : *(m_ctx.get()), poFieldDefn->GetNameRef(),
2578 20 : poValue->float_value, tiledb_op));
2579 : }
2580 :
2581 10 : case OFTString:
2582 : {
2583 10 : if (poValue->field_type != SWQ_STRING)
2584 : {
2585 0 : CPLDebug("TILEDB",
2586 : "Unexpected field_type in SQL expression");
2587 0 : CPLAssert(false);
2588 : return nullptr;
2589 : }
2590 : return std::make_unique<tiledb::QueryCondition>(
2591 30 : tiledb::QueryCondition::create(
2592 10 : *(m_ctx.get()), poFieldDefn->GetNameRef(),
2593 30 : std::string(poValue->string_value), tiledb_op));
2594 : }
2595 :
2596 4 : case OFTDateTime:
2597 : {
2598 4 : if (poValue->field_type == SWQ_TIMESTAMP ||
2599 0 : poValue->field_type == SWQ_DATE ||
2600 0 : poValue->field_type == SWQ_TIME)
2601 : {
2602 : OGRField sField;
2603 4 : if (OGRParseDate(poValue->string_value, &sField, 0))
2604 : {
2605 : return std::make_unique<tiledb::QueryCondition>(
2606 6 : tiledb::QueryCondition::create(
2607 2 : *(m_ctx.get()), poFieldDefn->GetNameRef(),
2608 2 : OGRFieldToDateTimeMS(sField), tiledb_op));
2609 : }
2610 : else
2611 : {
2612 2 : CPLError(CE_Failure, CPLE_AppDefined,
2613 : "Failed to parse %s as a date time",
2614 2 : poValue->string_value);
2615 : }
2616 : }
2617 2 : break;
2618 : }
2619 :
2620 4 : case OFTDate:
2621 : {
2622 4 : if (poValue->field_type == SWQ_TIMESTAMP ||
2623 0 : poValue->field_type == SWQ_DATE ||
2624 0 : poValue->field_type == SWQ_TIME)
2625 : {
2626 : OGRField sField;
2627 4 : if (OGRParseDate(poValue->string_value, &sField, 0))
2628 : {
2629 : return std::make_unique<tiledb::QueryCondition>(
2630 6 : tiledb::QueryCondition::create(
2631 2 : *(m_ctx.get()), poFieldDefn->GetNameRef(),
2632 2 : OGRFieldToDateDay(sField), tiledb_op));
2633 : }
2634 : else
2635 : {
2636 2 : CPLError(CE_Failure, CPLE_AppDefined,
2637 : "Failed to parse %s as a date",
2638 2 : poValue->string_value);
2639 : }
2640 : }
2641 2 : break;
2642 : }
2643 :
2644 : #ifdef not_supported_by_tiledb
2645 : // throws the following error:
2646 : // C API: TileDB Internal, std::exception; Cannot perform query comparison; Unsupported query conditional type on
2647 : case OFTTime:
2648 : {
2649 : if (poValue->field_type == SWQ_TIMESTAMP ||
2650 : poValue->field_type == SWQ_DATE ||
2651 : poValue->field_type == SWQ_TIME)
2652 : {
2653 : OGRField sField;
2654 : if (OGRParseDate(poValue->string_value, &sField, 0))
2655 : {
2656 : return std::make_unique<tiledb::QueryCondition>(
2657 : tiledb::QueryCondition::create(
2658 : *(m_ctx.get()), poFieldDefn->GetNameRef(),
2659 : OGRFieldToTimeMS(sField), tiledb_op));
2660 : }
2661 : }
2662 : break;
2663 : }
2664 : #endif
2665 :
2666 2 : default:
2667 2 : break;
2668 : }
2669 : }
2670 25 : return nullptr;
2671 : }
2672 :
2673 : /***********************************************************************/
2674 : /* CreateQueryCondition() */
2675 : /***********************************************************************/
2676 :
2677 : std::unique_ptr<tiledb::QueryCondition>
2678 323 : OGRTileDBLayer::CreateQueryCondition(const swq_expr_node *poNode,
2679 : bool &bAlwaysTrue, bool &bAlwaysFalse)
2680 : {
2681 323 : bAlwaysTrue = false;
2682 323 : bAlwaysFalse = false;
2683 :
2684 : // A AND B
2685 323 : if (poNode->eNodeType == SNT_OPERATION && poNode->nOperation == SWQ_AND &&
2686 30 : poNode->nSubExprCount == 2)
2687 : {
2688 : bool bAlwaysTrueLeft, bAlwaysFalseLeft, bAlwaysTrueRight,
2689 : bAlwaysFalseRight;
2690 30 : auto left = CreateQueryCondition(poNode->papoSubExpr[0],
2691 60 : bAlwaysTrueLeft, bAlwaysFalseLeft);
2692 30 : auto right = CreateQueryCondition(poNode->papoSubExpr[1],
2693 60 : bAlwaysTrueRight, bAlwaysFalseRight);
2694 30 : if (bAlwaysFalseLeft || bAlwaysFalseRight)
2695 : {
2696 5 : bAlwaysFalse = true;
2697 5 : return nullptr;
2698 : }
2699 25 : if (bAlwaysTrueLeft)
2700 : {
2701 3 : if (bAlwaysTrueRight)
2702 : {
2703 1 : bAlwaysTrue = true;
2704 1 : return nullptr;
2705 : }
2706 2 : return right;
2707 : }
2708 22 : if (bAlwaysTrueRight)
2709 : {
2710 2 : return left;
2711 : }
2712 20 : if (left && right)
2713 : {
2714 : return std::make_unique<tiledb::QueryCondition>(
2715 32 : left->combine(*(right.get()), TILEDB_AND));
2716 : }
2717 : // Returning only left or right member is OK for a AND
2718 4 : m_bAttributeFilterPartiallyTranslated = true;
2719 4 : if (left)
2720 2 : return left;
2721 2 : return right;
2722 : }
2723 :
2724 : // A OR B
2725 293 : else if (poNode->eNodeType == SNT_OPERATION &&
2726 293 : poNode->nOperation == SWQ_OR && poNode->nSubExprCount == 2)
2727 : {
2728 : bool bAlwaysTrueLeft, bAlwaysFalseLeft, bAlwaysTrueRight,
2729 : bAlwaysFalseRight;
2730 34 : auto left = CreateQueryCondition(poNode->papoSubExpr[0],
2731 68 : bAlwaysTrueLeft, bAlwaysFalseLeft);
2732 34 : auto right = CreateQueryCondition(poNode->papoSubExpr[1],
2733 68 : bAlwaysTrueRight, bAlwaysFalseRight);
2734 34 : if (bAlwaysTrueLeft || bAlwaysTrueRight)
2735 : {
2736 5 : bAlwaysTrue = true;
2737 5 : return nullptr;
2738 : }
2739 29 : if (bAlwaysFalseLeft)
2740 : {
2741 3 : if (bAlwaysFalseRight)
2742 : {
2743 1 : bAlwaysFalse = true;
2744 1 : return nullptr;
2745 : }
2746 2 : return right;
2747 : }
2748 26 : if (bAlwaysFalseRight)
2749 : {
2750 2 : return left;
2751 : }
2752 24 : if (left && right)
2753 : {
2754 : return std::make_unique<tiledb::QueryCondition>(
2755 32 : left->combine(*(right.get()), TILEDB_OR));
2756 : }
2757 8 : m_bAttributeFilterPartiallyTranslated = true;
2758 8 : return nullptr;
2759 : }
2760 :
2761 : // field_name IN (constant, ..., constant)
2762 777 : else if (poNode->eNodeType == SNT_OPERATION &&
2763 259 : poNode->nOperation == SWQ_IN && poNode->nSubExprCount >= 2 &&
2764 522 : poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
2765 4 : poNode->papoSubExpr[0]->field_index <
2766 4 : m_poFeatureDefn->GetFieldCount())
2767 : {
2768 4 : std::unique_ptr<tiledb::QueryCondition> cond;
2769 12 : for (int i = 1; i < poNode->nSubExprCount; ++i)
2770 : {
2771 8 : if (poNode->papoSubExpr[i]->eNodeType == SNT_CONSTANT)
2772 : {
2773 : bool bAlwaysTrueTmp;
2774 : bool bAlwaysFalseTmp;
2775 : auto newCond = CreateQueryCondition(
2776 8 : SWQ_EQ, true, poNode->papoSubExpr[0],
2777 8 : poNode->papoSubExpr[i], bAlwaysTrueTmp, bAlwaysFalseTmp);
2778 8 : if (bAlwaysFalseTmp)
2779 0 : continue;
2780 8 : if (!newCond)
2781 : {
2782 0 : m_bAttributeFilterPartiallyTranslated = true;
2783 0 : return nullptr;
2784 : }
2785 8 : if (!cond)
2786 : {
2787 4 : cond = std::move(newCond);
2788 : }
2789 : else
2790 : {
2791 8 : cond = std::make_unique<tiledb::QueryCondition>(
2792 12 : cond->combine(*(newCond.get()), TILEDB_OR));
2793 : }
2794 : }
2795 : else
2796 : {
2797 0 : m_bAttributeFilterPartiallyTranslated = true;
2798 0 : return nullptr;
2799 : }
2800 : }
2801 4 : if (!cond)
2802 0 : bAlwaysFalse = true;
2803 4 : return cond;
2804 : }
2805 :
2806 : // field_name =/<>/</>/<=/>= constant (or the reverse)
2807 255 : else if (poNode->eNodeType == SNT_OPERATION &&
2808 510 : IsComparisonOp(poNode->nOperation) && poNode->nSubExprCount == 2)
2809 : {
2810 199 : const swq_expr_node *poColumn = GetColumnSubNode(poNode);
2811 199 : const swq_expr_node *poValue = GetConstantSubNode(poNode);
2812 : return CreateQueryCondition(
2813 199 : poNode->nOperation, poColumn == poNode->papoSubExpr[0], poColumn,
2814 199 : poValue, bAlwaysTrue, bAlwaysFalse);
2815 : }
2816 :
2817 : // field_name IS NULL
2818 168 : else if (poNode->eNodeType == SNT_OPERATION &&
2819 56 : poNode->nOperation == SWQ_ISNULL && poNode->nSubExprCount == 1 &&
2820 140 : poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
2821 28 : poNode->papoSubExpr[0]->field_index <
2822 28 : m_poFeatureDefn->GetFieldCount())
2823 : {
2824 : const OGRFieldDefn *poFieldDefn =
2825 28 : m_poFeatureDefn->GetFieldDefn(poNode->papoSubExpr[0]->field_index);
2826 28 : if (!poFieldDefn->IsNullable())
2827 : {
2828 14 : bAlwaysFalse = true;
2829 14 : return nullptr;
2830 : }
2831 28 : auto qc = std::make_unique<tiledb::QueryCondition>(*(m_ctx.get()));
2832 14 : qc->init(poFieldDefn->GetNameRef(), nullptr, 0, TILEDB_EQ);
2833 14 : return qc;
2834 : }
2835 :
2836 : // field_name IS NOT NULL
2837 84 : else if (poNode->eNodeType == SNT_OPERATION &&
2838 28 : poNode->nOperation == SWQ_NOT && poNode->nSubExprCount == 1 &&
2839 28 : poNode->papoSubExpr[0]->nOperation == SWQ_ISNULL &&
2840 28 : poNode->papoSubExpr[0]->nSubExprCount == 1 &&
2841 84 : poNode->papoSubExpr[0]->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
2842 28 : poNode->papoSubExpr[0]->papoSubExpr[0]->field_index <
2843 28 : m_poFeatureDefn->GetFieldCount())
2844 : {
2845 56 : const OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(
2846 28 : poNode->papoSubExpr[0]->papoSubExpr[0]->field_index);
2847 28 : if (!poFieldDefn->IsNullable())
2848 : {
2849 14 : bAlwaysTrue = true;
2850 14 : return nullptr;
2851 : }
2852 28 : auto qc = std::make_unique<tiledb::QueryCondition>(*(m_ctx.get()));
2853 14 : qc->init(poFieldDefn->GetNameRef(), nullptr, 0, TILEDB_NE);
2854 14 : return qc;
2855 : }
2856 :
2857 0 : m_bAttributeFilterPartiallyTranslated = true;
2858 0 : return nullptr;
2859 : }
2860 :
2861 : /***********************************************************************/
2862 : /* SetAttributeFilter() */
2863 : /***********************************************************************/
2864 :
2865 215 : OGRErr OGRTileDBLayer::SetAttributeFilter(const char *pszFilter)
2866 : {
2867 215 : m_bAttributeFilterPartiallyTranslated = false;
2868 215 : m_poQueryCondition.reset();
2869 215 : m_bAttributeFilterAlwaysFalse = false;
2870 215 : m_bAttributeFilterAlwaysTrue = false;
2871 215 : OGRErr eErr = OGRLayer::SetAttributeFilter(pszFilter);
2872 215 : if (eErr != OGRERR_NONE)
2873 0 : return eErr;
2874 :
2875 215 : if (m_poAttrQuery != nullptr)
2876 : {
2877 195 : if (m_nUseOptimizedAttributeFilter < 0)
2878 : {
2879 3 : m_nUseOptimizedAttributeFilter = CPLTestBool(CPLGetConfigOption(
2880 : "OGR_TILEDB_OPTIMIZED_ATTRIBUTE_FILTER", "YES"));
2881 : }
2882 195 : if (m_nUseOptimizedAttributeFilter)
2883 : {
2884 : swq_expr_node *poNode =
2885 195 : static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
2886 195 : poNode->ReplaceBetweenByGEAndLERecurse();
2887 195 : poNode->PushNotOperationDownToStack();
2888 : bool bAlwaysTrue, bAlwaysFalse;
2889 195 : CPLErrorReset();
2890 : try
2891 : {
2892 : m_poQueryCondition =
2893 195 : CreateQueryCondition(poNode, bAlwaysTrue, bAlwaysFalse);
2894 : }
2895 0 : catch (const std::exception &e)
2896 : {
2897 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
2898 0 : return OGRERR_FAILURE;
2899 : }
2900 195 : if (CPLGetLastErrorType() == CE_Failure)
2901 4 : return OGRERR_FAILURE;
2902 191 : if (m_poQueryCondition && m_bAttributeFilterPartiallyTranslated)
2903 : {
2904 4 : CPLDebug("TILEDB", "Attribute filter partially translated to "
2905 : "libtiledb query condition");
2906 : }
2907 187 : else if (!m_poQueryCondition)
2908 : {
2909 61 : CPLDebug("TILEDB", "Attribute filter could not be translated "
2910 : "to libtiledb query condition");
2911 : }
2912 191 : m_bAttributeFilterAlwaysTrue = bAlwaysTrue;
2913 191 : m_bAttributeFilterAlwaysFalse = bAlwaysFalse;
2914 : }
2915 : }
2916 :
2917 211 : return OGRERR_NONE;
2918 : }
2919 :
2920 : /************************************************************************/
2921 : /* GetMetadataItem() */
2922 : /************************************************************************/
2923 :
2924 186 : const char *OGRTileDBLayer::GetMetadataItem(const char *pszName,
2925 : const char *pszDomain)
2926 : {
2927 186 : if (pszDomain && EQUAL(pszDomain, "_DEBUG_"))
2928 : {
2929 180 : if (EQUAL(pszName, "ATTRIBUTE_FILTER_TRANSLATION"))
2930 : {
2931 212 : if (!m_poQueryCondition && !m_bAttributeFilterAlwaysFalse &&
2932 32 : !m_bAttributeFilterAlwaysTrue)
2933 10 : return "NONE";
2934 170 : if (m_bAttributeFilterPartiallyTranslated)
2935 4 : return "PARTIAL";
2936 166 : return "WHOLE";
2937 : }
2938 : }
2939 6 : return OGRLayer::GetMetadataItem(pszName, pszDomain);
2940 : }
2941 :
2942 : /************************************************************************/
2943 : /* TranslateCurrentFeature() */
2944 : /************************************************************************/
2945 :
2946 503 : OGRFeature *OGRTileDBLayer::TranslateCurrentFeature()
2947 : {
2948 503 : auto poFeature = new OGRFeature(m_poFeatureDefn);
2949 :
2950 503 : poFeature->SetFID((*m_anFIDs)[m_nOffsetInResultSet]);
2951 :
2952 : // For a variable size attribute (list type), return the number of elements
2953 : // for the feature of index m_nOffsetInResultSet.
2954 2258 : const auto GetEltCount = [this](const std::vector<uint64_t> &anOffsets,
2955 : size_t nEltSizeInBytes,
2956 5420 : size_t nTotalSizeInBytes)
2957 : {
2958 : uint64_t nSize;
2959 2258 : if (static_cast<size_t>(m_nOffsetInResultSet + 1) < anOffsets.size())
2960 : {
2961 1808 : nSize = anOffsets[m_nOffsetInResultSet + 1] -
2962 904 : anOffsets[m_nOffsetInResultSet];
2963 : }
2964 : else
2965 : {
2966 1354 : nSize = nTotalSizeInBytes - anOffsets[m_nOffsetInResultSet];
2967 : }
2968 2258 : return static_cast<size_t>(nSize / nEltSizeInBytes);
2969 503 : };
2970 :
2971 503 : if (!m_poFeatureDefn->GetGeomFieldDefn(0)->IsIgnored())
2972 : {
2973 493 : const char *pszGeomColName = GetDatabaseGeomColName();
2974 493 : if (pszGeomColName)
2975 : {
2976 : const size_t nWKBSize =
2977 489 : GetEltCount(*m_anGeometryOffsets, 1, m_abyGeometries->size());
2978 489 : OGRGeometry *poGeom = nullptr;
2979 978 : OGRGeometryFactory::createFromWkb(
2980 978 : m_abyGeometries->data() +
2981 : static_cast<size_t>(
2982 489 : (*m_anGeometryOffsets)[m_nOffsetInResultSet]),
2983 489 : GetSpatialRef(), &poGeom, nWKBSize);
2984 489 : poFeature->SetGeometryDirectly(poGeom);
2985 : }
2986 : else
2987 : {
2988 : OGRPoint *poPoint =
2989 4 : m_adfZs->empty()
2990 8 : ? new OGRPoint((*m_adfXs)[m_nOffsetInResultSet],
2991 3 : (*m_adfYs)[m_nOffsetInResultSet])
2992 1 : : new OGRPoint((*m_adfXs)[m_nOffsetInResultSet],
2993 1 : (*m_adfYs)[m_nOffsetInResultSet],
2994 1 : (*m_adfZs)[m_nOffsetInResultSet]);
2995 4 : poPoint->assignSpatialReference(GetSpatialRef());
2996 4 : poFeature->SetGeometryDirectly(poPoint);
2997 : }
2998 : }
2999 :
3000 503 : const int nFieldCount = m_poFeatureDefn->GetFieldCount();
3001 5957 : for (int i = 0; i < nFieldCount; ++i)
3002 : {
3003 : const OGRFieldDefn *poFieldDefn =
3004 5454 : m_poFeatureDefn->GetFieldDefnUnsafe(i);
3005 5454 : if (poFieldDefn->IsIgnored())
3006 : {
3007 10 : continue;
3008 : }
3009 5444 : if (poFieldDefn->IsNullable())
3010 : {
3011 2974 : if (!m_aFieldValidity[i][m_nOffsetInResultSet])
3012 : {
3013 558 : poFeature->SetFieldNull(i);
3014 558 : continue;
3015 : }
3016 : }
3017 :
3018 4886 : const auto &anOffsets = *(m_aFieldValueOffsets[i]);
3019 4886 : auto &fieldValues = m_aFieldValues[i];
3020 4886 : switch (poFieldDefn->GetType())
3021 : {
3022 1389 : case OFTInteger:
3023 : {
3024 1389 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
3025 : {
3026 : const auto &v = *(
3027 225 : std::get<std::shared_ptr<VECTOR_OF_BOOL>>(fieldValues));
3028 225 : poFeature->SetFieldSameTypeUnsafe(i,
3029 225 : v[m_nOffsetInResultSet]);
3030 : }
3031 1164 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
3032 : {
3033 : const auto &v =
3034 : *(std::get<std::shared_ptr<std::vector<int16_t>>>(
3035 225 : fieldValues));
3036 225 : poFeature->SetFieldSameTypeUnsafe(i,
3037 225 : v[m_nOffsetInResultSet]);
3038 : }
3039 939 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
3040 : {
3041 : const auto &v =
3042 : *(std::get<std::shared_ptr<std::vector<int32_t>>>(
3043 489 : fieldValues));
3044 489 : poFeature->SetFieldSameTypeUnsafe(i,
3045 489 : v[m_nOffsetInResultSet]);
3046 : }
3047 450 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
3048 : {
3049 : const auto &v =
3050 : *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
3051 225 : fieldValues));
3052 225 : poFeature->SetFieldSameTypeUnsafe(i,
3053 225 : v[m_nOffsetInResultSet]);
3054 : }
3055 225 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
3056 : {
3057 : const auto &v =
3058 : *(std::get<std::shared_ptr<std::vector<uint16_t>>>(
3059 225 : fieldValues));
3060 225 : poFeature->SetFieldSameTypeUnsafe(i,
3061 225 : v[m_nOffsetInResultSet]);
3062 : }
3063 : else
3064 : {
3065 0 : CPLAssert(false);
3066 : }
3067 1389 : break;
3068 : }
3069 :
3070 675 : case OFTIntegerList:
3071 : {
3072 675 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
3073 : {
3074 : const auto &v = *(
3075 225 : std::get<std::shared_ptr<VECTOR_OF_BOOL>>(fieldValues));
3076 225 : const size_t nEltCount = GetEltCount(
3077 : anOffsets, sizeof(v[0]), v.size() * sizeof(v[0]));
3078 450 : std::vector<int32_t> tmp;
3079 : const auto *inPtr =
3080 225 : v.data() +
3081 225 : static_cast<size_t>(anOffsets[m_nOffsetInResultSet] /
3082 225 : sizeof(v[0]));
3083 605 : for (size_t j = 0; j < nEltCount; ++j)
3084 380 : tmp.push_back(inPtr[j]);
3085 225 : poFeature->SetField(i, static_cast<int>(nEltCount),
3086 225 : tmp.data());
3087 : }
3088 450 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
3089 : {
3090 : const auto &v =
3091 : *(std::get<std::shared_ptr<std::vector<int16_t>>>(
3092 225 : fieldValues));
3093 225 : const size_t nEltCount = GetEltCount(
3094 225 : anOffsets, sizeof(v[0]), v.size() * sizeof(v[0]));
3095 450 : std::vector<int32_t> tmp;
3096 : const auto *inPtr =
3097 225 : v.data() +
3098 225 : static_cast<size_t>(anOffsets[m_nOffsetInResultSet] /
3099 225 : sizeof(v[0]));
3100 605 : for (size_t j = 0; j < nEltCount; ++j)
3101 380 : tmp.push_back(inPtr[j]);
3102 225 : poFeature->SetField(i, static_cast<int>(nEltCount),
3103 225 : tmp.data());
3104 : }
3105 225 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
3106 : {
3107 : const auto &v =
3108 : *(std::get<std::shared_ptr<std::vector<int32_t>>>(
3109 225 : fieldValues));
3110 225 : const size_t nEltCount = GetEltCount(
3111 225 : anOffsets, sizeof(v[0]), v.size() * sizeof(v[0]));
3112 225 : poFeature->SetField(
3113 : i, static_cast<int>(nEltCount),
3114 225 : v.data() + static_cast<size_t>(
3115 225 : anOffsets[m_nOffsetInResultSet] /
3116 : sizeof(v[0])));
3117 : }
3118 0 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
3119 : {
3120 : const auto &v =
3121 : *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
3122 0 : fieldValues));
3123 0 : const size_t nEltCount = GetEltCount(
3124 : anOffsets, sizeof(v[0]), v.size() * sizeof(v[0]));
3125 0 : std::vector<int32_t> tmp;
3126 : const auto *inPtr =
3127 0 : v.data() +
3128 0 : static_cast<size_t>(anOffsets[m_nOffsetInResultSet] /
3129 0 : sizeof(v[0]));
3130 0 : for (size_t j = 0; j < nEltCount; ++j)
3131 0 : tmp.push_back(inPtr[j]);
3132 0 : poFeature->SetField(i, static_cast<int>(nEltCount),
3133 0 : tmp.data());
3134 : }
3135 0 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
3136 : {
3137 : const auto &v =
3138 : *(std::get<std::shared_ptr<std::vector<uint16_t>>>(
3139 0 : fieldValues));
3140 0 : const size_t nEltCount = GetEltCount(
3141 0 : anOffsets, sizeof(v[0]), v.size() * sizeof(v[0]));
3142 0 : poFeature->SetField(
3143 : i, static_cast<int>(nEltCount),
3144 0 : v.data() + static_cast<size_t>(
3145 0 : anOffsets[m_nOffsetInResultSet] /
3146 : sizeof(v[0])));
3147 : }
3148 : else
3149 : {
3150 0 : CPLAssert(false);
3151 : }
3152 675 : break;
3153 : }
3154 :
3155 419 : case OFTInteger64:
3156 : {
3157 : const auto &v =
3158 : *(std::get<std::shared_ptr<std::vector<int64_t>>>(
3159 419 : fieldValues));
3160 419 : poFeature->SetFieldSameTypeUnsafe(
3161 419 : i, static_cast<GIntBig>(v[m_nOffsetInResultSet]));
3162 419 : break;
3163 : }
3164 :
3165 0 : case OFTInteger64List:
3166 : {
3167 : const auto &v =
3168 : *(std::get<std::shared_ptr<std::vector<int64_t>>>(
3169 0 : fieldValues));
3170 0 : const size_t nEltCount = GetEltCount(anOffsets, sizeof(v[0]),
3171 0 : v.size() * sizeof(v[0]));
3172 0 : poFeature->SetField(
3173 : i, static_cast<int>(nEltCount),
3174 0 : v.data() +
3175 0 : static_cast<size_t>(anOffsets[m_nOffsetInResultSet] /
3176 : sizeof(v[0])));
3177 0 : break;
3178 : }
3179 :
3180 634 : case OFTReal:
3181 : {
3182 634 : if (poFieldDefn->GetSubType() == OFSTFloat32)
3183 : {
3184 : const auto &v =
3185 : *(std::get<std::shared_ptr<std::vector<float>>>(
3186 225 : fieldValues));
3187 225 : poFeature->SetFieldSameTypeUnsafe(i,
3188 225 : v[m_nOffsetInResultSet]);
3189 : }
3190 : else
3191 : {
3192 : const auto &v =
3193 : *(std::get<std::shared_ptr<std::vector<double>>>(
3194 409 : fieldValues));
3195 409 : poFeature->SetFieldSameTypeUnsafe(i,
3196 409 : v[m_nOffsetInResultSet]);
3197 : }
3198 634 : break;
3199 : }
3200 :
3201 450 : case OFTRealList:
3202 : {
3203 450 : if (poFieldDefn->GetSubType() == OFSTFloat32)
3204 : {
3205 : const auto &v =
3206 : *(std::get<std::shared_ptr<std::vector<float>>>(
3207 225 : fieldValues));
3208 225 : const size_t nEltCount = GetEltCount(
3209 225 : anOffsets, sizeof(v[0]), v.size() * sizeof(v[0]));
3210 450 : std::vector<double> tmp;
3211 : const auto *inPtr =
3212 225 : v.data() +
3213 225 : static_cast<size_t>(anOffsets[m_nOffsetInResultSet] /
3214 225 : sizeof(v[0]));
3215 795 : for (size_t j = 0; j < nEltCount; ++j)
3216 570 : tmp.push_back(inPtr[j]);
3217 225 : poFeature->SetField(i, static_cast<int>(nEltCount),
3218 225 : tmp.data());
3219 : }
3220 : else
3221 : {
3222 : const auto &v =
3223 : *(std::get<std::shared_ptr<std::vector<double>>>(
3224 225 : fieldValues));
3225 225 : const size_t nEltCount = GetEltCount(
3226 225 : anOffsets, sizeof(v[0]), v.size() * sizeof(v[0]));
3227 225 : poFeature->SetField(
3228 : i, static_cast<int>(nEltCount),
3229 225 : v.data() + static_cast<size_t>(
3230 225 : anOffsets[m_nOffsetInResultSet] /
3231 : sizeof(v[0])));
3232 : }
3233 450 : break;
3234 : }
3235 :
3236 419 : case OFTString:
3237 : {
3238 : auto &v =
3239 419 : *(std::get<std::shared_ptr<std::string>>(fieldValues));
3240 419 : const size_t nEltCount = GetEltCount(anOffsets, 1, v.size());
3241 419 : if (static_cast<size_t>(m_nOffsetInResultSet + 1) <
3242 419 : anOffsets.size())
3243 : {
3244 : char &chSavedRef =
3245 234 : v[static_cast<size_t>(anOffsets[m_nOffsetInResultSet]) +
3246 234 : nEltCount];
3247 234 : const char chSavedBackup = chSavedRef;
3248 234 : chSavedRef = 0;
3249 234 : poFeature->SetField(
3250 468 : i, v.data() + static_cast<size_t>(
3251 234 : anOffsets[m_nOffsetInResultSet]));
3252 234 : chSavedRef = chSavedBackup;
3253 : }
3254 : else
3255 : {
3256 185 : poFeature->SetField(
3257 370 : i, v.data() + static_cast<size_t>(
3258 185 : anOffsets[m_nOffsetInResultSet]));
3259 : }
3260 419 : break;
3261 : }
3262 :
3263 225 : case OFTBinary:
3264 : {
3265 : auto &v = *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
3266 225 : fieldValues));
3267 225 : const size_t nEltCount = GetEltCount(anOffsets, 1, v.size());
3268 225 : poFeature->SetField(
3269 : i, static_cast<int>(nEltCount),
3270 : static_cast<const void *>(
3271 225 : v.data() +
3272 225 : static_cast<size_t>(anOffsets[m_nOffsetInResultSet])));
3273 225 : break;
3274 : }
3275 :
3276 225 : case OFTDate:
3277 : {
3278 : const auto &v =
3279 : *(std::get<std::shared_ptr<std::vector<int64_t>>>(
3280 225 : fieldValues));
3281 225 : auto psField = poFeature->GetRawFieldRef(i);
3282 225 : psField->Set.nMarker1 = OGRUnsetMarker;
3283 225 : psField->Set.nMarker2 = OGRUnsetMarker;
3284 225 : psField->Set.nMarker3 = OGRUnsetMarker;
3285 225 : constexpr int DAYS_IN_YEAR_APPROX = 365;
3286 : // Avoid overflow in the x SECONDS_PER_DAY muliplication
3287 450 : if (v[m_nOffsetInResultSet] > DAYS_IN_YEAR_APPROX * 100000 ||
3288 225 : v[m_nOffsetInResultSet] < -DAYS_IN_YEAR_APPROX * 100000)
3289 : {
3290 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid date value");
3291 : }
3292 : else
3293 : {
3294 : GIntBig timestamp =
3295 225 : static_cast<GIntBig>(v[m_nOffsetInResultSet]) *
3296 225 : SECONDS_PER_DAY;
3297 : struct tm dt;
3298 225 : CPLUnixTimeToYMDHMS(timestamp, &dt);
3299 :
3300 225 : psField->Date.Year = static_cast<GInt16>(dt.tm_year + 1900);
3301 225 : psField->Date.Month = static_cast<GByte>(dt.tm_mon + 1);
3302 225 : psField->Date.Day = static_cast<GByte>(dt.tm_mday);
3303 225 : psField->Date.Hour = 0;
3304 225 : psField->Date.Minute = 0;
3305 225 : psField->Date.Second = 0;
3306 225 : psField->Date.TZFlag = 0;
3307 : }
3308 225 : break;
3309 : }
3310 :
3311 225 : case OFTDateTime:
3312 : {
3313 : const auto &v =
3314 : *(std::get<std::shared_ptr<std::vector<int64_t>>>(
3315 225 : fieldValues));
3316 : GIntBig timestamp =
3317 225 : static_cast<GIntBig>(v[m_nOffsetInResultSet]);
3318 225 : double floatingPart = (timestamp % 1000) / 1e3;
3319 225 : timestamp /= 1000;
3320 : struct tm dt;
3321 225 : CPLUnixTimeToYMDHMS(timestamp, &dt);
3322 225 : auto psField = poFeature->GetRawFieldRef(i);
3323 225 : psField->Set.nMarker1 = OGRUnsetMarker;
3324 225 : psField->Set.nMarker2 = OGRUnsetMarker;
3325 225 : psField->Set.nMarker3 = OGRUnsetMarker;
3326 225 : psField->Date.Year = static_cast<GInt16>(dt.tm_year + 1900);
3327 225 : psField->Date.Month = static_cast<GByte>(dt.tm_mon + 1);
3328 225 : psField->Date.Day = static_cast<GByte>(dt.tm_mday);
3329 225 : psField->Date.Hour = static_cast<GByte>(dt.tm_hour);
3330 225 : psField->Date.Minute = static_cast<GByte>(dt.tm_min);
3331 225 : psField->Date.Second =
3332 225 : static_cast<float>(dt.tm_sec + floatingPart);
3333 225 : psField->Date.TZFlag = static_cast<GByte>(100);
3334 225 : break;
3335 : }
3336 :
3337 225 : case OFTTime:
3338 : {
3339 : const auto &v =
3340 : *(std::get<std::shared_ptr<std::vector<int64_t>>>(
3341 225 : fieldValues));
3342 225 : GIntBig value = static_cast<GIntBig>(v[m_nOffsetInResultSet]);
3343 225 : double floatingPart = (value % 1000) / 1e3;
3344 225 : value /= 1000;
3345 225 : auto psField = poFeature->GetRawFieldRef(i);
3346 225 : psField->Set.nMarker1 = OGRUnsetMarker;
3347 225 : psField->Set.nMarker2 = OGRUnsetMarker;
3348 225 : psField->Set.nMarker3 = OGRUnsetMarker;
3349 225 : psField->Date.Year = 0;
3350 225 : psField->Date.Month = 0;
3351 225 : psField->Date.Day = 0;
3352 225 : const int nHour = static_cast<int>(value / 3600);
3353 225 : const int nMinute = static_cast<int>((value / 60) % 60);
3354 225 : const int nSecond = static_cast<int>(value % 60);
3355 225 : psField->Date.Hour = static_cast<GByte>(nHour);
3356 225 : psField->Date.Minute = static_cast<GByte>(nMinute);
3357 225 : psField->Date.Second =
3358 225 : static_cast<float>(nSecond + floatingPart);
3359 225 : psField->Date.TZFlag = 0;
3360 225 : break;
3361 : }
3362 :
3363 0 : default:
3364 : {
3365 0 : CPLAssert(false);
3366 : break;
3367 : }
3368 : }
3369 : }
3370 503 : m_nOffsetInResultSet++;
3371 :
3372 503 : return poFeature;
3373 : }
3374 :
3375 : /************************************************************************/
3376 : /* GetFeature() */
3377 : /************************************************************************/
3378 :
3379 14 : OGRFeature *OGRTileDBLayer::GetFeature(GIntBig nFID)
3380 : {
3381 14 : if (m_osFIDColumn.empty())
3382 0 : return OGRLayer::GetFeature(nFID);
3383 :
3384 28 : tiledb::QueryCondition qc(*(m_ctx.get()));
3385 14 : qc.init(m_osFIDColumn, &nFID, sizeof(nFID), TILEDB_EQ);
3386 14 : ResetReading();
3387 14 : if (!SetupQuery(&qc))
3388 5 : return nullptr;
3389 9 : auto poFeat = TranslateCurrentFeature();
3390 9 : ResetReading();
3391 9 : return poFeat;
3392 : }
3393 :
3394 : /************************************************************************/
3395 : /* GetFeatureCount() */
3396 : /************************************************************************/
3397 :
3398 30 : GIntBig OGRTileDBLayer::GetFeatureCount(int bForce)
3399 : {
3400 30 : if (!m_poAttrQuery && !m_poFilterGeom && m_nTotalFeatureCount >= 0)
3401 16 : return m_nTotalFeatureCount;
3402 14 : GIntBig nRet = OGRLayer::GetFeatureCount(bForce);
3403 14 : if (nRet >= 0 && !m_poAttrQuery && !m_poFilterGeom)
3404 2 : m_nTotalFeatureCount = nRet;
3405 14 : return nRet;
3406 : }
3407 :
3408 : /************************************************************************/
3409 : /* IGetExtent() */
3410 : /************************************************************************/
3411 :
3412 8 : OGRErr OGRTileDBLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
3413 : bool bForce)
3414 : {
3415 8 : if (m_oLayerExtent.IsInit())
3416 : {
3417 8 : *psExtent = m_oLayerExtent;
3418 8 : return OGRERR_NONE;
3419 : }
3420 0 : return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
3421 : }
3422 :
3423 : /************************************************************************/
3424 : /* ResetReading() */
3425 : /************************************************************************/
3426 :
3427 592 : void OGRTileDBLayer::ResetReading()
3428 : {
3429 592 : if (m_eCurrentMode == CurrentMode::WriteInProgress && !m_array)
3430 1 : return;
3431 :
3432 591 : SwitchToReadingMode();
3433 591 : ResetBuffers();
3434 591 : m_nNextFID = 1;
3435 591 : m_nOffsetInResultSet = 0;
3436 591 : m_nRowCountInResultSet = 0;
3437 591 : m_query.reset();
3438 591 : m_bQueryComplete = false;
3439 : }
3440 :
3441 : /************************************************************************/
3442 : /* CreateField() */
3443 : /************************************************************************/
3444 :
3445 145 : OGRErr OGRTileDBLayer::CreateField(const OGRFieldDefn *poField,
3446 : int /* bApproxOK*/)
3447 : {
3448 145 : if (!m_bUpdatable)
3449 0 : return OGRERR_FAILURE;
3450 145 : if (m_schema)
3451 : {
3452 1 : CPLError(CE_Failure, CPLE_NotSupported,
3453 : "Cannot add field after schema has been initialized");
3454 1 : return OGRERR_FAILURE;
3455 : }
3456 144 : if (poField->GetType() == OFTStringList)
3457 : {
3458 0 : CPLError(CE_Failure, CPLE_NotSupported, "Unsupported field type");
3459 0 : return OGRERR_FAILURE;
3460 : }
3461 144 : const char *pszFieldName = poField->GetNameRef();
3462 288 : if (m_poFeatureDefn->GetFieldIndex(pszFieldName) >= 0 ||
3463 144 : pszFieldName == m_osFIDColumn ||
3464 276 : strcmp(pszFieldName, GetGeometryColumn()) == 0 ||
3465 564 : pszFieldName == m_osXDim || pszFieldName == m_osYDim ||
3466 138 : pszFieldName == m_osZDim)
3467 : {
3468 6 : CPLError(CE_Failure, CPLE_AppDefined,
3469 : "A field or dimension of same name (%s) already exists",
3470 : pszFieldName);
3471 6 : return OGRERR_FAILURE;
3472 : }
3473 138 : OGRFieldDefn oFieldDefn(poField);
3474 138 : m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
3475 138 : m_aeFieldTypesInCreateField.push_back(-1);
3476 236 : if (poField->GetType() == OFTInteger ||
3477 98 : poField->GetType() == OFTIntegerList)
3478 : {
3479 : const char *pszTileDBIntType =
3480 61 : CPLGetConfigOption("TILEDB_INT_TYPE", "INT32");
3481 61 : if (EQUAL(pszTileDBIntType, "UINT8"))
3482 : {
3483 6 : m_aeFieldTypesInCreateField.back() = TILEDB_UINT8;
3484 : }
3485 55 : else if (EQUAL(pszTileDBIntType, "UINT16"))
3486 : {
3487 6 : m_aeFieldTypesInCreateField.back() = TILEDB_UINT16;
3488 : }
3489 : }
3490 138 : return OGRERR_NONE;
3491 : }
3492 :
3493 : /************************************************************************/
3494 : /* InitializeSchemaAndArray() */
3495 : /************************************************************************/
3496 :
3497 34 : void OGRTileDBLayer::InitializeSchemaAndArray()
3498 : {
3499 34 : m_bInitializationAttempted = true;
3500 :
3501 : try
3502 : {
3503 : // create the tiledb schema
3504 : // dimensions will be _x and _y, we can also add _z (2.5d)
3505 : // set dimensions and attribute type for schema
3506 : // we will use row-major for now but we could use hilbert indexing
3507 34 : m_schema.reset(new tiledb::ArraySchema(*m_ctx, TILEDB_SPARSE));
3508 34 : m_schema->set_tile_order(TILEDB_ROW_MAJOR);
3509 34 : m_schema->set_cell_order(TILEDB_ROW_MAJOR);
3510 :
3511 34 : m_schema->set_coords_filter_list(*m_filterList);
3512 34 : m_schema->set_offsets_filter_list(*m_filterList);
3513 :
3514 34 : tiledb::Domain domain(*m_ctx);
3515 :
3516 : auto xdim = tiledb::Dimension::create<double>(
3517 34 : *m_ctx, m_osXDim, {m_dfXStart, m_dfXEnd}, m_dfTileExtent);
3518 : auto ydim = tiledb::Dimension::create<double>(
3519 34 : *m_ctx, m_osYDim, {m_dfYStart, m_dfYEnd}, m_dfTileExtent);
3520 34 : if (!m_osZDim.empty())
3521 : {
3522 : auto zdim = tiledb::Dimension::create<double>(
3523 16 : *m_ctx, m_osZDim, {m_dfZStart, m_dfZEnd}, m_dfZTileExtent);
3524 32 : domain.add_dimensions(std::move(xdim), std::move(ydim),
3525 48 : std::move(zdim));
3526 : }
3527 : else
3528 : {
3529 18 : domain.add_dimensions(std::move(xdim), std::move(ydim));
3530 : }
3531 :
3532 34 : m_schema->set_domain(domain);
3533 :
3534 34 : m_schema->set_capacity(m_nTileCapacity);
3535 :
3536 : // allow geometries with same _X, _Y
3537 34 : m_schema->set_allows_dups(true);
3538 :
3539 : // add FID attribute
3540 34 : if (!m_osFIDColumn.empty())
3541 : {
3542 96 : m_schema->add_attribute(tiledb::Attribute::create<int64_t>(
3543 64 : *m_ctx, m_osFIDColumn, *m_filterList));
3544 : }
3545 :
3546 : // add geometry attribute
3547 34 : const char *pszGeomColName = GetDatabaseGeomColName();
3548 34 : if (pszGeomColName)
3549 : {
3550 : const char *pszWkbBlobType =
3551 29 : CPLGetConfigOption("TILEDB_WKB_GEOMETRY_TYPE",
3552 : #ifdef HAS_TILEDB_GEOM_WKB_WKT
3553 : "GEOM_WKB"
3554 : #else
3555 : "BLOB"
3556 : #endif
3557 : );
3558 : auto wkbGeometryAttr = tiledb::Attribute::create(
3559 29 : *m_ctx, pszGeomColName,
3560 : #ifdef HAS_TILEDB_GEOM_WKB_WKT
3561 : EQUAL(pszWkbBlobType, "GEOM_WKB") ? TILEDB_GEOM_WKB :
3562 : #endif
3563 29 : EQUAL(pszWkbBlobType, "UINT8") ? TILEDB_UINT8
3564 116 : : TILEDB_BLOB);
3565 :
3566 29 : wkbGeometryAttr.set_filter_list(*m_filterList);
3567 29 : wkbGeometryAttr.set_cell_val_num(TILEDB_VAR_NUM);
3568 29 : m_schema->add_attribute(wkbGeometryAttr);
3569 : }
3570 :
3571 34 : auto &aFieldValues = m_aFieldValues;
3572 34 : CPLAssert(static_cast<int>(m_aeFieldTypesInCreateField.size()) ==
3573 : m_poFeatureDefn->GetFieldCount());
3574 172 : for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
3575 : {
3576 138 : const OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
3577 138 : const bool bIsNullable = poFieldDefn->IsNullable();
3578 :
3579 : const auto CreateAttr =
3580 138 : [this, poFieldDefn, bIsNullable](tiledb_datatype_t type,
3581 966 : bool bIsVariableSize = false)
3582 : {
3583 138 : m_aeFieldTypes.push_back(type);
3584 : auto attr = tiledb::Attribute::create(
3585 414 : *m_ctx, poFieldDefn->GetNameRef(), m_aeFieldTypes.back());
3586 138 : attr.set_filter_list(*m_filterList);
3587 138 : attr.set_nullable(bIsNullable);
3588 138 : if (bIsVariableSize)
3589 54 : attr.set_cell_val_num(TILEDB_VAR_NUM);
3590 138 : m_schema->add_attribute(attr);
3591 138 : };
3592 :
3593 138 : const auto eType = poFieldDefn->GetType();
3594 138 : switch (eType)
3595 : {
3596 61 : case OFTInteger:
3597 : case OFTIntegerList:
3598 : {
3599 61 : if (poFieldDefn->GetSubType() == OFSTBoolean)
3600 : {
3601 14 : CreateAttr(TILEDB_BOOL, eType == OFTIntegerList);
3602 14 : aFieldValues.push_back(
3603 28 : std::make_shared<VECTOR_OF_BOOL>());
3604 : }
3605 47 : else if (poFieldDefn->GetSubType() == OFSTInt16)
3606 : {
3607 14 : CreateAttr(TILEDB_INT16, eType == OFTIntegerList);
3608 14 : aFieldValues.push_back(
3609 28 : std::make_shared<std::vector<int16_t>>());
3610 : }
3611 33 : else if (m_aeFieldTypesInCreateField[i] >= 0)
3612 : {
3613 12 : if (m_aeFieldTypesInCreateField[i] == TILEDB_UINT8)
3614 : {
3615 6 : CreateAttr(TILEDB_UINT8, eType == OFTIntegerList);
3616 6 : aFieldValues.push_back(
3617 12 : std::make_shared<std::vector<uint8_t>>());
3618 : }
3619 6 : else if (m_aeFieldTypesInCreateField[i] ==
3620 : TILEDB_UINT16)
3621 : {
3622 6 : CreateAttr(TILEDB_UINT16, eType == OFTIntegerList);
3623 6 : aFieldValues.push_back(
3624 12 : std::make_shared<std::vector<uint16_t>>());
3625 : }
3626 : else
3627 : {
3628 0 : CPLAssert(false);
3629 : }
3630 : }
3631 : else
3632 : {
3633 : const char *pszTileDBIntType =
3634 21 : CPLGetConfigOption("TILEDB_INT_TYPE", "INT32");
3635 21 : if (EQUAL(pszTileDBIntType, "UINT8"))
3636 : {
3637 0 : CreateAttr(TILEDB_UINT8, eType == OFTIntegerList);
3638 0 : aFieldValues.push_back(
3639 0 : std::make_shared<std::vector<uint8_t>>());
3640 : }
3641 21 : else if (EQUAL(pszTileDBIntType, "UINT16"))
3642 : {
3643 0 : CreateAttr(TILEDB_UINT16, eType == OFTIntegerList);
3644 0 : aFieldValues.push_back(
3645 0 : std::make_shared<std::vector<uint16_t>>());
3646 : }
3647 : else
3648 : {
3649 21 : CreateAttr(TILEDB_INT32, eType == OFTIntegerList);
3650 21 : aFieldValues.push_back(
3651 42 : std::make_shared<std::vector<int32_t>>());
3652 : }
3653 : }
3654 61 : break;
3655 : }
3656 :
3657 8 : case OFTInteger64:
3658 : {
3659 8 : CreateAttr(TILEDB_INT64);
3660 8 : aFieldValues.push_back(
3661 16 : std::make_shared<std::vector<int64_t>>());
3662 8 : break;
3663 : }
3664 :
3665 1 : case OFTInteger64List:
3666 : {
3667 1 : CreateAttr(TILEDB_INT64, true);
3668 1 : aFieldValues.push_back(
3669 2 : std::make_shared<std::vector<int64_t>>());
3670 1 : break;
3671 : }
3672 :
3673 29 : case OFTReal:
3674 : case OFTRealList:
3675 : {
3676 29 : if (poFieldDefn->GetSubType() == OFSTFloat32)
3677 : {
3678 14 : CreateAttr(TILEDB_FLOAT32, eType == OFTRealList);
3679 14 : aFieldValues.push_back(
3680 28 : std::make_shared<std::vector<float>>());
3681 : }
3682 : else
3683 : {
3684 15 : CreateAttr(TILEDB_FLOAT64, eType == OFTRealList);
3685 15 : aFieldValues.push_back(
3686 30 : std::make_shared<std::vector<double>>());
3687 : }
3688 29 : break;
3689 : }
3690 :
3691 11 : case OFTString:
3692 : {
3693 11 : CreateAttr(m_eTileDBStringType, true);
3694 11 : aFieldValues.push_back(std::make_shared<std::string>());
3695 11 : break;
3696 : }
3697 :
3698 7 : case OFTDate:
3699 : {
3700 7 : CreateAttr(TILEDB_DATETIME_DAY);
3701 7 : aFieldValues.push_back(
3702 14 : std::make_shared<std::vector<int64_t>>());
3703 7 : break;
3704 : }
3705 :
3706 7 : case OFTDateTime:
3707 : {
3708 7 : CreateAttr(TILEDB_DATETIME_MS);
3709 7 : aFieldValues.push_back(
3710 14 : std::make_shared<std::vector<int64_t>>());
3711 7 : break;
3712 : }
3713 :
3714 7 : case OFTTime:
3715 : {
3716 7 : CreateAttr(TILEDB_TIME_MS);
3717 7 : aFieldValues.push_back(
3718 14 : std::make_shared<std::vector<int64_t>>());
3719 7 : break;
3720 : }
3721 :
3722 7 : case OFTBinary:
3723 : {
3724 : const char *pszBlobType =
3725 7 : CPLGetConfigOption("TILEDB_BINARY_TYPE", "BLOB");
3726 7 : CreateAttr(EQUAL(pszBlobType, "UINT8") ? TILEDB_UINT8
3727 : : TILEDB_BLOB,
3728 : true);
3729 7 : aFieldValues.push_back(
3730 14 : std::make_shared<std::vector<uint8_t>>());
3731 7 : break;
3732 : }
3733 :
3734 0 : default:
3735 : {
3736 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
3737 : "Unsupported attribute definition.\n");
3738 0 : return;
3739 : }
3740 : }
3741 : }
3742 :
3743 172 : for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
3744 : {
3745 138 : m_aFieldValueOffsets.push_back(
3746 276 : std::make_shared<std::vector<uint64_t>>());
3747 : }
3748 34 : m_aFieldValidity.resize(m_poFeatureDefn->GetFieldCount());
3749 :
3750 34 : tiledb::Array::create(m_osFilename, *m_schema);
3751 :
3752 34 : if (!m_osGroupName.empty())
3753 : {
3754 3 : tiledb::Group group(*m_ctx, m_osGroupName, TILEDB_WRITE);
3755 3 : group.add_member(m_osFilename, false, GetDescription());
3756 : }
3757 :
3758 34 : if (m_nTimestamp)
3759 0 : m_array.reset(new tiledb::Array(
3760 0 : *m_ctx, m_osFilename, TILEDB_WRITE,
3761 0 : tiledb::TemporalPolicy(tiledb::TimeTravel, m_nTimestamp)));
3762 : else
3763 68 : m_array.reset(
3764 68 : new tiledb::Array(*m_ctx, m_osFilename, TILEDB_WRITE));
3765 :
3766 34 : if (!m_osFIDColumn.empty())
3767 : {
3768 64 : m_array->put_metadata("FID_ATTRIBUTE_NAME", TILEDB_STRING_UTF8,
3769 32 : static_cast<int>(m_osFIDColumn.size()),
3770 32 : m_osFIDColumn.c_str());
3771 : }
3772 :
3773 63 : if (pszGeomColName &&
3774 29 : CPLTestBool(CPLGetConfigOption(
3775 : "OGR_TILEDB_WRITE_GEOMETRY_ATTRIBUTE_NAME", "YES")))
3776 : {
3777 58 : m_array->put_metadata("GEOMETRY_ATTRIBUTE_NAME", TILEDB_STRING_UTF8,
3778 29 : static_cast<int>(strlen(pszGeomColName)),
3779 : pszGeomColName);
3780 : }
3781 :
3782 34 : m_array->put_metadata(DATASET_TYPE_ATTRIBUTE_NAME, TILEDB_STRING_UTF8,
3783 : static_cast<int>(strlen(GEOMETRY_DATASET_TYPE)),
3784 : GEOMETRY_DATASET_TYPE);
3785 :
3786 34 : auto poSRS = GetSpatialRef();
3787 34 : if (poSRS)
3788 : {
3789 10 : char *pszStr = nullptr;
3790 10 : poSRS->exportToPROJJSON(&pszStr, nullptr);
3791 10 : if (!pszStr)
3792 0 : poSRS->exportToWkt(&pszStr, nullptr);
3793 10 : if (pszStr)
3794 : {
3795 20 : m_array->put_metadata("CRS", TILEDB_STRING_UTF8,
3796 10 : static_cast<int>(strlen(pszStr)), pszStr);
3797 : }
3798 10 : CPLFree(pszStr);
3799 : }
3800 :
3801 34 : const auto GetStringGeometryType = [](OGRwkbGeometryType eType)
3802 : {
3803 34 : const auto eFlattenType = wkbFlatten(eType);
3804 34 : std::string osType = "Unknown";
3805 34 : if (wkbPoint == eFlattenType)
3806 7 : osType = "Point";
3807 27 : else if (wkbLineString == eFlattenType)
3808 1 : osType = "LineString";
3809 26 : else if (wkbPolygon == eFlattenType)
3810 2 : osType = "Polygon";
3811 24 : else if (wkbMultiPoint == eFlattenType)
3812 1 : osType = "MultiPoint";
3813 23 : else if (wkbMultiLineString == eFlattenType)
3814 1 : osType = "MultiLineString";
3815 22 : else if (wkbMultiPolygon == eFlattenType)
3816 1 : osType = "MultiPolygon";
3817 21 : else if (wkbGeometryCollection == eFlattenType)
3818 1 : osType = "GeometryCollection";
3819 20 : else if (wkbCircularString == eFlattenType)
3820 1 : osType = "CircularString";
3821 19 : else if (wkbCompoundCurve == eFlattenType)
3822 1 : osType = "CompoundCurve";
3823 18 : else if (wkbCurvePolygon == eFlattenType)
3824 1 : osType = "CurvePolygon";
3825 17 : else if (wkbMultiCurve == eFlattenType)
3826 1 : osType = "MultiCurve";
3827 16 : else if (wkbMultiSurface == eFlattenType)
3828 1 : osType = "MultiSurface";
3829 15 : else if (wkbPolyhedralSurface == eFlattenType)
3830 1 : osType = "PolyhedralSurface";
3831 14 : else if (wkbTIN == eFlattenType)
3832 1 : osType = "TIN";
3833 :
3834 34 : if (OGR_GT_HasZ(eType) && OGR_GT_HasM(eType))
3835 1 : osType += " ZM";
3836 33 : else if (OGR_GT_HasZ(eType))
3837 2 : osType += " Z";
3838 31 : else if (OGR_GT_HasM(eType))
3839 1 : osType += " M";
3840 :
3841 34 : return osType;
3842 : };
3843 34 : const auto eGeomType = GetGeomType();
3844 34 : const std::string osGeometryType = GetStringGeometryType(eGeomType);
3845 68 : m_array->put_metadata("GeometryType", TILEDB_STRING_ASCII,
3846 34 : static_cast<int>(osGeometryType.size()),
3847 34 : osGeometryType.data());
3848 :
3849 34 : m_bInitialized = true;
3850 : }
3851 0 : catch (const tiledb::TileDBError &e)
3852 : {
3853 0 : CPLError(CE_Failure, CPLE_AppDefined,
3854 0 : "InitializeSchemaAndArray() failed: %s", e.what());
3855 : }
3856 : }
3857 :
3858 : /************************************************************************/
3859 : /* SwitchToWritingMode() */
3860 : /************************************************************************/
3861 :
3862 102 : void OGRTileDBLayer::SwitchToWritingMode()
3863 : {
3864 102 : if (m_eCurrentMode != CurrentMode::WriteInProgress)
3865 : {
3866 7 : m_nNextFID = GetFeatureCount(true) + 1;
3867 7 : if (m_eCurrentMode == CurrentMode::ReadInProgress)
3868 : {
3869 6 : m_eCurrentMode = CurrentMode::None;
3870 6 : ResetBuffers();
3871 : }
3872 :
3873 7 : m_query.reset();
3874 7 : m_array.reset();
3875 :
3876 : try
3877 : {
3878 7 : if (m_nTimestamp)
3879 0 : m_array.reset(new tiledb::Array(
3880 0 : *m_ctx, m_osFilename, TILEDB_WRITE,
3881 0 : tiledb::TemporalPolicy(tiledb::TimeTravel, m_nTimestamp)));
3882 : else
3883 14 : m_array.reset(
3884 14 : new tiledb::Array(*m_ctx, m_osFilename, TILEDB_WRITE));
3885 : }
3886 0 : catch (const std::exception &e)
3887 : {
3888 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
3889 0 : return;
3890 : }
3891 : }
3892 102 : m_eCurrentMode = CurrentMode::WriteInProgress;
3893 : }
3894 :
3895 : /************************************************************************/
3896 : /* ICreateFeature() */
3897 : /************************************************************************/
3898 :
3899 64 : OGRErr OGRTileDBLayer::ICreateFeature(OGRFeature *poFeature)
3900 : {
3901 64 : if (!m_bUpdatable)
3902 0 : return OGRERR_FAILURE;
3903 :
3904 64 : SwitchToWritingMode();
3905 :
3906 64 : if (!m_bInitializationAttempted)
3907 : {
3908 30 : InitializeSchemaAndArray();
3909 : }
3910 64 : if (!m_bInitialized)
3911 0 : return OGRERR_FAILURE;
3912 :
3913 64 : if (!m_array)
3914 0 : return OGRERR_FAILURE;
3915 :
3916 64 : const OGRGeometry *poGeom = poFeature->GetGeometryRef();
3917 64 : if (!poGeom || poGeom->IsEmpty())
3918 : {
3919 2 : CPLError(CE_Failure, CPLE_NotSupported,
3920 : "Features without geometry (or with empty geometry) are not "
3921 : "supported");
3922 2 : return OGRERR_FAILURE;
3923 : }
3924 :
3925 62 : if (GetDatabaseGeomColName())
3926 : {
3927 55 : const size_t nWkbSize = poGeom->WkbSize();
3928 55 : std::vector<unsigned char> aGeometry(nWkbSize);
3929 55 : poGeom->exportToWkb(wkbNDR, aGeometry.data(), wkbVariantIso);
3930 55 : m_abyGeometries->insert(m_abyGeometries->end(), aGeometry.begin(),
3931 110 : aGeometry.end());
3932 55 : if (m_anGeometryOffsets->empty())
3933 29 : m_anGeometryOffsets->push_back(0);
3934 55 : m_anGeometryOffsets->push_back(m_anGeometryOffsets->back() + nWkbSize);
3935 : }
3936 7 : else if (wkbFlatten(poGeom->getGeometryType()) != wkbPoint)
3937 : {
3938 0 : CPLError(CE_Failure, CPLE_AppDefined,
3939 : "Cannot write non-Point geometry in a layer without a "
3940 : "geometry attribute");
3941 0 : return OGRERR_FAILURE;
3942 : }
3943 :
3944 62 : int64_t nFID = poFeature->GetFID();
3945 62 : if (nFID < 0)
3946 : {
3947 56 : nFID = m_nNextFID++;
3948 56 : poFeature->SetFID(nFID);
3949 : }
3950 62 : if (!m_osFIDColumn.empty())
3951 59 : m_anFIDs->push_back(nFID);
3952 :
3953 62 : const int nFieldCount = m_poFeatureDefn->GetFieldCountUnsafe();
3954 476 : for (int i = 0; i < nFieldCount; i++)
3955 : {
3956 414 : const OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
3957 414 : const bool bFieldIsValid = poFeature->IsFieldSetAndNotNull(i);
3958 414 : auto &anOffsets = *(m_aFieldValueOffsets[i]);
3959 414 : if (poFieldDefn->IsNullable())
3960 : {
3961 224 : m_aFieldValidity[i].push_back(bFieldIsValid);
3962 : }
3963 : else
3964 : {
3965 190 : if (!bFieldIsValid)
3966 : {
3967 54 : CPLError(CE_Warning, CPLE_AppDefined,
3968 : "Field %d of feature " CPL_FRMT_GIB
3969 : " is null or unset, "
3970 : "but field is declared as not nullable. Readers "
3971 : "will see an incorrect value",
3972 : i, static_cast<GIntBig>(nFID));
3973 : }
3974 : }
3975 414 : auto &fieldValues = m_aFieldValues[i];
3976 :
3977 414 : switch (poFieldDefn->GetType())
3978 : {
3979 124 : case OFTInteger:
3980 : {
3981 : const int nVal =
3982 124 : bFieldIsValid ? poFeature->GetFieldAsIntegerUnsafe(i) : 0;
3983 124 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
3984 20 : std::get<std::shared_ptr<VECTOR_OF_BOOL>>(fieldValues)
3985 20 : ->push_back(static_cast<uint8_t>(nVal));
3986 104 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
3987 20 : std::get<std::shared_ptr<std::vector<int16_t>>>(fieldValues)
3988 20 : ->push_back(static_cast<int16_t>(nVal));
3989 84 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
3990 44 : std::get<std::shared_ptr<std::vector<int32_t>>>(fieldValues)
3991 44 : ->push_back(nVal);
3992 40 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
3993 20 : std::get<std::shared_ptr<std::vector<uint8_t>>>(fieldValues)
3994 20 : ->push_back(static_cast<uint8_t>(nVal));
3995 20 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
3996 : std::get<std::shared_ptr<std::vector<uint16_t>>>(
3997 20 : fieldValues)
3998 20 : ->push_back(static_cast<uint16_t>(nVal));
3999 : else
4000 : {
4001 0 : CPLAssert(false);
4002 : }
4003 124 : break;
4004 : }
4005 :
4006 60 : case OFTIntegerList:
4007 : {
4008 60 : int nCount = 0;
4009 : const int *panVal =
4010 60 : poFeature->GetFieldAsIntegerList(i, &nCount);
4011 60 : if (anOffsets.empty())
4012 27 : anOffsets.push_back(0);
4013 60 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
4014 : {
4015 : auto &v = *(
4016 20 : std::get<std::shared_ptr<VECTOR_OF_BOOL>>(fieldValues));
4017 48 : for (int j = 0; j < nCount; ++j)
4018 28 : v.push_back(static_cast<uint8_t>(panVal[j]));
4019 40 : anOffsets.push_back(anOffsets.back() +
4020 20 : nCount * sizeof(v[0]));
4021 : }
4022 40 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
4023 : {
4024 : auto &v = *(std::get<std::shared_ptr<std::vector<int16_t>>>(
4025 20 : fieldValues));
4026 48 : for (int j = 0; j < nCount; ++j)
4027 28 : v.push_back(static_cast<int16_t>(panVal[j]));
4028 40 : anOffsets.push_back(anOffsets.back() +
4029 20 : nCount * sizeof(v[0]));
4030 : }
4031 20 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
4032 : {
4033 : auto &v = *(std::get<std::shared_ptr<std::vector<int32_t>>>(
4034 20 : fieldValues));
4035 20 : v.insert(v.end(), panVal, panVal + nCount);
4036 40 : anOffsets.push_back(anOffsets.back() +
4037 20 : nCount * sizeof(v[0]));
4038 : }
4039 0 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
4040 : {
4041 : auto &v = *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
4042 0 : fieldValues));
4043 0 : for (int j = 0; j < nCount; ++j)
4044 0 : v.push_back(static_cast<uint8_t>(panVal[j]));
4045 0 : anOffsets.push_back(anOffsets.back() +
4046 0 : nCount * sizeof(v[0]));
4047 : }
4048 0 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
4049 : {
4050 : auto &v =
4051 : *(std::get<std::shared_ptr<std::vector<uint16_t>>>(
4052 0 : fieldValues));
4053 0 : for (int j = 0; j < nCount; ++j)
4054 0 : v.push_back(static_cast<uint16_t>(panVal[j]));
4055 0 : anOffsets.push_back(anOffsets.back() +
4056 0 : nCount * sizeof(v[0]));
4057 : }
4058 : else
4059 : {
4060 0 : CPLAssert(false);
4061 : }
4062 60 : break;
4063 : }
4064 :
4065 30 : case OFTInteger64:
4066 : {
4067 30 : std::get<std::shared_ptr<std::vector<int64_t>>>(fieldValues)
4068 30 : ->push_back(bFieldIsValid
4069 30 : ? poFeature->GetFieldAsInteger64Unsafe(i)
4070 : : 0);
4071 30 : break;
4072 : }
4073 :
4074 0 : case OFTInteger64List:
4075 : {
4076 0 : int nCount = 0;
4077 : const int64_t *panVal = reinterpret_cast<const int64_t *>(
4078 0 : poFeature->GetFieldAsInteger64List(i, &nCount));
4079 0 : if (anOffsets.empty())
4080 0 : anOffsets.push_back(0);
4081 : auto &v = *(std::get<std::shared_ptr<std::vector<int64_t>>>(
4082 0 : fieldValues));
4083 0 : v.insert(v.end(), panVal, panVal + nCount);
4084 0 : anOffsets.push_back(anOffsets.back() + nCount * sizeof(v[0]));
4085 0 : break;
4086 : }
4087 :
4088 50 : case OFTReal:
4089 : {
4090 : const double dfVal =
4091 50 : bFieldIsValid ? poFeature->GetFieldAsDoubleUnsafe(i)
4092 12 : : std::numeric_limits<double>::quiet_NaN();
4093 50 : if (poFieldDefn->GetSubType() == OFSTFloat32)
4094 20 : std::get<std::shared_ptr<std::vector<float>>>(fieldValues)
4095 20 : ->push_back(static_cast<float>(dfVal));
4096 : else
4097 30 : std::get<std::shared_ptr<std::vector<double>>>(fieldValues)
4098 30 : ->push_back(dfVal);
4099 50 : break;
4100 : }
4101 :
4102 40 : case OFTRealList:
4103 : {
4104 40 : int nCount = 0;
4105 : const double *padfVal =
4106 40 : poFeature->GetFieldAsDoubleList(i, &nCount);
4107 40 : if (anOffsets.empty())
4108 18 : anOffsets.push_back(0);
4109 40 : if (poFieldDefn->GetSubType() == OFSTFloat32)
4110 : {
4111 : auto &v = *(std::get<std::shared_ptr<std::vector<float>>>(
4112 20 : fieldValues));
4113 62 : for (int j = 0; j < nCount; ++j)
4114 42 : v.push_back(static_cast<float>(padfVal[j]));
4115 40 : anOffsets.push_back(anOffsets.back() +
4116 20 : nCount * sizeof(v[0]));
4117 : }
4118 : else
4119 : {
4120 : auto &v = *(std::get<std::shared_ptr<std::vector<double>>>(
4121 20 : fieldValues));
4122 20 : v.insert(v.end(), padfVal, padfVal + nCount);
4123 40 : anOffsets.push_back(anOffsets.back() +
4124 20 : nCount * sizeof(v[0]));
4125 : }
4126 40 : break;
4127 : }
4128 :
4129 30 : case OFTString:
4130 : {
4131 : const char *pszValue =
4132 30 : bFieldIsValid ? poFeature->GetFieldAsStringUnsafe(i)
4133 30 : : nullptr;
4134 30 : const size_t nValueLen = pszValue ? strlen(pszValue) : 0;
4135 30 : if (pszValue)
4136 : {
4137 : auto &v =
4138 24 : *(std::get<std::shared_ptr<std::string>>(fieldValues));
4139 24 : v.insert(v.end(), pszValue, pszValue + nValueLen);
4140 : }
4141 30 : if (anOffsets.empty())
4142 10 : anOffsets.push_back(0);
4143 30 : anOffsets.push_back(anOffsets.back() + nValueLen);
4144 30 : break;
4145 : }
4146 :
4147 20 : case OFTBinary:
4148 : {
4149 20 : int nCount = 0;
4150 : const GByte *pabyValue =
4151 20 : poFeature->GetFieldAsBinary(i, &nCount);
4152 : auto &v = *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
4153 20 : fieldValues));
4154 20 : v.insert(v.end(), pabyValue, pabyValue + nCount);
4155 20 : if (anOffsets.empty())
4156 9 : anOffsets.push_back(0);
4157 20 : anOffsets.push_back(anOffsets.back() + nCount);
4158 20 : break;
4159 : }
4160 :
4161 20 : case OFTDate:
4162 : {
4163 : auto &v = *(std::get<std::shared_ptr<std::vector<int64_t>>>(
4164 20 : fieldValues));
4165 20 : if (bFieldIsValid)
4166 : {
4167 14 : const auto poRawField = poFeature->GetRawFieldRef(i);
4168 14 : v.push_back(OGRFieldToDateDay(*poRawField));
4169 : }
4170 : else
4171 : {
4172 6 : v.push_back(0);
4173 : }
4174 20 : break;
4175 : }
4176 :
4177 20 : case OFTDateTime:
4178 : {
4179 : auto &v = *(std::get<std::shared_ptr<std::vector<int64_t>>>(
4180 20 : fieldValues));
4181 20 : if (bFieldIsValid)
4182 : {
4183 14 : const auto poRawField = poFeature->GetRawFieldRef(i);
4184 14 : v.push_back(OGRFieldToDateTimeMS(*poRawField));
4185 : }
4186 : else
4187 : {
4188 6 : v.push_back(0);
4189 : }
4190 20 : break;
4191 : }
4192 :
4193 20 : case OFTTime:
4194 : {
4195 : auto &v = *(std::get<std::shared_ptr<std::vector<int64_t>>>(
4196 20 : fieldValues));
4197 20 : if (bFieldIsValid)
4198 : {
4199 14 : const auto poRawField = poFeature->GetRawFieldRef(i);
4200 14 : v.push_back(OGRFieldToTimeMS(*poRawField));
4201 : }
4202 : else
4203 : {
4204 6 : v.push_back(0);
4205 : }
4206 20 : break;
4207 : }
4208 :
4209 0 : default:
4210 : {
4211 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
4212 : "Unsupported attribute definition.\n");
4213 0 : return OGRERR_FAILURE;
4214 : }
4215 : }
4216 : }
4217 :
4218 62 : OGREnvelope sEnvelope;
4219 62 : OGREnvelope3D sEnvelope3D;
4220 62 : if (!m_osZDim.empty())
4221 : {
4222 34 : poGeom->getEnvelope(&sEnvelope3D);
4223 34 : sEnvelope = sEnvelope3D;
4224 : }
4225 : else
4226 : {
4227 28 : poGeom->getEnvelope(&sEnvelope);
4228 : }
4229 :
4230 62 : m_oLayerExtent.Merge(sEnvelope);
4231 :
4232 : // use mid point of envelope
4233 62 : m_adfXs->push_back(sEnvelope.MinX +
4234 62 : ((sEnvelope.MaxX - sEnvelope.MinX) / 2.0));
4235 62 : m_adfYs->push_back(sEnvelope.MinY +
4236 62 : ((sEnvelope.MaxY - sEnvelope.MinY) / 2.0));
4237 :
4238 : // Compute maximum "radius" of a geometry around its mid point,
4239 : // for later spatial requests
4240 62 : m_dfPadX = std::max(m_dfPadX, (sEnvelope.MaxX - sEnvelope.MinX) / 2);
4241 62 : m_dfPadY = std::max(m_dfPadY, (sEnvelope.MaxY - sEnvelope.MinY) / 2);
4242 :
4243 62 : if (!m_osZDim.empty())
4244 : {
4245 34 : m_adfZs->push_back(sEnvelope3D.MinZ +
4246 34 : ((sEnvelope3D.MaxZ - sEnvelope3D.MinZ) / 2.0));
4247 34 : m_dfPadZ =
4248 34 : std::max(m_dfPadZ, (sEnvelope3D.MaxZ - sEnvelope3D.MinZ) / 2);
4249 : }
4250 :
4251 62 : if (m_nTotalFeatureCount < 0)
4252 29 : m_nTotalFeatureCount = 1;
4253 : else
4254 33 : ++m_nTotalFeatureCount;
4255 :
4256 62 : if (m_adfXs->size() == m_nBatchSize)
4257 : {
4258 : try
4259 : {
4260 4 : FlushArrays();
4261 : }
4262 0 : catch (const std::exception &e)
4263 : {
4264 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
4265 0 : return OGRERR_FAILURE;
4266 : }
4267 : }
4268 :
4269 62 : return OGRERR_NONE;
4270 : }
4271 :
4272 : /************************************************************************/
4273 : /* FlushArrays() */
4274 : /************************************************************************/
4275 :
4276 34 : void OGRTileDBLayer::FlushArrays()
4277 : {
4278 34 : CPLDebug("TILEDB", "Flush %d records", static_cast<int>(m_adfXs->size()));
4279 :
4280 : try
4281 : {
4282 68 : tiledb::Query query(*m_ctx, *m_array);
4283 34 : query.set_layout(TILEDB_UNORDERED);
4284 34 : if (!m_osFIDColumn.empty())
4285 32 : query.set_data_buffer(m_osFIDColumn, *m_anFIDs);
4286 34 : query.set_data_buffer(m_osXDim, *m_adfXs);
4287 34 : query.set_data_buffer(m_osYDim, *m_adfYs);
4288 34 : if (!m_osZDim.empty())
4289 16 : query.set_data_buffer(m_osZDim, *m_adfZs);
4290 :
4291 34 : const char *pszGeomColName = GetDatabaseGeomColName();
4292 34 : if (pszGeomColName)
4293 : {
4294 29 : m_anGeometryOffsets->pop_back();
4295 29 : const auto eTileDBType = m_schema->attribute(pszGeomColName).type();
4296 29 : if (eTileDBType == TILEDB_UINT8)
4297 : {
4298 0 : query.set_data_buffer(pszGeomColName, *m_abyGeometries);
4299 0 : query.set_offsets_buffer(pszGeomColName, *m_anGeometryOffsets);
4300 : }
4301 29 : else if (eTileDBType == TILEDB_BLOB)
4302 : {
4303 : query.set_data_buffer(
4304 : pszGeomColName,
4305 29 : reinterpret_cast<std::byte *>(m_abyGeometries->data()),
4306 58 : m_abyGeometries->size());
4307 : query.set_offsets_buffer(pszGeomColName,
4308 29 : m_anGeometryOffsets->data(),
4309 29 : m_anGeometryOffsets->size());
4310 : }
4311 : #ifdef HAS_TILEDB_GEOM_WKB_WKT
4312 : else if (eTileDBType == TILEDB_GEOM_WKB)
4313 : {
4314 : query.set_offsets_buffer(pszGeomColName, *m_anGeometryOffsets);
4315 : // We could use API expected std::byte, but this requires
4316 : // TileDB 2.22 because of https://github.com/TileDB-Inc/TileDB/pull/4826
4317 : query.set_data_buffer(
4318 : pszGeomColName,
4319 : static_cast<void *>(m_abyGeometries->data()),
4320 : m_abyGeometries->size());
4321 : }
4322 : #endif
4323 : else
4324 : {
4325 0 : CPLAssert(false);
4326 : }
4327 : }
4328 :
4329 211 : for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
4330 : {
4331 177 : const OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
4332 177 : const char *pszFieldName = poFieldDefn->GetNameRef();
4333 177 : auto &anOffsets = *(m_aFieldValueOffsets[i]);
4334 177 : auto &fieldValues = m_aFieldValues[i];
4335 :
4336 177 : if (poFieldDefn->IsNullable())
4337 63 : query.set_validity_buffer(pszFieldName, m_aFieldValidity[i]);
4338 :
4339 177 : const auto eType = poFieldDefn->GetType();
4340 177 : switch (eType)
4341 : {
4342 84 : case OFTInteger:
4343 : case OFTIntegerList:
4344 : {
4345 84 : if (eType == OFTIntegerList)
4346 : {
4347 27 : anOffsets.pop_back();
4348 27 : query.set_offsets_buffer(pszFieldName, anOffsets);
4349 : }
4350 :
4351 84 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
4352 : {
4353 : auto &v = *(std::get<std::shared_ptr<VECTOR_OF_BOOL>>(
4354 18 : fieldValues));
4355 : #ifdef VECTOR_OF_BOOL_IS_NOT_UINT8_T
4356 : query.set_data_buffer(pszFieldName, v.data(), v.size());
4357 : #else
4358 18 : query.set_data_buffer(pszFieldName, v);
4359 : #endif
4360 : }
4361 66 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
4362 : {
4363 : auto &v =
4364 : *(std::get<std::shared_ptr<std::vector<int16_t>>>(
4365 18 : fieldValues));
4366 18 : query.set_data_buffer(pszFieldName, v);
4367 : }
4368 48 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
4369 : {
4370 : auto &v =
4371 : *(std::get<std::shared_ptr<std::vector<int32_t>>>(
4372 30 : fieldValues));
4373 30 : query.set_data_buffer(pszFieldName, v);
4374 : }
4375 18 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
4376 : {
4377 : auto &v =
4378 : *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
4379 9 : fieldValues));
4380 9 : query.set_data_buffer(pszFieldName, v);
4381 : }
4382 9 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
4383 : {
4384 : auto &v =
4385 : *(std::get<std::shared_ptr<std::vector<uint16_t>>>(
4386 9 : fieldValues));
4387 9 : query.set_data_buffer(pszFieldName, v);
4388 : }
4389 84 : break;
4390 : }
4391 :
4392 10 : case OFTInteger64:
4393 : {
4394 : query.set_data_buffer(
4395 : pszFieldName,
4396 : *std::get<std::shared_ptr<std::vector<int64_t>>>(
4397 10 : fieldValues));
4398 10 : break;
4399 : }
4400 :
4401 0 : case OFTInteger64List:
4402 : {
4403 0 : anOffsets.pop_back();
4404 : query.set_data_buffer(
4405 : pszFieldName,
4406 : *std::get<std::shared_ptr<std::vector<int64_t>>>(
4407 0 : fieldValues));
4408 0 : query.set_offsets_buffer(pszFieldName, anOffsets);
4409 0 : break;
4410 : }
4411 :
4412 19 : case OFTReal:
4413 : {
4414 19 : if (poFieldDefn->GetSubType() == OFSTFloat32)
4415 : {
4416 : query.set_data_buffer(
4417 : pszFieldName,
4418 : *std::get<std::shared_ptr<std::vector<float>>>(
4419 9 : fieldValues));
4420 : }
4421 : else
4422 : {
4423 : query.set_data_buffer(
4424 : pszFieldName,
4425 : *std::get<std::shared_ptr<std::vector<double>>>(
4426 10 : fieldValues));
4427 : }
4428 19 : break;
4429 : }
4430 :
4431 18 : case OFTRealList:
4432 : {
4433 18 : anOffsets.pop_back();
4434 18 : if (poFieldDefn->GetSubType() == OFSTFloat32)
4435 : {
4436 : query.set_data_buffer(
4437 : pszFieldName,
4438 : *std::get<std::shared_ptr<std::vector<float>>>(
4439 9 : fieldValues));
4440 9 : query.set_offsets_buffer(pszFieldName, anOffsets);
4441 : }
4442 : else
4443 : {
4444 : query.set_data_buffer(
4445 : pszFieldName,
4446 : *std::get<std::shared_ptr<std::vector<double>>>(
4447 9 : fieldValues));
4448 9 : query.set_offsets_buffer(pszFieldName, anOffsets);
4449 : }
4450 18 : break;
4451 : }
4452 :
4453 10 : case OFTString:
4454 : {
4455 10 : anOffsets.pop_back();
4456 : query.set_data_buffer(
4457 : pszFieldName,
4458 10 : *std::get<std::shared_ptr<std::string>>(fieldValues));
4459 10 : query.set_offsets_buffer(pszFieldName, anOffsets);
4460 10 : break;
4461 : }
4462 :
4463 9 : case OFTBinary:
4464 : {
4465 9 : anOffsets.pop_back();
4466 : auto &v = *(std::get<std::shared_ptr<std::vector<uint8_t>>>(
4467 9 : fieldValues));
4468 9 : if (m_aeFieldTypes[i] == TILEDB_UINT8)
4469 : {
4470 0 : query.set_data_buffer(pszFieldName, v);
4471 0 : query.set_offsets_buffer(pszFieldName, anOffsets);
4472 : }
4473 9 : else if (m_aeFieldTypes[i] == TILEDB_BLOB)
4474 : {
4475 : query.set_data_buffer(
4476 : pszFieldName,
4477 9 : reinterpret_cast<std::byte *>(v.data()), v.size());
4478 : query.set_offsets_buffer(pszFieldName, anOffsets.data(),
4479 9 : anOffsets.size());
4480 : }
4481 : else
4482 : {
4483 0 : CPLAssert(false);
4484 : }
4485 9 : break;
4486 : }
4487 :
4488 27 : case OFTDate:
4489 : case OFTDateTime:
4490 : case OFTTime:
4491 : {
4492 : query.set_data_buffer(
4493 : pszFieldName,
4494 : *std::get<std::shared_ptr<std::vector<int64_t>>>(
4495 27 : fieldValues));
4496 27 : break;
4497 : }
4498 :
4499 0 : default:
4500 : {
4501 0 : CPLAssert(false);
4502 : break;
4503 : }
4504 : }
4505 : }
4506 :
4507 34 : if (m_bStats)
4508 0 : tiledb::Stats::enable();
4509 :
4510 34 : query.submit();
4511 :
4512 34 : if (m_bStats)
4513 : {
4514 0 : tiledb::Stats::dump(stdout);
4515 0 : tiledb::Stats::disable();
4516 : }
4517 : }
4518 0 : catch (const std::exception &)
4519 : {
4520 0 : ResetBuffers();
4521 0 : throw;
4522 : }
4523 34 : ResetBuffers();
4524 34 : }
4525 :
4526 : /************************************************************************/
4527 : /* ResetBuffers() */
4528 : /************************************************************************/
4529 :
4530 : namespace
4531 : {
4532 : template <class T> struct ClearArray
4533 : {
4534 8725 : static void exec(OGRTileDBLayer::ArrayType &array)
4535 : {
4536 8725 : std::get<std::shared_ptr<T>>(array)->clear();
4537 8725 : }
4538 : };
4539 : } // namespace
4540 :
4541 631 : void OGRTileDBLayer::ResetBuffers()
4542 : {
4543 631 : if (!m_bArrowBatchReleased)
4544 : {
4545 39 : AllocateNewBuffers();
4546 : }
4547 : else
4548 : {
4549 : // Reset buffers
4550 592 : m_anFIDs->clear();
4551 592 : m_adfXs->clear();
4552 592 : m_adfYs->clear();
4553 592 : m_adfZs->clear();
4554 592 : m_abyGeometries->clear();
4555 592 : m_anGeometryOffsets->clear();
4556 9317 : for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
4557 : {
4558 8725 : m_aFieldValueOffsets[i]->clear();
4559 8725 : m_aFieldValidity[i].clear();
4560 8725 : ProcessField<ClearArray>::exec(m_aeFieldTypes[i],
4561 8725 : m_aFieldValues[i]);
4562 : }
4563 : }
4564 631 : }
4565 :
4566 : /************************************************************************/
4567 : /* TestCapability() */
4568 : /************************************************************************/
4569 :
4570 293 : int OGRTileDBLayer::TestCapability(const char *pszCap)
4571 : {
4572 293 : if (EQUAL(pszCap, OLCCreateField))
4573 4 : return m_bUpdatable && m_schema == nullptr;
4574 :
4575 289 : if (EQUAL(pszCap, OLCSequentialWrite))
4576 3 : return m_bUpdatable;
4577 :
4578 286 : if (EQUAL(pszCap, OLCFastFeatureCount))
4579 0 : return (!m_poAttrQuery && !m_poFilterGeom && m_nTotalFeatureCount >= 0);
4580 :
4581 286 : if (EQUAL(pszCap, OLCFastGetExtent))
4582 2 : return m_oLayerExtent.IsInit();
4583 :
4584 284 : if (EQUAL(pszCap, OLCStringsAsUTF8))
4585 196 : return true;
4586 :
4587 88 : if (EQUAL(pszCap, OLCCurveGeometries))
4588 41 : return true;
4589 :
4590 47 : if (EQUAL(pszCap, OLCMeasuredGeometries))
4591 35 : return true;
4592 :
4593 12 : if (EQUAL(pszCap, OLCFastSpatialFilter))
4594 0 : return true;
4595 :
4596 12 : if (EQUAL(pszCap, OLCIgnoreFields))
4597 1 : return true;
4598 :
4599 11 : if (EQUAL(pszCap, OLCFastGetArrowStream))
4600 0 : return true;
4601 :
4602 11 : return false;
4603 : }
4604 :
4605 : /************************************************************************/
4606 : /* GetArrowSchema() */
4607 : /************************************************************************/
4608 :
4609 44 : int OGRTileDBLayer::GetArrowSchema(struct ArrowArrayStream *out_stream,
4610 : struct ArrowSchema *out_schema)
4611 : {
4612 44 : int ret = OGRLayer::GetArrowSchema(out_stream, out_schema);
4613 44 : if (ret != 0)
4614 0 : return ret;
4615 :
4616 : // Patch integer fields
4617 44 : const bool bIncludeFID = CPLTestBool(
4618 : m_aosArrowArrayStreamOptions.FetchNameValueDef("INCLUDE_FID", "YES"));
4619 44 : const int nFieldCount = m_poFeatureDefn->GetFieldCount();
4620 44 : int iSchemaChild = bIncludeFID ? 1 : 0;
4621 581 : for (int i = 0; i < nFieldCount; ++i)
4622 : {
4623 537 : const auto poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
4624 537 : if (poFieldDefn->IsIgnored())
4625 : {
4626 2 : continue;
4627 : }
4628 535 : const auto eType = poFieldDefn->GetType();
4629 535 : if (eType == OFTInteger || eType == OFTIntegerList)
4630 : {
4631 243 : const char *&format =
4632 : eType == OFTInteger
4633 162 : ? out_schema->children[iSchemaChild]->format
4634 81 : : out_schema->children[iSchemaChild]->children[0]->format;
4635 243 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
4636 54 : format = "b";
4637 189 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
4638 54 : format = "s";
4639 135 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
4640 81 : format = "i";
4641 54 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
4642 27 : format = "C";
4643 27 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
4644 27 : format = "S";
4645 : else
4646 : {
4647 0 : CPLAssert(false);
4648 : }
4649 : }
4650 535 : ++iSchemaChild;
4651 : }
4652 :
4653 : // Patch other fields
4654 663 : for (int64_t i = 0; i < out_schema->n_children; ++i)
4655 : {
4656 619 : const char *&format = out_schema->children[i]->format;
4657 619 : if (strcmp(format, "+l") == 0)
4658 : {
4659 : // 32-bit list to 64-bit list
4660 135 : format = "+L";
4661 : }
4662 484 : else if (strcmp(format, "u") == 0)
4663 : {
4664 : // 32-bit string to 64-bit string
4665 33 : format = "U";
4666 : }
4667 451 : else if (strcmp(format, "z") == 0)
4668 : {
4669 : // 32-bit binary to 64-bit binary
4670 69 : format = "Z";
4671 : }
4672 : }
4673 44 : return 0;
4674 : }
4675 :
4676 : /************************************************************************/
4677 : /* ReleaseArrowArray() */
4678 : /************************************************************************/
4679 :
4680 975 : void OGRTileDBLayer::ReleaseArrowArray(struct ArrowArray *array)
4681 : {
4682 1901 : for (int i = 0; i < static_cast<int>(array->n_children); ++i)
4683 : {
4684 926 : if (array->children[i] && array->children[i]->release)
4685 : {
4686 926 : array->children[i]->release(array->children[i]);
4687 926 : CPLFree(array->children[i]);
4688 : }
4689 : }
4690 975 : CPLFree(array->children);
4691 975 : CPLFree(array->buffers);
4692 :
4693 975 : OGRTileDBArrowArrayPrivateData *psPrivateData =
4694 : static_cast<OGRTileDBArrowArrayPrivateData *>(array->private_data);
4695 1005 : if (psPrivateData->m_pbLayerStillAlive &&
4696 1005 : *psPrivateData->m_pbLayerStillAlive)
4697 : {
4698 23 : psPrivateData->m_poLayer->m_bArrowBatchReleased = true;
4699 : }
4700 975 : delete psPrivateData;
4701 975 : array->private_data = nullptr;
4702 975 : array->release = nullptr;
4703 975 : }
4704 :
4705 : /************************************************************************/
4706 : /* SetNullBuffer() */
4707 : /************************************************************************/
4708 :
4709 662 : void OGRTileDBLayer::SetNullBuffer(
4710 : struct ArrowArray *psChild, int iField,
4711 : const std::vector<bool> &abyValidityFromFilters)
4712 : {
4713 662 : if (m_poFeatureDefn->GetFieldDefn(iField)->IsNullable())
4714 : {
4715 : // TileDB used a std::vector<uint8_t> with 1 element per byte
4716 : // whereas Arrow uses a ~ std::vector<bool> with 8 elements per byte
4717 245 : OGRTileDBArrowArrayPrivateData *psPrivateData =
4718 : static_cast<OGRTileDBArrowArrayPrivateData *>(
4719 : psChild->private_data);
4720 245 : const auto &v_validity = m_aFieldValidity[iField];
4721 245 : uint8_t *pabyNull = nullptr;
4722 245 : const size_t nSrcSize = static_cast<size_t>(m_nRowCountInResultSet);
4723 245 : if (abyValidityFromFilters.empty())
4724 : {
4725 852 : for (size_t i = 0; i < nSrcSize; ++i)
4726 : {
4727 686 : if (!v_validity[i])
4728 : {
4729 143 : ++psChild->null_count;
4730 143 : if (pabyNull == nullptr)
4731 : {
4732 : psPrivateData->nullHolder =
4733 143 : std::make_shared<std::vector<uint8_t>>(
4734 143 : (nSrcSize + 7) / 8, static_cast<uint8_t>(0xFF));
4735 143 : pabyNull = psPrivateData->nullHolder->data();
4736 143 : psChild->buffers[0] = pabyNull;
4737 : }
4738 143 : pabyNull[i / 8] &= static_cast<uint8_t>(~(1 << (i % 8)));
4739 : }
4740 : }
4741 : }
4742 : else
4743 : {
4744 356 : for (size_t i = 0, j = 0; i < nSrcSize; ++i)
4745 : {
4746 277 : if (abyValidityFromFilters[i])
4747 : {
4748 97 : if (!v_validity[i])
4749 : {
4750 18 : ++psChild->null_count;
4751 18 : if (pabyNull == nullptr)
4752 : {
4753 18 : const size_t nDstSize =
4754 18 : static_cast<size_t>(psChild->length);
4755 : psPrivateData->nullHolder =
4756 18 : std::make_shared<std::vector<uint8_t>>(
4757 0 : (nDstSize + 7) / 8,
4758 18 : static_cast<uint8_t>(0xFF));
4759 18 : pabyNull = psPrivateData->nullHolder->data();
4760 18 : psChild->buffers[0] = pabyNull;
4761 : }
4762 18 : pabyNull[j / 8] &=
4763 18 : static_cast<uint8_t>(~(1 << (j % 8)));
4764 : }
4765 97 : ++j;
4766 : }
4767 : }
4768 : }
4769 : }
4770 662 : }
4771 :
4772 : /************************************************************************/
4773 : /* FillBoolArray() */
4774 : /************************************************************************/
4775 :
4776 34 : void OGRTileDBLayer::FillBoolArray(
4777 : struct ArrowArray *psChild, int iField,
4778 : const std::vector<bool> &abyValidityFromFilters)
4779 : {
4780 : OGRTileDBArrowArrayPrivateData *psPrivateData =
4781 34 : new OGRTileDBArrowArrayPrivateData;
4782 34 : psChild->private_data = psPrivateData;
4783 :
4784 34 : psChild->n_buffers = 2;
4785 34 : psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
4786 : // TileDB used a std::vector<uint8_t> with 1 element per byte
4787 : // whereas Arrow uses a ~ std::vector<bool> with 8 elements per byte
4788 : const auto &v_source =
4789 34 : *(std::get<std::shared_ptr<VECTOR_OF_BOOL>>(m_aFieldValues[iField]));
4790 34 : const size_t nDstSize = abyValidityFromFilters.empty()
4791 34 : ? v_source.size()
4792 10 : : static_cast<size_t>(psChild->length);
4793 : auto arrayValues =
4794 68 : std::make_shared<std::vector<uint8_t>>((nDstSize + 7) / 8);
4795 34 : psPrivateData->valueHolder = arrayValues;
4796 34 : auto panValues = arrayValues->data();
4797 34 : psChild->buffers[1] = panValues;
4798 34 : if (abyValidityFromFilters.empty())
4799 : {
4800 87 : for (size_t i = 0; i < v_source.size(); ++i)
4801 : {
4802 63 : if (v_source[i])
4803 : {
4804 17 : panValues[i / 8] |= static_cast<uint8_t>(1 << (i % 8));
4805 : }
4806 : }
4807 : }
4808 : else
4809 : {
4810 33 : for (size_t i = 0, j = 0; i < v_source.size(); ++i)
4811 : {
4812 23 : if (abyValidityFromFilters[i])
4813 : {
4814 5 : if (v_source[i])
4815 : {
4816 1 : panValues[j / 8] |= static_cast<uint8_t>(1 << (j % 8));
4817 : }
4818 5 : ++j;
4819 : }
4820 : }
4821 : }
4822 :
4823 34 : SetNullBuffer(psChild, iField, abyValidityFromFilters);
4824 34 : }
4825 :
4826 : /************************************************************************/
4827 : /* FillPrimitiveArray() */
4828 : /************************************************************************/
4829 :
4830 : template <typename T>
4831 318 : void OGRTileDBLayer::FillPrimitiveArray(
4832 : struct ArrowArray *psChild, int iField,
4833 : const std::vector<bool> &abyValidityFromFilters)
4834 : {
4835 318 : OGRTileDBArrowArrayPrivateData *psPrivateData =
4836 318 : new OGRTileDBArrowArrayPrivateData;
4837 318 : psChild->private_data = psPrivateData;
4838 :
4839 318 : psChild->n_buffers = 2;
4840 318 : psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
4841 : auto &v_source =
4842 318 : std::get<std::shared_ptr<std::vector<T>>>(m_aFieldValues[iField]);
4843 318 : psPrivateData->valueHolder = v_source;
4844 318 : psChild->buffers[1] = v_source->data();
4845 :
4846 318 : if (!abyValidityFromFilters.empty())
4847 : {
4848 92 : const size_t nSrcSize = static_cast<size_t>(m_nRowCountInResultSet);
4849 319 : for (size_t i = 0, j = 0; i < nSrcSize; ++i)
4850 : {
4851 227 : if (abyValidityFromFilters[i])
4852 : {
4853 59 : (*v_source)[j] = (*v_source)[i];
4854 59 : ++j;
4855 : }
4856 : }
4857 : }
4858 :
4859 318 : SetNullBuffer(psChild, iField, abyValidityFromFilters);
4860 318 : }
4861 :
4862 : /************************************************************************/
4863 : /* FillStringOrBinaryArray() */
4864 : /************************************************************************/
4865 :
4866 : template <typename T>
4867 72 : void OGRTileDBLayer::FillStringOrBinaryArray(
4868 : struct ArrowArray *psChild, int iField,
4869 : const std::vector<bool> &abyValidityFromFilters)
4870 : {
4871 72 : OGRTileDBArrowArrayPrivateData *psPrivateData =
4872 72 : new OGRTileDBArrowArrayPrivateData;
4873 72 : psChild->private_data = psPrivateData;
4874 :
4875 72 : psChild->n_buffers = 3;
4876 72 : psChild->buffers = static_cast<const void **>(CPLCalloc(3, sizeof(void *)));
4877 :
4878 72 : auto &v_source = std::get<std::shared_ptr<T>>(m_aFieldValues[iField]);
4879 :
4880 72 : psPrivateData->offsetHolder = m_aFieldValueOffsets[iField];
4881 : // Add back extra offset
4882 72 : if (!psPrivateData->offsetHolder->empty())
4883 72 : psPrivateData->offsetHolder->push_back(v_source->size());
4884 72 : psChild->buffers[1] = psPrivateData->offsetHolder->data();
4885 :
4886 72 : psPrivateData->valueHolder = v_source;
4887 72 : psChild->buffers[2] = v_source->data();
4888 :
4889 72 : if (!abyValidityFromFilters.empty())
4890 : {
4891 21 : const size_t nSrcSize = static_cast<size_t>(m_nRowCountInResultSet);
4892 21 : size_t nAccLen = 0;
4893 77 : for (size_t i = 0, j = 0; i < nSrcSize; ++i)
4894 : {
4895 56 : if (abyValidityFromFilters[i])
4896 : {
4897 17 : const size_t nSrcOffset =
4898 17 : static_cast<size_t>((*psPrivateData->offsetHolder)[i]);
4899 17 : const size_t nNextOffset =
4900 17 : static_cast<size_t>((*psPrivateData->offsetHolder)[i + 1]);
4901 17 : const size_t nItemLen = nNextOffset - nSrcOffset;
4902 17 : (*psPrivateData->offsetHolder)[j] = nAccLen;
4903 17 : if (nItemLen && nAccLen < nSrcOffset)
4904 : {
4905 5 : memmove(v_source->data() + nAccLen,
4906 5 : v_source->data() + nSrcOffset, nItemLen);
4907 : }
4908 17 : nAccLen += nItemLen;
4909 17 : ++j;
4910 : }
4911 : }
4912 21 : (*psPrivateData->offsetHolder)[static_cast<size_t>(psChild->length)] =
4913 : nAccLen;
4914 : }
4915 :
4916 72 : SetNullBuffer(psChild, iField, abyValidityFromFilters);
4917 72 : }
4918 :
4919 : /************************************************************************/
4920 : /* FillTimeOrDateArray() */
4921 : /************************************************************************/
4922 :
4923 68 : void OGRTileDBLayer::FillTimeOrDateArray(
4924 : struct ArrowArray *psChild, int iField,
4925 : const std::vector<bool> &abyValidityFromFilters)
4926 : {
4927 : // TileDB uses 64-bit for time[ms], whereas Arrow uses 32-bit
4928 : // Idem for date[day]
4929 : OGRTileDBArrowArrayPrivateData *psPrivateData =
4930 68 : new OGRTileDBArrowArrayPrivateData;
4931 68 : psChild->private_data = psPrivateData;
4932 :
4933 68 : psChild->n_buffers = 2;
4934 68 : psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
4935 :
4936 : const auto &v_source = *(std::get<std::shared_ptr<std::vector<int64_t>>>(
4937 68 : m_aFieldValues[iField]));
4938 68 : const size_t nDstSize = abyValidityFromFilters.empty()
4939 68 : ? v_source.size()
4940 20 : : static_cast<size_t>(psChild->length);
4941 136 : auto newValuesPtr = std::make_shared<std::vector<int32_t>>(nDstSize);
4942 68 : psPrivateData->valueHolder = newValuesPtr;
4943 68 : auto &newValues = *newValuesPtr;
4944 :
4945 68 : if (abyValidityFromFilters.empty())
4946 : {
4947 174 : for (size_t i = 0; i < v_source.size(); ++i)
4948 : {
4949 126 : newValues[i] = static_cast<int32_t>(v_source[i]);
4950 : }
4951 : }
4952 : else
4953 : {
4954 66 : for (size_t i = 0, j = 0; i < v_source.size(); ++i)
4955 : {
4956 46 : if (abyValidityFromFilters[i])
4957 : {
4958 10 : newValues[j] = static_cast<int32_t>(v_source[i]);
4959 10 : ++j;
4960 : }
4961 : }
4962 : }
4963 68 : psChild->buffers[1] = newValuesPtr->data();
4964 :
4965 68 : SetNullBuffer(psChild, iField, abyValidityFromFilters);
4966 68 : }
4967 :
4968 : /************************************************************************/
4969 : /* FillPrimitiveListArray() */
4970 : /************************************************************************/
4971 :
4972 : template <typename T>
4973 136 : void OGRTileDBLayer::FillPrimitiveListArray(
4974 : struct ArrowArray *psChild, int iField,
4975 : const std::vector<bool> &abyValidityFromFilters)
4976 : {
4977 136 : OGRTileDBArrowArrayPrivateData *psPrivateData =
4978 136 : new OGRTileDBArrowArrayPrivateData;
4979 136 : psChild->private_data = psPrivateData;
4980 :
4981 : // We cannot direct use m_aFieldValueOffsets as it uses offsets in
4982 : // bytes whereas Arrow uses offsets in number of elements
4983 136 : psChild->n_buffers = 2;
4984 136 : psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
4985 136 : auto offsetsPtr = std::make_shared<std::vector<uint64_t>>();
4986 136 : const auto &offsetsSrc = *(m_aFieldValueOffsets[iField]);
4987 136 : const size_t nSrcVals = offsetsSrc.size();
4988 136 : if (abyValidityFromFilters.empty())
4989 : {
4990 96 : offsetsPtr->reserve(nSrcVals + 1);
4991 : }
4992 : else
4993 : {
4994 40 : offsetsPtr->reserve(static_cast<size_t>(psChild->length) + 1);
4995 : }
4996 136 : psPrivateData->offsetHolder = offsetsPtr;
4997 136 : auto &offsets = *offsetsPtr;
4998 : auto &v_source =
4999 136 : std::get<std::shared_ptr<std::vector<T>>>(m_aFieldValues[iField]);
5000 :
5001 136 : if (abyValidityFromFilters.empty())
5002 : {
5003 348 : for (size_t i = 0; i < nSrcVals; ++i)
5004 252 : offsets.push_back(offsetsSrc[i] / sizeof(T));
5005 96 : offsets.push_back(v_source->size());
5006 : }
5007 : else
5008 : {
5009 40 : size_t nAccLen = 0;
5010 132 : for (size_t i = 0; i < nSrcVals; ++i)
5011 : {
5012 92 : if (abyValidityFromFilters[i])
5013 : {
5014 20 : const auto nSrcOffset =
5015 20 : static_cast<size_t>(offsetsSrc[i] / sizeof(T));
5016 40 : const auto nNextOffset = i + 1 < nSrcVals
5017 20 : ? offsetsSrc[i + 1] / sizeof(T)
5018 : : v_source->size();
5019 20 : const size_t nItemLen =
5020 : static_cast<size_t>(nNextOffset - nSrcOffset);
5021 20 : offsets.push_back(nAccLen);
5022 20 : if (nItemLen && nAccLen < nSrcOffset)
5023 : {
5024 4 : memmove(v_source->data() + nAccLen,
5025 4 : v_source->data() + nSrcOffset,
5026 : nItemLen * sizeof(T));
5027 : }
5028 20 : nAccLen += nItemLen;
5029 : }
5030 : }
5031 40 : offsets.push_back(nAccLen);
5032 : }
5033 :
5034 136 : psChild->buffers[1] = offsetsPtr->data();
5035 :
5036 136 : SetNullBuffer(psChild, iField, abyValidityFromFilters);
5037 :
5038 136 : psChild->n_children = 1;
5039 136 : psChild->children = static_cast<struct ArrowArray **>(
5040 136 : CPLCalloc(1, sizeof(struct ArrowArray *)));
5041 272 : psChild->children[0] = static_cast<struct ArrowArray *>(
5042 136 : CPLCalloc(1, sizeof(struct ArrowArray)));
5043 136 : auto psValueChild = psChild->children[0];
5044 :
5045 136 : psValueChild->release = psChild->release;
5046 :
5047 136 : psValueChild->n_buffers = 2;
5048 136 : psValueChild->buffers =
5049 136 : static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
5050 136 : psValueChild->length = offsets.back();
5051 :
5052 136 : psPrivateData = new OGRTileDBArrowArrayPrivateData;
5053 136 : psValueChild->private_data = psPrivateData;
5054 136 : psPrivateData->valueHolder = v_source;
5055 136 : psValueChild->buffers[1] = v_source->data();
5056 136 : }
5057 :
5058 : /************************************************************************/
5059 : /* FillBoolListArray() */
5060 : /************************************************************************/
5061 :
5062 34 : void OGRTileDBLayer::FillBoolListArray(
5063 : struct ArrowArray *psChild, int iField,
5064 : const std::vector<bool> &abyValidityFromFilters)
5065 : {
5066 : OGRTileDBArrowArrayPrivateData *psPrivateData =
5067 34 : new OGRTileDBArrowArrayPrivateData;
5068 34 : psChild->private_data = psPrivateData;
5069 :
5070 34 : psChild->n_buffers = 2;
5071 34 : psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
5072 34 : auto &offsetsPtr = m_aFieldValueOffsets[iField];
5073 34 : psPrivateData->offsetHolder = offsetsPtr;
5074 : auto &v_source =
5075 34 : *(std::get<std::shared_ptr<VECTOR_OF_BOOL>>(m_aFieldValues[iField]));
5076 :
5077 34 : psChild->n_children = 1;
5078 34 : psChild->children = static_cast<struct ArrowArray **>(
5079 34 : CPLCalloc(1, sizeof(struct ArrowArray *)));
5080 68 : psChild->children[0] = static_cast<struct ArrowArray *>(
5081 34 : CPLCalloc(1, sizeof(struct ArrowArray)));
5082 34 : auto psValueChild = psChild->children[0];
5083 :
5084 34 : psValueChild->release = psChild->release;
5085 :
5086 34 : psValueChild->n_buffers = 2;
5087 34 : psValueChild->buffers =
5088 34 : static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
5089 :
5090 34 : psPrivateData = new OGRTileDBArrowArrayPrivateData;
5091 34 : psValueChild->private_data = psPrivateData;
5092 :
5093 : // TileDB used a std::vector<uint8_t> with 1 element per byte
5094 : // whereas Arrow uses a ~ std::vector<bool> with 8 elements per byte
5095 : auto arrayValues =
5096 68 : std::make_shared<std::vector<uint8_t>>((v_source.size() + 7) / 8);
5097 34 : psPrivateData->valueHolder = arrayValues;
5098 34 : auto panValues = arrayValues->data();
5099 34 : psValueChild->buffers[1] = panValues;
5100 :
5101 34 : if (abyValidityFromFilters.empty())
5102 : {
5103 24 : offsetsPtr->push_back(v_source.size());
5104 :
5105 116 : for (size_t iFeat = 0; iFeat < v_source.size(); ++iFeat)
5106 : {
5107 92 : if (v_source[iFeat])
5108 46 : panValues[iFeat / 8] |= static_cast<uint8_t>(1 << (iFeat % 8));
5109 : }
5110 :
5111 24 : psValueChild->length = v_source.size();
5112 : }
5113 : else
5114 : {
5115 10 : CPLAssert(offsetsPtr->size() > static_cast<size_t>(psChild->length));
5116 :
5117 10 : auto &offsets = *offsetsPtr;
5118 10 : const size_t nSrcVals = offsets.size();
5119 10 : size_t nAccLen = 0;
5120 33 : for (size_t i = 0, j = 0; i < nSrcVals; ++i)
5121 : {
5122 23 : if (abyValidityFromFilters[i])
5123 : {
5124 5 : const auto nSrcOffset = static_cast<size_t>(offsets[i]);
5125 : const auto nNextOffset =
5126 5 : i + 1 < nSrcVals ? offsets[i + 1] : v_source.size();
5127 5 : const size_t nItemLen =
5128 : static_cast<size_t>(nNextOffset - nSrcOffset);
5129 5 : offsets[j] = nAccLen;
5130 13 : for (size_t k = 0; k < nItemLen; ++k)
5131 : {
5132 8 : if (v_source[nSrcOffset + k])
5133 : {
5134 4 : panValues[(nAccLen + k) / 8] |=
5135 4 : static_cast<uint8_t>(1 << ((nAccLen + k) % 8));
5136 : }
5137 : }
5138 5 : ++j;
5139 5 : nAccLen += nItemLen;
5140 : }
5141 : }
5142 10 : offsets[static_cast<size_t>(psChild->length)] = nAccLen;
5143 :
5144 10 : psValueChild->length = nAccLen;
5145 : }
5146 :
5147 34 : psChild->buffers[1] = offsetsPtr->data();
5148 :
5149 34 : SetNullBuffer(psChild, iField, abyValidityFromFilters);
5150 34 : }
5151 :
5152 : /************************************************************************/
5153 : /* GetNextArrowArray() */
5154 : /************************************************************************/
5155 :
5156 91 : int OGRTileDBLayer::GetNextArrowArray(struct ArrowArrayStream *stream,
5157 : struct ArrowArray *out_array)
5158 : {
5159 91 : memset(out_array, 0, sizeof(*out_array));
5160 :
5161 91 : if (m_eCurrentMode == CurrentMode::WriteInProgress)
5162 : {
5163 0 : ResetReading();
5164 : }
5165 91 : if (!m_array)
5166 0 : return 0;
5167 91 : if (m_bQueryComplete)
5168 42 : return 0;
5169 :
5170 49 : const size_t nBatchSizeBackup = m_nBatchSize;
5171 : const char *pszBatchSize =
5172 49 : m_aosArrowArrayStreamOptions.FetchNameValue("MAX_FEATURES_IN_BATCH");
5173 49 : if (pszBatchSize)
5174 6 : m_nBatchSize = atoi(pszBatchSize);
5175 49 : if (m_nBatchSize > INT_MAX - 1)
5176 0 : m_nBatchSize = INT_MAX - 1;
5177 49 : const bool bSetupOK = SetupQuery(nullptr);
5178 49 : m_nBatchSize = nBatchSizeBackup;
5179 49 : if (!bSetupOK)
5180 0 : return 0;
5181 :
5182 49 : const bool bIncludeFID = CPLTestBool(
5183 : m_aosArrowArrayStreamOptions.FetchNameValueDef("INCLUDE_FID", "YES"));
5184 :
5185 49 : int nChildren = 0;
5186 49 : if (bIncludeFID)
5187 : {
5188 47 : nChildren++;
5189 : }
5190 49 : const int nFieldCount = m_poFeatureDefn->GetFieldCount();
5191 713 : for (int i = 0; i < nFieldCount; i++)
5192 : {
5193 664 : const auto poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
5194 664 : if (!poFieldDefn->IsIgnored())
5195 : {
5196 662 : nChildren++;
5197 : }
5198 : }
5199 98 : for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); i++)
5200 : {
5201 49 : if (!m_poFeatureDefn->GetGeomFieldDefn(i)->IsIgnored())
5202 : {
5203 47 : nChildren++;
5204 : }
5205 : }
5206 49 : out_array->length = m_nRowCountInResultSet;
5207 49 : out_array->n_children = nChildren;
5208 49 : out_array->children =
5209 49 : (struct ArrowArray **)CPLCalloc(sizeof(struct ArrowArray *), nChildren);
5210 :
5211 : // Allocate list of parent buffers: no nulls, null bitmap can be omitted
5212 49 : out_array->n_buffers = 1;
5213 49 : out_array->buffers =
5214 49 : static_cast<const void **>(CPLCalloc(1, sizeof(void *)));
5215 :
5216 : {
5217 : OGRTileDBArrowArrayPrivateData *psPrivateData =
5218 49 : new OGRTileDBArrowArrayPrivateData;
5219 49 : if (m_bArrowBatchReleased)
5220 : {
5221 30 : psPrivateData->m_poLayer = this;
5222 30 : psPrivateData->m_pbLayerStillAlive = m_pbLayerStillAlive;
5223 : }
5224 49 : out_array->private_data = psPrivateData;
5225 : }
5226 49 : out_array->release = OGRTileDBLayer::ReleaseArrowArray;
5227 :
5228 98 : std::vector<bool> abyValidityFromFilters;
5229 49 : size_t nCountIntersecting = 0;
5230 49 : if (!m_anGeometryOffsets->empty())
5231 : {
5232 : // Add back extra offset
5233 45 : m_anGeometryOffsets->push_back(m_abyGeometries->size());
5234 :
5235 : // Given that the TileDB filtering is based only on the center point
5236 : // of geometries, we need to refine it a bit from the actual WKB we get
5237 45 : if (m_poFilterGeom && (m_dfPadX > 0 || m_dfPadY > 0))
5238 : {
5239 26 : const size_t nSrcVals = static_cast<size_t>(m_nRowCountInResultSet);
5240 26 : abyValidityFromFilters.resize(nSrcVals);
5241 26 : OGREnvelope sEnvelope;
5242 26 : size_t nAccLen = 0;
5243 113 : for (size_t i = 0; i < nSrcVals; ++i)
5244 : {
5245 : const auto nSrcOffset =
5246 87 : static_cast<size_t>((*m_anGeometryOffsets)[i]);
5247 : const auto nNextOffset =
5248 87 : static_cast<size_t>((*m_anGeometryOffsets)[i + 1]);
5249 87 : const auto nItemLen = nNextOffset - nSrcOffset;
5250 87 : const GByte *pabyWKB = m_abyGeometries->data() + nSrcOffset;
5251 87 : const size_t nWKBSize = nItemLen;
5252 87 : if (FilterWKBGeometry(pabyWKB, nWKBSize,
5253 : /* bEnvelopeAlreadySet=*/false,
5254 : sEnvelope))
5255 : {
5256 39 : abyValidityFromFilters[i] = true;
5257 39 : (*m_anGeometryOffsets)[nCountIntersecting] = nAccLen;
5258 39 : if (nItemLen && nAccLen < nSrcOffset)
5259 : {
5260 13 : memmove(m_abyGeometries->data() + nAccLen,
5261 13 : m_abyGeometries->data() + nSrcOffset, nItemLen);
5262 : }
5263 39 : nAccLen += nItemLen;
5264 39 : nCountIntersecting++;
5265 : }
5266 : }
5267 26 : (*m_anGeometryOffsets)[nCountIntersecting] = nAccLen;
5268 :
5269 26 : if (nCountIntersecting == m_nRowCountInResultSet)
5270 : {
5271 8 : abyValidityFromFilters.clear();
5272 : }
5273 : else
5274 : {
5275 18 : out_array->length = nCountIntersecting;
5276 : }
5277 : }
5278 : }
5279 :
5280 49 : int iSchemaChild = 0;
5281 49 : if (bIncludeFID)
5282 : {
5283 94 : out_array->children[iSchemaChild] = static_cast<struct ArrowArray *>(
5284 47 : CPLCalloc(1, sizeof(struct ArrowArray)));
5285 47 : auto psChild = out_array->children[iSchemaChild];
5286 47 : ++iSchemaChild;
5287 : OGRTileDBArrowArrayPrivateData *psPrivateData =
5288 47 : new OGRTileDBArrowArrayPrivateData;
5289 47 : psPrivateData->valueHolder = m_anFIDs;
5290 47 : psChild->private_data = psPrivateData;
5291 47 : psChild->release = OGRTileDBLayer::ReleaseArrowArray;
5292 47 : psChild->length = out_array->length;
5293 47 : psChild->n_buffers = 2;
5294 47 : psChild->buffers =
5295 47 : static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
5296 47 : if (!abyValidityFromFilters.empty())
5297 : {
5298 88 : for (size_t i = 0, j = 0; i < m_nRowCountInResultSet; ++i)
5299 : {
5300 70 : if (abyValidityFromFilters[i])
5301 : {
5302 22 : (*m_anFIDs)[j] = (*m_anFIDs)[i];
5303 22 : ++j;
5304 : }
5305 : }
5306 : }
5307 47 : psChild->buffers[1] = m_anFIDs->data();
5308 : }
5309 :
5310 : try
5311 : {
5312 713 : for (int i = 0; i < nFieldCount; ++i)
5313 : {
5314 664 : const auto poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
5315 664 : if (poFieldDefn->IsIgnored())
5316 : {
5317 2 : continue;
5318 : }
5319 :
5320 1324 : out_array->children[iSchemaChild] =
5321 : static_cast<struct ArrowArray *>(
5322 662 : CPLCalloc(1, sizeof(struct ArrowArray)));
5323 662 : auto psChild = out_array->children[iSchemaChild];
5324 662 : ++iSchemaChild;
5325 662 : psChild->release = OGRTileDBLayer::ReleaseArrowArray;
5326 662 : psChild->length = out_array->length;
5327 662 : const auto eSubType = poFieldDefn->GetSubType();
5328 662 : switch (poFieldDefn->GetType())
5329 : {
5330 204 : case OFTInteger:
5331 : {
5332 204 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
5333 : {
5334 34 : FillBoolArray(psChild, i, abyValidityFromFilters);
5335 : }
5336 170 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
5337 : {
5338 34 : FillPrimitiveArray<int16_t>(psChild, i,
5339 : abyValidityFromFilters);
5340 : }
5341 136 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
5342 : {
5343 68 : FillPrimitiveArray<int32_t>(psChild, i,
5344 : abyValidityFromFilters);
5345 : }
5346 68 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
5347 : {
5348 34 : FillPrimitiveArray<uint8_t>(psChild, i,
5349 : abyValidityFromFilters);
5350 : }
5351 34 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
5352 : {
5353 34 : FillPrimitiveArray<uint16_t>(psChild, i,
5354 : abyValidityFromFilters);
5355 : }
5356 : else
5357 : {
5358 0 : CPLAssert(false);
5359 : }
5360 204 : break;
5361 : }
5362 :
5363 102 : case OFTIntegerList:
5364 : {
5365 102 : if (m_aeFieldTypes[i] == TILEDB_BOOL)
5366 : {
5367 34 : FillBoolListArray(psChild, i, abyValidityFromFilters);
5368 : }
5369 68 : else if (m_aeFieldTypes[i] == TILEDB_INT16)
5370 : {
5371 34 : FillPrimitiveListArray<int16_t>(psChild, i,
5372 : abyValidityFromFilters);
5373 : }
5374 34 : else if (m_aeFieldTypes[i] == TILEDB_INT32)
5375 : {
5376 34 : FillPrimitiveListArray<int32_t>(psChild, i,
5377 : abyValidityFromFilters);
5378 : }
5379 0 : else if (m_aeFieldTypes[i] == TILEDB_UINT8)
5380 : {
5381 0 : FillPrimitiveListArray<uint8_t>(psChild, i,
5382 : abyValidityFromFilters);
5383 : }
5384 0 : else if (m_aeFieldTypes[i] == TILEDB_UINT16)
5385 : {
5386 0 : FillPrimitiveListArray<uint16_t>(
5387 : psChild, i, abyValidityFromFilters);
5388 : }
5389 : else
5390 : {
5391 0 : CPLAssert(false);
5392 : }
5393 102 : break;
5394 : }
5395 :
5396 74 : case OFTInteger64:
5397 : case OFTDateTime:
5398 : {
5399 74 : FillPrimitiveArray<int64_t>(psChild, i,
5400 : abyValidityFromFilters);
5401 74 : break;
5402 : }
5403 :
5404 0 : case OFTInteger64List:
5405 : {
5406 0 : FillPrimitiveListArray<int64_t>(psChild, i,
5407 : abyValidityFromFilters);
5408 0 : break;
5409 : }
5410 :
5411 74 : case OFTReal:
5412 : {
5413 74 : if (eSubType == OFSTFloat32)
5414 : {
5415 34 : FillPrimitiveArray<float>(psChild, i,
5416 : abyValidityFromFilters);
5417 : }
5418 : else
5419 : {
5420 40 : FillPrimitiveArray<double>(psChild, i,
5421 : abyValidityFromFilters);
5422 : }
5423 74 : break;
5424 : }
5425 :
5426 68 : case OFTRealList:
5427 : {
5428 68 : if (eSubType == OFSTFloat32)
5429 : {
5430 34 : FillPrimitiveListArray<float>(psChild, i,
5431 : abyValidityFromFilters);
5432 : }
5433 : else
5434 : {
5435 34 : FillPrimitiveListArray<double>(psChild, i,
5436 : abyValidityFromFilters);
5437 : }
5438 68 : break;
5439 : }
5440 :
5441 38 : case OFTString:
5442 : {
5443 38 : FillStringOrBinaryArray<std::string>(
5444 : psChild, i, abyValidityFromFilters);
5445 38 : break;
5446 : }
5447 :
5448 34 : case OFTBinary:
5449 : {
5450 34 : FillStringOrBinaryArray<std::vector<uint8_t>>(
5451 : psChild, i, abyValidityFromFilters);
5452 34 : break;
5453 : }
5454 :
5455 68 : case OFTTime:
5456 : case OFTDate:
5457 : {
5458 68 : FillTimeOrDateArray(psChild, i, abyValidityFromFilters);
5459 68 : break;
5460 : }
5461 :
5462 0 : case OFTStringList:
5463 : case OFTWideString:
5464 : case OFTWideStringList:
5465 0 : break;
5466 : }
5467 : }
5468 :
5469 49 : if (!m_poFeatureDefn->GetGeomFieldDefn(0)->IsIgnored())
5470 : {
5471 94 : out_array->children[iSchemaChild] =
5472 : static_cast<struct ArrowArray *>(
5473 47 : CPLCalloc(1, sizeof(struct ArrowArray)));
5474 47 : auto psChild = out_array->children[iSchemaChild];
5475 47 : ++iSchemaChild;
5476 47 : psChild->release = OGRTileDBLayer::ReleaseArrowArray;
5477 47 : psChild->length = out_array->length;
5478 :
5479 : OGRTileDBArrowArrayPrivateData *psPrivateData =
5480 47 : new OGRTileDBArrowArrayPrivateData;
5481 47 : psChild->private_data = psPrivateData;
5482 :
5483 47 : psChild->n_buffers = 3;
5484 47 : psChild->buffers =
5485 47 : static_cast<const void **>(CPLCalloc(3, sizeof(void *)));
5486 :
5487 47 : if (!m_anGeometryOffsets->empty() || m_adfXs->empty())
5488 : {
5489 45 : psPrivateData->offsetHolder = m_anGeometryOffsets;
5490 45 : psChild->buffers[1] = m_anGeometryOffsets->data();
5491 :
5492 45 : psPrivateData->valueHolder = m_abyGeometries;
5493 45 : psChild->buffers[2] = m_abyGeometries->data();
5494 : }
5495 : else
5496 : {
5497 : // Build Point WKB from X/Y/Z arrays
5498 :
5499 2 : const int nDims = m_osZDim.empty() ? 2 : 3;
5500 2 : const size_t nPointWKBSize = 5 + nDims * sizeof(double);
5501 :
5502 4 : auto offsets = std::make_shared<std::vector<uint64_t>>();
5503 2 : psPrivateData->offsetHolder = offsets;
5504 2 : offsets->reserve(m_adfXs->size());
5505 :
5506 2 : auto pabyWKB = std::make_shared<std::vector<unsigned char>>();
5507 2 : pabyWKB->reserve(nPointWKBSize * m_adfXs->size());
5508 2 : psPrivateData->valueHolder = pabyWKB;
5509 :
5510 : unsigned char wkbHeader[5];
5511 2 : wkbHeader[0] = static_cast<unsigned char>(wkbNDR);
5512 2 : uint32_t wkbType = wkbPoint + ((nDims == 3) ? 1000 : 0);
5513 2 : CPL_LSBPTR32(&wkbType);
5514 2 : memcpy(wkbHeader + 1, &wkbType, sizeof(uint32_t));
5515 2 : double *padfX = m_adfXs->data();
5516 2 : double *padfY = m_adfYs->data();
5517 2 : double *padfZ = m_adfZs->data();
5518 2 : uint64_t nOffset = 0;
5519 6 : for (size_t i = 0; i < m_adfXs->size(); ++i)
5520 : {
5521 4 : pabyWKB->insert(pabyWKB->end(), wkbHeader,
5522 8 : wkbHeader + sizeof(wkbHeader));
5523 4 : unsigned char *x =
5524 4 : reinterpret_cast<unsigned char *>(&padfX[i]);
5525 4 : CPL_LSBPTR64(x);
5526 4 : pabyWKB->insert(pabyWKB->end(), x, x + sizeof(double));
5527 4 : CPL_LSBPTR64(x);
5528 4 : unsigned char *y =
5529 4 : reinterpret_cast<unsigned char *>(&padfY[i]);
5530 4 : CPL_LSBPTR64(y);
5531 4 : pabyWKB->insert(pabyWKB->end(), y, y + sizeof(double));
5532 4 : CPL_LSBPTR64(y);
5533 4 : if (nDims == 3)
5534 : {
5535 2 : unsigned char *z =
5536 2 : reinterpret_cast<unsigned char *>(&padfZ[i]);
5537 2 : CPL_LSBPTR64(z);
5538 2 : pabyWKB->insert(pabyWKB->end(), z, z + sizeof(double));
5539 2 : CPL_LSBPTR64(z);
5540 : }
5541 4 : offsets->push_back(nOffset);
5542 4 : nOffset += nPointWKBSize;
5543 : }
5544 2 : offsets->push_back(nOffset);
5545 :
5546 2 : psChild->buffers[1] = offsets->data();
5547 2 : psChild->buffers[2] = pabyWKB->data();
5548 : }
5549 : }
5550 49 : CPL_IGNORE_RET_VAL(iSchemaChild);
5551 :
5552 53 : if (m_poAttrQuery &&
5553 4 : (!m_poQueryCondition || m_bAttributeFilterPartiallyTranslated))
5554 : {
5555 : struct ArrowSchema schema;
5556 2 : stream->get_schema(stream, &schema);
5557 2 : CPLAssert(schema.release != nullptr);
5558 2 : CPLAssert(schema.n_children == out_array->n_children);
5559 : // Spatial filter already evaluated
5560 2 : auto poFilterGeomBackup = m_poFilterGeom;
5561 2 : m_poFilterGeom = nullptr;
5562 2 : if (CanPostFilterArrowArray(&schema))
5563 2 : PostFilterArrowArray(&schema, out_array, nullptr);
5564 2 : schema.release(&schema);
5565 2 : m_poFilterGeom = poFilterGeomBackup;
5566 : }
5567 : }
5568 0 : catch (const std::exception &e)
5569 : {
5570 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
5571 0 : out_array->release(out_array);
5572 0 : memset(out_array, 0, sizeof(*out_array));
5573 0 : return ENOMEM;
5574 : }
5575 :
5576 49 : m_bArrowBatchReleased = false;
5577 :
5578 49 : return 0;
5579 : }
|