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