Coverage Report

Created: 2026-05-16 08:20

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