Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: Arrow Database Connectivity driver
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
9 : * Copyright (c) 2024, Dewey Dunnington <dewey@voltrondata.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "ogr_adbc.h"
15 : #include "ogradbcdrivercore.h"
16 : #include "memdataset.h"
17 : #include "ogr_p.h"
18 : #include "cpl_error.h"
19 : #include "cpl_json.h"
20 : #include "gdal_adbc.h"
21 :
22 : #if defined(OGR_ADBC_HAS_DRIVER_MANAGER)
23 : #include <arrow-adbc/adbc_driver_manager.h>
24 : #endif
25 :
26 : #define OGR_ADBC_VERSION ADBC_VERSION_1_1_0
27 : static_assert(sizeof(AdbcDriver) == ADBC_DRIVER_1_1_0_SIZE);
28 :
29 : namespace
30 : {
31 :
32 0 : AdbcStatusCode OGRADBCLoadDriver(const char *driver_name,
33 : const char *entrypoint, void *driver,
34 : struct AdbcError *error)
35 : {
36 : GDALAdbcLoadDriverFunc load_driver_override =
37 0 : GDALGetAdbcLoadDriverOverride();
38 0 : if (load_driver_override)
39 : {
40 0 : return load_driver_override(driver_name, entrypoint, OGR_ADBC_VERSION,
41 0 : driver, error);
42 : }
43 : else
44 : {
45 : #if defined(OGR_ADBC_HAS_DRIVER_MANAGER)
46 : return AdbcLoadDriver(driver_name, entrypoint, OGR_ADBC_VERSION, driver,
47 : error);
48 : #else
49 0 : return ADBC_STATUS_NOT_IMPLEMENTED;
50 : #endif
51 : }
52 : }
53 :
54 : } // namespace
55 :
56 : // Helper to wrap driver callbacks
57 : #define ADBC_CALL(func, ...) m_driver.func(__VA_ARGS__)
58 :
59 : /************************************************************************/
60 : /* ~OGRADBCDataset() */
61 : /************************************************************************/
62 :
63 0 : OGRADBCDataset::~OGRADBCDataset()
64 : {
65 : // Layers must be closed before the connection
66 0 : m_apoLayers.clear();
67 0 : OGRADBCError error;
68 0 : if (m_connection)
69 0 : ADBC_CALL(ConnectionRelease, m_connection.get(), error);
70 0 : error.clear();
71 0 : if (m_driver.release)
72 : {
73 0 : ADBC_CALL(DatabaseRelease, &m_database, error);
74 0 : m_driver.release(&m_driver, error);
75 : }
76 0 : }
77 :
78 : /************************************************************************/
79 : /* CreateLayer() */
80 : /************************************************************************/
81 :
82 : std::unique_ptr<OGRADBCLayer>
83 0 : OGRADBCDataset::CreateLayer(const char *pszStatement, const char *pszLayerName,
84 : bool bInternalUse)
85 : {
86 :
87 0 : OGRADBCError error;
88 :
89 0 : CPLString osStatement(pszStatement);
90 0 : if (!m_osParquetFilename.empty())
91 : {
92 0 : const char *pszSrcLayerName = m_apoLayers.size() == 1
93 0 : ? m_apoLayers[0]->GetDescription()
94 0 : : pszLayerName;
95 : // Substitute the OGR layer name with the DuckDB expected filename,
96 : // single-quoted
97 : const std::string osFrom =
98 0 : std::string(" FROM ").append(pszSrcLayerName);
99 0 : const auto nPos = osStatement.ifind(osFrom);
100 0 : if (nPos != std::string::npos)
101 : {
102 : osStatement =
103 0 : osStatement.substr(0, nPos)
104 0 : .append(" FROM '")
105 0 : .append(OGRDuplicateCharacter(m_osParquetFilename, '\''))
106 0 : .append("'")
107 0 : .append(osStatement.substr(nPos + osFrom.size()));
108 : }
109 : else
110 : {
111 : const std::string osFrom2 =
112 0 : std::string(" FROM \"")
113 0 : .append(OGRDuplicateCharacter(pszSrcLayerName, '"'))
114 0 : .append("\"");
115 0 : const auto nPos2 = osStatement.ifind(osFrom2);
116 0 : if (nPos2 != std::string::npos)
117 : {
118 : osStatement =
119 0 : osStatement.substr(0, nPos2)
120 0 : .append(" FROM '")
121 : .append(
122 0 : OGRDuplicateCharacter(m_osParquetFilename, '\''))
123 0 : .append("'")
124 0 : .append(osStatement.substr(nPos2 + osFrom2.size()));
125 : }
126 : }
127 : }
128 :
129 0 : auto statement = std::make_unique<AdbcStatement>();
130 0 : if (ADBC_CALL(StatementNew, m_connection.get(), statement.get(), error) !=
131 : ADBC_STATUS_OK)
132 : {
133 0 : CPLError(CE_Failure, CPLE_AppDefined, "AdbcStatementNew() failed: %s",
134 : error.message());
135 0 : return nullptr;
136 : }
137 :
138 0 : if (ADBC_CALL(StatementSetSqlQuery, statement.get(), osStatement.c_str(),
139 0 : error) != ADBC_STATUS_OK)
140 : {
141 0 : CPLError(CE_Failure, CPLE_AppDefined,
142 : "AdbcStatementSetSqlQuery() failed: %s", error.message());
143 0 : error.clear();
144 0 : ADBC_CALL(StatementRelease, statement.get(), error);
145 0 : return nullptr;
146 : }
147 :
148 0 : auto stream = std::make_unique<OGRArrowArrayStream>();
149 0 : int64_t rows_affected = -1;
150 0 : if (ADBC_CALL(StatementExecuteQuery, statement.get(), stream->get(),
151 0 : &rows_affected, error) != ADBC_STATUS_OK)
152 : {
153 0 : CPLError(CE_Failure, CPLE_AppDefined,
154 : "AdbcStatementExecuteQuery() failed: %s", error.message());
155 0 : error.clear();
156 0 : ADBC_CALL(StatementRelease, statement.get(), error);
157 0 : return nullptr;
158 : }
159 :
160 0 : ArrowSchema schema = {};
161 0 : if (stream->get_schema(&schema) != 0)
162 : {
163 0 : CPLError(CE_Failure, CPLE_AppDefined, "get_schema() failed");
164 0 : ADBC_CALL(StatementRelease, statement.get(), error);
165 0 : return nullptr;
166 : }
167 :
168 : return std::make_unique<OGRADBCLayer>(
169 0 : this, pszLayerName, osStatement.c_str(), std::move(statement),
170 0 : std::move(stream), &schema, bInternalUse);
171 : }
172 :
173 : /************************************************************************/
174 : /* ExecuteSQL() */
175 : /************************************************************************/
176 :
177 0 : OGRLayer *OGRADBCDataset::ExecuteSQL(const char *pszStatement,
178 : OGRGeometry *poSpatialFilter,
179 : const char *pszDialect)
180 : {
181 0 : if (pszDialect && pszDialect[0] != 0 && !EQUAL(pszDialect, "NATIVE"))
182 : {
183 0 : return GDALDataset::ExecuteSQL(pszStatement, poSpatialFilter,
184 0 : pszDialect);
185 : }
186 :
187 0 : auto poLayer = CreateLayer(pszStatement, "RESULTSET", false);
188 0 : if (poLayer && poSpatialFilter)
189 : {
190 0 : if (poLayer->GetGeomType() == wkbNone)
191 0 : return nullptr;
192 0 : poLayer->SetSpatialFilter(poSpatialFilter);
193 : }
194 0 : return poLayer.release();
195 : }
196 :
197 : /************************************************************************/
198 : /* IsParquetExtension() */
199 : /************************************************************************/
200 :
201 0 : static bool IsParquetExtension(const char *pszStr)
202 : {
203 0 : const std::string osExt = CPLGetExtensionSafe(pszStr);
204 0 : return EQUAL(osExt.c_str(), "parquet") || EQUAL(osExt.c_str(), "parq");
205 : }
206 :
207 : /************************************************************************/
208 : /* Open() */
209 : /************************************************************************/
210 :
211 0 : bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo)
212 : {
213 0 : OGRADBCError error;
214 :
215 0 : const char *pszFilename = poOpenInfo->pszFilename;
216 0 : std::unique_ptr<GDALOpenInfo> poTmpOpenInfo;
217 0 : if (STARTS_WITH(pszFilename, "ADBC:"))
218 : {
219 0 : pszFilename += strlen("ADBC:");
220 : poTmpOpenInfo =
221 0 : std::make_unique<GDALOpenInfo>(pszFilename, GA_ReadOnly);
222 0 : poTmpOpenInfo->papszOpenOptions = poOpenInfo->papszOpenOptions;
223 0 : poOpenInfo = poTmpOpenInfo.get();
224 : }
225 : const char *pszADBCDriverName =
226 0 : CSLFetchNameValue(poOpenInfo->papszOpenOptions, "ADBC_DRIVER");
227 0 : m_bIsDuckDBDataset = OGRADBCDriverIsDuckDB(poOpenInfo);
228 : const bool bIsSQLite3 =
229 0 : (pszADBCDriverName && EQUAL(pszADBCDriverName, "adbc_driver_sqlite")) ||
230 0 : OGRADBCDriverIsSQLite3(poOpenInfo);
231 : bool bIsParquet =
232 0 : OGRADBCDriverIsParquet(poOpenInfo) || IsParquetExtension(pszFilename);
233 0 : const char *pszSQL = CSLFetchNameValue(poOpenInfo->papszOpenOptions, "SQL");
234 0 : if (!bIsParquet && pszSQL)
235 : {
236 0 : CPLString osSQL(pszSQL);
237 0 : auto iPos = osSQL.find("FROM '");
238 0 : if (iPos != std::string::npos)
239 : {
240 0 : iPos += strlen("FROM '");
241 0 : const auto iPos2 = osSQL.find("'", iPos);
242 0 : if (iPos2 != std::string::npos)
243 : {
244 0 : std::string osFilename = osSQL.substr(iPos, iPos2 - iPos);
245 0 : if (IsParquetExtension(osFilename.c_str()))
246 : {
247 0 : m_osParquetFilename = std::move(osFilename);
248 0 : bIsParquet = true;
249 : }
250 : }
251 : }
252 : }
253 0 : const bool bIsPostgreSQL = STARTS_WITH(pszFilename, "postgresql://");
254 :
255 0 : if (!pszADBCDriverName)
256 : {
257 0 : if (m_bIsDuckDBDataset || bIsParquet)
258 : {
259 0 : pszADBCDriverName =
260 : #ifdef _WIN32
261 : "duckdb.dll"
262 : #elif defined(__MACH__) && defined(__APPLE__)
263 : "libduckdb.dylib"
264 : #else
265 : "libduckdb.so"
266 : #endif
267 : ;
268 : }
269 0 : else if (bIsPostgreSQL)
270 0 : pszADBCDriverName = "adbc_driver_postgresql";
271 0 : else if (bIsSQLite3)
272 : {
273 0 : pszADBCDriverName = "adbc_driver_sqlite";
274 : }
275 : else
276 : {
277 0 : CPLError(CE_Failure, CPLE_AppDefined,
278 : "Open option ADBC_DRIVER must be specified");
279 0 : return false;
280 : }
281 : }
282 :
283 0 : m_bIsDuckDBDriver =
284 0 : m_bIsDuckDBDataset || bIsParquet ||
285 0 : (pszADBCDriverName && strstr(pszADBCDriverName, "duckdb"));
286 :
287 : // Load the driver
288 0 : if (m_bIsDuckDBDriver)
289 : {
290 0 : if (OGRADBCLoadDriver(pszADBCDriverName, "duckdb_adbc_init", &m_driver,
291 0 : error) != ADBC_STATUS_OK)
292 : {
293 0 : CPLError(CE_Failure, CPLE_AppDefined, "AdbcLoadDriver() failed: %s",
294 : error.message());
295 0 : return false;
296 : }
297 : }
298 : else
299 : {
300 0 : if (OGRADBCLoadDriver(pszADBCDriverName, nullptr, &m_driver, error) !=
301 : ADBC_STATUS_OK)
302 : {
303 0 : CPLError(CE_Failure, CPLE_AppDefined, "AdbcLoadDriver() failed: %s",
304 : error.message());
305 0 : return false;
306 : }
307 : }
308 :
309 : // Allocate the database
310 0 : if (ADBC_CALL(DatabaseNew, &m_database, error) != ADBC_STATUS_OK)
311 : {
312 0 : CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseNew() failed: %s",
313 : error.message());
314 0 : return false;
315 : }
316 :
317 : // Set options
318 0 : if (m_bIsDuckDBDriver)
319 : {
320 0 : if (ADBC_CALL(DatabaseSetOption, &m_database, "path",
321 : bIsParquet ? ":memory:" : pszFilename,
322 0 : error) != ADBC_STATUS_OK)
323 : {
324 0 : CPLError(CE_Failure, CPLE_AppDefined,
325 : "AdbcDatabaseSetOption() failed: %s", error.message());
326 0 : return false;
327 : }
328 : }
329 0 : else if (pszFilename[0])
330 : {
331 0 : if (ADBC_CALL(DatabaseSetOption, &m_database, "uri", pszFilename,
332 0 : error) != ADBC_STATUS_OK)
333 : {
334 0 : CPLError(CE_Failure, CPLE_AppDefined,
335 : "AdbcDatabaseSetOption() failed: %s", error.message());
336 0 : return false;
337 : }
338 : }
339 :
340 0 : for (const auto &[pszKey, pszValue] : cpl::IterateNameValue(
341 0 : static_cast<CSLConstList>(poOpenInfo->papszOpenOptions)))
342 : {
343 0 : if (STARTS_WITH_CI(pszKey, "ADBC_OPTION_"))
344 : {
345 0 : if (ADBC_CALL(DatabaseSetOption, &m_database,
346 : pszKey + strlen("ADBC_OPTION_"), pszValue,
347 0 : error) != ADBC_STATUS_OK)
348 : {
349 0 : CPLError(CE_Failure, CPLE_AppDefined,
350 : "AdbcDatabaseSetOption() failed: %s", error.message());
351 0 : return false;
352 : }
353 : }
354 : }
355 :
356 0 : if (ADBC_CALL(DatabaseInit, &m_database, error) != ADBC_STATUS_OK)
357 : {
358 0 : CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseInit() failed: %s",
359 : error.message());
360 0 : return false;
361 : }
362 :
363 0 : m_connection = std::make_unique<AdbcConnection>();
364 0 : if (ADBC_CALL(ConnectionNew, m_connection.get(), error) != ADBC_STATUS_OK)
365 : {
366 0 : CPLError(CE_Failure, CPLE_AppDefined, "AdbcConnectionNew() failed: %s",
367 : error.message());
368 0 : return false;
369 : }
370 :
371 0 : if (ADBC_CALL(ConnectionInit, m_connection.get(), &m_database, error) !=
372 : ADBC_STATUS_OK)
373 : {
374 0 : CPLError(CE_Failure, CPLE_AppDefined, "AdbcConnectionInit() failed: %s",
375 : error.message());
376 0 : return false;
377 : }
378 :
379 0 : char **papszPreludeStatements = CSLFetchNameValueMultiple(
380 0 : poOpenInfo->papszOpenOptions, "PRELUDE_STATEMENTS");
381 0 : for (const char *pszStatement :
382 0 : cpl::Iterate(CSLConstList(papszPreludeStatements)))
383 : {
384 0 : CreateInternalLayer(pszStatement);
385 : }
386 0 : CSLDestroy(papszPreludeStatements);
387 0 : if (m_bIsDuckDBDriver && CPLTestBool(CPLGetConfigOption(
388 : "OGR_ADBC_AUTO_LOAD_DUCKDB_SPATIAL", "ON")))
389 : {
390 : auto poTmpLayer =
391 : CreateInternalLayer("SELECT 1 FROM duckdb_extensions() WHERE "
392 0 : "extension_name='spatial' AND loaded = false");
393 0 : if (poTmpLayer && std::unique_ptr<OGRFeature>(
394 0 : poTmpLayer->GetNextFeature()) != nullptr)
395 : {
396 0 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
397 0 : CreateInternalLayer("LOAD spatial");
398 : }
399 :
400 : poTmpLayer =
401 0 : CreateInternalLayer("SELECT 1 FROM duckdb_extensions() WHERE "
402 0 : "extension_name='spatial' AND loaded = true");
403 0 : m_bSpatialLoaded =
404 0 : poTmpLayer && std::unique_ptr<OGRFeature>(
405 0 : poTmpLayer->GetNextFeature()) != nullptr;
406 : }
407 :
408 0 : std::string osLayerName = "RESULTSET";
409 0 : std::string osSQL;
410 0 : bool bIsParquetLayer = false;
411 0 : if (bIsParquet)
412 : {
413 0 : if (m_osParquetFilename.empty())
414 0 : m_osParquetFilename = pszFilename;
415 0 : osLayerName = CPLGetBasenameSafe(m_osParquetFilename.c_str());
416 0 : if (osLayerName == "*")
417 0 : osLayerName = CPLGetBasenameSafe(
418 0 : CPLGetDirnameSafe(m_osParquetFilename.c_str()).c_str());
419 0 : if (!pszSQL)
420 : {
421 : osSQL =
422 : CPLSPrintf("SELECT * FROM read_parquet('%s')",
423 0 : OGRDuplicateCharacter(pszFilename, '\'').c_str());
424 0 : pszSQL = osSQL.c_str();
425 0 : bIsParquetLayer = true;
426 : }
427 : }
428 :
429 0 : if (pszSQL)
430 : {
431 0 : if (pszSQL[0])
432 : {
433 0 : std::unique_ptr<OGRADBCLayer> poLayer;
434 0 : if ((bIsParquet || m_bIsDuckDBDataset) && m_bSpatialLoaded)
435 : {
436 0 : std::string osErrorMsg;
437 : {
438 0 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
439 0 : poLayer = CreateLayer(pszSQL, osLayerName.c_str(), false);
440 0 : if (!poLayer)
441 0 : osErrorMsg = CPLGetLastErrorMsg();
442 : }
443 0 : if (!poLayer)
444 : {
445 0 : CPLDebug("ADBC",
446 : "Connecting with 'LOAD spatial' did not work "
447 : "(%s). Retrying without it",
448 : osErrorMsg.c_str());
449 0 : ADBC_CALL(ConnectionRelease, m_connection.get(), error);
450 0 : m_connection.reset();
451 :
452 0 : ADBC_CALL(DatabaseRelease, &m_database, error);
453 0 : memset(&m_database, 0, sizeof(m_database));
454 :
455 0 : if (ADBC_CALL(DatabaseNew, &m_database, error) !=
456 : ADBC_STATUS_OK)
457 : {
458 0 : CPLError(CE_Failure, CPLE_AppDefined,
459 : "AdbcDatabaseNew() failed: %s",
460 : error.message());
461 0 : return false;
462 : }
463 0 : if (ADBC_CALL(DatabaseSetOption, &m_database, "path",
464 0 : ":memory:", error) != ADBC_STATUS_OK)
465 : {
466 0 : CPLError(CE_Failure, CPLE_AppDefined,
467 : "AdbcDatabaseSetOption() failed: %s",
468 : error.message());
469 0 : return false;
470 : }
471 :
472 0 : if (ADBC_CALL(DatabaseInit, &m_database, error) !=
473 : ADBC_STATUS_OK)
474 : {
475 0 : CPLError(CE_Failure, CPLE_AppDefined,
476 : "AdbcDatabaseInit() failed: %s",
477 : error.message());
478 0 : return false;
479 : }
480 :
481 0 : m_connection = std::make_unique<AdbcConnection>();
482 0 : if (ADBC_CALL(ConnectionNew, m_connection.get(), error) !=
483 : ADBC_STATUS_OK)
484 : {
485 0 : CPLError(CE_Failure, CPLE_AppDefined,
486 : "AdbcConnectionNew() failed: %s",
487 : error.message());
488 0 : return false;
489 : }
490 :
491 0 : if (ADBC_CALL(ConnectionInit, m_connection.get(),
492 0 : &m_database, error) != ADBC_STATUS_OK)
493 : {
494 0 : CPLError(CE_Failure, CPLE_AppDefined,
495 : "AdbcConnectionInit() failed: %s",
496 : error.message());
497 0 : return false;
498 : }
499 : }
500 : }
501 0 : if (!poLayer)
502 : {
503 0 : poLayer = CreateLayer(pszSQL, osLayerName.c_str(), false);
504 0 : if (!poLayer)
505 0 : return false;
506 : }
507 :
508 0 : poLayer->m_bIsParquetLayer = bIsParquetLayer;
509 0 : m_apoLayers.emplace_back(std::move(poLayer));
510 : }
511 : }
512 0 : else if (m_bIsDuckDBDataset || bIsSQLite3)
513 : {
514 : auto poLayerList = CreateInternalLayer(
515 0 : "SELECT name FROM sqlite_master WHERE type IN ('table', 'view')");
516 0 : if (!poLayerList || poLayerList->GetLayerDefn()->GetFieldCount() != 1)
517 : {
518 0 : return false;
519 : }
520 :
521 0 : for (const auto &poFeature : poLayerList.get())
522 : {
523 0 : const char *pszLayerName = poFeature->GetFieldAsString(0);
524 0 : if (bIsSQLite3 && EQUAL(pszLayerName, "SpatialIndex"))
525 0 : continue;
526 : const std::string osStatement =
527 : CPLSPrintf("SELECT * FROM \"%s\"",
528 0 : OGRDuplicateCharacter(pszLayerName, '"').c_str());
529 0 : CPLTurnFailureIntoWarningBackuper oErrorsToWarnings{};
530 : auto poLayer =
531 0 : CreateLayer(osStatement.c_str(), pszLayerName, false);
532 0 : if (poLayer)
533 : {
534 0 : m_apoLayers.emplace_back(std::move(poLayer));
535 : }
536 0 : }
537 : }
538 0 : else if (bIsPostgreSQL)
539 : {
540 : auto poLayerList = CreateInternalLayer(
541 : "SELECT n.nspname, c.relname FROM pg_class c "
542 : "JOIN pg_namespace n ON c.relnamespace = n.oid "
543 : "AND c.relkind in ('r','v','m','f') "
544 : "AND n.nspname NOT IN ('pg_catalog', 'information_schema') "
545 0 : "ORDER BY c.oid");
546 0 : if (!poLayerList || poLayerList->GetLayerDefn()->GetFieldCount() != 2)
547 : {
548 0 : return false;
549 : }
550 :
551 0 : for (const auto &poFeature : poLayerList.get())
552 : {
553 0 : const char *pszNamespace = poFeature->GetFieldAsString(0);
554 0 : const char *pszTableName = poFeature->GetFieldAsString(1);
555 : const std::string osStatement =
556 : CPLSPrintf("SELECT * FROM \"%s\".\"%s\"",
557 0 : OGRDuplicateCharacter(pszNamespace, '"').c_str(),
558 0 : OGRDuplicateCharacter(pszTableName, '"').c_str());
559 :
560 0 : CPLTurnFailureIntoWarningBackuper oErrorsToWarnings{};
561 : auto poLayer = CreateLayer(
562 : osStatement.c_str(),
563 0 : CPLSPrintf("%s.%s", pszNamespace, pszTableName), false);
564 0 : if (poLayer)
565 : {
566 0 : m_apoLayers.emplace_back(std::move(poLayer));
567 : }
568 : }
569 : }
570 :
571 0 : return true;
572 : }
573 :
574 : /************************************************************************/
575 : /* GetLayerByName() */
576 : /************************************************************************/
577 :
578 0 : OGRLayer *OGRADBCDataset::GetLayerByName(const char *pszName)
579 : {
580 0 : OGRLayer *poLayer = GDALDataset::GetLayerByName(pszName);
581 0 : if (poLayer || !EQUAL(pszName, "table_list"))
582 0 : return poLayer;
583 :
584 0 : OGRADBCError error;
585 0 : auto objectsStream = std::make_unique<OGRArrowArrayStream>();
586 0 : ADBC_CALL(ConnectionGetObjects, m_connection.get(),
587 : ADBC_OBJECT_DEPTH_TABLES,
588 : /* catalog = */ nullptr,
589 : /* db_schema = */ nullptr,
590 : /* table_name = */ nullptr,
591 : /* table_type = */ nullptr,
592 : /* column_name = */ nullptr, objectsStream->get(), error);
593 :
594 0 : ArrowSchema schema = {};
595 0 : if (objectsStream->get_schema(&schema) != 0)
596 : {
597 0 : CPLError(CE_Failure, CPLE_AppDefined, "get_schema() failed");
598 0 : return nullptr;
599 : }
600 :
601 0 : auto statement = std::make_unique<AdbcStatement>();
602 0 : OGRADBCLayer tmpLayer(this, "", "", std::move(statement),
603 0 : std::move(objectsStream), &schema,
604 0 : /* bInternalUse = */ true);
605 0 : const auto tmpLayerDefn = tmpLayer.GetLayerDefn();
606 0 : if (tmpLayerDefn->GetFieldIndex("catalog_name") < 0 ||
607 0 : tmpLayerDefn->GetFieldIndex("catalog_db_schemas") < 0)
608 : {
609 0 : return nullptr;
610 : }
611 :
612 : auto poTableListLayer =
613 0 : std::make_unique<OGRMemLayer>("table_list", nullptr, wkbNone);
614 : {
615 0 : OGRFieldDefn oField("catalog_name", OFTString);
616 0 : poTableListLayer->CreateField(&oField);
617 : }
618 : {
619 0 : OGRFieldDefn oField("schema_name", OFTString);
620 0 : poTableListLayer->CreateField(&oField);
621 : }
622 : {
623 0 : OGRFieldDefn oField("table_name", OFTString);
624 0 : poTableListLayer->CreateField(&oField);
625 : }
626 : {
627 0 : OGRFieldDefn oField("table_type", OFTString);
628 0 : poTableListLayer->CreateField(&oField);
629 : }
630 :
631 0 : for (const auto &poFeature : tmpLayer)
632 : {
633 : const char *pszCatalogName =
634 0 : poFeature->GetFieldAsString("catalog_name");
635 : const char *pszCatalogDBSchemas =
636 0 : poFeature->GetFieldAsString("catalog_db_schemas");
637 0 : if (pszCatalogDBSchemas)
638 : {
639 0 : CPLJSONDocument oDoc;
640 0 : if (oDoc.LoadMemory(pszCatalogDBSchemas))
641 : {
642 0 : auto oRoot = oDoc.GetRoot();
643 0 : if (oRoot.GetType() == CPLJSONObject::Type::Array)
644 : {
645 0 : for (const auto &oSchema : oRoot.ToArray())
646 : {
647 0 : if (oSchema.GetType() == CPLJSONObject::Type::Object)
648 : {
649 : const std::string osSchemaName =
650 0 : oSchema.GetString("schema_name");
651 : const auto oTables =
652 0 : oSchema.GetArray("db_schema_tables");
653 0 : if (oTables.IsValid())
654 : {
655 0 : for (const auto &oTable : oTables)
656 : {
657 0 : if (oTable.GetType() ==
658 : CPLJSONObject::Type::Object)
659 : {
660 : const std::string osTableName =
661 0 : oTable.GetString("table_name");
662 : const std::string osTableType =
663 0 : oTable.GetString("table_type");
664 0 : if (!osTableName.empty() &&
665 0 : osTableType != "index" &&
666 0 : osTableType != "trigger")
667 : {
668 : OGRFeature oFeat(
669 : poTableListLayer
670 0 : ->GetLayerDefn());
671 0 : if (pszCatalogName)
672 0 : oFeat.SetField("catalog_name",
673 : pszCatalogName);
674 0 : if (oSchema.GetObj("schema_name")
675 0 : .IsValid())
676 0 : oFeat.SetField(
677 : "schema_name",
678 : osSchemaName.c_str());
679 0 : oFeat.SetField("table_name",
680 : osTableName.c_str());
681 0 : if (oTable.GetObj("table_type")
682 0 : .IsValid())
683 0 : oFeat.SetField(
684 : "table_type",
685 : osTableType.c_str());
686 0 : CPL_IGNORE_RET_VAL(
687 0 : poTableListLayer->CreateFeature(
688 : &oFeat));
689 : }
690 : }
691 : }
692 : }
693 : }
694 : }
695 : }
696 : }
697 : }
698 : }
699 :
700 0 : m_apoLayers.emplace_back(std::move(poTableListLayer));
701 0 : return m_apoLayers.back().get();
702 : }
703 :
704 : #undef ADBC_CALL
|