Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Carto Translator
4 : * Purpose: Implements OGRCARTOTableLayer class.
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "ogr_carto.h"
14 : #include "ogr_p.h"
15 : #include "ogr_pgdump.h"
16 : #include "ogrlibjsonutils.h"
17 :
18 : /************************************************************************/
19 : /* OGRCARTOEscapeIdentifier( ) */
20 : /************************************************************************/
21 :
22 246 : CPLString OGRCARTOEscapeIdentifier(const char *pszStr)
23 : {
24 246 : CPLString osStr;
25 :
26 246 : osStr += "\"";
27 :
28 246 : char ch = '\0';
29 2352 : for (int i = 0; (ch = pszStr[i]) != '\0'; i++)
30 : {
31 2106 : if (ch == '"')
32 0 : osStr.append(1, ch);
33 2106 : osStr.append(1, ch);
34 : }
35 :
36 246 : osStr += "\"";
37 :
38 246 : return osStr;
39 : }
40 :
41 : /************************************************************************/
42 : /* OGRCARTOEscapeLiteralCopy( ) */
43 : /************************************************************************/
44 :
45 1 : CPLString OGRCARTOEscapeLiteralCopy(const char *pszStr)
46 : {
47 1 : CPLString osStr;
48 :
49 : /* convert special characters in COPY text format */
50 : /* into their escaped forms, and double up the escape */
51 : /* character */
52 1 : char ch = '\0';
53 9 : for (int i = 0; (ch = pszStr[i]) != '\0'; i++)
54 : {
55 8 : if (ch == '\t') // tab
56 0 : osStr += "\\t";
57 8 : else if (ch == '\n') // new line
58 0 : osStr += "\\n";
59 8 : else if (ch == '\r') // carriage return
60 0 : osStr += "\\r";
61 8 : else if (ch == '\\') // escape character
62 0 : osStr += "\\\\";
63 : else
64 8 : osStr.append(1, ch);
65 : }
66 :
67 1 : return osStr;
68 : }
69 :
70 : /************************************************************************/
71 : /* OGRCARTOEscapeLiteral( ) */
72 : /************************************************************************/
73 :
74 52 : CPLString OGRCARTOEscapeLiteral(const char *pszStr)
75 : {
76 52 : CPLString osStr;
77 :
78 52 : char ch = '\0';
79 425 : for (int i = 0; (ch = pszStr[i]) != '\0'; i++)
80 : {
81 373 : if (ch == '\'')
82 0 : osStr.append(1, ch);
83 373 : osStr.append(1, ch);
84 : }
85 :
86 52 : return osStr;
87 : }
88 :
89 : /************************************************************************/
90 : /* OGRCARTOEscapeLiteral( ) */
91 : /************************************************************************/
92 :
93 4 : char *OGRCARTOTableLayer::OGRCARTOGetHexGeometry(OGRGeometry *poGeom, int i)
94 : {
95 : OGRCartoGeomFieldDefn *poGeomFieldDefn =
96 4 : cpl::down_cast<OGRCartoGeomFieldDefn *>(
97 4 : poFeatureDefn->GetGeomFieldDefn(i));
98 4 : int nSRID = poGeomFieldDefn->nSRID;
99 4 : if (nSRID == 0)
100 1 : nSRID = 4326;
101 : char *pszEWKB;
102 5 : if (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon &&
103 1 : wkbFlatten(GetGeomType()) == wkbMultiPolygon)
104 : {
105 1 : OGRMultiPolygon *poNewGeom = new OGRMultiPolygon();
106 1 : poNewGeom->addGeometry(poGeom);
107 1 : pszEWKB = OGRGeometryToHexEWKB(
108 1 : poNewGeom, nSRID, poDS->GetPostGISMajor(), poDS->GetPostGISMinor());
109 1 : delete poNewGeom;
110 : }
111 : else
112 3 : pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID, poDS->GetPostGISMajor(),
113 3 : poDS->GetPostGISMinor());
114 4 : return pszEWKB;
115 : }
116 :
117 : /************************************************************************/
118 : /* OGRCARTOTableLayer() */
119 : /************************************************************************/
120 :
121 22 : OGRCARTOTableLayer::OGRCARTOTableLayer(OGRCARTODataSource *poDSIn,
122 22 : const char *pszName)
123 22 : : OGRCARTOLayer(poDSIn), osName(pszName)
124 : {
125 22 : SetDescription(osName);
126 22 : bLaunderColumnNames = true;
127 22 : bInDeferredInsert = poDS->DoBatchInsert();
128 22 : bCopyMode = poDS->DoCopyMode();
129 22 : eDeferredInsertState = INSERT_UNINIT;
130 22 : m_nNextFIDWrite = -1;
131 22 : bDeferredCreation = false;
132 22 : bCartodbfy = false;
133 22 : nMaxChunkSize = atoi(CPLGetConfigOption(
134 : "CARTO_MAX_CHUNK_SIZE",
135 : CPLGetConfigOption("CARTODB_MAX_CHUNK_SIZE", "15"))) *
136 22 : 1024 * 1024;
137 22 : bDropOnCreation = false;
138 22 : }
139 :
140 : /************************************************************************/
141 : /* ~OGRCARTOTableLayer() */
142 : /************************************************************************/
143 :
144 44 : OGRCARTOTableLayer::~OGRCARTOTableLayer()
145 :
146 : {
147 22 : if (bDeferredCreation)
148 0 : RunDeferredCreationIfNecessary();
149 22 : CPL_IGNORE_RET_VAL(FlushDeferredBuffer());
150 22 : RunDeferredCartofy();
151 44 : }
152 :
153 : /************************************************************************/
154 : /* GetLayerDefnInternal() */
155 : /************************************************************************/
156 :
157 : OGRFeatureDefn *
158 131 : OGRCARTOTableLayer::GetLayerDefnInternal(CPL_UNUSED json_object *poObjIn)
159 : {
160 131 : if (poFeatureDefn != nullptr)
161 116 : return poFeatureDefn;
162 :
163 15 : CPLString osCommand;
164 15 : if (poDS->IsAuthenticatedConnection())
165 : {
166 : // Get everything !
167 : osCommand.Printf(
168 : "SELECT a.attname, t.typname, a.attlen, "
169 : "format_type(a.atttypid,a.atttypmod), "
170 : "a.attnum, "
171 : "a.attnotnull, "
172 : "i.indisprimary, "
173 : "pg_get_expr(def.adbin, c.oid) AS defaultexpr, "
174 : "postgis_typmod_dims(a.atttypmod) dim, "
175 : "postgis_typmod_srid(a.atttypmod) srid, "
176 : "postgis_typmod_type(a.atttypmod)::text geomtyp, "
177 : "srtext "
178 : "FROM pg_class c "
179 : "JOIN pg_attribute a ON a.attnum > 0 AND "
180 : "a.attrelid = c.oid AND c.relname = '%s' "
181 : "JOIN pg_type t ON a.atttypid = t.oid "
182 : "JOIN pg_namespace n ON c.relnamespace=n.oid AND n.nspname= '%s' "
183 : "LEFT JOIN pg_index i ON c.oid = i.indrelid AND "
184 : "i.indisprimary = 't' AND a.attnum = ANY(i.indkey) "
185 : "LEFT JOIN pg_attrdef def ON def.adrelid = c.oid AND "
186 : "def.adnum = a.attnum "
187 : "LEFT JOIN spatial_ref_sys srs ON srs.srid = "
188 : "postgis_typmod_srid(a.atttypmod) "
189 : "ORDER BY a.attnum",
190 24 : OGRCARTOEscapeLiteral(osName).c_str(),
191 36 : OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str());
192 : }
193 3 : else if (poDS->HasOGRMetadataFunction() != FALSE)
194 : {
195 : osCommand.Printf(
196 : "SELECT * FROM ogr_table_metadata('%s', '%s')",
197 6 : OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
198 9 : OGRCARTOEscapeLiteral(osName).c_str());
199 : }
200 :
201 15 : if (!osCommand.empty())
202 : {
203 18 : if (!poDS->IsAuthenticatedConnection() &&
204 3 : poDS->HasOGRMetadataFunction() < 0)
205 3 : CPLPushErrorHandler(CPLQuietErrorHandler);
206 15 : OGRLayer *poLyr = poDS->ExecuteSQLInternal(osCommand);
207 18 : if (!poDS->IsAuthenticatedConnection() &&
208 3 : poDS->HasOGRMetadataFunction() < 0)
209 : {
210 3 : CPLPopErrorHandler();
211 3 : if (poLyr == nullptr)
212 : {
213 3 : CPLDebug("CARTO",
214 : "ogr_table_metadata(text, text) not available");
215 3 : CPLErrorReset();
216 : }
217 0 : else if (poLyr->GetLayerDefn()->GetFieldCount() != 12)
218 : {
219 0 : CPLDebug("CARTO", "ogr_table_metadata(text, text) has "
220 : "unexpected column count");
221 0 : poDS->ReleaseResultSet(poLyr);
222 0 : poLyr = nullptr;
223 : }
224 3 : poDS->SetOGRMetadataFunction(poLyr != nullptr);
225 : }
226 15 : if (poLyr)
227 : {
228 : OGRFeature *poFeat;
229 102 : while ((poFeat = poLyr->GetNextFeature()) != nullptr)
230 : {
231 91 : if (poFeatureDefn == nullptr)
232 : {
233 : // We could do that outside of the while() loop, but
234 : // by doing that here, we are somewhat robust to
235 : // ogr_table_metadata() returning suddenly an empty result
236 : // set for example if CDB_UserTables() no longer works
237 10 : poFeatureDefn = new OGRFeatureDefn(osName);
238 10 : poFeatureDefn->Reference();
239 10 : poFeatureDefn->SetGeomType(wkbNone);
240 : }
241 :
242 91 : const char *pszAttname = poFeat->GetFieldAsString("attname");
243 91 : const char *pszType = poFeat->GetFieldAsString("typname");
244 91 : int nWidth = poFeat->GetFieldAsInteger("attlen");
245 : const char *pszFormatType =
246 91 : poFeat->GetFieldAsString("format_type");
247 91 : int bNotNull = poFeat->GetFieldAsInteger("attnotnull");
248 91 : int bIsPrimary = poFeat->GetFieldAsInteger("indisprimary");
249 : int iDefaultExpr =
250 91 : poLyr->GetLayerDefn()->GetFieldIndex("defaultexpr");
251 : const char *pszDefault =
252 90 : (iDefaultExpr >= 0 &&
253 90 : poFeat->IsFieldSetAndNotNull(iDefaultExpr))
254 181 : ? poFeat->GetFieldAsString(iDefaultExpr)
255 91 : : nullptr;
256 :
257 91 : if (bIsPrimary &&
258 9 : (EQUAL(pszType, "int2") || EQUAL(pszType, "int4") ||
259 0 : EQUAL(pszType, "int8") || EQUAL(pszType, "serial") ||
260 0 : EQUAL(pszType, "bigserial")))
261 : {
262 9 : osFIDColName = pszAttname;
263 : }
264 82 : else if (strcmp(pszAttname, "created_at") == 0 ||
265 73 : strcmp(pszAttname, "updated_at") == 0 ||
266 64 : strcmp(pszAttname, "the_geom_webmercator") == 0)
267 : {
268 : /* ignored */
269 : }
270 : else
271 : {
272 55 : if (EQUAL(pszType, "geometry"))
273 : {
274 9 : int nDim = poFeat->GetFieldAsInteger("dim");
275 9 : int nSRID = poFeat->GetFieldAsInteger("srid");
276 : const char *pszGeomType =
277 9 : poFeat->GetFieldAsString("geomtyp");
278 : const char *pszSRText =
279 9 : (poFeat->IsFieldSetAndNotNull(
280 9 : poLyr->GetLayerDefn()->GetFieldIndex("srtext")))
281 9 : ? poFeat->GetFieldAsString("srtext")
282 9 : : nullptr;
283 : OGRwkbGeometryType eType =
284 9 : OGRFromOGCGeomType(pszGeomType);
285 9 : if (nDim == 3)
286 9 : eType = wkbSetZ(eType);
287 : auto poFieldDefn =
288 : std::make_unique<OGRCartoGeomFieldDefn>(pszAttname,
289 9 : eType);
290 9 : if (bNotNull)
291 0 : poFieldDefn->SetNullable(FALSE);
292 9 : if (pszSRText != nullptr)
293 : {
294 9 : auto l_poSRS = new OGRSpatialReference();
295 9 : l_poSRS->SetAxisMappingStrategy(
296 : OAMS_TRADITIONAL_GIS_ORDER);
297 :
298 9 : if (l_poSRS->importFromWkt(pszSRText) !=
299 : OGRERR_NONE)
300 : {
301 0 : delete l_poSRS;
302 0 : l_poSRS = nullptr;
303 : }
304 9 : if (l_poSRS != nullptr)
305 : {
306 9 : poFieldDefn->SetSpatialRef(l_poSRS);
307 9 : l_poSRS->Release();
308 : }
309 : }
310 9 : poFieldDefn->nSRID = nSRID;
311 9 : poFeatureDefn->AddGeomFieldDefn(std::move(poFieldDefn));
312 : }
313 : else
314 : {
315 92 : OGRFieldDefn oField(pszAttname, OFTString);
316 46 : if (bNotNull)
317 3 : oField.SetNullable(FALSE);
318 46 : OGRPGCommonLayerSetType(oField, pszType, pszFormatType,
319 : nWidth);
320 46 : if (pszDefault)
321 3 : OGRPGCommonLayerNormalizeDefault(&oField,
322 : pszDefault);
323 :
324 46 : poFeatureDefn->AddFieldDefn(&oField);
325 : }
326 : }
327 91 : delete poFeat;
328 : }
329 :
330 11 : poDS->ReleaseResultSet(poLyr);
331 : }
332 : }
333 :
334 15 : if (poFeatureDefn == nullptr)
335 : {
336 : osBaseSQL.Printf("SELECT * FROM %s",
337 5 : OGRCARTOEscapeIdentifier(osName).c_str());
338 5 : EstablishLayerDefn(osName, nullptr);
339 5 : osBaseSQL = "";
340 : }
341 :
342 15 : if (!osFIDColName.empty())
343 : {
344 9 : osBaseSQL = "SELECT ";
345 9 : osBaseSQL += OGRCARTOEscapeIdentifier(osFIDColName);
346 : }
347 24 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
348 : {
349 9 : if (osBaseSQL.empty())
350 0 : osBaseSQL = "SELECT ";
351 : else
352 9 : osBaseSQL += ", ";
353 18 : osBaseSQL += OGRCARTOEscapeIdentifier(
354 18 : poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
355 : }
356 65 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
357 : {
358 50 : if (osBaseSQL.empty())
359 2 : osBaseSQL = "SELECT ";
360 : else
361 48 : osBaseSQL += ", ";
362 100 : osBaseSQL += OGRCARTOEscapeIdentifier(
363 100 : poFeatureDefn->GetFieldDefn(i)->GetNameRef());
364 : }
365 15 : if (osBaseSQL.empty())
366 4 : osBaseSQL = "SELECT *";
367 15 : osBaseSQL += " FROM ";
368 15 : osBaseSQL += OGRCARTOEscapeIdentifier(osName);
369 :
370 15 : osSELECTWithoutWHERE = osBaseSQL;
371 :
372 15 : return poFeatureDefn;
373 : }
374 :
375 : /************************************************************************/
376 : /* FetchNewFeatures() */
377 : /************************************************************************/
378 :
379 19 : json_object *OGRCARTOTableLayer::FetchNewFeatures()
380 : {
381 19 : if (!osFIDColName.empty())
382 : {
383 32 : CPLString osSQL;
384 : osSQL.Printf(
385 : "%s WHERE %s%s >= " CPL_FRMT_GIB " ORDER BY %s ASC LIMIT %d",
386 : osSELECTWithoutWHERE.c_str(),
387 21 : (osWHERE.size()) ? CPLSPrintf("%s AND ", osWHERE.c_str()) : "",
388 32 : OGRCARTOEscapeIdentifier(osFIDColName).c_str(), m_nNextFID,
389 32 : OGRCARTOEscapeIdentifier(osFIDColName).c_str(),
390 69 : GetFeaturesToFetch());
391 16 : return poDS->RunSQL(osSQL);
392 : }
393 : else
394 3 : return OGRCARTOLayer::FetchNewFeatures();
395 : }
396 :
397 : /************************************************************************/
398 : /* GetNextRawFeature() */
399 : /************************************************************************/
400 :
401 25 : OGRFeature *OGRCARTOTableLayer::GetNextRawFeature()
402 : {
403 25 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
404 1 : return nullptr;
405 24 : if (FlushDeferredBuffer() != OGRERR_NONE)
406 0 : return nullptr;
407 24 : return OGRCARTOLayer::GetNextRawFeature();
408 : }
409 :
410 : /************************************************************************/
411 : /* SetAttributeFilter() */
412 : /************************************************************************/
413 :
414 7 : OGRErr OGRCARTOTableLayer::SetAttributeFilter(const char *pszQuery)
415 :
416 : {
417 7 : GetLayerDefn();
418 :
419 7 : if (pszQuery == nullptr)
420 6 : osQuery = "";
421 : else
422 : {
423 1 : osQuery = "(";
424 1 : osQuery += pszQuery;
425 1 : osQuery += ")";
426 : }
427 :
428 7 : BuildWhere();
429 :
430 7 : ResetReading();
431 :
432 7 : return OGRERR_NONE;
433 : }
434 :
435 : /************************************************************************/
436 : /* ISetSpatialFilter() */
437 : /************************************************************************/
438 :
439 7 : OGRErr OGRCARTOTableLayer::ISetSpatialFilter(int iGeomField,
440 : const OGRGeometry *poGeomIn)
441 :
442 : {
443 7 : m_iGeomFieldFilter = iGeomField;
444 :
445 7 : if (InstallFilter(poGeomIn))
446 : {
447 1 : BuildWhere();
448 :
449 1 : ResetReading();
450 : }
451 :
452 7 : return OGRERR_NONE;
453 : }
454 :
455 : /************************************************************************/
456 : /* RunDeferredCartofy() */
457 : /************************************************************************/
458 :
459 23 : void OGRCARTOTableLayer::RunDeferredCartofy()
460 :
461 : {
462 23 : if (bCartodbfy)
463 : {
464 1 : bCartodbfy = false;
465 :
466 2 : CPLString osSQL;
467 1 : if (poDS->GetCurrentSchema() == "public")
468 : osSQL.Printf("SELECT cdb_cartodbfytable('%s')",
469 1 : OGRCARTOEscapeLiteral(osName).c_str());
470 : else
471 : osSQL.Printf(
472 : "SELECT cdb_cartodbfytable('%s', '%s')",
473 0 : OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
474 0 : OGRCARTOEscapeLiteral(osName).c_str());
475 :
476 1 : json_object *poObj = poDS->RunSQL(osSQL);
477 1 : if (poObj != nullptr)
478 1 : json_object_put(poObj);
479 : }
480 23 : }
481 :
482 : /************************************************************************/
483 : /* CARTOGeometryType() */
484 : /************************************************************************/
485 :
486 4 : static CPLString OGRCARTOGeometryType(OGRCartoGeomFieldDefn *poGeomField)
487 : {
488 4 : OGRwkbGeometryType eType = poGeomField->GetType();
489 4 : const char *pszGeometryType = OGRToOGCGeomType(eType);
490 4 : const char *suffix = "";
491 :
492 4 : if (OGR_GT_HasM(eType) && OGR_GT_HasZ(eType))
493 : {
494 0 : suffix = "ZM";
495 : }
496 4 : else if (OGR_GT_HasM(eType))
497 : {
498 0 : suffix = "M";
499 : }
500 4 : else if (OGR_GT_HasZ(eType))
501 : {
502 0 : suffix = "Z";
503 : }
504 :
505 4 : CPLString osSQL;
506 : osSQL.Printf("Geometry(%s%s,%d)", pszGeometryType, suffix,
507 4 : poGeomField->nSRID);
508 :
509 4 : return osSQL;
510 : }
511 :
512 : /************************************************************************/
513 : /* FlushDeferredBuffer() */
514 : /************************************************************************/
515 :
516 78 : OGRErr OGRCARTOTableLayer::FlushDeferredBuffer(bool bReset)
517 : {
518 78 : if (bCopyMode)
519 61 : return FlushDeferredCopy(bReset);
520 : else
521 17 : return FlushDeferredInsert(bReset);
522 : }
523 :
524 : /************************************************************************/
525 : /* FlushDeferredInsert() */
526 : /************************************************************************/
527 :
528 17 : OGRErr OGRCARTOTableLayer::FlushDeferredInsert(bool bReset)
529 : {
530 17 : OGRErr eErr = OGRERR_NONE;
531 17 : if (bInDeferredInsert && !osDeferredBuffer.empty())
532 : {
533 6 : osDeferredBuffer = "BEGIN;" + osDeferredBuffer;
534 6 : if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE)
535 : {
536 2 : osDeferredBuffer += ";";
537 2 : eDeferredInsertState = INSERT_UNINIT;
538 : }
539 6 : osDeferredBuffer += "COMMIT;";
540 :
541 6 : json_object *poObj = poDS->RunSQL(osDeferredBuffer);
542 6 : if (poObj != nullptr)
543 : {
544 5 : json_object_put(poObj);
545 : }
546 : else
547 : {
548 1 : bInDeferredInsert = false;
549 1 : eErr = OGRERR_FAILURE;
550 : }
551 : }
552 :
553 17 : osDeferredBuffer = "";
554 17 : if (bReset)
555 : {
556 16 : bInDeferredInsert = false;
557 16 : m_nNextFIDWrite = -1;
558 : }
559 17 : return eErr;
560 : }
561 :
562 : /************************************************************************/
563 : /* FlushDeferredCopy() */
564 : /************************************************************************/
565 :
566 61 : OGRErr OGRCARTOTableLayer::FlushDeferredCopy(bool bReset)
567 : {
568 61 : OGRErr eErr = OGRERR_NONE;
569 61 : if (!osDeferredBuffer.empty())
570 : {
571 : /* And end-of-file marker to data buffer */
572 2 : osDeferredBuffer += "\\.\n";
573 :
574 2 : json_object *poObj = poDS->RunCopyFrom(osCopySQL, osDeferredBuffer);
575 2 : if (poObj != nullptr)
576 : {
577 1 : json_object_put(poObj);
578 : }
579 : else
580 : {
581 1 : bInDeferredInsert = false;
582 1 : eErr = OGRERR_FAILURE;
583 : }
584 : }
585 :
586 61 : osDeferredBuffer.clear();
587 61 : if (bReset)
588 : {
589 60 : bInDeferredInsert = false;
590 60 : m_nNextFIDWrite = -1;
591 : }
592 61 : return eErr;
593 : }
594 :
595 : /************************************************************************/
596 : /* CreateGeomField() */
597 : /************************************************************************/
598 :
599 : OGRErr
600 0 : OGRCARTOTableLayer::CreateGeomField(const OGRGeomFieldDefn *poGeomFieldIn,
601 : CPL_UNUSED int bApproxOK)
602 : {
603 0 : if (!poDS->IsReadWrite())
604 : {
605 0 : CPLError(CE_Failure, CPLE_AppDefined,
606 : "Operation not available in read-only mode");
607 0 : return OGRERR_FAILURE;
608 : }
609 :
610 0 : OGRwkbGeometryType eType = poGeomFieldIn->GetType();
611 0 : if (eType == wkbNone)
612 : {
613 0 : CPLError(CE_Failure, CPLE_AppDefined,
614 : "Cannot create geometry field of type wkbNone");
615 0 : return OGRERR_FAILURE;
616 : }
617 :
618 0 : const char *pszNameIn = poGeomFieldIn->GetNameRef();
619 0 : if (pszNameIn == nullptr || EQUAL(pszNameIn, ""))
620 : {
621 0 : CPLError(CE_Failure, CPLE_AppDefined,
622 : "Cannot add un-named geometry field");
623 0 : return OGRERR_FAILURE;
624 : }
625 :
626 : /* Flush the write buffer before trying this. */
627 0 : if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE)
628 : {
629 0 : if (FlushDeferredBuffer() != OGRERR_NONE)
630 0 : return OGRERR_FAILURE;
631 : }
632 :
633 : auto poGeomField =
634 0 : std::make_unique<OGRCartoGeomFieldDefn>(pszNameIn, eType);
635 0 : if (EQUAL(poGeomField->GetNameRef(), ""))
636 : {
637 0 : if (poFeatureDefn->GetGeomFieldCount() == 0)
638 0 : poGeomField->SetName("the_geom");
639 : }
640 0 : const auto poSRSIn = poGeomFieldIn->GetSpatialRef();
641 0 : if (poSRSIn)
642 : {
643 0 : auto l_poSRS = poSRSIn->Clone();
644 0 : l_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
645 0 : poGeomField->SetSpatialRef(l_poSRS);
646 0 : l_poSRS->Release();
647 : }
648 :
649 0 : if (bLaunderColumnNames)
650 : {
651 : char *pszSafeName =
652 0 : OGRPGCommonLaunderName(poGeomField->GetNameRef(), "CARTO", false);
653 0 : poGeomField->SetName(pszSafeName);
654 0 : CPLFree(pszSafeName);
655 : }
656 :
657 0 : const OGRSpatialReference *poSRS = poGeomField->GetSpatialRef();
658 0 : int nSRID = 0;
659 0 : if (poSRS != nullptr)
660 0 : nSRID = poDS->FetchSRSId(poSRS);
661 :
662 0 : poGeomField->SetType(eType);
663 0 : poGeomField->SetNullable(poGeomFieldIn->IsNullable());
664 0 : poGeomField->nSRID = nSRID;
665 :
666 : /* -------------------------------------------------------------------- */
667 : /* Create the new field. */
668 : /* -------------------------------------------------------------------- */
669 :
670 0 : if (!bDeferredCreation)
671 : {
672 0 : CPLString osSQL;
673 : osSQL.Printf(
674 : "ALTER TABLE %s ADD COLUMN %s %s",
675 0 : OGRCARTOEscapeIdentifier(osName).c_str(),
676 0 : OGRCARTOEscapeIdentifier(poGeomField->GetNameRef()).c_str(),
677 0 : OGRCARTOGeometryType(poGeomField.get()).c_str());
678 0 : if (!poGeomField->IsNullable())
679 0 : osSQL += " NOT NULL";
680 :
681 0 : json_object *poObj = poDS->RunSQL(osSQL);
682 0 : if (poObj == nullptr)
683 0 : return OGRERR_FAILURE;
684 0 : json_object_put(poObj);
685 : }
686 :
687 0 : poFeatureDefn->AddGeomFieldDefn(std::move(poGeomField));
688 0 : return OGRERR_NONE;
689 : }
690 :
691 : /************************************************************************/
692 : /* CreateField() */
693 : /************************************************************************/
694 :
695 6 : OGRErr OGRCARTOTableLayer::CreateField(const OGRFieldDefn *poFieldIn,
696 : CPL_UNUSED int bApproxOK)
697 : {
698 6 : GetLayerDefn();
699 :
700 6 : if (!poDS->IsReadWrite())
701 : {
702 1 : CPLError(CE_Failure, CPLE_AppDefined,
703 : "Operation not available in read-only mode");
704 1 : return OGRERR_FAILURE;
705 : }
706 :
707 5 : if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE)
708 : {
709 0 : if (FlushDeferredBuffer() != OGRERR_NONE)
710 0 : return OGRERR_FAILURE;
711 : }
712 :
713 10 : OGRFieldDefn oField(poFieldIn);
714 5 : if (bLaunderColumnNames)
715 : {
716 : char *pszName =
717 5 : OGRPGCommonLaunderName(oField.GetNameRef(), "CARTO", false);
718 5 : oField.SetName(pszName);
719 5 : CPLFree(pszName);
720 : }
721 :
722 : /* -------------------------------------------------------------------- */
723 : /* Create the new field. */
724 : /* -------------------------------------------------------------------- */
725 :
726 5 : if (!bDeferredCreation)
727 : {
728 4 : CPLString osSQL;
729 : osSQL.Printf("ALTER TABLE %s ADD COLUMN %s %s",
730 8 : OGRCARTOEscapeIdentifier(osName).c_str(),
731 8 : OGRCARTOEscapeIdentifier(oField.GetNameRef()).c_str(),
732 16 : OGRPGCommonLayerGetType(oField, false, true).c_str());
733 4 : if (!oField.IsNullable())
734 0 : osSQL += " NOT NULL";
735 4 : if (oField.GetDefault() != nullptr && !oField.IsDefaultDriverSpecific())
736 : {
737 0 : osSQL += " DEFAULT ";
738 0 : osSQL += OGRPGCommonLayerGetPGDefault(&oField);
739 : }
740 :
741 4 : json_object *poObj = poDS->RunSQL(osSQL);
742 4 : if (poObj == nullptr)
743 1 : return OGRERR_FAILURE;
744 3 : json_object_put(poObj);
745 : }
746 :
747 4 : poFeatureDefn->AddFieldDefn(&oField);
748 :
749 4 : return OGRERR_NONE;
750 : }
751 :
752 : /************************************************************************/
753 : /* DeleteField() */
754 : /************************************************************************/
755 :
756 4 : OGRErr OGRCARTOTableLayer::DeleteField(int iField)
757 : {
758 8 : CPLString osSQL;
759 :
760 4 : if (!poDS->IsReadWrite())
761 : {
762 1 : CPLError(CE_Failure, CPLE_AppDefined,
763 : "Operation not available in read-only mode");
764 1 : return OGRERR_FAILURE;
765 : }
766 :
767 3 : if (iField < 0 || iField >= poFeatureDefn->GetFieldCount())
768 : {
769 1 : CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
770 1 : return OGRERR_FAILURE;
771 : }
772 :
773 2 : if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE)
774 : {
775 0 : if (FlushDeferredBuffer() != OGRERR_NONE)
776 0 : return OGRERR_FAILURE;
777 : }
778 :
779 : /* -------------------------------------------------------------------- */
780 : /* Drop the field. */
781 : /* -------------------------------------------------------------------- */
782 :
783 : osSQL.Printf("ALTER TABLE %s DROP COLUMN %s",
784 4 : OGRCARTOEscapeIdentifier(osName).c_str(),
785 4 : OGRCARTOEscapeIdentifier(
786 2 : poFeatureDefn->GetFieldDefn(iField)->GetNameRef())
787 4 : .c_str());
788 :
789 2 : json_object *poObj = poDS->RunSQL(osSQL);
790 2 : if (poObj == nullptr)
791 1 : return OGRERR_FAILURE;
792 1 : json_object_put(poObj);
793 :
794 1 : return poFeatureDefn->DeleteFieldDefn(iField);
795 : }
796 :
797 : /************************************************************************/
798 : /* ICreateFeature() */
799 : /************************************************************************/
800 :
801 16 : OGRErr OGRCARTOTableLayer::ICreateFeature(OGRFeature *poFeature)
802 :
803 : {
804 16 : if (bDeferredCreation)
805 : {
806 3 : if (RunDeferredCreationIfNecessary() != OGRERR_NONE)
807 1 : return OGRERR_FAILURE;
808 : }
809 :
810 15 : GetLayerDefn();
811 15 : bool bHasUserFieldMatchingFID = false;
812 15 : if (!osFIDColName.empty())
813 15 : bHasUserFieldMatchingFID =
814 15 : poFeatureDefn->GetFieldIndex(osFIDColName) >= 0;
815 :
816 15 : if (!poDS->IsReadWrite())
817 : {
818 1 : CPLError(CE_Failure, CPLE_AppDefined,
819 : "Operation not available in read-only mode");
820 1 : return OGRERR_FAILURE;
821 : }
822 :
823 28 : CPLString osSQL;
824 :
825 14 : bool bHasJustGotNextFID = false;
826 18 : if (!bHasUserFieldMatchingFID && bInDeferredInsert && m_nNextFIDWrite < 0 &&
827 4 : !osFIDColName.empty())
828 : {
829 8 : CPLString osSeqName;
830 : osSQL.Printf(
831 : "SELECT pg_catalog.pg_get_serial_sequence('%s', '%s') AS seq_name",
832 8 : OGRCARTOEscapeLiteral(osName).c_str(),
833 12 : OGRCARTOEscapeLiteral(osFIDColName).c_str());
834 4 : json_object *poObj = poDS->RunSQL(osSQL);
835 4 : json_object *poRowObj = OGRCARTOGetSingleRow(poObj);
836 4 : if (poRowObj != nullptr)
837 : {
838 : json_object *poSeqName =
839 4 : CPL_json_object_object_get(poRowObj, "seq_name");
840 8 : if (poSeqName != nullptr &&
841 4 : json_object_get_type(poSeqName) == json_type_string)
842 : {
843 4 : osSeqName = json_object_get_string(poSeqName);
844 : }
845 : }
846 :
847 4 : if (poObj != nullptr)
848 4 : json_object_put(poObj);
849 :
850 4 : if (!osSeqName.empty())
851 : {
852 : osSQL.Printf("SELECT nextval('%s') AS nextid",
853 4 : OGRCARTOEscapeLiteral(osSeqName).c_str());
854 :
855 4 : poObj = poDS->RunSQL(osSQL);
856 4 : poRowObj = OGRCARTOGetSingleRow(poObj);
857 4 : if (poRowObj != nullptr)
858 : {
859 : json_object *poID =
860 4 : CPL_json_object_object_get(poRowObj, "nextid");
861 8 : if (poID != nullptr &&
862 4 : json_object_get_type(poID) == json_type_int)
863 : {
864 4 : m_nNextFIDWrite = json_object_get_int64(poID);
865 4 : bHasJustGotNextFID = true;
866 : }
867 : }
868 :
869 4 : if (poObj != nullptr)
870 4 : json_object_put(poObj);
871 : }
872 : }
873 :
874 14 : if (bCopyMode)
875 2 : return ICreateFeatureCopy(poFeature, bHasUserFieldMatchingFID,
876 2 : bHasJustGotNextFID);
877 : else
878 12 : return ICreateFeatureInsert(poFeature, bHasUserFieldMatchingFID,
879 12 : bHasJustGotNextFID);
880 : }
881 :
882 : /************************************************************************/
883 : /* ICreateFeatureCopy() */
884 : /************************************************************************/
885 :
886 2 : OGRErr OGRCARTOTableLayer::ICreateFeatureCopy(OGRFeature *poFeature,
887 : bool bHasUserFieldMatchingFID,
888 : bool bHasJustGotNextFID)
889 : {
890 4 : CPLString osCopyFile;
891 2 : GetLayerDefn();
892 :
893 2 : if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE)
894 : {
895 1 : bool bReset = false;
896 1 : if (m_abFieldSetForInsert.size() !=
897 1 : static_cast<size_t>(poFeatureDefn->GetFieldCount()))
898 : {
899 0 : bReset = true;
900 : }
901 : else
902 : {
903 1 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
904 : {
905 2 : if (m_abFieldSetForInsert[i] !=
906 1 : CPL_TO_BOOL(poFeature->IsFieldSet(i)))
907 : {
908 1 : bReset = true;
909 1 : break;
910 : }
911 : }
912 : }
913 1 : if (bReset)
914 : {
915 1 : if (FlushDeferredBuffer(false) != OGRERR_NONE)
916 : {
917 0 : return OGRERR_FAILURE;
918 : }
919 1 : eDeferredInsertState = INSERT_UNINIT;
920 : }
921 : }
922 :
923 : /* We are doing a new COPY for each full buffer, so we will */
924 : /* construct a new COPY statement here, even though we could */
925 : /* reuse the same one over and over if we cached it (hmm) */
926 2 : if (eDeferredInsertState == INSERT_UNINIT)
927 : {
928 2 : osCopySQL.clear();
929 2 : osCopySQL.Printf("COPY %s ", OGRCARTOEscapeIdentifier(osName).c_str());
930 2 : bool bMustComma = false;
931 : /* Non-spatial column names */
932 2 : m_abFieldSetForInsert.resize(poFeatureDefn->GetFieldCount());
933 12 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
934 : {
935 : /* We base the columns we attempt to COPY based on */
936 : /* the set pattern of the first feature we see. */
937 10 : m_abFieldSetForInsert[i] = CPL_TO_BOOL(poFeature->IsFieldSet(i));
938 10 : if (!poFeature->IsFieldSet(i))
939 8 : continue;
940 :
941 2 : if (bMustComma)
942 0 : osCopySQL += ",";
943 : else
944 : {
945 2 : osCopySQL += "(";
946 2 : bMustComma = true;
947 : }
948 :
949 4 : osCopySQL += OGRCARTOEscapeIdentifier(
950 4 : poFeatureDefn->GetFieldDefn(i)->GetNameRef());
951 : }
952 : /* Geometry column names */
953 4 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
954 : {
955 2 : if (bMustComma)
956 2 : osCopySQL += ",";
957 : else
958 0 : bMustComma = true;
959 :
960 4 : osCopySQL += OGRCARTOEscapeIdentifier(
961 4 : poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
962 : }
963 : /* FID column */
964 6 : if (!bHasUserFieldMatchingFID && !osFIDColName.empty() &&
965 2 : (poFeature->GetFID() != OGRNullFID ||
966 2 : (m_nNextFIDWrite >= 0 && bHasJustGotNextFID)))
967 : {
968 1 : if (bMustComma)
969 1 : osCopySQL += ",";
970 : else
971 : {
972 0 : osCopySQL += "(";
973 0 : bMustComma = true;
974 : }
975 :
976 1 : osCopySQL += OGRCARTOEscapeIdentifier(osFIDColName);
977 : }
978 : /* No columns at all? Return an error! */
979 2 : if (!bMustComma)
980 0 : return OGRERR_FAILURE;
981 : else
982 2 : osCopySQL += ")";
983 :
984 2 : osCopySQL += " FROM STDIN WITH (FORMAT text, ENCODING UTF8)";
985 2 : CPLDebug("CARTO", "ICreateFeatureCopy(%s)", osCopySQL.c_str());
986 :
987 2 : eDeferredInsertState = INSERT_MULTIPLE_FEATURE;
988 : }
989 :
990 : /* Now write the data line into the copy file */
991 2 : bool bMustTab = false;
992 12 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
993 : {
994 : /* Unset fields get skipped (assuming same field set
995 : pattern as first input feature) */
996 10 : if (!poFeature->IsFieldSet(i))
997 8 : continue;
998 :
999 : /* Tab separator for 'text' format as necessary */
1000 2 : if (bMustTab)
1001 0 : osCopyFile += "\t";
1002 : else
1003 2 : bMustTab = true;
1004 :
1005 2 : OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
1006 : /* Null fields get a NULL marker */
1007 2 : if (poFeature->IsFieldNull(i))
1008 : {
1009 0 : osCopyFile += "\\N";
1010 : }
1011 2 : else if (eType == OFTString || eType == OFTDateTime ||
1012 1 : eType == OFTDate || eType == OFTTime)
1013 : {
1014 : /* Strip out tab and newline characters */
1015 1 : osCopyFile +=
1016 1 : OGRCARTOEscapeLiteralCopy(poFeature->GetFieldAsString(i));
1017 : }
1018 2 : else if ((eType == OFTInteger || eType == OFTInteger64) &&
1019 1 : poFeatureDefn->GetFieldDefn(i)->GetSubType() == OFSTBoolean)
1020 : {
1021 0 : osCopyFile += poFeature->GetFieldAsInteger(i) ? "t" : "f";
1022 : }
1023 : else
1024 1 : osCopyFile += poFeature->GetFieldAsString(i);
1025 : }
1026 :
1027 4 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
1028 : {
1029 2 : if (bMustTab)
1030 2 : osCopyFile += "\t";
1031 : else
1032 0 : bMustTab = true;
1033 :
1034 2 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
1035 2 : if (poGeom == nullptr)
1036 : {
1037 0 : osCopyFile += "\\N";
1038 0 : continue;
1039 : }
1040 :
1041 2 : char *pszEWKB = OGRCARTOGetHexGeometry(poGeom, i);
1042 2 : osCopyFile += pszEWKB;
1043 2 : CPLFree(pszEWKB);
1044 : }
1045 :
1046 2 : if (!bHasUserFieldMatchingFID && !osFIDColName.empty())
1047 : {
1048 2 : if (poFeature->GetFID() != OGRNullFID)
1049 : {
1050 0 : if (bMustTab)
1051 0 : osCopyFile += "\t";
1052 :
1053 0 : osCopyFile += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFID());
1054 : }
1055 2 : else if (m_nNextFIDWrite >= 0 && bHasJustGotNextFID)
1056 : {
1057 1 : if (bMustTab)
1058 1 : osCopyFile += "\t";
1059 :
1060 1 : osCopyFile += CPLSPrintf(CPL_FRMT_GIB, m_nNextFIDWrite);
1061 : }
1062 : }
1063 :
1064 : /* If we do have access to the FID (because we're incrementing it */
1065 : /* ourselves) set it onto the incoming feature so it knows what */
1066 : /* FID was supplied by the back-end. */
1067 2 : if (!bHasUserFieldMatchingFID && !osFIDColName.empty() &&
1068 4 : m_nNextFIDWrite >= 0 && poFeature->GetFID() == OGRNullFID)
1069 : {
1070 2 : poFeature->SetFID(m_nNextFIDWrite);
1071 2 : m_nNextFIDWrite++;
1072 : }
1073 :
1074 2 : OGRErr eRet = OGRERR_NONE;
1075 : /* Add current record to buffer */
1076 2 : osDeferredBuffer += osCopyFile;
1077 2 : osDeferredBuffer += "\n";
1078 2 : if ((int)osDeferredBuffer.size() > nMaxChunkSize)
1079 : {
1080 0 : eRet = FlushDeferredBuffer(false);
1081 0 : eDeferredInsertState = INSERT_UNINIT;
1082 : }
1083 :
1084 2 : return eRet;
1085 : }
1086 :
1087 : /************************************************************************/
1088 : /* ICreateFeatureInsert() */
1089 : /************************************************************************/
1090 :
1091 12 : OGRErr OGRCARTOTableLayer::ICreateFeatureInsert(OGRFeature *poFeature,
1092 : bool bHasUserFieldMatchingFID,
1093 : bool bHasJustGotNextFID)
1094 : {
1095 24 : CPLString osSQL;
1096 12 : GetLayerDefn();
1097 :
1098 : // Check if we can go on with multiple insertion mode
1099 12 : if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE)
1100 : {
1101 3 : if (!bHasUserFieldMatchingFID && !osFIDColName.empty() &&
1102 1 : (poFeature->GetFID() != OGRNullFID ||
1103 1 : (m_nNextFIDWrite >= 0 && bHasJustGotNextFID)))
1104 : {
1105 0 : if (FlushDeferredBuffer(false) != OGRERR_NONE)
1106 0 : return OGRERR_FAILURE;
1107 : }
1108 : }
1109 :
1110 12 : bool bWriteInsertInto = (eDeferredInsertState != INSERT_MULTIPLE_FEATURE);
1111 12 : bool bResetToUninitInsertStateAfterwards = false;
1112 12 : if (eDeferredInsertState == INSERT_UNINIT)
1113 : {
1114 8 : if (!bInDeferredInsert)
1115 : {
1116 0 : eDeferredInsertState = INSERT_SINGLE_FEATURE;
1117 : }
1118 23 : else if (!bHasUserFieldMatchingFID && !osFIDColName.empty() &&
1119 8 : (poFeature->GetFID() != OGRNullFID ||
1120 7 : (m_nNextFIDWrite >= 0 && bHasJustGotNextFID)))
1121 : {
1122 4 : eDeferredInsertState = INSERT_SINGLE_FEATURE;
1123 4 : bResetToUninitInsertStateAfterwards = true;
1124 : }
1125 : else
1126 : {
1127 4 : eDeferredInsertState = INSERT_MULTIPLE_FEATURE;
1128 17 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
1129 : {
1130 13 : if (poFeatureDefn->GetFieldDefn(i)->GetDefault() != nullptr)
1131 2 : eDeferredInsertState = INSERT_SINGLE_FEATURE;
1132 : }
1133 : }
1134 : }
1135 :
1136 12 : bool bMustComma = false;
1137 12 : if (bWriteInsertInto)
1138 : {
1139 : osSQL.Printf("INSERT INTO %s ",
1140 11 : OGRCARTOEscapeIdentifier(osName).c_str());
1141 48 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
1142 : {
1143 69 : if (eDeferredInsertState != INSERT_MULTIPLE_FEATURE &&
1144 32 : !poFeature->IsFieldSet(i))
1145 26 : continue;
1146 :
1147 11 : if (bMustComma)
1148 6 : osSQL += ", ";
1149 : else
1150 : {
1151 5 : osSQL += "(";
1152 5 : bMustComma = true;
1153 : }
1154 :
1155 22 : osSQL += OGRCARTOEscapeIdentifier(
1156 22 : poFeatureDefn->GetFieldDefn(i)->GetNameRef());
1157 : }
1158 :
1159 22 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
1160 : {
1161 20 : if (eDeferredInsertState != INSERT_MULTIPLE_FEATURE &&
1162 9 : poFeature->GetGeomFieldRef(i) == nullptr)
1163 8 : continue;
1164 :
1165 3 : if (bMustComma)
1166 2 : osSQL += ", ";
1167 : else
1168 : {
1169 1 : osSQL += "(";
1170 1 : bMustComma = true;
1171 : }
1172 :
1173 6 : osSQL += OGRCARTOEscapeIdentifier(
1174 6 : poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
1175 : }
1176 :
1177 32 : if (!bHasUserFieldMatchingFID && !osFIDColName.empty() &&
1178 11 : (poFeature->GetFID() != OGRNullFID ||
1179 10 : (m_nNextFIDWrite >= 0 && bHasJustGotNextFID)))
1180 : {
1181 4 : if (bMustComma)
1182 3 : osSQL += ", ";
1183 : else
1184 : {
1185 1 : osSQL += "(";
1186 1 : bMustComma = true;
1187 : }
1188 :
1189 4 : osSQL += OGRCARTOEscapeIdentifier(osFIDColName);
1190 : }
1191 :
1192 11 : if (!bMustComma && eDeferredInsertState == INSERT_MULTIPLE_FEATURE)
1193 0 : eDeferredInsertState = INSERT_SINGLE_FEATURE;
1194 : }
1195 :
1196 12 : if (!bMustComma && eDeferredInsertState == INSERT_SINGLE_FEATURE)
1197 4 : osSQL += "DEFAULT VALUES";
1198 : else
1199 : {
1200 8 : if (!bWriteInsertInto &&
1201 1 : eDeferredInsertState == INSERT_MULTIPLE_FEATURE)
1202 1 : osSQL += ", (";
1203 : else
1204 7 : osSQL += ") VALUES (";
1205 :
1206 8 : bMustComma = false;
1207 36 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
1208 : {
1209 28 : if (!poFeature->IsFieldSet(i))
1210 : {
1211 20 : if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE)
1212 : {
1213 8 : if (bMustComma)
1214 8 : osSQL += ", ";
1215 : else
1216 0 : bMustComma = true;
1217 8 : osSQL += "NULL";
1218 : }
1219 20 : continue;
1220 : }
1221 :
1222 8 : if (bMustComma)
1223 2 : osSQL += ", ";
1224 : else
1225 6 : bMustComma = true;
1226 :
1227 8 : OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
1228 8 : if (poFeature->IsFieldNull(i))
1229 : {
1230 1 : osSQL += "NULL";
1231 : }
1232 7 : else if (eType == OFTString || eType == OFTDateTime ||
1233 2 : eType == OFTDate || eType == OFTTime)
1234 : {
1235 5 : osSQL += "'";
1236 5 : osSQL += OGRCARTOEscapeLiteral(poFeature->GetFieldAsString(i));
1237 5 : osSQL += "'";
1238 : }
1239 4 : else if ((eType == OFTInteger || eType == OFTInteger64) &&
1240 2 : poFeatureDefn->GetFieldDefn(i)->GetSubType() ==
1241 : OFSTBoolean)
1242 : {
1243 1 : osSQL += poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'";
1244 : }
1245 : else
1246 1 : osSQL += poFeature->GetFieldAsString(i);
1247 : }
1248 :
1249 16 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
1250 : {
1251 8 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
1252 8 : if (poGeom == nullptr)
1253 : {
1254 6 : if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE)
1255 : {
1256 2 : if (bMustComma)
1257 2 : osSQL += ", ";
1258 : else
1259 0 : bMustComma = true;
1260 2 : osSQL += "NULL";
1261 : }
1262 6 : continue;
1263 : }
1264 :
1265 2 : if (bMustComma)
1266 1 : osSQL += ", ";
1267 : else
1268 1 : bMustComma = true;
1269 :
1270 2 : char *pszEWKB = OGRCARTOGetHexGeometry(poGeom, i);
1271 :
1272 2 : osSQL += "'";
1273 2 : osSQL += pszEWKB;
1274 2 : osSQL += "'";
1275 2 : CPLFree(pszEWKB);
1276 : }
1277 :
1278 15 : if (bWriteInsertInto && !bHasUserFieldMatchingFID &&
1279 7 : !osFIDColName.empty())
1280 : {
1281 7 : if (poFeature->GetFID() != OGRNullFID)
1282 : {
1283 1 : if (bMustComma)
1284 0 : osSQL += ", ";
1285 : // No need to set bMustComma to true in else case
1286 : // Not in a loop.
1287 :
1288 1 : osSQL += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFID());
1289 : }
1290 6 : else if (m_nNextFIDWrite >= 0 && bHasJustGotNextFID)
1291 : {
1292 3 : if (bMustComma)
1293 3 : osSQL += ", ";
1294 : // No need to set bMustComma to true in else case.
1295 : // Not in a loop.
1296 3 : osSQL += CPLSPrintf(CPL_FRMT_GIB, m_nNextFIDWrite);
1297 : }
1298 : }
1299 :
1300 8 : osSQL += ")";
1301 : }
1302 :
1303 12 : if (!bHasUserFieldMatchingFID && !osFIDColName.empty() &&
1304 24 : m_nNextFIDWrite >= 0 && poFeature->GetFID() == OGRNullFID)
1305 : {
1306 9 : poFeature->SetFID(m_nNextFIDWrite);
1307 9 : m_nNextFIDWrite++;
1308 : }
1309 :
1310 12 : if (bInDeferredInsert)
1311 : {
1312 9 : OGRErr eRet = OGRERR_NONE;
1313 : // In multiple mode, this would require rebuilding the osSQL
1314 : // buffer. Annoying.
1315 24 : if (eDeferredInsertState == INSERT_SINGLE_FEATURE &&
1316 10 : !osDeferredBuffer.empty() &&
1317 1 : (int)osDeferredBuffer.size() + (int)osSQL.size() > nMaxChunkSize)
1318 : {
1319 0 : eRet = FlushDeferredBuffer(false);
1320 : }
1321 :
1322 9 : osDeferredBuffer += osSQL;
1323 9 : if (eDeferredInsertState == INSERT_SINGLE_FEATURE)
1324 6 : osDeferredBuffer += ";";
1325 :
1326 9 : if ((int)osDeferredBuffer.size() > nMaxChunkSize)
1327 : {
1328 1 : eRet = FlushDeferredBuffer(false);
1329 : }
1330 :
1331 9 : if (bResetToUninitInsertStateAfterwards)
1332 4 : eDeferredInsertState = INSERT_UNINIT;
1333 :
1334 9 : return eRet;
1335 : }
1336 :
1337 3 : if (!osFIDColName.empty())
1338 : {
1339 3 : osSQL += " RETURNING ";
1340 3 : osSQL += OGRCARTOEscapeIdentifier(osFIDColName);
1341 :
1342 3 : json_object *poObj = poDS->RunSQL(osSQL);
1343 3 : json_object *poRowObj = OGRCARTOGetSingleRow(poObj);
1344 3 : if (poRowObj == nullptr)
1345 : {
1346 1 : if (poObj != nullptr)
1347 0 : json_object_put(poObj);
1348 1 : return OGRERR_FAILURE;
1349 : }
1350 :
1351 2 : json_object *poID = CPL_json_object_object_get(poRowObj, osFIDColName);
1352 2 : if (poID != nullptr && json_object_get_type(poID) == json_type_int)
1353 : {
1354 2 : poFeature->SetFID(json_object_get_int64(poID));
1355 : }
1356 :
1357 2 : if (poObj != nullptr)
1358 2 : json_object_put(poObj);
1359 :
1360 2 : return OGRERR_NONE;
1361 : }
1362 : else
1363 : {
1364 0 : OGRErr eRet = OGRERR_FAILURE;
1365 0 : json_object *poObj = poDS->RunSQL(osSQL);
1366 0 : if (poObj != nullptr)
1367 : {
1368 : json_object *poTotalRows =
1369 0 : CPL_json_object_object_get(poObj, "total_rows");
1370 0 : if (poTotalRows != nullptr &&
1371 0 : json_object_get_type(poTotalRows) == json_type_int)
1372 : {
1373 0 : int nTotalRows = json_object_get_int(poTotalRows);
1374 0 : if (nTotalRows == 1)
1375 : {
1376 0 : eRet = OGRERR_NONE;
1377 : }
1378 : }
1379 0 : json_object_put(poObj);
1380 : }
1381 :
1382 0 : return eRet;
1383 : }
1384 : }
1385 :
1386 : /************************************************************************/
1387 : /* ISetFeature() */
1388 : /************************************************************************/
1389 :
1390 5 : OGRErr OGRCARTOTableLayer::ISetFeature(OGRFeature *poFeature)
1391 :
1392 : {
1393 5 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
1394 0 : return OGRERR_FAILURE;
1395 5 : if (FlushDeferredBuffer() != OGRERR_NONE)
1396 0 : return OGRERR_FAILURE;
1397 :
1398 5 : GetLayerDefn();
1399 :
1400 5 : if (!poDS->IsReadWrite())
1401 : {
1402 1 : CPLError(CE_Failure, CPLE_AppDefined,
1403 : "Operation not available in read-only mode");
1404 1 : return OGRERR_FAILURE;
1405 : }
1406 :
1407 4 : if (poFeature->GetFID() == OGRNullFID)
1408 : {
1409 1 : CPLError(CE_Failure, CPLE_AppDefined,
1410 : "FID required on features given to SetFeature().");
1411 1 : return OGRERR_FAILURE;
1412 : }
1413 :
1414 6 : CPLString osSQL;
1415 3 : osSQL.Printf("UPDATE %s SET ", OGRCARTOEscapeIdentifier(osName).c_str());
1416 3 : bool bMustComma = false;
1417 12 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
1418 : {
1419 9 : if (!poFeature->IsFieldSet(i))
1420 0 : continue;
1421 :
1422 9 : if (bMustComma)
1423 6 : osSQL += ", ";
1424 : else
1425 3 : bMustComma = true;
1426 :
1427 18 : osSQL += OGRCARTOEscapeIdentifier(
1428 18 : poFeatureDefn->GetFieldDefn(i)->GetNameRef());
1429 9 : osSQL += " = ";
1430 :
1431 9 : if (poFeature->IsFieldNull(i))
1432 : {
1433 0 : osSQL += "NULL";
1434 : }
1435 : else
1436 : {
1437 9 : OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
1438 9 : if (eType == OFTString || eType == OFTDateTime ||
1439 6 : eType == OFTDate || eType == OFTTime)
1440 : {
1441 3 : osSQL += "'";
1442 3 : osSQL += OGRCARTOEscapeLiteral(poFeature->GetFieldAsString(i));
1443 3 : osSQL += "'";
1444 : }
1445 12 : else if ((eType == OFTInteger || eType == OFTInteger64) &&
1446 6 : poFeatureDefn->GetFieldDefn(i)->GetSubType() ==
1447 : OFSTBoolean)
1448 : {
1449 3 : osSQL += poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'";
1450 : }
1451 : else
1452 3 : osSQL += poFeature->GetFieldAsString(i);
1453 : }
1454 : }
1455 :
1456 6 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
1457 : {
1458 3 : if (bMustComma)
1459 3 : osSQL += ", ";
1460 : else
1461 0 : bMustComma = true;
1462 :
1463 6 : osSQL += OGRCARTOEscapeIdentifier(
1464 6 : poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
1465 3 : osSQL += " = ";
1466 :
1467 3 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
1468 3 : if (poGeom == nullptr)
1469 : {
1470 0 : osSQL += "NULL";
1471 : }
1472 : else
1473 : {
1474 : OGRCartoGeomFieldDefn *poGeomFieldDefn =
1475 3 : cpl::down_cast<OGRCartoGeomFieldDefn *>(
1476 3 : poFeatureDefn->GetGeomFieldDefn(i));
1477 3 : int nSRID = poGeomFieldDefn->nSRID;
1478 3 : if (nSRID == 0)
1479 0 : nSRID = 4326;
1480 : char *pszEWKB =
1481 3 : OGRGeometryToHexEWKB(poGeom, nSRID, poDS->GetPostGISMajor(),
1482 3 : poDS->GetPostGISMinor());
1483 3 : osSQL += "'";
1484 3 : osSQL += pszEWKB;
1485 3 : osSQL += "'";
1486 3 : CPLFree(pszEWKB);
1487 : }
1488 : }
1489 :
1490 3 : if (!bMustComma) // nothing to do
1491 0 : return OGRERR_NONE;
1492 :
1493 : osSQL += CPLSPrintf(" WHERE %s = " CPL_FRMT_GIB,
1494 6 : OGRCARTOEscapeIdentifier(osFIDColName).c_str(),
1495 6 : poFeature->GetFID());
1496 :
1497 3 : OGRErr eRet = OGRERR_FAILURE;
1498 3 : json_object *poObj = poDS->RunSQL(osSQL);
1499 3 : if (poObj != nullptr)
1500 : {
1501 : json_object *poTotalRows =
1502 2 : CPL_json_object_object_get(poObj, "total_rows");
1503 4 : if (poTotalRows != nullptr &&
1504 2 : json_object_get_type(poTotalRows) == json_type_int)
1505 : {
1506 2 : int nTotalRows = json_object_get_int(poTotalRows);
1507 2 : if (nTotalRows > 0)
1508 : {
1509 1 : eRet = OGRERR_NONE;
1510 : }
1511 : else
1512 1 : eRet = OGRERR_NON_EXISTING_FEATURE;
1513 : }
1514 2 : json_object_put(poObj);
1515 : }
1516 :
1517 3 : return eRet;
1518 : }
1519 :
1520 : /************************************************************************/
1521 : /* DeleteFeature() */
1522 : /************************************************************************/
1523 :
1524 4 : OGRErr OGRCARTOTableLayer::DeleteFeature(GIntBig nFID)
1525 :
1526 : {
1527 :
1528 4 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
1529 0 : return OGRERR_FAILURE;
1530 4 : if (FlushDeferredBuffer() != OGRERR_NONE)
1531 0 : return OGRERR_FAILURE;
1532 :
1533 4 : GetLayerDefn();
1534 :
1535 4 : if (!poDS->IsReadWrite())
1536 : {
1537 1 : CPLError(CE_Failure, CPLE_AppDefined,
1538 : "Operation not available in read-only mode");
1539 1 : return OGRERR_FAILURE;
1540 : }
1541 :
1542 3 : if (osFIDColName.empty())
1543 0 : return OGRERR_FAILURE;
1544 :
1545 3 : CPLString osSQL;
1546 : osSQL.Printf("DELETE FROM %s WHERE %s = " CPL_FRMT_GIB,
1547 6 : OGRCARTOEscapeIdentifier(osName).c_str(),
1548 9 : OGRCARTOEscapeIdentifier(osFIDColName).c_str(), nFID);
1549 :
1550 3 : OGRErr eRet = OGRERR_FAILURE;
1551 3 : json_object *poObj = poDS->RunSQL(osSQL);
1552 3 : if (poObj != nullptr)
1553 : {
1554 : json_object *poTotalRows =
1555 2 : CPL_json_object_object_get(poObj, "total_rows");
1556 4 : if (poTotalRows != nullptr &&
1557 2 : json_object_get_type(poTotalRows) == json_type_int)
1558 : {
1559 2 : int nTotalRows = json_object_get_int(poTotalRows);
1560 2 : if (nTotalRows > 0)
1561 : {
1562 1 : eRet = OGRERR_NONE;
1563 : }
1564 : else
1565 1 : eRet = OGRERR_NON_EXISTING_FEATURE;
1566 : }
1567 2 : json_object_put(poObj);
1568 : }
1569 :
1570 3 : return eRet;
1571 : }
1572 :
1573 : /************************************************************************/
1574 : /* GetSRS_SQL() */
1575 : /************************************************************************/
1576 :
1577 0 : CPLString OGRCARTOTableLayer::GetSRS_SQL(const char *pszGeomCol)
1578 : {
1579 0 : CPLString osSQL;
1580 :
1581 : osSQL.Printf("SELECT srid, srtext FROM spatial_ref_sys WHERE srid IN "
1582 : "(SELECT Find_SRID('%s', '%s', '%s'))",
1583 0 : OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
1584 0 : OGRCARTOEscapeLiteral(osName).c_str(),
1585 0 : OGRCARTOEscapeLiteral(pszGeomCol).c_str());
1586 :
1587 0 : return osSQL;
1588 : }
1589 :
1590 : /************************************************************************/
1591 : /* BuildWhere() */
1592 : /* */
1593 : /* Build the WHERE statement appropriate to the current set of */
1594 : /* criteria (spatial and attribute queries). */
1595 : /************************************************************************/
1596 :
1597 8 : void OGRCARTOTableLayer::BuildWhere()
1598 :
1599 : {
1600 8 : osWHERE = "";
1601 :
1602 9 : if (m_poFilterGeom != nullptr && m_iGeomFieldFilter >= 0 &&
1603 1 : m_iGeomFieldFilter < poFeatureDefn->GetGeomFieldCount())
1604 : {
1605 1 : OGREnvelope sEnvelope;
1606 :
1607 1 : m_poFilterGeom->getEnvelope(&sEnvelope);
1608 :
1609 : CPLString osGeomColumn(
1610 1 : poFeatureDefn->GetGeomFieldDefn(m_iGeomFieldFilter)->GetNameRef());
1611 :
1612 : char szBox3D_1[128];
1613 : char szBox3D_2[128];
1614 : char *pszComma;
1615 :
1616 1 : CPLsnprintf(szBox3D_1, sizeof(szBox3D_1), "%.17g %.17g", sEnvelope.MinX,
1617 : sEnvelope.MinY);
1618 1 : while ((pszComma = strchr(szBox3D_1, ',')) != nullptr)
1619 0 : *pszComma = '.';
1620 1 : CPLsnprintf(szBox3D_2, sizeof(szBox3D_2), "%.17g %.17g", sEnvelope.MaxX,
1621 : sEnvelope.MaxY);
1622 1 : while ((pszComma = strchr(szBox3D_2, ',')) != nullptr)
1623 0 : *pszComma = '.';
1624 : osWHERE.Printf("(%s && 'BOX3D(%s, %s)'::box3d)",
1625 2 : OGRCARTOEscapeIdentifier(osGeomColumn).c_str(),
1626 2 : szBox3D_1, szBox3D_2);
1627 : }
1628 :
1629 8 : if (!osQuery.empty())
1630 : {
1631 2 : if (!osWHERE.empty())
1632 1 : osWHERE += " AND ";
1633 2 : osWHERE += osQuery;
1634 : }
1635 :
1636 8 : if (osFIDColName.empty())
1637 : {
1638 2 : osBaseSQL = osSELECTWithoutWHERE;
1639 2 : if (!osWHERE.empty())
1640 : {
1641 0 : osBaseSQL += " WHERE ";
1642 0 : osBaseSQL += osWHERE;
1643 : }
1644 : }
1645 8 : }
1646 :
1647 : /************************************************************************/
1648 : /* GetFeature() */
1649 : /************************************************************************/
1650 :
1651 5 : OGRFeature *OGRCARTOTableLayer::GetFeature(GIntBig nFeatureId)
1652 : {
1653 :
1654 5 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
1655 0 : return nullptr;
1656 5 : if (FlushDeferredBuffer() != OGRERR_NONE)
1657 0 : return nullptr;
1658 :
1659 5 : GetLayerDefn();
1660 :
1661 5 : if (osFIDColName.empty())
1662 1 : return OGRCARTOLayer::GetFeature(nFeatureId);
1663 :
1664 8 : CPLString osSQL = osSELECTWithoutWHERE;
1665 4 : osSQL += " WHERE ";
1666 4 : osSQL += OGRCARTOEscapeIdentifier(osFIDColName).c_str();
1667 4 : osSQL += " = ";
1668 4 : osSQL += CPLSPrintf(CPL_FRMT_GIB, nFeatureId);
1669 :
1670 4 : json_object *poObj = poDS->RunSQL(osSQL);
1671 4 : json_object *poRowObj = OGRCARTOGetSingleRow(poObj);
1672 4 : if (poRowObj == nullptr)
1673 : {
1674 2 : if (poObj != nullptr)
1675 0 : json_object_put(poObj);
1676 2 : return OGRCARTOLayer::GetFeature(nFeatureId);
1677 : }
1678 :
1679 2 : OGRFeature *poFeature = BuildFeature(poRowObj);
1680 2 : json_object_put(poObj);
1681 :
1682 2 : return poFeature;
1683 : }
1684 :
1685 : /************************************************************************/
1686 : /* GetFeatureCount() */
1687 : /************************************************************************/
1688 :
1689 9 : GIntBig OGRCARTOTableLayer::GetFeatureCount(int bForce)
1690 : {
1691 :
1692 9 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
1693 0 : return 0;
1694 9 : if (FlushDeferredBuffer() != OGRERR_NONE)
1695 0 : return 0;
1696 :
1697 9 : GetLayerDefn();
1698 :
1699 : CPLString osSQL(CPLSPrintf("SELECT COUNT(*) FROM %s",
1700 18 : OGRCARTOEscapeIdentifier(osName).c_str()));
1701 9 : if (!osWHERE.empty())
1702 : {
1703 5 : osSQL += " WHERE ";
1704 5 : osSQL += osWHERE;
1705 : }
1706 :
1707 9 : json_object *poObj = poDS->RunSQL(osSQL);
1708 9 : json_object *poRowObj = OGRCARTOGetSingleRow(poObj);
1709 9 : if (poRowObj == nullptr)
1710 : {
1711 5 : if (poObj != nullptr)
1712 1 : json_object_put(poObj);
1713 5 : return OGRCARTOLayer::GetFeatureCount(bForce);
1714 : }
1715 :
1716 4 : json_object *poCount = CPL_json_object_object_get(poRowObj, "count");
1717 4 : if (poCount == nullptr || json_object_get_type(poCount) != json_type_int)
1718 : {
1719 1 : json_object_put(poObj);
1720 1 : return OGRCARTOLayer::GetFeatureCount(bForce);
1721 : }
1722 :
1723 3 : GIntBig nRet = (GIntBig)json_object_get_int64(poCount);
1724 :
1725 3 : json_object_put(poObj);
1726 :
1727 3 : return nRet;
1728 : }
1729 :
1730 : /************************************************************************/
1731 : /* IGetExtent() */
1732 : /* */
1733 : /* For PostGIS use internal Extend(geometry) function */
1734 : /* in other cases we use standard OGRLayer::IGetExtent() */
1735 : /************************************************************************/
1736 :
1737 6 : OGRErr OGRCARTOTableLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
1738 : bool bForce)
1739 : {
1740 12 : CPLString osSQL;
1741 :
1742 6 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
1743 0 : return OGRERR_FAILURE;
1744 6 : if (FlushDeferredBuffer() != OGRERR_NONE)
1745 0 : return OGRERR_FAILURE;
1746 :
1747 : OGRGeomFieldDefn *poGeomFieldDefn =
1748 6 : poFeatureDefn->GetGeomFieldDefn(iGeomField);
1749 :
1750 : /* Do not take the spatial filter into account */
1751 : osSQL.Printf(
1752 : "SELECT ST_Extent(%s) FROM %s",
1753 12 : OGRCARTOEscapeIdentifier(poGeomFieldDefn->GetNameRef()).c_str(),
1754 18 : OGRCARTOEscapeIdentifier(osName).c_str());
1755 :
1756 6 : json_object *poObj = poDS->RunSQL(osSQL);
1757 6 : json_object *poRowObj = OGRCARTOGetSingleRow(poObj);
1758 6 : if (poRowObj != nullptr)
1759 : {
1760 : json_object *poExtent =
1761 5 : CPL_json_object_object_get(poRowObj, "st_extent");
1762 9 : if (poExtent != nullptr &&
1763 4 : json_object_get_type(poExtent) == json_type_string)
1764 : {
1765 4 : const char *pszBox = json_object_get_string(poExtent);
1766 : const char *ptr, *ptrEndParenthesis;
1767 : char szVals[64 * 6 + 6];
1768 :
1769 4 : ptr = strchr(pszBox, '(');
1770 4 : if (ptr)
1771 3 : ptr++;
1772 7 : if (ptr == nullptr ||
1773 6 : (ptrEndParenthesis = strchr(ptr, ')')) == nullptr ||
1774 2 : ptrEndParenthesis - ptr > (int)(sizeof(szVals) - 1))
1775 : {
1776 2 : CPLError(CE_Failure, CPLE_IllegalArg,
1777 : "Bad extent representation: '%s'", pszBox);
1778 :
1779 2 : json_object_put(poObj);
1780 2 : return OGRERR_FAILURE;
1781 : }
1782 :
1783 2 : strncpy(szVals, ptr, ptrEndParenthesis - ptr);
1784 2 : szVals[ptrEndParenthesis - ptr] = '\0';
1785 :
1786 : char **papszTokens =
1787 2 : CSLTokenizeString2(szVals, " ,", CSLT_HONOURSTRINGS);
1788 2 : int nTokenCnt = 4;
1789 :
1790 2 : if (CSLCount(papszTokens) != nTokenCnt)
1791 : {
1792 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1793 : "Bad extent representation: '%s'", pszBox);
1794 1 : CSLDestroy(papszTokens);
1795 :
1796 1 : json_object_put(poObj);
1797 1 : return OGRERR_FAILURE;
1798 : }
1799 :
1800 : // Take X,Y coords
1801 : // For PostGIS ver >= 1.0.0 -> Tokens: X1 Y1 X2 Y2 (nTokenCnt = 4)
1802 : // For PostGIS ver < 1.0.0 -> Tokens: X1 Y1 Z1 X2 Y2 Z2 (nTokenCnt =
1803 : // 6)
1804 : // => X2 index calculated as nTokenCnt/2
1805 : // Y2 index calculated as nTokenCnt/2+1
1806 :
1807 1 : psExtent->MinX = CPLAtof(papszTokens[0]);
1808 1 : psExtent->MinY = CPLAtof(papszTokens[1]);
1809 1 : psExtent->MaxX = CPLAtof(papszTokens[nTokenCnt / 2]);
1810 1 : psExtent->MaxY = CPLAtof(papszTokens[nTokenCnt / 2 + 1]);
1811 :
1812 1 : CSLDestroy(papszTokens);
1813 :
1814 1 : json_object_put(poObj);
1815 1 : return OGRERR_NONE;
1816 : }
1817 : }
1818 :
1819 2 : if (poObj != nullptr)
1820 1 : json_object_put(poObj);
1821 :
1822 2 : return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
1823 : }
1824 :
1825 : /************************************************************************/
1826 : /* TestCapability() */
1827 : /************************************************************************/
1828 :
1829 16 : int OGRCARTOTableLayer::TestCapability(const char *pszCap)
1830 :
1831 : {
1832 16 : if (EQUAL(pszCap, OLCFastFeatureCount))
1833 0 : return TRUE;
1834 16 : if (EQUAL(pszCap, OLCFastGetExtent))
1835 0 : return TRUE;
1836 16 : if (EQUAL(pszCap, OLCRandomRead))
1837 : {
1838 0 : GetLayerDefn();
1839 0 : return !osFIDColName.empty();
1840 : }
1841 :
1842 16 : if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCRandomWrite) ||
1843 16 : EQUAL(pszCap, OLCDeleteFeature) || EQUAL(pszCap, OLCCreateField) ||
1844 16 : EQUAL(pszCap, OLCDeleteField) || EQUAL(pszCap, OLCCreateGeomField))
1845 : {
1846 0 : return poDS->IsReadWrite();
1847 : }
1848 :
1849 16 : return OGRCARTOLayer::TestCapability(pszCap);
1850 : }
1851 :
1852 : /************************************************************************/
1853 : /* SetDeferredCreation() */
1854 : /************************************************************************/
1855 :
1856 4 : void OGRCARTOTableLayer::SetDeferredCreation(OGRwkbGeometryType eGType,
1857 : OGRSpatialReference *poSRSIn,
1858 : bool bGeomNullable,
1859 : bool bCartodbfyIn)
1860 : {
1861 4 : bDeferredCreation = true;
1862 4 : m_nNextFIDWrite = 1;
1863 4 : CPLAssert(poFeatureDefn == nullptr);
1864 4 : bCartodbfy = bCartodbfyIn;
1865 4 : poFeatureDefn = new OGRFeatureDefn(osName);
1866 4 : poFeatureDefn->Reference();
1867 4 : poFeatureDefn->SetGeomType(wkbNone);
1868 4 : if (eGType == wkbPolygon)
1869 2 : eGType = wkbMultiPolygon;
1870 2 : else if (eGType == wkbPolygon25D)
1871 0 : eGType = wkbMultiPolygon25D;
1872 4 : if (eGType != wkbNone)
1873 : {
1874 : auto poFieldDefn =
1875 4 : std::make_unique<OGRCartoGeomFieldDefn>("the_geom", eGType);
1876 4 : poFieldDefn->SetNullable(bGeomNullable);
1877 4 : if (poSRSIn != nullptr)
1878 : {
1879 1 : poFieldDefn->nSRID = poDS->FetchSRSId(poSRSIn);
1880 1 : poFieldDefn->SetSpatialRef(poSRSIn);
1881 : }
1882 4 : poFeatureDefn->AddGeomFieldDefn(std::move(poFieldDefn));
1883 : }
1884 4 : osFIDColName = "cartodb_id";
1885 : osBaseSQL.Printf("SELECT * FROM %s",
1886 4 : OGRCARTOEscapeIdentifier(osName).c_str());
1887 4 : osSELECTWithoutWHERE = osBaseSQL;
1888 4 : }
1889 :
1890 : /************************************************************************/
1891 : /* RunDeferredCreationIfNecessary() */
1892 : /************************************************************************/
1893 :
1894 5 : OGRErr OGRCARTOTableLayer::RunDeferredCreationIfNecessary()
1895 : {
1896 5 : if (!bDeferredCreation)
1897 1 : return OGRERR_NONE;
1898 4 : bDeferredCreation = false;
1899 :
1900 8 : CPLString osSQL;
1901 4 : CPLDebug("CARTO", "Overwrite on creation (%d)", bDropOnCreation);
1902 4 : if (bDropOnCreation)
1903 : osSQL.Printf("BEGIN; DROP TABLE IF EXISTS %s;",
1904 2 : OGRCARTOEscapeIdentifier(osName).c_str());
1905 :
1906 : osSQL += CPLSPrintf("CREATE TABLE %s ( %s SERIAL,",
1907 8 : OGRCARTOEscapeIdentifier(osName).c_str(),
1908 8 : osFIDColName.c_str());
1909 :
1910 8 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
1911 : {
1912 : OGRCartoGeomFieldDefn *poFieldDefn =
1913 4 : cpl::down_cast<OGRCartoGeomFieldDefn *>(
1914 4 : poFeatureDefn->GetGeomFieldDefn(i));
1915 4 : OGRwkbGeometryType eGType = poFieldDefn->GetType();
1916 4 : if (eGType == wkbNone)
1917 0 : continue;
1918 :
1919 4 : const char *pszFieldName = "the_geom";
1920 :
1921 4 : if (i > 0)
1922 0 : pszFieldName = poFieldDefn->GetNameRef();
1923 :
1924 4 : if (pszFieldName == nullptr || strlen(pszFieldName) == 0)
1925 0 : return OGRERR_FAILURE;
1926 :
1927 : osSQL += CPLSPrintf("%s %s%s,", pszFieldName,
1928 8 : OGRCARTOGeometryType(poFieldDefn).c_str(),
1929 8 : (!poFieldDefn->IsNullable()) ? " NOT NULL" : "");
1930 : }
1931 :
1932 5 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
1933 : {
1934 1 : OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(i);
1935 1 : if (strcmp(poFieldDefn->GetNameRef(), osFIDColName) != 0)
1936 : {
1937 1 : osSQL += OGRCARTOEscapeIdentifier(poFieldDefn->GetNameRef());
1938 1 : osSQL += " ";
1939 1 : osSQL += OGRPGCommonLayerGetType(*poFieldDefn, false, true);
1940 1 : if (!poFieldDefn->IsNullable())
1941 1 : osSQL += " NOT NULL";
1942 2 : if (poFieldDefn->GetDefault() != nullptr &&
1943 1 : !poFieldDefn->IsDefaultDriverSpecific())
1944 : {
1945 1 : osSQL += " DEFAULT ";
1946 1 : osSQL += poFieldDefn->GetDefault();
1947 : }
1948 1 : osSQL += ",";
1949 : }
1950 : }
1951 :
1952 4 : osSQL += CPLSPrintf("PRIMARY KEY (%s) )", osFIDColName.c_str());
1953 :
1954 : CPLString osSeqName(OGRCARTOEscapeIdentifier(
1955 8 : CPLSPrintf("%s_%s_seq", osName.c_str(), osFIDColName.c_str())));
1956 :
1957 4 : osSQL += ";";
1958 : osSQL +=
1959 4 : CPLSPrintf("DROP SEQUENCE IF EXISTS %s CASCADE", osSeqName.c_str());
1960 4 : osSQL += ";";
1961 4 : osSQL += CPLSPrintf("CREATE SEQUENCE %s START 1", osSeqName.c_str());
1962 4 : osSQL += ";";
1963 : osSQL += CPLSPrintf("ALTER SEQUENCE %s OWNED BY %s.%s", osSeqName.c_str(),
1964 8 : OGRCARTOEscapeIdentifier(osName).c_str(),
1965 8 : osFIDColName.c_str());
1966 4 : osSQL += ";";
1967 : osSQL +=
1968 : CPLSPrintf("ALTER TABLE %s ALTER COLUMN %s SET DEFAULT nextval('%s')",
1969 8 : OGRCARTOEscapeIdentifier(osName).c_str(),
1970 8 : osFIDColName.c_str(), osSeqName.c_str());
1971 :
1972 4 : if (bDropOnCreation)
1973 2 : osSQL += "; COMMIT;";
1974 :
1975 4 : bDropOnCreation = false;
1976 :
1977 4 : json_object *poObj = poDS->RunSQL(osSQL);
1978 4 : if (poObj == nullptr)
1979 2 : return OGRERR_FAILURE;
1980 2 : json_object_put(poObj);
1981 :
1982 2 : return OGRERR_NONE;
1983 : }
|