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