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