1 /******************************************************************************
2  * $Id: ogrcartodbtablelayer.cpp 29004 2015-04-25 08:38:29Z rouault $
3  *
4  * Project:  CartoDB Translator
5  * Purpose:  Implements OGRCARTODBTableLayer class.
6  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
7  *
8  ******************************************************************************
9  * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  ****************************************************************************/
29 
30 #include "ogr_cartodb.h"
31 #include "ogr_p.h"
32 #include "ogr_pgdump.h"
33 
34 CPL_CVSID("$Id: ogrcartodbtablelayer.cpp 29004 2015-04-25 08:38:29Z rouault $");
35 
36 /************************************************************************/
37 /*                    OGRCARTODBEscapeIdentifier( )                     */
38 /************************************************************************/
39 
OGRCARTODBEscapeIdentifier(const char * pszStr)40 CPLString OGRCARTODBEscapeIdentifier(const char* pszStr)
41 {
42     CPLString osStr;
43 
44     osStr += "\"";
45 
46     char ch;
47     for(int i=0; (ch = pszStr[i]) != '\0'; i++)
48     {
49         if (ch == '"')
50             osStr.append(1, ch);
51         osStr.append(1, ch);
52     }
53 
54     osStr += "\"";
55 
56     return osStr;
57 }
58 
59 /************************************************************************/
60 /*                    OGRCARTODBEscapeLiteral( )                        */
61 /************************************************************************/
62 
OGRCARTODBEscapeLiteral(const char * pszStr)63 CPLString OGRCARTODBEscapeLiteral(const char* pszStr)
64 {
65     CPLString osStr;
66 
67     char ch;
68     for(int i=0; (ch = pszStr[i]) != '\0'; i++)
69     {
70         if (ch == '\'')
71             osStr.append(1, ch);
72         osStr.append(1, ch);
73     }
74 
75     return osStr;
76 }
77 
78 /************************************************************************/
79 /*                        OGRCARTODBTableLayer()                        */
80 /************************************************************************/
81 
OGRCARTODBTableLayer(OGRCARTODBDataSource * poDS,const char * pszName)82 OGRCARTODBTableLayer::OGRCARTODBTableLayer(OGRCARTODBDataSource* poDS,
83                                            const char* pszName) :
84                                            OGRCARTODBLayer(poDS)
85 
86 {
87     osName = pszName;
88     SetDescription( osName );
89     bLaunderColumnNames = TRUE;
90     bInDeferedInsert = poDS->DoBatchInsert();
91     nNextFID = -1;
92     bDeferedCreation = FALSE;
93     bCartoDBify = FALSE;
94     nMaxChunkSize = atoi(CPLGetConfigOption("CARTODB_MAX_CHUNK_SIZE", "15")) * 1024 * 1024;
95 }
96 
97 /************************************************************************/
98 /*                    ~OGRCARTODBTableLayer()                           */
99 /************************************************************************/
100 
~OGRCARTODBTableLayer()101 OGRCARTODBTableLayer::~OGRCARTODBTableLayer()
102 
103 {
104     if( bDeferedCreation ) RunDeferedCreationIfNecessary();
105     FlushDeferedInsert();
106 }
107 
108 /************************************************************************/
109 /*                          GetLayerDefnInternal()                      */
110 /************************************************************************/
111 
GetLayerDefnInternal(CPL_UNUSED json_object * poObjIn)112 OGRFeatureDefn * OGRCARTODBTableLayer::GetLayerDefnInternal(CPL_UNUSED json_object* poObjIn)
113 {
114     if( poFeatureDefn != NULL )
115         return poFeatureDefn;
116 
117     CPLString osCommand;
118     if( poDS->IsAuthenticatedConnection() )
119     {
120         // Get everything !
121         osCommand.Printf(
122                  "SELECT a.attname, t.typname, a.attlen, "
123                         "format_type(a.atttypid,a.atttypmod), "
124                         "a.attnum, "
125                         "a.attnotnull, "
126                         "i.indisprimary, "
127                         "pg_get_expr(def.adbin, c.oid) AS defaultexpr, "
128                         "postgis_typmod_dims(a.atttypmod) dim, "
129                         "postgis_typmod_srid(a.atttypmod) srid, "
130                         "postgis_typmod_type(a.atttypmod)::text geomtyp, "
131                         "srtext "
132                  "FROM pg_class c "
133                  "JOIN pg_attribute a ON a.attnum > 0 AND "
134                                         "a.attrelid = c.oid AND c.relname = '%s' "
135                  "JOIN pg_type t ON a.atttypid = t.oid "
136                  "JOIN pg_namespace n ON c.relnamespace=n.oid AND n.nspname= '%s' "
137                  "LEFT JOIN pg_index i ON c.oid = i.indrelid AND "
138                                          "i.indisprimary = 't' AND a.attnum = ANY(i.indkey) "
139                  "LEFT JOIN pg_attrdef def ON def.adrelid = c.oid AND "
140                                               "def.adnum = a.attnum "
141                  "LEFT JOIN spatial_ref_sys srs ON srs.srid = postgis_typmod_srid(a.atttypmod) "
142                  "ORDER BY a.attnum",
143                  OGRCARTODBEscapeLiteral(osName).c_str(),
144                  OGRCARTODBEscapeLiteral(poDS->GetCurrentSchema()).c_str());
145     }
146     else if( poDS->HasOGRMetadataFunction() != FALSE )
147     {
148         osCommand.Printf( "SELECT * FROM ogr_table_metadata('%s', '%s')",
149                           OGRCARTODBEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
150                           OGRCARTODBEscapeLiteral(osName).c_str() );
151     }
152 
153     if( osCommand.size() )
154     {
155         if( !poDS->IsAuthenticatedConnection() && poDS->HasOGRMetadataFunction() < 0 )
156             CPLPushErrorHandler(CPLQuietErrorHandler);
157         OGRLayer* poLyr = poDS->ExecuteSQLInternal(osCommand);
158         if( !poDS->IsAuthenticatedConnection() && poDS->HasOGRMetadataFunction() < 0 )
159         {
160             CPLPopErrorHandler();
161             if( poLyr == NULL )
162             {
163                 CPLDebug("CARTODB", "ogr_table_metadata(text, text) not available");
164                 CPLErrorReset();
165             }
166             else if( poLyr->GetLayerDefn()->GetFieldCount() != 12 )
167             {
168                 CPLDebug("CARTODB", "ogr_table_metadata(text, text) has unexpected column count");
169                 poDS->ReleaseResultSet(poLyr);
170                 poLyr = NULL;
171             }
172             poDS->SetOGRMetadataFunction(poLyr != NULL);
173         }
174         if( poLyr )
175         {
176             poFeatureDefn = new OGRFeatureDefn(osName);
177             poFeatureDefn->Reference();
178             poFeatureDefn->SetGeomType(wkbNone);
179 
180             OGRFeature* poFeat;
181             while( (poFeat = poLyr->GetNextFeature()) != NULL )
182             {
183                 const char* pszAttname = poFeat->GetFieldAsString("attname");
184                 const char* pszType = poFeat->GetFieldAsString("typname");
185                 int nWidth = poFeat->GetFieldAsInteger("attlen");
186                 const char* pszFormatType = poFeat->GetFieldAsString("format_type");
187                 int bNotNull = poFeat->GetFieldAsInteger("attnotnull");
188                 int bIsPrimary = poFeat->GetFieldAsInteger("indisprimary");
189                 const char* pszDefault = (poFeat->IsFieldSet(poLyr->GetLayerDefn()->GetFieldIndex("defaultexpr"))) ?
190                             poFeat->GetFieldAsString("defaultexpr") : NULL;
191 
192                 if( bIsPrimary &&
193                     (EQUAL(pszType, "int2") ||
194                      EQUAL(pszType, "int4") ||
195                      EQUAL(pszType, "int8") ||
196                      EQUAL(pszType, "serial") ||
197                      EQUAL(pszType, "bigserial")) )
198                 {
199                     osFIDColName = pszAttname;
200                 }
201                 else if( strcmp(pszAttname, "created_at") == 0 ||
202                          strcmp(pszAttname, "updated_at") == 0 ||
203                          strcmp(pszAttname, "the_geom_webmercator") == 0)
204                 {
205                     /* ignored */
206                 }
207                 else
208                 {
209                     if( EQUAL(pszType,"geometry") )
210                     {
211                         int nDim = poFeat->GetFieldAsInteger("dim");
212                         int nSRID = poFeat->GetFieldAsInteger("srid");
213                         const char* pszGeomType = poFeat->GetFieldAsString("geomtyp");
214                         const char* pszSRText = (poFeat->IsFieldSet(
215                             poLyr->GetLayerDefn()->GetFieldIndex("srtext"))) ?
216                                     poFeat->GetFieldAsString("srtext") : NULL;
217                         OGRwkbGeometryType eType = OGRFromOGCGeomType(pszGeomType);
218                         if( nDim == 3 )
219                             eType = wkbSetZ(eType);
220                         OGRCartoDBGeomFieldDefn *poFieldDefn =
221                             new OGRCartoDBGeomFieldDefn(pszAttname, eType);
222                         if( bNotNull )
223                             poFieldDefn->SetNullable(FALSE);
224                         OGRSpatialReference* poSRS = NULL;
225                         if( pszSRText != NULL )
226                         {
227                             poSRS = new OGRSpatialReference();
228                             char* pszTmp = (char* )pszSRText;
229                             if( poSRS->importFromWkt(&pszTmp) != OGRERR_NONE )
230                             {
231                                 delete poSRS;
232                                 poSRS = NULL;
233                             }
234                             if( poSRS != NULL )
235                             {
236                                 poFieldDefn->SetSpatialRef(poSRS);
237                                 poSRS->Release();
238                             }
239                         }
240                         poFieldDefn->nSRID = nSRID;
241                         poFeatureDefn->AddGeomFieldDefn(poFieldDefn, FALSE);
242                     }
243                     else
244                     {
245                         OGRFieldDefn oField(pszAttname, OFTString);
246                         if( bNotNull )
247                             oField.SetNullable(FALSE);
248                         OGRPGCommonLayerSetType(oField, pszType, pszFormatType, nWidth);
249                         if( pszDefault )
250                             OGRPGCommonLayerNormalizeDefault(&oField, pszDefault);
251 
252                         poFeatureDefn->AddFieldDefn( &oField );
253                     }
254                 }
255                 delete poFeat;
256             }
257 
258             poDS->ReleaseResultSet(poLyr);
259         }
260     }
261 
262     if( poFeatureDefn == NULL )
263     {
264         osBaseSQL.Printf("SELECT * FROM %s", OGRCARTODBEscapeIdentifier(osName).c_str());
265         EstablishLayerDefn(osName, NULL);
266         osBaseSQL = "";
267     }
268 
269     if( osFIDColName.size() > 0 )
270     {
271         osBaseSQL = "SELECT ";
272         osBaseSQL += OGRCARTODBEscapeIdentifier(osFIDColName);
273     }
274     for(int i=0; i<poFeatureDefn->GetGeomFieldCount(); i++)
275     {
276         if( osBaseSQL.size() == 0 )
277             osBaseSQL = "SELECT ";
278         else
279             osBaseSQL += ", ";
280         osBaseSQL += OGRCARTODBEscapeIdentifier(poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
281     }
282     for(int i=0; i<poFeatureDefn->GetFieldCount(); i++)
283     {
284         if( osBaseSQL.size() == 0 )
285             osBaseSQL = "SELECT ";
286         else
287             osBaseSQL += ", ";
288         osBaseSQL += OGRCARTODBEscapeIdentifier(poFeatureDefn->GetFieldDefn(i)->GetNameRef());
289     }
290     if( osBaseSQL.size() == 0 )
291         osBaseSQL = "SELECT *";
292     osBaseSQL += " FROM ";
293     osBaseSQL += OGRCARTODBEscapeIdentifier(osName);
294 
295     osSELECTWithoutWHERE = osBaseSQL;
296 
297     return poFeatureDefn;
298 }
299 
300 /************************************************************************/
301 /*                        FetchNewFeatures()                            */
302 /************************************************************************/
303 
FetchNewFeatures(GIntBig iNext)304 json_object* OGRCARTODBTableLayer::FetchNewFeatures(GIntBig iNext)
305 {
306     if( osFIDColName.size() > 0 )
307     {
308         CPLString osSQL;
309         osSQL.Printf("%s WHERE %s%s >= " CPL_FRMT_GIB " ORDER BY %s ASC LIMIT %d",
310                      osSELECTWithoutWHERE.c_str(),
311                      ( osWHERE.size() ) ? CPLSPrintf("%s AND ", osWHERE.c_str()) : "",
312                      OGRCARTODBEscapeIdentifier(osFIDColName).c_str(),
313                      iNext,
314                      OGRCARTODBEscapeIdentifier(osFIDColName).c_str(),
315                      GetFeaturesToFetch());
316         return poDS->RunSQL(osSQL);
317     }
318     else
319         return OGRCARTODBLayer::FetchNewFeatures(iNext);
320 }
321 
322 /************************************************************************/
323 /*                           GetNextRawFeature()                        */
324 /************************************************************************/
325 
GetNextRawFeature()326 OGRFeature  *OGRCARTODBTableLayer::GetNextRawFeature()
327 {
328     if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
329         return NULL;
330     FlushDeferedInsert();
331     return OGRCARTODBLayer::GetNextRawFeature();
332 }
333 
334 /************************************************************************/
335 /*                         SetAttributeFilter()                         */
336 /************************************************************************/
337 
SetAttributeFilter(const char * pszQuery)338 OGRErr OGRCARTODBTableLayer::SetAttributeFilter( const char *pszQuery )
339 
340 {
341     GetLayerDefn();
342 
343     if( pszQuery == NULL )
344         osQuery = "";
345     else
346     {
347         osQuery = "(";
348         osQuery += pszQuery;
349         osQuery += ")";
350     }
351 
352     BuildWhere();
353 
354     ResetReading();
355 
356     return OGRERR_NONE;
357 }
358 
359 /************************************************************************/
360 /*                          SetSpatialFilter()                          */
361 /************************************************************************/
362 
SetSpatialFilter(int iGeomField,OGRGeometry * poGeomIn)363 void OGRCARTODBTableLayer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn )
364 
365 {
366     if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
367         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone )
368     {
369         if( iGeomField != 0 )
370         {
371             CPLError(CE_Failure, CPLE_AppDefined,
372                      "Invalid geometry field index : %d", iGeomField);
373         }
374         return;
375     }
376     m_iGeomFieldFilter = iGeomField;
377 
378     if( InstallFilter( poGeomIn ) )
379     {
380         BuildWhere();
381 
382         ResetReading();
383     }
384 }
385 
386 /************************************************************************/
387 /*                         FlushDeferedInsert()                          */
388 /************************************************************************/
389 
FlushDeferedInsert()390 void OGRCARTODBTableLayer::FlushDeferedInsert()
391 
392 {
393     if( bInDeferedInsert && osDeferedInsertSQL.size() > 0 )
394     {
395         osDeferedInsertSQL = "BEGIN;" + osDeferedInsertSQL + "COMMIT;";
396         json_object* poObj = poDS->RunSQL(osDeferedInsertSQL);
397         if( poObj != NULL )
398         {
399             json_object_put(poObj);
400         }
401     }
402 
403     bInDeferedInsert = FALSE;
404     osDeferedInsertSQL = "";
405     nNextFID = -1;
406 }
407 
408 /************************************************************************/
409 /*                            CreateField()                             */
410 /************************************************************************/
411 
CreateField(OGRFieldDefn * poFieldIn,CPL_UNUSED int bApproxOK)412 OGRErr OGRCARTODBTableLayer::CreateField( OGRFieldDefn *poFieldIn,
413                                           CPL_UNUSED int bApproxOK )
414 {
415     GetLayerDefn();
416 
417     if (!poDS->IsReadWrite())
418     {
419         CPLError(CE_Failure, CPLE_AppDefined,
420                  "Operation not available in read-only mode");
421         return OGRERR_FAILURE;
422     }
423 
424     OGRFieldDefn oField(poFieldIn);
425     if( bLaunderColumnNames )
426     {
427         char* pszName = OGRPGCommonLaunderName(oField.GetNameRef());
428         oField.SetName(pszName);
429         CPLFree(pszName);
430     }
431 
432 /* -------------------------------------------------------------------- */
433 /*      Create the new field.                                           */
434 /* -------------------------------------------------------------------- */
435 
436     if( !bDeferedCreation )
437     {
438         CPLString osSQL;
439         osSQL.Printf( "ALTER TABLE %s ADD COLUMN %s %s",
440                     OGRCARTODBEscapeIdentifier(osName).c_str(),
441                     OGRCARTODBEscapeIdentifier(oField.GetNameRef()).c_str(),
442                     OGRPGCommonLayerGetType(oField, FALSE, TRUE).c_str() );
443         if( !oField.IsNullable() )
444             osSQL += " NOT NULL";
445         if( oField.GetDefault() != NULL && !oField.IsDefaultDriverSpecific() )
446         {
447             osSQL += " DEFAULT ";
448             osSQL += OGRPGCommonLayerGetPGDefault(&oField);
449         }
450 
451         json_object* poObj = poDS->RunSQL(osSQL);
452         if( poObj == NULL )
453             return OGRERR_FAILURE;
454         json_object_put(poObj);
455     }
456 
457     poFeatureDefn->AddFieldDefn( &oField );
458 
459     return OGRERR_NONE;
460 }
461 
462 /************************************************************************/
463 /*                           ICreateFeature()                            */
464 /************************************************************************/
465 
ICreateFeature(OGRFeature * poFeature)466 OGRErr OGRCARTODBTableLayer::ICreateFeature( OGRFeature *poFeature )
467 
468 {
469     int i;
470 
471     if( bDeferedCreation )
472     {
473         if( RunDeferedCreationIfNecessary() != OGRERR_NONE )
474             return OGRERR_FAILURE;
475     }
476 
477     GetLayerDefn();
478     int bHasUserFieldMatchingFID = FALSE;
479     if( osFIDColName.size() )
480         bHasUserFieldMatchingFID = poFeatureDefn->GetFieldIndex(osFIDColName) >= 0;
481 
482     if (!poDS->IsReadWrite())
483     {
484         CPLError(CE_Failure, CPLE_AppDefined,
485                  "Operation not available in read-only mode");
486         return OGRERR_FAILURE;
487     }
488 
489     CPLString osSQL;
490 
491     int bHasJustGotNextFID = FALSE;
492     if( !bHasUserFieldMatchingFID && bInDeferedInsert && nNextFID < 0 && osFIDColName.size() )
493     {
494         osSQL.Printf("SELECT nextval('%s') AS nextid",
495                      OGRCARTODBEscapeLiteral(CPLSPrintf("%s_%s_seq", osName.c_str(), osFIDColName.c_str())).c_str());
496 
497         json_object* poObj = poDS->RunSQL(osSQL);
498         json_object* poRowObj = OGRCARTODBGetSingleRow(poObj);
499         if( poRowObj != NULL )
500         {
501             json_object* poID = json_object_object_get(poRowObj, "nextid");
502             if( poID != NULL && json_object_get_type(poID) == json_type_int )
503             {
504                 nNextFID = json_object_get_int64(poID);
505                 bHasJustGotNextFID = TRUE;
506             }
507         }
508 
509         if( poObj != NULL )
510             json_object_put(poObj);
511     }
512 
513     osSQL.Printf("INSERT INTO %s ", OGRCARTODBEscapeIdentifier(osName).c_str());
514     int bMustComma = FALSE;
515     for(i = 0; i < poFeatureDefn->GetFieldCount(); i++)
516     {
517         if( !poFeature->IsFieldSet(i) )
518             continue;
519 
520         if( bMustComma )
521             osSQL += ", ";
522         else
523         {
524             osSQL += "(";
525             bMustComma = TRUE;
526         }
527 
528         osSQL += OGRCARTODBEscapeIdentifier(poFeatureDefn->GetFieldDefn(i)->GetNameRef());
529     }
530 
531     for(i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
532     {
533         if( poFeature->GetGeomFieldRef(i) == NULL )
534             continue;
535 
536         if( bMustComma )
537             osSQL += ", ";
538         else
539         {
540             osSQL += "(";
541             bMustComma = TRUE;
542         }
543 
544         osSQL += OGRCARTODBEscapeIdentifier(poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
545     }
546 
547     if( !bHasUserFieldMatchingFID &&
548         osFIDColName.size() && (poFeature->GetFID() != OGRNullFID || nNextFID >= 0) )
549     {
550         if( bMustComma )
551             osSQL += ", ";
552         else
553         {
554             osSQL += "(";
555             bMustComma = TRUE;
556         }
557 
558         osSQL += OGRCARTODBEscapeIdentifier(osFIDColName);
559     }
560 
561     if( !bMustComma )
562         osSQL += " DEFAULT VALUES";
563     else
564     {
565         osSQL += ") VALUES (";
566 
567         bMustComma = FALSE;
568         for(i = 0; i < poFeatureDefn->GetFieldCount(); i++)
569         {
570             if( !poFeature->IsFieldSet(i) )
571                 continue;
572 
573             if( bMustComma )
574                 osSQL += ", ";
575             else
576                 bMustComma = TRUE;
577 
578             OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
579             if( eType == OFTString || eType == OFTDateTime || eType == OFTDate || eType == OFTTime )
580             {
581                 osSQL += "'";
582                 osSQL += OGRCARTODBEscapeLiteral(poFeature->GetFieldAsString(i));
583                 osSQL += "'";
584             }
585             else if( (eType == OFTInteger || eType == OFTInteger64) &&
586                      poFeatureDefn->GetFieldDefn(i)->GetSubType() == OFSTBoolean )
587             {
588                 osSQL += poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'";
589             }
590             else
591                 osSQL += poFeature->GetFieldAsString(i);
592         }
593 
594         for(i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
595         {
596             OGRGeometry* poGeom = poFeature->GetGeomFieldRef(i);
597             if( poGeom == NULL )
598                 continue;
599 
600             if( bMustComma )
601                 osSQL += ", ";
602             else
603                 bMustComma = TRUE;
604 
605             OGRCartoDBGeomFieldDefn* poGeomFieldDefn =
606                 (OGRCartoDBGeomFieldDefn *)poFeatureDefn->GetGeomFieldDefn(i);
607             int nSRID = poGeomFieldDefn->nSRID;
608             if( nSRID == 0 )
609                 nSRID = 4326;
610             char* pszEWKB;
611             if( wkbFlatten(poGeom->getGeometryType()) == wkbPolygon &&
612                 wkbFlatten(GetGeomType()) == wkbMultiPolygon )
613             {
614                 OGRMultiPolygon* poNewGeom = new OGRMultiPolygon();
615                 poNewGeom->addGeometry(poGeom);
616                 pszEWKB = OGRGeometryToHexEWKB(poNewGeom, nSRID, FALSE);
617                 delete poNewGeom;
618             }
619             else
620                 pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID, FALSE);
621             osSQL += "'";
622             osSQL += pszEWKB;
623             osSQL += "'";
624             CPLFree(pszEWKB);
625         }
626 
627         if( !bHasUserFieldMatchingFID )
628         {
629             if( osFIDColName.size() && nNextFID >= 0 )
630             {
631                 if( bMustComma )
632                     osSQL += ", ";
633                 else
634                     bMustComma = TRUE;
635 
636                 if( bHasJustGotNextFID )
637                 {
638                     osSQL += CPLSPrintf(CPL_FRMT_GIB, nNextFID);
639                 }
640                 else
641                 {
642                     osSQL += CPLSPrintf("nextval('%s')",
643                             OGRCARTODBEscapeLiteral(CPLSPrintf("%s_%s_seq", osName.c_str(), osFIDColName.c_str())).c_str());
644                 }
645                 poFeature->SetFID(nNextFID);
646                 nNextFID ++;
647             }
648             else if( osFIDColName.size() && poFeature->GetFID() != OGRNullFID )
649             {
650                 if( bMustComma )
651                     osSQL += ", ";
652                 else
653                     bMustComma = TRUE;
654 
655                 osSQL += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFID());
656             }
657         }
658 
659         osSQL += ")";
660     }
661 
662     if( bInDeferedInsert )
663     {
664         OGRErr eRet = OGRERR_NONE;
665         if( osDeferedInsertSQL.size() != 0 &&
666             (int)osDeferedInsertSQL.size() + (int)osSQL.size() > nMaxChunkSize )
667         {
668             osDeferedInsertSQL = "BEGIN;" + osDeferedInsertSQL + "COMMIT;";
669             json_object* poObj = poDS->RunSQL(osDeferedInsertSQL);
670             if( poObj != NULL )
671                 json_object_put(poObj);
672             else
673             {
674                 bInDeferedInsert = FALSE;
675                 eRet = OGRERR_FAILURE;
676             }
677             osDeferedInsertSQL = "";
678         }
679 
680         osDeferedInsertSQL += osSQL;
681         osDeferedInsertSQL += ";";
682 
683         if( (int)osDeferedInsertSQL.size() > nMaxChunkSize )
684         {
685             osDeferedInsertSQL = "BEGIN;" + osDeferedInsertSQL + "COMMIT;";
686             json_object* poObj = poDS->RunSQL(osDeferedInsertSQL);
687             if( poObj != NULL )
688                 json_object_put(poObj);
689             else
690             {
691                 bInDeferedInsert = FALSE;
692                 eRet = OGRERR_FAILURE;
693             }
694             osDeferedInsertSQL = "";
695         }
696 
697         return eRet;
698     }
699 
700     if( osFIDColName.size() )
701     {
702         osSQL += " RETURNING ";
703         osSQL += OGRCARTODBEscapeIdentifier(osFIDColName);
704 
705         json_object* poObj = poDS->RunSQL(osSQL);
706         json_object* poRowObj = OGRCARTODBGetSingleRow(poObj);
707         if( poRowObj == NULL )
708         {
709             if( poObj != NULL )
710                 json_object_put(poObj);
711             return OGRERR_FAILURE;
712         }
713 
714         json_object* poID = json_object_object_get(poRowObj, osFIDColName);
715         if( poID != NULL && json_object_get_type(poID) == json_type_int )
716         {
717             poFeature->SetFID(json_object_get_int64(poID));
718         }
719 
720         if( poObj != NULL )
721             json_object_put(poObj);
722 
723         return OGRERR_NONE;
724     }
725     else
726     {
727         OGRErr eRet = OGRERR_FAILURE;
728         json_object* poObj = poDS->RunSQL(osSQL);
729         if( poObj != NULL )
730         {
731             json_object* poTotalRows = json_object_object_get(poObj, "total_rows");
732             if( poTotalRows != NULL && json_object_get_type(poTotalRows) == json_type_int )
733             {
734                 int nTotalRows = json_object_get_int(poTotalRows);
735                 if( nTotalRows == 1 )
736                 {
737                     eRet = OGRERR_NONE;
738                 }
739             }
740             json_object_put(poObj);
741         }
742 
743         return eRet;
744     }
745 }
746 
747 /************************************************************************/
748 /*                            ISetFeature()                              */
749 /************************************************************************/
750 
ISetFeature(OGRFeature * poFeature)751 OGRErr OGRCARTODBTableLayer::ISetFeature( OGRFeature *poFeature )
752 
753 {
754     int i;
755 
756     if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
757         return OGRERR_FAILURE;
758     FlushDeferedInsert();
759 
760     GetLayerDefn();
761 
762     if (!poDS->IsReadWrite())
763     {
764         CPLError(CE_Failure, CPLE_AppDefined,
765                  "Operation not available in read-only mode");
766         return OGRERR_FAILURE;
767     }
768 
769     if (poFeature->GetFID() == OGRNullFID)
770     {
771         CPLError( CE_Failure, CPLE_AppDefined,
772                   "FID required on features given to SetFeature()." );
773         return OGRERR_FAILURE;
774     }
775 
776     CPLString osSQL;
777     osSQL.Printf("UPDATE %s SET ", OGRCARTODBEscapeIdentifier(osName).c_str());
778     int bMustComma = FALSE;
779     for(i = 0; i < poFeatureDefn->GetFieldCount(); i++)
780     {
781         if( bMustComma )
782             osSQL += ", ";
783         else
784             bMustComma = TRUE;
785 
786         osSQL += OGRCARTODBEscapeIdentifier(poFeatureDefn->GetFieldDefn(i)->GetNameRef());
787         osSQL += " = ";
788 
789         if( !poFeature->IsFieldSet(i) )
790         {
791             osSQL += "NULL";
792         }
793         else
794         {
795             OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
796             if( eType == OFTString || eType == OFTDateTime || eType == OFTDate || eType == OFTTime )
797             {
798                 osSQL += "'";
799                 osSQL += OGRCARTODBEscapeLiteral(poFeature->GetFieldAsString(i));
800                 osSQL += "'";
801             }
802             else if( (eType == OFTInteger || eType == OFTInteger64) &&
803                 poFeatureDefn->GetFieldDefn(i)->GetSubType() == OFSTBoolean )
804             {
805                 osSQL += poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'";
806             }
807             else
808                 osSQL += poFeature->GetFieldAsString(i);
809         }
810     }
811 
812     for(i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
813     {
814         if( bMustComma )
815             osSQL += ", ";
816         else
817             bMustComma = TRUE;
818 
819         osSQL += OGRCARTODBEscapeIdentifier(poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
820         osSQL += " = ";
821 
822         OGRGeometry* poGeom = poFeature->GetGeomFieldRef(i);
823         if( poGeom == NULL )
824         {
825             osSQL += "NULL";
826         }
827         else
828         {
829             OGRCartoDBGeomFieldDefn* poGeomFieldDefn =
830                 (OGRCartoDBGeomFieldDefn *)poFeatureDefn->GetGeomFieldDefn(i);
831             int nSRID = poGeomFieldDefn->nSRID;
832             if( nSRID == 0 )
833                 nSRID = 4326;
834             char* pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID, FALSE);
835             osSQL += "'";
836             osSQL += pszEWKB;
837             osSQL += "'";
838             CPLFree(pszEWKB);
839         }
840     }
841 
842     osSQL += CPLSPrintf(" WHERE %s = " CPL_FRMT_GIB,
843                     OGRCARTODBEscapeIdentifier(osFIDColName).c_str(),
844                     poFeature->GetFID());
845 
846     OGRErr eRet = OGRERR_FAILURE;
847     json_object* poObj = poDS->RunSQL(osSQL);
848     if( poObj != NULL )
849     {
850         json_object* poTotalRows = json_object_object_get(poObj, "total_rows");
851         if( poTotalRows != NULL && json_object_get_type(poTotalRows) == json_type_int )
852         {
853             int nTotalRows = json_object_get_int(poTotalRows);
854             if( nTotalRows > 0 )
855             {
856                 eRet = OGRERR_NONE;
857             }
858             else
859                 eRet = OGRERR_NON_EXISTING_FEATURE;
860         }
861         json_object_put(poObj);
862     }
863 
864     return eRet;
865 }
866 
867 /************************************************************************/
868 /*                          DeleteFeature()                             */
869 /************************************************************************/
870 
DeleteFeature(GIntBig nFID)871 OGRErr OGRCARTODBTableLayer::DeleteFeature( GIntBig nFID )
872 
873 {
874 
875     if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
876         return OGRERR_FAILURE;
877     FlushDeferedInsert();
878 
879     GetLayerDefn();
880 
881     if (!poDS->IsReadWrite())
882     {
883         CPLError(CE_Failure, CPLE_AppDefined,
884                  "Operation not available in read-only mode");
885         return OGRERR_FAILURE;
886     }
887 
888     if( osFIDColName.size() == 0 )
889         return OGRERR_FAILURE;
890 
891     CPLString osSQL;
892     osSQL.Printf("DELETE FROM %s WHERE %s = " CPL_FRMT_GIB,
893                     OGRCARTODBEscapeIdentifier(osName).c_str(),
894                     OGRCARTODBEscapeIdentifier(osFIDColName).c_str(),
895                     nFID);
896 
897     OGRErr eRet = OGRERR_FAILURE;
898     json_object* poObj = poDS->RunSQL(osSQL);
899     if( poObj != NULL )
900     {
901         json_object* poTotalRows = json_object_object_get(poObj, "total_rows");
902         if( poTotalRows != NULL && json_object_get_type(poTotalRows) == json_type_int )
903         {
904             int nTotalRows = json_object_get_int(poTotalRows);
905             if( nTotalRows > 0 )
906             {
907                 eRet = OGRERR_NONE;
908             }
909             else
910                 eRet = OGRERR_NON_EXISTING_FEATURE;
911         }
912         json_object_put(poObj);
913     }
914 
915     return eRet;
916 }
917 
918 /************************************************************************/
919 /*                             GetSRS_SQL()                             */
920 /************************************************************************/
921 
GetSRS_SQL(const char * pszGeomCol)922 CPLString OGRCARTODBTableLayer::GetSRS_SQL(const char* pszGeomCol)
923 {
924     CPLString osSQL;
925 
926     osSQL.Printf("SELECT srid, srtext FROM spatial_ref_sys WHERE srid IN "
927                 "(SELECT Find_SRID('%s', '%s', '%s'))",
928                 OGRCARTODBEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
929                 OGRCARTODBEscapeLiteral(osName).c_str(),
930                 OGRCARTODBEscapeLiteral(pszGeomCol).c_str());
931 
932     return osSQL;
933 }
934 
935 /************************************************************************/
936 /*                             BuildWhere()                             */
937 /*                                                                      */
938 /*      Build the WHERE statement appropriate to the current set of     */
939 /*      criteria (spatial and attribute queries).                       */
940 /************************************************************************/
941 
BuildWhere()942 void OGRCARTODBTableLayer::BuildWhere()
943 
944 {
945     osWHERE = "";
946 
947     if( m_poFilterGeom != NULL &&
948         m_iGeomFieldFilter >= 0 &&
949         m_iGeomFieldFilter < poFeatureDefn->GetGeomFieldCount() )
950     {
951         OGREnvelope  sEnvelope;
952 
953         m_poFilterGeom->getEnvelope( &sEnvelope );
954 
955         CPLString osGeomColumn(poFeatureDefn->GetGeomFieldDefn(m_iGeomFieldFilter)->GetNameRef());
956 
957         char szBox3D_1[128];
958         char szBox3D_2[128];
959         char* pszComma;
960 
961         CPLsnprintf(szBox3D_1, sizeof(szBox3D_1), "%.18g %.18g", sEnvelope.MinX, sEnvelope.MinY);
962         while((pszComma = strchr(szBox3D_1, ',')) != NULL)
963             *pszComma = '.';
964         CPLsnprintf(szBox3D_2, sizeof(szBox3D_2), "%.18g %.18g", sEnvelope.MaxX, sEnvelope.MaxY);
965         while((pszComma = strchr(szBox3D_2, ',')) != NULL)
966             *pszComma = '.';
967         osWHERE.Printf("(%s && 'BOX3D(%s, %s)'::box3d)",
968                        OGRCARTODBEscapeIdentifier(osGeomColumn).c_str(),
969                        szBox3D_1, szBox3D_2 );
970     }
971 
972     if( strlen(osQuery) > 0 )
973     {
974         if( osWHERE.size() > 0 )
975             osWHERE += " AND ";
976         osWHERE += osQuery;
977     }
978 
979     if( osFIDColName.size() == 0 )
980     {
981         osBaseSQL = osSELECTWithoutWHERE;
982         if( osWHERE.size() )
983         {
984             osBaseSQL += " WHERE ";
985             osBaseSQL += osWHERE;
986         }
987     }
988 }
989 
990 /************************************************************************/
991 /*                              GetFeature()                            */
992 /************************************************************************/
993 
GetFeature(GIntBig nFeatureId)994 OGRFeature* OGRCARTODBTableLayer::GetFeature( GIntBig nFeatureId )
995 {
996 
997     if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
998         return NULL;
999     FlushDeferedInsert();
1000 
1001     GetLayerDefn();
1002 
1003     if( osFIDColName.size() == 0 )
1004         return OGRCARTODBLayer::GetFeature(nFeatureId);
1005 
1006     CPLString osSQL = osSELECTWithoutWHERE;
1007     osSQL += " WHERE ";
1008     osSQL += OGRCARTODBEscapeIdentifier(osFIDColName).c_str();
1009     osSQL += " = ";
1010     osSQL += CPLSPrintf(CPL_FRMT_GIB, nFeatureId);
1011 
1012     json_object* poObj = poDS->RunSQL(osSQL);
1013     json_object* poRowObj = OGRCARTODBGetSingleRow(poObj);
1014     if( poRowObj == NULL )
1015     {
1016         if( poObj != NULL )
1017             json_object_put(poObj);
1018         return OGRCARTODBLayer::GetFeature(nFeatureId);
1019     }
1020 
1021     OGRFeature* poFeature = BuildFeature(poRowObj);
1022     json_object_put(poObj);
1023 
1024     return poFeature;
1025 }
1026 
1027 /************************************************************************/
1028 /*                          GetFeatureCount()                           */
1029 /************************************************************************/
1030 
GetFeatureCount(int bForce)1031 GIntBig OGRCARTODBTableLayer::GetFeatureCount(int bForce)
1032 {
1033 
1034     if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
1035         return 0;
1036     FlushDeferedInsert();
1037 
1038     GetLayerDefn();
1039 
1040     CPLString osSQL(CPLSPrintf("SELECT COUNT(*) FROM %s",
1041                                OGRCARTODBEscapeIdentifier(osName).c_str()));
1042     if( osWHERE.size() )
1043     {
1044         osSQL += " WHERE ";
1045         osSQL += osWHERE;
1046     }
1047 
1048     json_object* poObj = poDS->RunSQL(osSQL);
1049     json_object* poRowObj = OGRCARTODBGetSingleRow(poObj);
1050     if( poRowObj == NULL )
1051     {
1052         if( poObj != NULL )
1053             json_object_put(poObj);
1054         return OGRCARTODBLayer::GetFeatureCount(bForce);
1055     }
1056 
1057     json_object* poCount = json_object_object_get(poRowObj, "count");
1058     if( poCount == NULL || json_object_get_type(poCount) != json_type_int )
1059     {
1060         json_object_put(poObj);
1061         return OGRCARTODBLayer::GetFeatureCount(bForce);
1062     }
1063 
1064     GIntBig nRet = (GIntBig)json_object_get_int64(poCount);
1065 
1066     json_object_put(poObj);
1067 
1068     return nRet;
1069 }
1070 
1071 /************************************************************************/
1072 /*                             GetExtent()                              */
1073 /*                                                                      */
1074 /*      For PostGIS use internal Extend(geometry) function              */
1075 /*      in other cases we use standard OGRLayer::GetExtent()            */
1076 /************************************************************************/
1077 
GetExtent(int iGeomField,OGREnvelope * psExtent,int bForce)1078 OGRErr OGRCARTODBTableLayer::GetExtent( int iGeomField, OGREnvelope *psExtent, int bForce )
1079 {
1080     CPLString   osSQL;
1081 
1082     if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
1083         return OGRERR_FAILURE;
1084     FlushDeferedInsert();
1085 
1086     if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
1087         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone )
1088     {
1089         if( iGeomField != 0 )
1090         {
1091             CPLError(CE_Failure, CPLE_AppDefined,
1092                      "Invalid geometry field index : %d", iGeomField);
1093         }
1094         return OGRERR_FAILURE;
1095     }
1096 
1097     OGRGeomFieldDefn* poGeomFieldDefn =
1098         poFeatureDefn->GetGeomFieldDefn(iGeomField);
1099 
1100     /* Do not take the spatial filter into account */
1101     osSQL.Printf( "SELECT ST_Extent(%s) FROM %s",
1102                   OGRCARTODBEscapeIdentifier(poGeomFieldDefn->GetNameRef()).c_str(),
1103                   OGRCARTODBEscapeIdentifier(osName).c_str());
1104 
1105     json_object* poObj = poDS->RunSQL(osSQL);
1106     json_object* poRowObj = OGRCARTODBGetSingleRow(poObj);
1107     if( poRowObj != NULL )
1108     {
1109         json_object* poExtent = json_object_object_get(poRowObj, "st_extent");
1110         if( poExtent != NULL && json_object_get_type(poExtent) == json_type_string )
1111         {
1112             const char* pszBox = json_object_get_string(poExtent);
1113             const char * ptr, *ptrEndParenthesis;
1114             char szVals[64*6+6];
1115 
1116             ptr = strchr(pszBox, '(');
1117             if (ptr)
1118                 ptr ++;
1119             if (ptr == NULL ||
1120                 (ptrEndParenthesis = strchr(ptr, ')')) == NULL ||
1121                 ptrEndParenthesis - ptr > (int)(sizeof(szVals) - 1))
1122             {
1123                 CPLError( CE_Failure, CPLE_IllegalArg,
1124                             "Bad extent representation: '%s'", pszBox);
1125 
1126                 json_object_put(poObj);
1127                 return OGRERR_FAILURE;
1128             }
1129 
1130             strncpy(szVals,ptr,ptrEndParenthesis - ptr);
1131             szVals[ptrEndParenthesis - ptr] = '\0';
1132 
1133             char ** papszTokens = CSLTokenizeString2(szVals," ,",CSLT_HONOURSTRINGS);
1134             int nTokenCnt = 4;
1135 
1136             if ( CSLCount(papszTokens) != nTokenCnt )
1137             {
1138                 CPLError( CE_Failure, CPLE_IllegalArg,
1139                             "Bad extent representation: '%s'", pszBox);
1140                 CSLDestroy(papszTokens);
1141 
1142                 json_object_put(poObj);
1143                 return OGRERR_FAILURE;
1144             }
1145 
1146             // Take X,Y coords
1147             // For PostGis ver >= 1.0.0 -> Tokens: X1 Y1 X2 Y2 (nTokenCnt = 4)
1148             // For PostGIS ver < 1.0.0 -> Tokens: X1 Y1 Z1 X2 Y2 Z2 (nTokenCnt = 6)
1149             // =>   X2 index calculated as nTokenCnt/2
1150             //      Y2 index caluclated as nTokenCnt/2+1
1151 
1152             psExtent->MinX = CPLAtof( papszTokens[0] );
1153             psExtent->MinY = CPLAtof( papszTokens[1] );
1154             psExtent->MaxX = CPLAtof( papszTokens[nTokenCnt/2] );
1155             psExtent->MaxY = CPLAtof( papszTokens[nTokenCnt/2+1] );
1156 
1157             CSLDestroy(papszTokens);
1158 
1159             json_object_put(poObj);
1160             return OGRERR_NONE;
1161         }
1162     }
1163 
1164     if( poObj != NULL )
1165         json_object_put(poObj);
1166 
1167     if( iGeomField == 0 )
1168         return OGRLayer::GetExtent( psExtent, bForce );
1169     else
1170         return OGRLayer::GetExtent( iGeomField, psExtent, bForce );
1171 }
1172 
1173 /************************************************************************/
1174 /*                           TestCapability()                           */
1175 /************************************************************************/
1176 
TestCapability(const char * pszCap)1177 int OGRCARTODBTableLayer::TestCapability( const char * pszCap )
1178 
1179 {
1180     if( EQUAL(pszCap, OLCFastFeatureCount) )
1181         return TRUE;
1182     if( EQUAL(pszCap, OLCFastGetExtent) )
1183         return TRUE;
1184     if( EQUAL(pszCap, OLCRandomRead) )
1185     {
1186         GetLayerDefn();
1187         return osFIDColName.size() != 0;
1188     }
1189 
1190     if( EQUAL(pszCap,OLCSequentialWrite)
1191      || EQUAL(pszCap,OLCRandomWrite)
1192      || EQUAL(pszCap,OLCDeleteFeature)
1193      || EQUAL(pszCap,OLCCreateField) )
1194     {
1195         return poDS->IsReadWrite();
1196     }
1197 
1198     return OGRCARTODBLayer::TestCapability(pszCap);
1199 }
1200 
1201 /************************************************************************/
1202 /*                        SetDeferedCreation()                          */
1203 /************************************************************************/
1204 
SetDeferedCreation(OGRwkbGeometryType eGType,OGRSpatialReference * poSRS,int bGeomNullable,int bCartoDBify)1205 void OGRCARTODBTableLayer::SetDeferedCreation (OGRwkbGeometryType eGType,
1206                                                OGRSpatialReference* poSRS,
1207                                                int bGeomNullable,
1208                                                int bCartoDBify)
1209 {
1210     bDeferedCreation = TRUE;
1211     nNextFID = 1;
1212     CPLAssert(poFeatureDefn == NULL);
1213     this->bCartoDBify = bCartoDBify;
1214     poFeatureDefn = new OGRFeatureDefn(osName);
1215     poFeatureDefn->Reference();
1216     poFeatureDefn->SetGeomType(wkbNone);
1217     if( eGType == wkbPolygon )
1218         eGType = wkbMultiPolygon;
1219     else if( eGType == wkbPolygon25D )
1220         eGType = wkbMultiPolygon25D;
1221     if( eGType != wkbNone )
1222     {
1223         OGRCartoDBGeomFieldDefn *poFieldDefn =
1224             new OGRCartoDBGeomFieldDefn("the_geom", eGType);
1225         poFieldDefn->SetNullable(bGeomNullable);
1226         poFeatureDefn->AddGeomFieldDefn(poFieldDefn, FALSE);
1227         if( poSRS != NULL )
1228         {
1229             poFieldDefn->nSRID = poDS->FetchSRSId( poSRS );
1230             poFeatureDefn->GetGeomFieldDefn(
1231                 poFeatureDefn->GetGeomFieldCount() - 1)->SetSpatialRef(poSRS);
1232         }
1233     }
1234     osFIDColName = "cartodb_id";
1235     osBaseSQL.Printf("SELECT * FROM %s",
1236                      OGRCARTODBEscapeIdentifier(osName).c_str());
1237 }
1238 
1239 /************************************************************************/
1240 /*                      RunDeferedCreationIfNecessary()                 */
1241 /************************************************************************/
1242 
RunDeferedCreationIfNecessary()1243 OGRErr OGRCARTODBTableLayer::RunDeferedCreationIfNecessary()
1244 {
1245     if( !bDeferedCreation )
1246         return OGRERR_NONE;
1247     bDeferedCreation = FALSE;
1248 
1249     CPLString osSQL;
1250     osSQL.Printf("CREATE TABLE %s ( %s SERIAL,",
1251                  OGRCARTODBEscapeIdentifier(osName).c_str(),
1252                  osFIDColName.c_str());
1253 
1254     int nSRID = 0;
1255     OGRwkbGeometryType eGType = GetGeomType();
1256     if( eGType != wkbNone )
1257     {
1258         CPLString osGeomType = OGRToOGCGeomType(eGType);
1259         if( wkbHasZ(eGType) )
1260             osGeomType += "Z";
1261 
1262         OGRCartoDBGeomFieldDefn *poFieldDefn =
1263             (OGRCartoDBGeomFieldDefn *)poFeatureDefn->GetGeomFieldDefn(0);
1264         nSRID = poFieldDefn->nSRID;
1265 
1266         osSQL += CPLSPrintf("%s GEOMETRY(%s, %d)%s, %s GEOMETRY(%s, %d),",
1267                  "the_geom",
1268                  osGeomType.c_str(),
1269                  nSRID,
1270                  (!poFieldDefn->IsNullable()) ? " NOT NULL" : "",
1271                  "the_geom_webmercator",
1272                  osGeomType.c_str(),
1273                  3857);
1274     }
1275 
1276     for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
1277     {
1278         OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn(i);
1279         if( strcmp(poFieldDefn->GetNameRef(), osFIDColName) != 0 )
1280         {
1281             osSQL += OGRCARTODBEscapeIdentifier(poFieldDefn->GetNameRef());
1282             osSQL += " ";
1283             osSQL += OGRPGCommonLayerGetType(*poFieldDefn, FALSE, TRUE);
1284             if( !poFieldDefn->IsNullable() )
1285                 osSQL += " NOT NULL";
1286             if( poFieldDefn->GetDefault() != NULL && !poFieldDefn->IsDefaultDriverSpecific() )
1287             {
1288                 osSQL += " DEFAULT ";
1289                 osSQL += poFieldDefn->GetDefault();
1290             }
1291             osSQL += ",";
1292         }
1293     }
1294 
1295     osSQL += CPLSPrintf("PRIMARY KEY (%s) )", osFIDColName.c_str());
1296 
1297     CPLString osSeqName(OGRCARTODBEscapeIdentifier(CPLSPrintf("%s_%s_seq",
1298                                 osName.c_str(), osFIDColName.c_str())));
1299 
1300     osSQL += ";";
1301     osSQL += CPLSPrintf("DROP SEQUENCE IF EXISTS %s CASCADE", osSeqName.c_str());
1302     osSQL += ";";
1303     osSQL += CPLSPrintf("CREATE SEQUENCE %s START 1", osSeqName.c_str());
1304     osSQL += ";";
1305     osSQL += CPLSPrintf("ALTER TABLE %s ALTER COLUMN %s SET DEFAULT nextval('%s')",
1306                         OGRCARTODBEscapeIdentifier(osName).c_str(),
1307                         osFIDColName.c_str(), osSeqName.c_str());
1308 
1309     json_object* poObj = poDS->RunSQL(osSQL);
1310     if( poObj == NULL )
1311         return OGRERR_FAILURE;
1312     json_object_put(poObj);
1313 
1314     if( bCartoDBify )
1315     {
1316         if( nSRID != 4326 )
1317         {
1318             if( eGType != wkbNone )
1319             {
1320                 CPLError(CE_Warning, CPLE_AppDefined,
1321                         "Cannot register table in dashboard with "
1322                         "cdb_cartodbfytable() since its SRS is not EPSG:4326");
1323             }
1324         }
1325         else
1326         {
1327             if( poDS->GetCurrentSchema() == "public" )
1328                 osSQL.Printf("SELECT cdb_cartodbfytable('%s')",
1329                                     OGRCARTODBEscapeLiteral(osName).c_str());
1330             else
1331                 osSQL.Printf("SELECT cdb_cartodbfytable('%s', '%s')",
1332                                     OGRCARTODBEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
1333                                     OGRCARTODBEscapeLiteral(osName).c_str());
1334 
1335             poObj = poDS->RunSQL(osSQL);
1336             if( poObj == NULL )
1337                 return OGRERR_FAILURE;
1338             json_object_put(poObj);
1339         }
1340     }
1341 
1342     return OGRERR_NONE;
1343 }
1344