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