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