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