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) 2025, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "ogr_adbc.h"
14 : #include "ogr_p.h"
15 :
16 : #include <algorithm>
17 :
18 : /************************************************************************/
19 : /* OGRADBCBigQueryLayer() */
20 : /************************************************************************/
21 :
22 0 : OGRADBCBigQueryLayer::OGRADBCBigQueryLayer(OGRADBCDataset *poDS,
23 : const char *pszName,
24 : const std::string &osStatement,
25 0 : bool bInternalUse)
26 0 : : OGRADBCLayer(poDS, pszName, osStatement, bInternalUse)
27 : {
28 0 : }
29 :
30 : /************************************************************************/
31 : /* GetBigQueryDatasetAndTableId() */
32 : /************************************************************************/
33 :
34 0 : bool OGRADBCBigQueryLayer::GetBigQueryDatasetAndTableId(
35 : std::string &osDatasetId, std::string &osTableId) const
36 : {
37 0 : auto nPos = CPLString(m_osBaseStatement).ifind(" FROM ");
38 0 : if (nPos != std::string::npos)
39 : {
40 0 : nPos += strlen(" FROM ");
41 0 : const auto nPos2 = m_osBaseStatement.find(' ', nPos);
42 : const std::string osTableName =
43 : (nPos2 != std::string::npos)
44 : ? m_osBaseStatement.substr(nPos, nPos2 - nPos)
45 0 : : m_osBaseStatement.substr(nPos);
46 :
47 0 : const auto nPosDot = osTableName.find('.');
48 0 : if (nPosDot != std::string::npos)
49 : {
50 0 : osDatasetId = osTableName.substr(0, nPosDot);
51 0 : osTableId = osTableName.substr(nPosDot + 1);
52 0 : if (osDatasetId.size() > 2 && osDatasetId[0] == '`' &&
53 0 : osDatasetId.back() == '`')
54 0 : osDatasetId = osDatasetId.substr(1, osDatasetId.size() - 2);
55 0 : if (osTableId.size() > 2 && osTableId[0] == '`' &&
56 0 : osTableId.back() == '`')
57 0 : osTableId = osTableId.substr(1, osTableId.size() - 2);
58 0 : return true;
59 : }
60 : }
61 0 : return false;
62 : }
63 :
64 : /************************************************************************/
65 : /* BuildLayerDefn() */
66 : /************************************************************************/
67 :
68 0 : void OGRADBCBigQueryLayer::BuildLayerDefn()
69 : {
70 0 : if (!BuildLayerDefnInit())
71 0 : return;
72 :
73 0 : std::map<std::string, std::unique_ptr<OGRSpatialReference>> oMapGeomColumns;
74 0 : std::map<std::string, bool> oMapIsNullable;
75 :
76 : const bool bIsLikelyTableExtract =
77 0 : !m_bInternalUse &&
78 0 : STARTS_WITH_CI(m_osBaseStatement.c_str(), "SELECT ") &&
79 0 : !STARTS_WITH_CI(m_osBaseStatement.c_str(), "SELECT COUNT(");
80 0 : if (bIsLikelyTableExtract)
81 : {
82 0 : std::string osDatasetId;
83 0 : std::string osTableId;
84 0 : if (GetBigQueryDatasetAndTableId(osDatasetId, osTableId))
85 : {
86 0 : auto poColumnList = m_poDS->CreateInternalLayer(CPLSPrintf(
87 : "SELECT c.column_name, c.data_type, c.is_nullable, "
88 : "keys.ordinal_position AS key_ordinal_position, "
89 : "keys.position_in_unique_constraint FROM "
90 : "`%s`.INFORMATION_SCHEMA.COLUMNS c "
91 : "LEFT JOIN `%s`.INFORMATION_SCHEMA.KEY_COLUMN_USAGE keys ON "
92 : "c.table_schema = keys.table_schema AND "
93 : "c.table_name = keys.table_name AND "
94 : "c.column_name = keys.column_name "
95 : "WHERE c.table_name='%s' AND c.is_hidden = 'NO' "
96 : "ORDER BY c.ordinal_position",
97 0 : OGRDuplicateCharacter(osDatasetId.c_str(), '`').c_str(),
98 0 : OGRDuplicateCharacter(osDatasetId.c_str(), '`').c_str(),
99 0 : OGRDuplicateCharacter(osTableId.c_str(), '\'').c_str()));
100 0 : if (poColumnList->GetLayerDefn()->GetFieldCount() == 5)
101 : {
102 0 : for (auto &&f : *poColumnList)
103 : {
104 0 : constexpr int IDX_COL_NAME = 0;
105 0 : constexpr int IDX_DATA_TYPE = 1;
106 0 : constexpr int IDX_IS_NULLABLE = 2;
107 0 : constexpr int IDX_KEY_ORDINAL_POSITION = 3;
108 0 : constexpr int IDX_POSITION_IN_UNIQUE_CONSTRAINT = 4;
109 0 : const char *pszColName = f->GetFieldAsString(IDX_COL_NAME);
110 0 : const char *pszColType = f->GetFieldAsString(IDX_DATA_TYPE);
111 0 : if (EQUAL(pszColType, "GEOGRAPHY"))
112 : {
113 0 : auto poSRS = std::make_unique<OGRSpatialReference>();
114 0 : poSRS->SetAxisMappingStrategy(
115 : OAMS_TRADITIONAL_GIS_ORDER);
116 0 : poSRS->importFromEPSG(4326);
117 0 : oMapGeomColumns[pszColName] = std::move(poSRS);
118 : }
119 0 : oMapIsNullable[pszColName] =
120 0 : EQUAL(f->GetFieldAsString(IDX_IS_NULLABLE), "YES");
121 0 : if (f->IsFieldNull(IDX_POSITION_IN_UNIQUE_CONSTRAINT) &&
122 0 : !f->IsFieldNull(IDX_KEY_ORDINAL_POSITION))
123 : {
124 0 : if (EQUAL(pszColType, "INT64") &&
125 0 : f->GetFieldAsInteger64(IDX_KEY_ORDINAL_POSITION) ==
126 0 : 1 &&
127 0 : m_osFIDColName.empty())
128 : {
129 0 : m_osFIDColName = pszColName;
130 : }
131 : else
132 : {
133 0 : m_osFIDColName.clear();
134 : }
135 : }
136 : }
137 :
138 0 : if (!oMapGeomColumns.empty())
139 : {
140 0 : std::string osNewStatement = "SELECT ";
141 0 : for (int i = 0; i < m_schema.n_children; ++i)
142 : {
143 0 : if (i > 0)
144 0 : osNewStatement += ", ";
145 0 : const char *pszColName = m_schema.children[i]->name;
146 0 : auto oIter = oMapGeomColumns.find(pszColName);
147 0 : if (oIter != oMapGeomColumns.end())
148 : {
149 0 : osNewStatement += "ST_AsBinary(`";
150 : osNewStatement +=
151 0 : OGRDuplicateCharacter(pszColName, '`');
152 0 : osNewStatement += "`) AS ";
153 : }
154 0 : osNewStatement += '`';
155 : osNewStatement +=
156 0 : OGRDuplicateCharacter(pszColName, '`');
157 0 : osNewStatement += '`';
158 : }
159 0 : m_osModifiedSelect = osNewStatement;
160 0 : osNewStatement += " FROM (";
161 0 : osNewStatement += m_osBaseStatement;
162 0 : osNewStatement += " )";
163 :
164 : #ifdef DEBUG_VEBOSE
165 : CPLDebug("ADBC", "%s -> %s", m_osBaseStatement.c_str(),
166 : osNewStatement.c_str());
167 : #endif
168 :
169 0 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
170 0 : if (ReplaceStatement(osNewStatement.c_str()))
171 : {
172 0 : m_osModifiedBaseStatement = std::move(osNewStatement);
173 : }
174 : else
175 : {
176 0 : m_osModifiedSelect.clear();
177 0 : oMapGeomColumns.clear();
178 : }
179 : }
180 : }
181 : }
182 : }
183 :
184 0 : auto poLayerDefn = m_poAdapterLayer->GetLayerDefn();
185 :
186 0 : for (int i = 0; i < m_schema.n_children; ++i)
187 : {
188 0 : const char *pszColName = m_schema.children[i]->name;
189 0 : auto oIter = oMapGeomColumns.find(pszColName);
190 0 : if (oIter != oMapGeomColumns.end())
191 : {
192 0 : OGRGeomFieldDefn oGeomFieldDefn(pszColName, wkbUnknown);
193 0 : auto poSRS = std::move(oIter->second).release();
194 0 : if (poSRS)
195 : {
196 0 : oGeomFieldDefn.SetSpatialRef(poSRS);
197 0 : poSRS->Release();
198 : }
199 0 : poLayerDefn->AddGeomFieldDefn(&oGeomFieldDefn);
200 : }
201 : else
202 : {
203 0 : m_poAdapterLayer->CreateFieldFromArrowSchema(m_schema.children[i]);
204 : }
205 : }
206 :
207 0 : if (bIsLikelyTableExtract)
208 : {
209 0 : for (int i = 0; i < poLayerDefn->GetFieldCount(); ++i)
210 : {
211 0 : auto poFldDefn = poLayerDefn->GetFieldDefn(i);
212 0 : auto oIter = oMapIsNullable.find(poFldDefn->GetNameRef());
213 0 : if (oIter != oMapIsNullable.end())
214 0 : poFldDefn->SetNullable(oIter->second);
215 : }
216 0 : for (int i = 0; i < poLayerDefn->GetGeomFieldCount(); ++i)
217 : {
218 0 : auto poGFldDefn = poLayerDefn->GetGeomFieldDefn(i);
219 0 : std::string osSQL = "SELECT DISTINCT ST_GeometryType(`";
220 0 : osSQL += OGRDuplicateCharacter(poGFldDefn->GetNameRef(), '`');
221 0 : osSQL += "`) FROM (";
222 0 : osSQL += m_osBaseStatement;
223 0 : osSQL += ')';
224 0 : auto poGeomTypeList = m_poDS->CreateInternalLayer(osSQL.c_str());
225 0 : if (poGeomTypeList->GetLayerDefn()->GetFieldCount() == 1)
226 : {
227 0 : std::string osType;
228 0 : for (auto &&f : *poGeomTypeList)
229 : {
230 0 : if (osType.empty())
231 : {
232 0 : osType = f->GetFieldAsString(0);
233 : }
234 : else
235 : {
236 0 : osType.clear();
237 0 : break;
238 : }
239 : }
240 0 : if (STARTS_WITH_CI(osType.c_str(), "ST_"))
241 : {
242 0 : poGFldDefn->SetType(
243 0 : OGRFromOGCGeomType(osType.c_str() + strlen("ST_")));
244 : }
245 : }
246 0 : auto oIter = oMapIsNullable.find(poGFldDefn->GetNameRef());
247 0 : if (oIter != oMapIsNullable.end())
248 0 : poGFldDefn->SetNullable(oIter->second);
249 : }
250 : }
251 : }
252 :
253 : /***********************************************************************/
254 : /* SetAttributeFilter() */
255 : /***********************************************************************/
256 :
257 0 : OGRErr OGRADBCBigQueryLayer::SetAttributeFilter(const char *pszFilter)
258 : {
259 0 : if (!m_osModifiedSelect.empty())
260 : {
261 0 : m_osAttributeFilter = pszFilter ? pszFilter : "";
262 0 : return UpdateStatement() ? OGRERR_NONE : OGRERR_FAILURE;
263 : }
264 : else
265 : {
266 0 : return OGRLayer::SetAttributeFilter(pszFilter);
267 : }
268 : }
269 :
270 : /************************************************************************/
271 : /* GetFeatureCount() */
272 : /************************************************************************/
273 :
274 0 : GIntBig OGRADBCBigQueryLayer::GetFeatureCount(int /*bForce*/)
275 : {
276 0 : if (!m_poAdapterLayer)
277 0 : BuildLayerDefn();
278 0 : if (m_bLayerDefinitionError)
279 0 : return 0;
280 :
281 0 : auto nCount = GetFeatureCountSelectCountStar();
282 0 : if (nCount >= 0)
283 0 : return nCount;
284 :
285 0 : return GetFeatureCountArrow();
286 : }
287 :
288 : /************************************************************************/
289 : /* TestCapability() */
290 : /************************************************************************/
291 :
292 0 : int OGRADBCBigQueryLayer::TestCapability(const char *pszCap) const
293 : {
294 0 : if (!m_poAdapterLayer)
295 0 : const_cast<OGRADBCBigQueryLayer *>(this)->BuildLayerDefn();
296 :
297 0 : if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCCreateField))
298 0 : return m_poDS->GetAccess() == GA_Update;
299 :
300 0 : if (EQUAL(pszCap, OLCRandomWrite) || EQUAL(pszCap, OLCDeleteFeature))
301 0 : return m_poDS->GetAccess() == GA_Update && !m_osFIDColName.empty();
302 :
303 0 : return OGRADBCLayer::TestCapability(pszCap);
304 : }
305 :
306 : /************************************************************************/
307 : /* IGetExtent() */
308 : /************************************************************************/
309 :
310 0 : OGRErr OGRADBCBigQueryLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
311 : bool bForce)
312 : {
313 0 : if (!m_poAdapterLayer)
314 0 : BuildLayerDefn();
315 :
316 : const char *pszGeomColName =
317 0 : GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetNameRef();
318 0 : std::string osSQL = "SELECT ST_Extent(`";
319 0 : osSQL += OGRDuplicateCharacter(pszGeomColName, '`');
320 0 : osSQL += "`) FROM (";
321 0 : osSQL += m_osBaseStatement;
322 0 : osSQL += ")";
323 0 : auto poExtentLayer = m_poDS->CreateInternalLayer(osSQL.c_str());
324 0 : if (poExtentLayer->GetLayerDefn()->GetFieldCount() == 4)
325 : {
326 0 : auto f = std::unique_ptr<OGRFeature>(poExtentLayer->GetNextFeature());
327 0 : if (f && f->IsFieldSetAndNotNull(0))
328 : {
329 0 : psExtent->MinX = f->GetFieldAsDouble(0);
330 0 : psExtent->MinY = f->GetFieldAsDouble(1);
331 0 : psExtent->MaxX = f->GetFieldAsDouble(2);
332 0 : psExtent->MaxY = f->GetFieldAsDouble(3);
333 0 : return OGRERR_NONE;
334 : }
335 : else
336 0 : return OGRERR_FAILURE;
337 : }
338 :
339 0 : return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
340 : }
341 :
342 : /************************************************************************/
343 : /* GetCurrentStatement() */
344 : /************************************************************************/
345 :
346 0 : std::string OGRADBCBigQueryLayer::GetCurrentStatement() const
347 : {
348 0 : if (!m_osAttributeFilter.empty() || m_poFilterGeom)
349 : {
350 0 : std::string osStatement(m_osModifiedSelect);
351 0 : osStatement.append(" FROM (")
352 0 : .append(m_osBaseStatement)
353 0 : .append(") WHERE ");
354 0 : if (m_poFilterGeom)
355 : {
356 0 : if (m_sFilterEnvelope.MinX > 180 || m_sFilterEnvelope.MinY > 90 ||
357 0 : m_sFilterEnvelope.MaxX < -180 || m_sFilterEnvelope.MaxY < -90)
358 : {
359 0 : osStatement.append(" FALSE");
360 0 : return osStatement;
361 : }
362 0 : constexpr double EPSILON = 1e-8;
363 : const double dfMinX =
364 0 : std::max(-180.0, m_sFilterEnvelope.MinX - EPSILON);
365 : const double dfMinY =
366 0 : std::max(-90.0, m_sFilterEnvelope.MinY - EPSILON);
367 : const double dfMaxX =
368 0 : std::min(180.0, m_sFilterEnvelope.MaxX + EPSILON);
369 : const double dfMaxY =
370 0 : std::min(90.0, m_sFilterEnvelope.MaxY + EPSILON);
371 : const char *pszGeomColName =
372 0 : m_poAdapterLayer->GetLayerDefn()
373 0 : ->GetGeomFieldDefn(m_iGeomFieldFilter)
374 0 : ->GetNameRef();
375 : osStatement +=
376 : CPLSPrintf("ST_IntersectsBox(`%s`,%.17g,%.17g,%.17g,%.17g)",
377 0 : OGRDuplicateCharacter(pszGeomColName, '`').c_str(),
378 0 : dfMinX, dfMinY, dfMaxX, dfMaxY);
379 : }
380 0 : if (!m_osAttributeFilter.empty())
381 : {
382 0 : if (m_poFilterGeom)
383 0 : osStatement.append(" AND ");
384 0 : osStatement.append("(");
385 0 : osStatement.append(m_osAttributeFilter);
386 0 : osStatement.append(")");
387 : }
388 :
389 : #ifdef DEBUG_VEBOSE
390 : CPLDebug("ADBC", "%s", osStatement.c_str());
391 : #endif
392 :
393 0 : return osStatement;
394 : }
395 : else
396 : {
397 0 : return m_osModifiedBaseStatement;
398 : }
399 : }
400 :
401 : /************************************************************************/
402 : /* GetSQLType() */
403 : /************************************************************************/
404 :
405 0 : static std::string GetSQLType(const OGRFieldDefn *poField)
406 : {
407 0 : switch (poField->GetType())
408 : {
409 0 : case OFTInteger:
410 0 : return poField->GetSubType() == OFSTBoolean ? "BOOLEAN" : "INTEGER";
411 0 : case OFTInteger64:
412 0 : return "INT64";
413 0 : case OFTReal:
414 0 : return "FLOAT64";
415 0 : case OFTDate:
416 0 : return "DATE";
417 0 : case OFTTime:
418 0 : return "TIME";
419 0 : case OFTDateTime:
420 0 : return "TIMESTAMP";
421 0 : case OFTString:
422 0 : return poField->GetSubType() == OFSTJSON ? "JSON" : "STRING";
423 0 : case OFTBinary:
424 0 : return "BYTES";
425 0 : case OFTStringList:
426 0 : return "ARRAY<STRING>";
427 0 : case OFTRealList:
428 0 : return "ARRAY<FLOAT64>";
429 0 : case OFTIntegerList:
430 0 : return "ARRAY<INTEGER>";
431 0 : case OFTInteger64List:
432 0 : return "ARRAY<INT64>";
433 0 : case OFTWideString:
434 : case OFTWideStringList:
435 0 : CPLError(CE_Failure, CPLE_NotSupported, "Unsupported type");
436 0 : break;
437 : }
438 0 : return std::string();
439 : }
440 :
441 : /************************************************************************/
442 : /* CreateField() */
443 : /************************************************************************/
444 :
445 0 : OGRErr OGRADBCBigQueryLayer::CreateField(const OGRFieldDefn *poField,
446 : int /*bApproxOK*/)
447 : {
448 0 : if (m_poDS->GetAccess() != GA_Update)
449 : {
450 0 : CPLError(
451 : CE_Failure, CPLE_NotSupported,
452 : "CreateField() only supported on datasets opened in update mode");
453 0 : return OGRERR_FAILURE;
454 : }
455 0 : if (!m_poAdapterLayer)
456 0 : BuildLayerDefn();
457 0 : if (m_bLayerDefinitionError)
458 0 : return OGRERR_FAILURE;
459 :
460 0 : if (GetLayerDefn()->GetFieldIndex(poField->GetNameRef()) >= 0)
461 : {
462 0 : CPLError(CE_Failure, CPLE_AppDefined, "Field '%s' already exists.",
463 : poField->GetNameRef());
464 0 : return OGRERR_FAILURE;
465 : }
466 :
467 0 : const auto osSQLType = GetSQLType(poField);
468 0 : if (osSQLType.empty())
469 0 : return OGRERR_FAILURE;
470 :
471 0 : if (!m_bDeferredCreation)
472 : {
473 0 : std::string osDatasetId, osTableId;
474 0 : if (!GetBigQueryDatasetAndTableId(osDatasetId, osTableId))
475 : {
476 0 : CPLError(CE_Failure, CPLE_NotSupported,
477 : "CreateField(): cannot get dataset and table ID");
478 0 : return OGRERR_FAILURE;
479 : }
480 :
481 0 : std::string osSQL = "ALTER TABLE `";
482 0 : osSQL += OGRDuplicateCharacter(osDatasetId.c_str(), '`');
483 0 : osSQL += "`.`";
484 0 : osSQL += OGRDuplicateCharacter(osTableId.c_str(), '`');
485 0 : osSQL += "` ADD COLUMN `";
486 0 : osSQL += OGRDuplicateCharacter(poField->GetNameRef(), '`');
487 0 : osSQL += "` ";
488 0 : osSQL += osSQLType;
489 0 : if (m_poDS->CreateInternalLayer(osSQL.c_str())->GotError())
490 0 : return OGRERR_FAILURE;
491 : }
492 :
493 0 : return m_poAdapterLayer->CreateField(poField, false);
494 : }
495 :
496 : /************************************************************************/
497 : /* GetFieldValue() */
498 : /************************************************************************/
499 :
500 0 : static std::string GetFieldValue(const OGRFieldDefn *poFldDefn,
501 : OGRFeature *poFeature, int iField)
502 : {
503 0 : std::string osVal;
504 :
505 0 : if (poFeature->IsFieldNull(iField))
506 0 : osVal = "NULL";
507 :
508 0 : else if (poFldDefn->GetType() == OFTInteger ||
509 0 : poFldDefn->GetType() == OFTInteger64)
510 : {
511 0 : const auto nVal = poFeature->GetFieldAsInteger64(iField);
512 0 : if (poFldDefn->GetSubType() == OFSTBoolean)
513 0 : osVal = nVal ? "TRUE" : "FALSE";
514 : else
515 0 : osVal = std::to_string(nVal);
516 : }
517 0 : else if (poFldDefn->GetType() == OFTReal)
518 : {
519 0 : osVal = CPLSPrintf("%.17g", poFeature->GetFieldAsDouble(iField));
520 : }
521 0 : else if (poFldDefn->GetType() == OFTDate)
522 : {
523 : char szTmpFieldValue[OGR_SIZEOF_ISO8601_DATETIME_BUFFER];
524 0 : constexpr bool bAlwaysMillisecond = false;
525 0 : OGRGetISO8601DateTime(poFeature->GetRawFieldRef(iField),
526 : bAlwaysMillisecond, szTmpFieldValue);
527 0 : szTmpFieldValue[strlen("YYYY-MM-DD")] = 0;
528 0 : osVal += "DATE \'";
529 0 : osVal += szTmpFieldValue;
530 0 : osVal += '\'';
531 : }
532 0 : else if (poFldDefn->GetType() == OFTDateTime)
533 : {
534 0 : osVal += '\'';
535 0 : osVal += poFeature->GetFieldAsISO8601DateTime(iField, nullptr);
536 0 : osVal += '\'';
537 : }
538 0 : else if (poFldDefn->GetType() == OFTBinary)
539 : {
540 0 : osVal += "b'";
541 0 : int nCount = 0;
542 0 : GByte *pabyVal = poFeature->GetFieldAsBinary(iField, &nCount);
543 0 : osVal.reserve(nCount * 4 + 4);
544 0 : for (int i = 0; i < nCount; ++i)
545 : {
546 0 : osVal += CPLSPrintf("\\x%02X", pabyVal[i]);
547 : }
548 0 : osVal += '\'';
549 : }
550 0 : else if (poFldDefn->GetType() == OFTStringList)
551 : {
552 0 : CSLConstList papszStr = poFeature->GetFieldAsStringList(iField);
553 0 : osVal += '[';
554 0 : for (int i = 0; papszStr && papszStr[i]; ++i)
555 : {
556 0 : if (i > 0)
557 0 : osVal += ',';
558 0 : osVal += '\'';
559 0 : osVal += OGRDuplicateCharacter(papszStr[i], '\'');
560 0 : osVal += '\'';
561 : }
562 0 : osVal += ']';
563 : }
564 0 : else if (poFldDefn->GetType() == OFTIntegerList)
565 : {
566 0 : int nCount = 0;
567 0 : const int *panVals = poFeature->GetFieldAsIntegerList(iField, &nCount);
568 0 : osVal += '[';
569 0 : for (int i = 0; i < nCount; ++i)
570 : {
571 0 : if (i > 0)
572 0 : osVal += ',';
573 0 : osVal += std::to_string(panVals[i]);
574 : }
575 0 : osVal += ']';
576 : }
577 0 : else if (poFldDefn->GetType() == OFTInteger64List)
578 : {
579 0 : int nCount = 0;
580 : const auto *panVals =
581 0 : poFeature->GetFieldAsInteger64List(iField, &nCount);
582 0 : osVal += '[';
583 0 : for (int i = 0; i < nCount; ++i)
584 : {
585 0 : if (i > 0)
586 0 : osVal += ',';
587 0 : osVal += std::to_string(panVals[i]);
588 : }
589 0 : osVal += ']';
590 : }
591 0 : else if (poFldDefn->GetType() == OFTRealList)
592 : {
593 0 : int nCount = 0;
594 : const double *padfVals =
595 0 : poFeature->GetFieldAsDoubleList(iField, &nCount);
596 0 : osVal += '[';
597 0 : for (int i = 0; i < nCount; ++i)
598 : {
599 0 : if (i > 0)
600 0 : osVal += ',';
601 0 : osVal += CPLSPrintf("%.17g", padfVals[i]);
602 : }
603 0 : osVal += ']';
604 : }
605 : else
606 : {
607 : // Cf https://cloud.google.com/bigquery/docs/json-data?hl=en#create_a_json_value
608 0 : if (poFldDefn->GetSubType() == OFSTJSON)
609 0 : osVal += "JSON ";
610 0 : osVal += '\'';
611 : osVal +=
612 0 : OGRDuplicateCharacter(poFeature->GetFieldAsString(iField), '\'');
613 0 : osVal += '\'';
614 : }
615 0 : return osVal;
616 : }
617 :
618 : /************************************************************************/
619 : /* ICreateFeature() */
620 : /************************************************************************/
621 :
622 0 : OGRErr OGRADBCBigQueryLayer::ICreateFeature(OGRFeature *poFeature)
623 : {
624 0 : if (m_poDS->GetAccess() != GA_Update)
625 : {
626 0 : CPLError(
627 : CE_Failure, CPLE_NotSupported,
628 : "CreateFeature() only supported on datasets opened in update mode");
629 0 : return OGRERR_FAILURE;
630 : }
631 0 : if (!m_poAdapterLayer)
632 0 : BuildLayerDefn();
633 0 : if (m_bDeferredCreation)
634 0 : RunDeferredCreation();
635 0 : if (m_bLayerDefinitionError)
636 0 : return OGRERR_FAILURE;
637 :
638 0 : std::string osDatasetId;
639 0 : std::string osTableId;
640 0 : if (!STARTS_WITH_CI(m_osBaseStatement.c_str(), "SELECT * FROM ") ||
641 0 : CPLString(m_osBaseStatement).ifind(" WHERE ") != std::string::npos ||
642 0 : !GetBigQueryDatasetAndTableId(osDatasetId, osTableId))
643 : {
644 0 : CPLError(CE_Failure, CPLE_NotSupported,
645 : "CreateFeature(): cannot get dataset and table ID");
646 0 : return OGRERR_FAILURE;
647 : }
648 :
649 0 : std::string osFieldNames;
650 0 : std::string osFieldValues;
651 :
652 0 : if (!m_osFIDColName.empty())
653 : {
654 0 : if (poFeature->GetFID() < 0)
655 : {
656 0 : if (m_nMaxFeatureID < 0)
657 : {
658 0 : std::string osSQL = "SELECT MAX(`";
659 0 : osSQL += OGRDuplicateCharacter(m_osFIDColName.c_str(), '`');
660 0 : osSQL += "`) FROM (";
661 0 : osSQL += m_osBaseStatement;
662 0 : osSQL += ')';
663 :
664 0 : auto poMaxFIDLayer = m_poDS->CreateInternalLayer(osSQL.c_str());
665 0 : if (poMaxFIDLayer->GetLayerDefn()->GetFieldCount() != 1)
666 0 : return OGRERR_FAILURE;
667 : auto f = std::unique_ptr<OGRFeature>(
668 0 : poMaxFIDLayer->GetNextFeature());
669 0 : if (f)
670 0 : m_nMaxFeatureID = f->GetFieldAsInteger64(0);
671 : else
672 0 : m_nMaxFeatureID = 0;
673 : }
674 0 : poFeature->SetFID(++m_nMaxFeatureID);
675 : }
676 0 : osFieldNames = m_osFIDColName;
677 0 : osFieldValues = std::to_string(poFeature->GetFID());
678 : }
679 :
680 0 : auto poFeatureDefn = GetLayerDefn();
681 0 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); ++i)
682 : {
683 0 : const char *pszName = poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef();
684 0 : if (!osFieldNames.empty())
685 0 : osFieldNames += ", ";
686 0 : osFieldNames += '`';
687 0 : osFieldNames += OGRDuplicateCharacter(pszName, '`');
688 0 : osFieldNames += '`';
689 :
690 0 : if (!osFieldValues.empty())
691 0 : osFieldValues += ", ";
692 :
693 0 : const auto poGeom = poFeature->GetGeomFieldRef(i);
694 0 : if (poGeom)
695 : {
696 0 : osFieldValues += "ST_GeogFromText('";
697 0 : char *pszWKT = nullptr;
698 0 : poGeom->exportToWkt(&pszWKT, wkbVariantIso);
699 0 : osFieldValues += pszWKT;
700 0 : CPLFree(pszWKT);
701 0 : osFieldValues += "')";
702 : }
703 : else
704 : {
705 0 : osFieldValues += "NULL";
706 : }
707 : }
708 0 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); ++i)
709 : {
710 0 : const auto poFieldDefn = poFeatureDefn->GetFieldDefn(i);
711 0 : const char *pszName = poFieldDefn->GetNameRef();
712 0 : if (!EQUAL(pszName, m_osFIDColName.c_str()) && poFeature->IsFieldSet(i))
713 : {
714 0 : if (!osFieldNames.empty())
715 0 : osFieldNames += ", ";
716 0 : osFieldNames += '`';
717 0 : osFieldNames += OGRDuplicateCharacter(pszName, '`');
718 0 : osFieldNames += '`';
719 :
720 0 : if (!osFieldValues.empty())
721 0 : osFieldValues += ", ";
722 :
723 0 : osFieldValues += GetFieldValue(poFieldDefn, poFeature, i);
724 : }
725 : }
726 :
727 0 : std::string osSQL = "INSERT INTO `";
728 0 : osSQL += OGRDuplicateCharacter(osDatasetId, '`');
729 0 : osSQL += "`.`";
730 0 : osSQL += OGRDuplicateCharacter(osTableId, '`');
731 0 : osSQL += "` ";
732 0 : if (osFieldNames.empty())
733 : {
734 0 : osSQL += "DEFAULT VALUES";
735 : }
736 : else
737 : {
738 0 : osSQL += '(';
739 0 : osSQL += osFieldNames;
740 0 : osSQL += ") VALUES (";
741 0 : osSQL += osFieldValues;
742 0 : osSQL += ')';
743 : }
744 0 : return m_poDS->CreateInternalLayer(osSQL.c_str())->GotError()
745 0 : ? OGRERR_FAILURE
746 0 : : OGRERR_NONE;
747 : }
748 :
749 : /************************************************************************/
750 : /* ISetFeature() */
751 : /************************************************************************/
752 :
753 0 : OGRErr OGRADBCBigQueryLayer::ISetFeature(OGRFeature *poFeature)
754 : {
755 0 : if (m_poDS->GetAccess() != GA_Update)
756 : {
757 0 : CPLError(
758 : CE_Failure, CPLE_NotSupported,
759 : "SetFeature() only supported on datasets opened in update mode");
760 0 : return OGRERR_FAILURE;
761 : }
762 0 : if (m_osFIDColName.empty())
763 : {
764 0 : CPLError(CE_Failure, CPLE_NotSupported,
765 : "SetFeature() only supported on tables with a INT64 single "
766 : "column primary key");
767 0 : return OGRERR_FAILURE;
768 : }
769 0 : if (poFeature->GetFID() < 0)
770 : {
771 0 : return OGRERR_NON_EXISTING_FEATURE;
772 : }
773 :
774 0 : if (!m_poAdapterLayer)
775 0 : BuildLayerDefn();
776 0 : if (m_bDeferredCreation)
777 0 : RunDeferredCreation();
778 0 : if (m_bLayerDefinitionError)
779 0 : return OGRERR_FAILURE;
780 :
781 0 : std::string osDatasetId;
782 0 : std::string osTableId;
783 0 : if (!STARTS_WITH_CI(m_osBaseStatement.c_str(), "SELECT * FROM ") ||
784 0 : CPLString(m_osBaseStatement).ifind(" WHERE ") != std::string::npos ||
785 0 : !GetBigQueryDatasetAndTableId(osDatasetId, osTableId))
786 : {
787 0 : CPLError(CE_Failure, CPLE_NotSupported,
788 : "SetFeature(): cannot get dataset and table ID");
789 0 : return OGRERR_FAILURE;
790 : }
791 :
792 0 : std::string osSQL = "UPDATE `";
793 0 : osSQL += OGRDuplicateCharacter(osDatasetId, '`');
794 0 : osSQL += "`.`";
795 0 : osSQL += OGRDuplicateCharacter(osTableId, '`');
796 0 : osSQL += "` SET ";
797 :
798 0 : bool bAddComma = false;
799 0 : const auto poFeatureDefn = GetLayerDefn();
800 :
801 0 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); ++i)
802 : {
803 0 : const char *pszName = poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef();
804 0 : if (bAddComma)
805 0 : osSQL += ", ";
806 0 : bAddComma = true;
807 0 : osSQL += '`';
808 0 : osSQL += OGRDuplicateCharacter(pszName, '`');
809 0 : osSQL += "` = ";
810 0 : const auto poGeom = poFeature->GetGeomFieldRef(i);
811 0 : if (poGeom)
812 : {
813 0 : osSQL += "ST_GeogFromText('";
814 0 : char *pszWKT = nullptr;
815 0 : poGeom->exportToWkt(&pszWKT, wkbVariantIso);
816 0 : osSQL += pszWKT;
817 0 : CPLFree(pszWKT);
818 0 : osSQL += "')";
819 : }
820 : else
821 : {
822 0 : osSQL += "NULL";
823 : }
824 : }
825 :
826 0 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); ++i)
827 : {
828 0 : const auto poFieldDefn = poFeatureDefn->GetFieldDefn(i);
829 0 : const char *pszName = poFieldDefn->GetNameRef();
830 0 : if (!EQUAL(pszName, m_osFIDColName.c_str()) && poFeature->IsFieldSet(i))
831 : {
832 0 : if (bAddComma)
833 0 : osSQL += ", ";
834 0 : bAddComma = true;
835 0 : osSQL += '`';
836 0 : osSQL += OGRDuplicateCharacter(pszName, '`');
837 0 : osSQL += "` = ";
838 0 : osSQL += GetFieldValue(poFieldDefn, poFeature, i);
839 : }
840 : }
841 :
842 0 : osSQL += " WHERE `";
843 0 : osSQL += OGRDuplicateCharacter(m_osFIDColName, '`');
844 0 : osSQL += "` = ";
845 0 : osSQL += std::to_string(poFeature->GetFID());
846 :
847 0 : return bAddComma && m_poDS->CreateInternalLayer(osSQL.c_str())->GotError()
848 0 : ? OGRERR_FAILURE
849 0 : : OGRERR_NONE;
850 : }
851 :
852 : /************************************************************************/
853 : /* DeleteFeature() */
854 : /************************************************************************/
855 :
856 0 : OGRErr OGRADBCBigQueryLayer::DeleteFeature(GIntBig nFID)
857 : {
858 0 : if (m_poDS->GetAccess() != GA_Update)
859 : {
860 0 : CPLError(
861 : CE_Failure, CPLE_NotSupported,
862 : "DeleteFeature() only supported on datasets opened in update mode");
863 0 : return OGRERR_FAILURE;
864 : }
865 0 : if (m_osFIDColName.empty())
866 : {
867 0 : CPLError(CE_Failure, CPLE_NotSupported,
868 : "DeleteFeature() only supported on tables with a INT64 single "
869 : "column primary key");
870 0 : return OGRERR_FAILURE;
871 : }
872 0 : if (!m_poAdapterLayer)
873 0 : BuildLayerDefn();
874 0 : if (m_bDeferredCreation)
875 0 : RunDeferredCreation();
876 0 : if (m_bLayerDefinitionError)
877 0 : return OGRERR_FAILURE;
878 0 : if (nFID < 0)
879 0 : return OGRERR_NON_EXISTING_FEATURE;
880 :
881 0 : std::string osDatasetId;
882 0 : std::string osTableId;
883 0 : if (!GetBigQueryDatasetAndTableId(osDatasetId, osTableId))
884 : {
885 0 : CPLError(CE_Failure, CPLE_NotSupported,
886 : "DeleteFeature(): cannot get dataset and table ID");
887 0 : return OGRERR_FAILURE;
888 : }
889 :
890 0 : std::string osSQL = "DELETE FROM `";
891 0 : osSQL += OGRDuplicateCharacter(osDatasetId, '`');
892 0 : osSQL += "`.`";
893 0 : osSQL += OGRDuplicateCharacter(osTableId, '`');
894 0 : osSQL += "` WHERE `";
895 0 : osSQL += OGRDuplicateCharacter(m_osFIDColName, '`');
896 0 : osSQL += "` = ";
897 0 : osSQL += std::to_string(nFID);
898 :
899 0 : return m_poDS->CreateInternalLayer(osSQL.c_str())->GotError()
900 0 : ? OGRERR_FAILURE
901 0 : : OGRERR_NONE;
902 : }
903 :
904 : /************************************************************************/
905 : /* SetDeferredCreation() */
906 : /************************************************************************/
907 :
908 0 : void OGRADBCBigQueryLayer::SetDeferredCreation(
909 : const char *pszFIDColName, const OGRGeomFieldDefn *poGeomFieldDefn)
910 : {
911 0 : m_bDeferredCreation = true;
912 0 : m_osFIDColName = pszFIDColName;
913 0 : m_poAdapterLayer = std::make_unique<OGRArrowArrayToOGRFeatureAdapterLayer>(
914 0 : GetDescription());
915 0 : if (poGeomFieldDefn && poGeomFieldDefn->GetType() != wkbNone)
916 : {
917 0 : OGRGeomFieldDefn oFieldDefn(poGeomFieldDefn);
918 0 : if (oFieldDefn.GetNameRef()[0] == '\0')
919 0 : oFieldDefn.SetName("geog");
920 0 : m_poAdapterLayer->CreateGeomField(&oFieldDefn, false);
921 : }
922 0 : }
923 :
924 : /************************************************************************/
925 : /* RunDeferredCreation() */
926 : /************************************************************************/
927 :
928 0 : bool OGRADBCBigQueryLayer::RunDeferredCreation()
929 : {
930 0 : if (m_bDeferredCreation)
931 : {
932 0 : m_bDeferredCreation = false;
933 :
934 0 : auto poFeatureDefn = m_poAdapterLayer->GetLayerDefn();
935 0 : std::string osDatasetId;
936 0 : std::string osTableId;
937 0 : CPL_IGNORE_RET_VAL(
938 0 : GetBigQueryDatasetAndTableId(osDatasetId, osTableId));
939 :
940 0 : std::string osSQL = "CREATE TABLE `";
941 0 : osSQL += OGRDuplicateCharacter(osDatasetId.c_str(), '`');
942 0 : osSQL += "`.`";
943 0 : osSQL += OGRDuplicateCharacter(osTableId.c_str(), '`');
944 0 : osSQL += "` (";
945 0 : bool bAddComma = false;
946 0 : if (!m_osFIDColName.empty())
947 : {
948 0 : osSQL += '`';
949 0 : osSQL += OGRDuplicateCharacter(m_osFIDColName.c_str(), '`');
950 0 : osSQL += "` INT64 PRIMARY KEY NOT ENFORCED";
951 0 : bAddComma = true;
952 : }
953 0 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); ++i)
954 : {
955 0 : const auto poFieldDefn = poFeatureDefn->GetGeomFieldDefn(i);
956 0 : if (bAddComma)
957 0 : osSQL += ", ";
958 0 : bAddComma = true;
959 0 : osSQL += '`';
960 0 : osSQL += OGRDuplicateCharacter(poFieldDefn->GetNameRef(), '`');
961 0 : osSQL += "` GEOGRAPHY";
962 0 : if (!poFieldDefn->IsNullable())
963 0 : osSQL += " NOT NULL";
964 : }
965 0 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); ++i)
966 : {
967 0 : const auto poFieldDefn = poFeatureDefn->GetFieldDefn(i);
968 0 : if (bAddComma)
969 0 : osSQL += ", ";
970 0 : bAddComma = true;
971 0 : osSQL += '`';
972 0 : osSQL += OGRDuplicateCharacter(poFieldDefn->GetNameRef(), '`');
973 0 : osSQL += "` ";
974 0 : osSQL += GetSQLType(poFieldDefn);
975 0 : if (!poFieldDefn->IsNullable())
976 0 : osSQL += " NOT NULL";
977 : }
978 0 : osSQL += ')';
979 :
980 0 : m_bLayerDefinitionError =
981 0 : m_poDS->CreateInternalLayer(osSQL.c_str())->GotError();
982 : }
983 0 : return !m_bLayerDefinitionError;
984 : }
|