1 /******************************************************************************
2 * $Id: ogrcartodbdatasource.cpp 29019 2015-04-25 20:34:19Z rouault $
3 *
4 * Project: CartoDB Translator
5 * Purpose: Implements OGRCARTODBDataSource 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_pgdump.h"
32
33 CPL_CVSID("$Id: ogrcartodbdatasource.cpp 29019 2015-04-25 20:34:19Z rouault $");
34
35 /************************************************************************/
36 /* OGRCARTODBDataSource() */
37 /************************************************************************/
38
OGRCARTODBDataSource()39 OGRCARTODBDataSource::OGRCARTODBDataSource()
40
41 {
42 papoLayers = NULL;
43 nLayers = 0;
44
45 pszName = NULL;
46 pszAccount = NULL;
47
48 bReadWrite = FALSE;
49 bBatchInsert = TRUE;
50 bUseHTTPS = FALSE;
51
52 bMustCleanPersistant = FALSE;
53 bHasOGRMetadataFunction = -1;
54 }
55
56 /************************************************************************/
57 /* ~OGRCARTODBDataSource() */
58 /************************************************************************/
59
~OGRCARTODBDataSource()60 OGRCARTODBDataSource::~OGRCARTODBDataSource()
61
62 {
63 for( int i = 0; i < nLayers; i++ )
64 delete papoLayers[i];
65 CPLFree( papoLayers );
66
67 if (bMustCleanPersistant)
68 {
69 char** papszOptions = NULL;
70 papszOptions = CSLSetNameValue(papszOptions, "CLOSE_PERSISTENT", CPLSPrintf("CARTODB:%p", this));
71 CPLHTTPFetch( GetAPIURL(), papszOptions);
72 CSLDestroy(papszOptions);
73 }
74
75 CPLFree( pszName );
76 CPLFree( pszAccount );
77 }
78
79 /************************************************************************/
80 /* TestCapability() */
81 /************************************************************************/
82
TestCapability(const char * pszCap)83 int OGRCARTODBDataSource::TestCapability( const char * pszCap )
84
85 {
86 if( bReadWrite && EQUAL(pszCap,ODsCCreateLayer) )
87 return TRUE;
88 else if( bReadWrite && EQUAL(pszCap,ODsCDeleteLayer) )
89 return TRUE;
90 else
91 return FALSE;
92 }
93
94 /************************************************************************/
95 /* GetLayer() */
96 /************************************************************************/
97
GetLayer(int iLayer)98 OGRLayer *OGRCARTODBDataSource::GetLayer( int iLayer )
99
100 {
101 if( iLayer < 0 || iLayer >= nLayers )
102 return NULL;
103 else
104 return papoLayers[iLayer];
105 }
106
107 /************************************************************************/
108 /* GetLayerByName() */
109 /************************************************************************/
110
GetLayerByName(const char * pszLayerName)111 OGRLayer *OGRCARTODBDataSource::GetLayerByName(const char * pszLayerName)
112 {
113 OGRLayer* poLayer = OGRDataSource::GetLayerByName(pszLayerName);
114 return poLayer;
115 }
116
117 /************************************************************************/
118 /* OGRCARTODBGetOptionValue() */
119 /************************************************************************/
120
OGRCARTODBGetOptionValue(const char * pszFilename,const char * pszOptionName)121 CPLString OGRCARTODBGetOptionValue(const char* pszFilename,
122 const char* pszOptionName)
123 {
124 CPLString osOptionName(pszOptionName);
125 osOptionName += "=";
126 const char* pszOptionValue = strstr(pszFilename, osOptionName);
127 if (!pszOptionValue)
128 return "";
129
130 CPLString osOptionValue(pszOptionValue + strlen(osOptionName));
131 const char* pszSpace = strchr(osOptionValue.c_str(), ' ');
132 if (pszSpace)
133 osOptionValue.resize(pszSpace - osOptionValue.c_str());
134 return osOptionValue;
135 }
136
137 /************************************************************************/
138 /* Open() */
139 /************************************************************************/
140
Open(const char * pszFilename,char ** papszOpenOptions,int bUpdateIn)141 int OGRCARTODBDataSource::Open( const char * pszFilename,
142 char** papszOpenOptions,
143 int bUpdateIn )
144
145 {
146 bReadWrite = bUpdateIn;
147 bBatchInsert = CSLTestBoolean(CSLFetchNameValueDef(papszOpenOptions, "BATCH_INSERT", "YES"));
148
149 pszName = CPLStrdup( pszFilename );
150 if( CSLFetchNameValue(papszOpenOptions, "ACCOUNT") )
151 pszAccount = CPLStrdup(CSLFetchNameValue(papszOpenOptions, "ACCOUNT"));
152 else
153 {
154 pszAccount = CPLStrdup(pszFilename + strlen("CARTODB:"));
155 char* pchSpace = strchr(pszAccount, ' ');
156 if( pchSpace )
157 *pchSpace = '\0';
158 if( pszAccount[0] == 0 )
159 {
160 CPLError(CE_Failure, CPLE_AppDefined, "Missing account name");
161 return FALSE;
162 }
163 }
164
165 osAPIKey = CSLFetchNameValueDef(papszOpenOptions, "API_KEY",
166 CPLGetConfigOption("CARTODB_API_KEY", ""));
167
168 CPLString osTables = OGRCARTODBGetOptionValue(pszFilename, "tables");
169
170 /*if( osTables.size() == 0 && osAPIKey.size() == 0 )
171 {
172 CPLError(CE_Failure, CPLE_AppDefined,
173 "When not specifying tables option, CARTODB_API_KEY must be defined");
174 return FALSE;
175 }*/
176
177 bUseHTTPS = CSLTestBoolean(CPLGetConfigOption("CARTODB_HTTPS", "YES"));
178
179 OGRLayer* poSchemaLayer = ExecuteSQLInternal("SELECT current_schema()");
180 if( poSchemaLayer )
181 {
182 OGRFeature* poFeat = poSchemaLayer->GetNextFeature();
183 if( poFeat )
184 {
185 if( poFeat->GetFieldCount() == 1 )
186 {
187 osCurrentSchema = poFeat->GetFieldAsString(0);
188 }
189 delete poFeat;
190 }
191 ReleaseResultSet(poSchemaLayer);
192 }
193 if( osCurrentSchema.size() == 0 )
194 return FALSE;
195
196 if( osAPIKey.size() && bUpdateIn )
197 {
198 ExecuteSQLInternal(
199 "DROP FUNCTION IF EXISTS ogr_table_metadata(TEXT,TEXT); "
200 "CREATE OR REPLACE FUNCTION ogr_table_metadata(schema_name TEXT, table_name TEXT) RETURNS TABLE "
201 "(attname TEXT, typname TEXT, attlen INT, format_type TEXT, "
202 "attnum INT, attnotnull BOOLEAN, indisprimary BOOLEAN, "
203 "defaultexpr TEXT, dim INT, srid INT, geomtyp TEXT, srtext TEXT) AS $$ "
204 "SELECT a.attname::text, t.typname::text, a.attlen::int, "
205 "format_type(a.atttypid,a.atttypmod)::text, "
206 "a.attnum::int, "
207 "a.attnotnull::boolean, "
208 "i.indisprimary::boolean, "
209 "pg_get_expr(def.adbin, c.oid)::text AS defaultexpr, "
210 "(CASE WHEN t.typname = 'geometry' THEN postgis_typmod_dims(a.atttypmod) ELSE NULL END)::int dim, "
211 "(CASE WHEN t.typname = 'geometry' THEN postgis_typmod_srid(a.atttypmod) ELSE NULL END)::int srid, "
212 "(CASE WHEN t.typname = 'geometry' THEN postgis_typmod_type(a.atttypmod) ELSE NULL END)::text geomtyp, "
213 "srtext "
214 "FROM pg_class c "
215 "JOIN pg_attribute a ON a.attnum > 0 AND "
216 "a.attrelid = c.oid AND c.relname = $2 "
217 "AND c.relname IN (SELECT CDB_UserTables())"
218 "JOIN pg_type t ON a.atttypid = t.oid "
219 "JOIN pg_namespace n ON c.relnamespace=n.oid AND n.nspname = $1 "
220 "LEFT JOIN pg_index i ON c.oid = i.indrelid AND "
221 "i.indisprimary = 't' AND a.attnum = ANY(i.indkey) "
222 "LEFT JOIN pg_attrdef def ON def.adrelid = c.oid AND "
223 "def.adnum = a.attnum "
224 "LEFT JOIN spatial_ref_sys srs ON srs.srid = postgis_typmod_srid(a.atttypmod) "
225 "ORDER BY a.attnum "
226 "$$ LANGUAGE SQL");
227 }
228
229 if (osTables.size() != 0)
230 {
231 char** papszTables = CSLTokenizeString2(osTables, ",", 0);
232 for(int i=0;papszTables && papszTables[i];i++)
233 {
234 papoLayers = (OGRCARTODBTableLayer**) CPLRealloc(
235 papoLayers, (nLayers + 1) * sizeof(OGRCARTODBTableLayer*));
236 papoLayers[nLayers ++] = new OGRCARTODBTableLayer(this, papszTables[i]);
237 }
238 CSLDestroy(papszTables);
239 return TRUE;
240 }
241
242 OGRLayer* poTableListLayer = ExecuteSQLInternal("SELECT CDB_UserTables()");
243 if( poTableListLayer )
244 {
245 OGRFeature* poFeat;
246 while( (poFeat = poTableListLayer->GetNextFeature()) != NULL )
247 {
248 if( poFeat->GetFieldCount() == 1 )
249 {
250 papoLayers = (OGRCARTODBTableLayer**) CPLRealloc(
251 papoLayers, (nLayers + 1) * sizeof(OGRCARTODBTableLayer*));
252 papoLayers[nLayers ++] = new OGRCARTODBTableLayer(
253 this, poFeat->GetFieldAsString(0));
254 }
255 delete poFeat;
256 }
257 ReleaseResultSet(poTableListLayer);
258 }
259 else if( osCurrentSchema == "public" )
260 return FALSE;
261
262 /* There's currently a bug with CDB_UserTables() on multi-user accounts */
263 if( nLayers == 0 && osCurrentSchema != "public" )
264 {
265 CPLString osSQL;
266 osSQL.Printf("SELECT c.relname FROM pg_class c, pg_namespace n "
267 "WHERE c.relkind in ('r', 'v') AND c.relname !~ '^pg_' AND c.relnamespace=n.oid AND n.nspname = '%s'",
268 OGRCARTODBEscapeLiteral(osCurrentSchema).c_str());
269 poTableListLayer = ExecuteSQLInternal(osSQL);
270 if( poTableListLayer )
271 {
272 OGRFeature* poFeat;
273 while( (poFeat = poTableListLayer->GetNextFeature()) != NULL )
274 {
275 if( poFeat->GetFieldCount() == 1 )
276 {
277 papoLayers = (OGRCARTODBTableLayer**) CPLRealloc(
278 papoLayers, (nLayers + 1) * sizeof(OGRCARTODBTableLayer*));
279 papoLayers[nLayers ++] = new OGRCARTODBTableLayer(
280 this, poFeat->GetFieldAsString(0));
281 }
282 delete poFeat;
283 }
284 ReleaseResultSet(poTableListLayer);
285 }
286 else
287 return FALSE;
288 }
289
290 return TRUE;
291 }
292
293 /************************************************************************/
294 /* GetAPIURL() */
295 /************************************************************************/
296
GetAPIURL() const297 const char* OGRCARTODBDataSource::GetAPIURL() const
298 {
299 const char* pszAPIURL = CPLGetConfigOption("CARTODB_API_URL", NULL);
300 if (pszAPIURL)
301 return pszAPIURL;
302 else if (bUseHTTPS)
303 return CPLSPrintf("https://%s.cartodb.com/api/v2/sql", pszAccount);
304 else
305 return CPLSPrintf("http://%s.cartodb.com/api/v2/sql", pszAccount);
306 }
307
308 /************************************************************************/
309 /* FetchSRSId() */
310 /************************************************************************/
311
FetchSRSId(OGRSpatialReference * poSRS)312 int OGRCARTODBDataSource::FetchSRSId( OGRSpatialReference * poSRS )
313
314 {
315 const char* pszAuthorityName;
316
317 if( poSRS == NULL )
318 return 0;
319
320 OGRSpatialReference oSRS(*poSRS);
321 poSRS = NULL;
322
323 pszAuthorityName = oSRS.GetAuthorityName(NULL);
324
325 if( pszAuthorityName == NULL || strlen(pszAuthorityName) == 0 )
326 {
327 /* -------------------------------------------------------------------- */
328 /* Try to identify an EPSG code */
329 /* -------------------------------------------------------------------- */
330 oSRS.AutoIdentifyEPSG();
331
332 pszAuthorityName = oSRS.GetAuthorityName(NULL);
333 if (pszAuthorityName != NULL && EQUAL(pszAuthorityName, "EPSG"))
334 {
335 const char* pszAuthorityCode = oSRS.GetAuthorityCode(NULL);
336 if ( pszAuthorityCode != NULL && strlen(pszAuthorityCode) > 0 )
337 {
338 /* Import 'clean' SRS */
339 oSRS.importFromEPSG( atoi(pszAuthorityCode) );
340
341 pszAuthorityName = oSRS.GetAuthorityName(NULL);
342 }
343 }
344 }
345 /* -------------------------------------------------------------------- */
346 /* Check whether the EPSG authority code is already mapped to a */
347 /* SRS ID. */
348 /* -------------------------------------------------------------------- */
349 if( pszAuthorityName != NULL && EQUAL( pszAuthorityName, "EPSG" ) )
350 {
351 int nAuthorityCode;
352
353 /* For the root authority name 'EPSG', the authority code
354 * should always be integral
355 */
356 nAuthorityCode = atoi( oSRS.GetAuthorityCode(NULL) );
357
358 return nAuthorityCode;
359 }
360
361 return 0;
362 }
363
364 /************************************************************************/
365 /* ICreateLayer() */
366 /************************************************************************/
367
ICreateLayer(const char * pszName,OGRSpatialReference * poSpatialRef,OGRwkbGeometryType eGType,char ** papszOptions)368 OGRLayer *OGRCARTODBDataSource::ICreateLayer( const char *pszName,
369 OGRSpatialReference *poSpatialRef,
370 OGRwkbGeometryType eGType,
371 char ** papszOptions )
372 {
373 if (!bReadWrite)
374 {
375 CPLError(CE_Failure, CPLE_AppDefined, "Operation not available in read-only mode");
376 return NULL;
377 }
378
379 /* -------------------------------------------------------------------- */
380 /* Do we already have this layer? If so, should we blow it */
381 /* away? */
382 /* -------------------------------------------------------------------- */
383 int iLayer;
384
385 for( iLayer = 0; iLayer < nLayers; iLayer++ )
386 {
387 if( EQUAL(pszName,papoLayers[iLayer]->GetName()) )
388 {
389 if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != NULL
390 && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
391 {
392 DeleteLayer( iLayer );
393 }
394 else
395 {
396 CPLError( CE_Failure, CPLE_AppDefined,
397 "Layer %s already exists, CreateLayer failed.\n"
398 "Use the layer creation option OVERWRITE=YES to "
399 "replace it.",
400 pszName );
401 return NULL;
402 }
403 }
404 }
405
406 CPLString osName(pszName);
407 if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
408 {
409 char* pszTmp = OGRPGCommonLaunderName(pszName);
410 osName = pszTmp;
411 CPLFree(pszTmp);
412 }
413
414 OGRCARTODBTableLayer* poLayer = new OGRCARTODBTableLayer(this, osName);
415 int bGeomNullable = CSLFetchBoolean(papszOptions, "GEOMETRY_NULLABLE", TRUE);
416 int bCartoDBify = CSLFetchBoolean(papszOptions, "CARTODBFY",
417 CSLFetchBoolean(papszOptions, "CARTODBIFY", TRUE));
418 poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
419 poLayer->SetDeferedCreation(eGType, poSpatialRef, bGeomNullable, bCartoDBify);
420 papoLayers = (OGRCARTODBTableLayer**) CPLRealloc(
421 papoLayers, (nLayers + 1) * sizeof(OGRCARTODBTableLayer*));
422 papoLayers[nLayers ++] = poLayer;
423
424 return poLayer;
425 }
426
427 /************************************************************************/
428 /* DeleteLayer() */
429 /************************************************************************/
430
DeleteLayer(int iLayer)431 OGRErr OGRCARTODBDataSource::DeleteLayer(int iLayer)
432 {
433 if (!bReadWrite)
434 {
435 CPLError(CE_Failure, CPLE_AppDefined,
436 "Operation not available in read-only mode");
437 return OGRERR_FAILURE;
438 }
439
440 if( iLayer < 0 || iLayer >= nLayers )
441 {
442 CPLError( CE_Failure, CPLE_AppDefined,
443 "Layer %d not in legal range of 0 to %d.",
444 iLayer, nLayers-1 );
445 return OGRERR_FAILURE;
446 }
447
448 /* -------------------------------------------------------------------- */
449 /* Blow away our OGR structures related to the layer. This is */
450 /* pretty dangerous if anything has a reference to this layer! */
451 /* -------------------------------------------------------------------- */
452 CPLString osLayerName = papoLayers[iLayer]->GetLayerDefn()->GetName();
453
454 CPLDebug( "CARTODB", "DeleteLayer(%s)", osLayerName.c_str() );
455
456 int bDeferedCreation = papoLayers[iLayer]->GetDeferedCreation();
457 papoLayers[iLayer]->CancelDeferedCreation();
458 delete papoLayers[iLayer];
459 memmove( papoLayers + iLayer, papoLayers + iLayer + 1,
460 sizeof(void *) * (nLayers - iLayer - 1) );
461 nLayers--;
462
463 if (osLayerName.size() == 0)
464 return OGRERR_NONE;
465
466 if( !bDeferedCreation )
467 {
468 CPLString osSQL;
469 osSQL.Printf("DROP TABLE %s",
470 OGRCARTODBEscapeIdentifier(osLayerName).c_str());
471
472 json_object* poObj = RunSQL(osSQL);
473 if( poObj == NULL )
474 return OGRERR_FAILURE;
475 json_object_put(poObj);
476 }
477
478 return OGRERR_NONE;
479 }
480
481 /************************************************************************/
482 /* AddHTTPOptions() */
483 /************************************************************************/
484
AddHTTPOptions()485 char** OGRCARTODBDataSource::AddHTTPOptions()
486 {
487 bMustCleanPersistant = TRUE;
488
489 return CSLAddString(NULL, CPLSPrintf("PERSISTENT=CARTODB:%p", this));
490 }
491
492 /************************************************************************/
493 /* RunSQL() */
494 /************************************************************************/
495
RunSQL(const char * pszUnescapedSQL)496 json_object* OGRCARTODBDataSource::RunSQL(const char* pszUnescapedSQL)
497 {
498 CPLString osSQL("POSTFIELDS=q=");
499 /* Do post escaping */
500 for(int i=0;pszUnescapedSQL[i] != 0;i++)
501 {
502 const int ch = ((unsigned char*)pszUnescapedSQL)[i];
503 if (ch != '&' && ch >= 32 && ch < 128)
504 osSQL += (char)ch;
505 else
506 osSQL += CPLSPrintf("%%%02X", ch);
507 }
508
509 /* -------------------------------------------------------------------- */
510 /* Provide the API Key */
511 /* -------------------------------------------------------------------- */
512 if( osAPIKey.size() )
513 {
514 osSQL += "&api_key=";
515 osSQL += osAPIKey;
516 }
517
518 /* -------------------------------------------------------------------- */
519 /* Collection the header options and execute request. */
520 /* -------------------------------------------------------------------- */
521 const char* pszAPIURL = GetAPIURL();
522 char** papszOptions = CSLAddString(
523 strncmp(pszAPIURL, "/vsimem/", strlen("/vsimem/")) != 0 ? AddHTTPOptions(): NULL, osSQL);
524 CPLHTTPResult * psResult = CPLHTTPFetch( GetAPIURL(), papszOptions);
525 CSLDestroy(papszOptions);
526
527 /* -------------------------------------------------------------------- */
528 /* Check for some error conditions and report. HTML Messages */
529 /* are transformed info failure. */
530 /* -------------------------------------------------------------------- */
531 if (psResult && psResult->pszContentType &&
532 strncmp(psResult->pszContentType, "text/html", 9) == 0)
533 {
534 CPLDebug( "CARTODB", "RunSQL HTML Response:%s", psResult->pabyData );
535 CPLError(CE_Failure, CPLE_AppDefined,
536 "HTML error page returned by server");
537 CPLHTTPDestroyResult(psResult);
538 return NULL;
539 }
540 if (psResult && psResult->pszErrBuf != NULL)
541 {
542 CPLDebug( "CARTODB", "RunSQL Error Message:%s", psResult->pszErrBuf );
543 }
544 else if (psResult && psResult->nStatus != 0)
545 {
546 CPLDebug( "CARTODB", "RunSQL Error Status:%d", psResult->nStatus );
547 }
548
549 if( psResult->pabyData == NULL )
550 {
551 CPLHTTPDestroyResult(psResult);
552 return NULL;
553 }
554
555 if( strlen((const char*)psResult->pabyData) < 1000 )
556 CPLDebug( "CARTODB", "RunSQL Response:%s", psResult->pabyData );
557
558 json_tokener* jstok = NULL;
559 json_object* poObj = NULL;
560
561 jstok = json_tokener_new();
562 poObj = json_tokener_parse_ex(jstok, (const char*) psResult->pabyData, -1);
563 if( jstok->err != json_tokener_success)
564 {
565 CPLError( CE_Failure, CPLE_AppDefined,
566 "JSON parsing error: %s (at offset %d)",
567 json_tokener_error_desc(jstok->err), jstok->char_offset);
568 json_tokener_free(jstok);
569 CPLHTTPDestroyResult(psResult);
570 return NULL;
571 }
572 json_tokener_free(jstok);
573
574 CPLHTTPDestroyResult(psResult);
575
576 if( poObj != NULL )
577 {
578 if( json_object_get_type(poObj) == json_type_object )
579 {
580 json_object* poError = json_object_object_get(poObj, "error");
581 if( poError != NULL && json_object_get_type(poError) == json_type_array &&
582 json_object_array_length(poError) > 0 )
583 {
584 poError = json_object_array_get_idx(poError, 0);
585 if( poError != NULL && json_object_get_type(poError) == json_type_string )
586 {
587 CPLError(CE_Failure, CPLE_AppDefined,
588 "Error returned by server : %s", json_object_get_string(poError));
589 json_object_put(poObj);
590 return NULL;
591 }
592 }
593 }
594 else
595 {
596 json_object_put(poObj);
597 return NULL;
598 }
599 }
600
601 return poObj;
602 }
603
604 /************************************************************************/
605 /* OGRCARTODBGetSingleRow() */
606 /************************************************************************/
607
OGRCARTODBGetSingleRow(json_object * poObj)608 json_object* OGRCARTODBGetSingleRow(json_object* poObj)
609 {
610 if( poObj == NULL )
611 {
612 return NULL;
613 }
614
615 json_object* poRows = json_object_object_get(poObj, "rows");
616 if( poRows == NULL ||
617 json_object_get_type(poRows) != json_type_array ||
618 json_object_array_length(poRows) != 1 )
619 {
620 return NULL;
621 }
622
623 json_object* poRowObj = json_object_array_get_idx(poRows, 0);
624 if( poRowObj == NULL || json_object_get_type(poRowObj) != json_type_object )
625 {
626 return NULL;
627 }
628
629 return poRowObj;
630 }
631
632 /************************************************************************/
633 /* ExecuteSQL() */
634 /************************************************************************/
635
ExecuteSQL(const char * pszSQLCommand,OGRGeometry * poSpatialFilter,const char * pszDialect)636 OGRLayer * OGRCARTODBDataSource::ExecuteSQL( const char *pszSQLCommand,
637 OGRGeometry *poSpatialFilter,
638 const char *pszDialect )
639
640 {
641 return ExecuteSQLInternal(pszSQLCommand, poSpatialFilter, pszDialect,
642 TRUE);
643 }
644
ExecuteSQLInternal(const char * pszSQLCommand,OGRGeometry * poSpatialFilter,const char * pszDialect,int bRunDeferedActions)645 OGRLayer * OGRCARTODBDataSource::ExecuteSQLInternal( const char *pszSQLCommand,
646 OGRGeometry *poSpatialFilter,
647 const char *pszDialect,
648 int bRunDeferedActions )
649
650 {
651 if( bRunDeferedActions )
652 {
653 for( int iLayer = 0; iLayer < nLayers; iLayer++ )
654 {
655 papoLayers[iLayer]->RunDeferedCreationIfNecessary();
656 papoLayers[iLayer]->FlushDeferedInsert();
657 }
658 }
659
660 /* Skip leading spaces */
661 while(*pszSQLCommand == ' ')
662 pszSQLCommand ++;
663
664 /* -------------------------------------------------------------------- */
665 /* Use generic implementation for recognized dialects */
666 /* -------------------------------------------------------------------- */
667 if( IsGenericSQLDialect(pszDialect) )
668 return OGRDataSource::ExecuteSQL( pszSQLCommand,
669 poSpatialFilter,
670 pszDialect );
671
672 /* -------------------------------------------------------------------- */
673 /* Special case DELLAYER: command. */
674 /* -------------------------------------------------------------------- */
675 if( EQUALN(pszSQLCommand,"DELLAYER:",9) )
676 {
677 const char *pszLayerName = pszSQLCommand + 9;
678
679 while( *pszLayerName == ' ' )
680 pszLayerName++;
681
682 for( int iLayer = 0; iLayer < nLayers; iLayer++ )
683 {
684 if( EQUAL(papoLayers[iLayer]->GetName(),
685 pszLayerName ))
686 {
687 DeleteLayer( iLayer );
688 break;
689 }
690 }
691 return NULL;
692 }
693
694 if( !EQUALN(pszSQLCommand, "SELECT", strlen("SELECT")) &&
695 !EQUALN(pszSQLCommand, "EXPLAIN", strlen("EXPLAIN")) &&
696 !EQUALN(pszSQLCommand, "WITH", strlen("WITH")) )
697 {
698 RunSQL(pszSQLCommand);
699 return NULL;
700 }
701
702 OGRCARTODBResultLayer* poLayer = new OGRCARTODBResultLayer( this, pszSQLCommand );
703
704 if( poSpatialFilter != NULL )
705 poLayer->SetSpatialFilter( poSpatialFilter );
706
707 if( !poLayer->IsOK() )
708 {
709 delete poLayer;
710 return NULL;
711 }
712
713 return poLayer;
714 }
715
716 /************************************************************************/
717 /* ReleaseResultSet() */
718 /************************************************************************/
719
ReleaseResultSet(OGRLayer * poLayer)720 void OGRCARTODBDataSource::ReleaseResultSet( OGRLayer * poLayer )
721
722 {
723 delete poLayer;
724 }
725