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