1 : /******************************************************************************
2 : * $Id: ogrsqlitedatasource.cpp 17990 2009-11-11 12:06:49Z chaitanya $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRSQLiteDataSource class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
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_sqlite.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "cpl_hash_set.h"
34 :
35 : #ifdef HAVE_SPATIALITE
36 : #include "spatialite.h"
37 : #endif
38 :
39 : static int bSpatialiteLoaded = FALSE;
40 :
41 : CPL_CVSID("$Id: ogrsqlitedatasource.cpp 17990 2009-11-11 12:06:49Z chaitanya $");
42 :
43 : /************************************************************************/
44 : /* OGRSQLiteDataSource() */
45 : /************************************************************************/
46 :
47 32 : OGRSQLiteDataSource::OGRSQLiteDataSource()
48 :
49 : {
50 32 : pszName = NULL;
51 32 : papoLayers = NULL;
52 32 : nLayers = 0;
53 :
54 32 : nSoftTransactionLevel = 0;
55 :
56 32 : nKnownSRID = 0;
57 32 : panSRID = NULL;
58 32 : papoSRS = NULL;
59 :
60 32 : bHaveGeometryColumns = FALSE;
61 32 : bIsSpatiaLite = FALSE;
62 32 : }
63 :
64 : /************************************************************************/
65 : /* ~OGRSQLiteDataSource() */
66 : /************************************************************************/
67 :
68 64 : OGRSQLiteDataSource::~OGRSQLiteDataSource()
69 :
70 : {
71 : int i;
72 :
73 32 : CPLFree( pszName );
74 :
75 136 : for( i = 0; i < nLayers; i++ )
76 104 : delete papoLayers[i];
77 :
78 32 : CPLFree( papoLayers );
79 :
80 44 : for( i = 0; i < nKnownSRID; i++ )
81 : {
82 12 : if( papoSRS[i] != NULL )
83 12 : papoSRS[i]->Release();
84 : }
85 32 : CPLFree( panSRID );
86 32 : CPLFree( papoSRS );
87 :
88 32 : if( hDB != NULL )
89 32 : sqlite3_close( hDB );
90 64 : }
91 :
92 : /************************************************************************/
93 : /* SpatiaLiteToOGRGeomType() */
94 : /* Map SpatiaLite geometry format strings to corresponding */
95 : /* OGR constants. */
96 : /************************************************************************/
97 :
98 : OGRwkbGeometryType
99 6 : OGRSQLiteDataSource::SpatiaLiteToOGRGeomType( const char *pszGeomType )
100 : {
101 6 : if ( EQUAL(pszGeomType, "POINT") )
102 0 : return wkbPoint;
103 6 : else if ( EQUAL(pszGeomType, "LINESTRING") )
104 0 : return wkbLineString;
105 6 : else if ( EQUAL(pszGeomType, "POLYGON") )
106 4 : return wkbPolygon;
107 2 : else if ( EQUAL(pszGeomType, "MULTIPOINT") )
108 0 : return wkbMultiPoint;
109 2 : else if ( EQUAL(pszGeomType, "MULTILINESTRING") )
110 0 : return wkbMultiLineString;
111 2 : else if ( EQUAL(pszGeomType, "MULTIPOLYGON") )
112 0 : return wkbMultiPolygon;
113 2 : else if ( EQUAL(pszGeomType, "GEOMETRYCOLLECTION") )
114 0 : return wkbGeometryCollection;
115 : else
116 2 : return wkbUnknown;
117 : }
118 :
119 : /************************************************************************/
120 : /* OGRToSpatiaLiteGeomType() */
121 : /* Map OGR geometry format constants to corresponding */
122 : /* SpatiaLite strings */
123 : /************************************************************************/
124 :
125 : const char *
126 1 : OGRSQLiteDataSource::OGRToSpatiaLiteGeomType( OGRwkbGeometryType eGeomType )
127 : {
128 1 : switch ( wkbFlatten(eGeomType) )
129 : {
130 : case wkbUnknown:
131 1 : return "GEOMETRY";
132 : case wkbPoint:
133 0 : return "POINT";
134 : case wkbLineString:
135 0 : return "LINESTRING";
136 : case wkbPolygon:
137 0 : return "POLYGON";
138 : case wkbMultiPoint:
139 0 : return "MULTIPOINT";
140 : case wkbMultiLineString:
141 0 : return "MULTILINESTRING";
142 : case wkbMultiPolygon:
143 0 : return "MULTIPOLYGON";
144 : case wkbGeometryCollection:
145 0 : return "GEOMETRYCOLLECTION";
146 : default:
147 0 : return "";
148 : }
149 : }
150 :
151 : /************************************************************************/
152 : /* Open() */
153 : /* */
154 : /* Note, the Open() will implicitly create the database if it */
155 : /* does not already exist. */
156 : /************************************************************************/
157 :
158 32 : int OGRSQLiteDataSource::Open( const char * pszNewName )
159 :
160 : {
161 : CPLAssert( nLayers == 0 );
162 :
163 32 : pszName = CPLStrdup( pszNewName );
164 :
165 : /* -------------------------------------------------------------------- */
166 : /* Try loading SpatiaLite. */
167 : /* -------------------------------------------------------------------- */
168 : #ifdef HAVE_SPATIALITE
169 : if (!bSpatialiteLoaded && CSLTestBoolean(CPLGetConfigOption("SPATIALITE_LOAD", "TRUE")))
170 : {
171 : bSpatialiteLoaded = TRUE;
172 : spatialite_init(CSLTestBoolean(CPLGetConfigOption("SPATIALITE_INIT_VERBOSE", "FALSE")));
173 : }
174 : #endif
175 :
176 32 : int bListAllTables = CSLTestBoolean(CPLGetConfigOption("SQLITE_LIST_ALL_TABLES", "NO"));
177 :
178 : /* -------------------------------------------------------------------- */
179 : /* Try to open the sqlite database properly now. */
180 : /* -------------------------------------------------------------------- */
181 : int rc;
182 :
183 32 : hDB = NULL;
184 32 : rc = sqlite3_open( pszNewName, &hDB );
185 32 : if( rc != SQLITE_OK )
186 : {
187 : CPLError( CE_Failure, CPLE_OpenFailed,
188 : "sqlite3_open(%s) failed: %s",
189 0 : pszNewName, sqlite3_errmsg( hDB ) );
190 :
191 0 : return FALSE;
192 : }
193 :
194 32 : CPLHashSet* hSet = CPLHashSetNew(CPLHashSetHashStr, CPLHashSetEqualStr, CPLFree);
195 :
196 : /* -------------------------------------------------------------------- */
197 : /* If we have a GEOMETRY_COLUMNS tables, initialize on the basis */
198 : /* of that. */
199 : /* -------------------------------------------------------------------- */
200 : char **papszResult;
201 : int nRowCount, iRow, nColCount;
202 : char *pszErrMsg;
203 :
204 : rc = sqlite3_get_table(
205 : hDB,
206 : "SELECT f_table_name, f_geometry_column, geometry_type, coord_dimension, geometry_format, srid"
207 : " FROM geometry_columns",
208 32 : &papszResult, &nRowCount, &nColCount, &pszErrMsg );
209 :
210 32 : if( rc == SQLITE_OK )
211 : {
212 9 : CPLDebug("SQLITE", "OGR style SQLite DB found !");
213 :
214 9 : bHaveGeometryColumns = TRUE;
215 :
216 40 : for( iRow = 0; iRow < nRowCount; iRow++ )
217 : {
218 31 : char **papszRow = papszResult + iRow * 6 + 6;
219 31 : OGRwkbGeometryType eGeomType = wkbUnknown;
220 31 : int nSRID = 0;
221 :
222 31 : eGeomType = (OGRwkbGeometryType) atoi(papszRow[2]);
223 :
224 31 : if( atoi(papszRow[3]) > 2 )
225 0 : eGeomType = (OGRwkbGeometryType) (((int)eGeomType) | wkb25DBit);
226 :
227 31 : if( papszRow[5] != NULL )
228 7 : nSRID = atoi(papszRow[5]);
229 :
230 62 : OpenTable( papszRow[0], papszRow[1], eGeomType, papszRow[4],
231 93 : FetchSRS( nSRID ) );
232 :
233 31 : if (bListAllTables)
234 0 : CPLHashSetInsert(hSet, CPLStrdup(papszRow[0]));
235 : }
236 :
237 9 : sqlite3_free_table(papszResult);
238 :
239 9 : if (bListAllTables)
240 0 : goto all_tables;
241 :
242 9 : CPLHashSetDestroy(hSet);
243 :
244 9 : return TRUE;
245 : }
246 :
247 : /* -------------------------------------------------------------------- */
248 : /* Otherwise we can deal with SpatiaLite database. */
249 : /* -------------------------------------------------------------------- */
250 23 : sqlite3_free( pszErrMsg );
251 : rc = sqlite3_get_table( hDB,
252 : "SELECT f_table_name, f_geometry_column, "
253 : "type, coord_dimension, srid, "
254 : "spatial_index_enabled FROM geometry_columns",
255 : &papszResult, &nRowCount,
256 23 : &nColCount, &pszErrMsg );
257 :
258 23 : if ( rc == SQLITE_OK )
259 : {
260 23 : CPLDebug("SQLITE", "SpatiaLite-style SQLite DB found !");
261 :
262 23 : bIsSpatiaLite = TRUE;
263 23 : bHaveGeometryColumns = TRUE;
264 :
265 29 : for ( iRow = 0; iRow < nRowCount; iRow++ )
266 : {
267 6 : char **papszRow = papszResult + iRow * 6 + 6;
268 : OGRwkbGeometryType eGeomType;
269 6 : int nSRID = 0;
270 6 : int bHasSpatialIndex = FALSE;
271 :
272 6 : eGeomType = SpatiaLiteToOGRGeomType(papszRow[2]);
273 :
274 6 : if( atoi(papszRow[3]) > 2 )
275 0 : eGeomType = (OGRwkbGeometryType) (((int)eGeomType) | wkb25DBit);
276 :
277 6 : if( papszRow[4] != NULL )
278 6 : nSRID = atoi(papszRow[4]);
279 :
280 : /* Only look for presence of a spatial index if linked against SpatiaLite */
281 6 : if( bSpatialiteLoaded && papszRow[5] != NULL )
282 0 : bHasSpatialIndex = atoi(papszRow[5]);
283 :
284 6 : OpenTable( papszRow[0], papszRow[1], eGeomType, "SpatiaLite",
285 12 : FetchSRS( nSRID ), nSRID, bHasSpatialIndex );
286 :
287 6 : if (bListAllTables)
288 4 : CPLHashSetInsert(hSet, CPLStrdup(papszRow[0]));
289 : }
290 :
291 23 : sqlite3_free_table(papszResult);
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Detect VirtualShape layers */
295 : /* -------------------------------------------------------------------- */
296 : #ifdef HAVE_SPATIALITE
297 : if (bSpatialiteLoaded)
298 : {
299 : rc = sqlite3_get_table( hDB,
300 : "SELECT name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE % USING %VirtualShape%'",
301 : &papszResult, &nRowCount,
302 : &nColCount, &pszErrMsg );
303 :
304 : if ( rc == SQLITE_OK )
305 : {
306 : for( iRow = 0; iRow < nRowCount; iRow++ )
307 : {
308 : OpenTable( papszResult[iRow+1] );
309 :
310 : if (bListAllTables)
311 : CPLHashSetInsert(hSet, CPLStrdup(papszResult[iRow+1]));
312 : }
313 : }
314 : else
315 : {
316 : CPLError( CE_Failure, CPLE_AppDefined,
317 : "Unable to fetch list of tables: %s",
318 : pszErrMsg );
319 : sqlite3_free( pszErrMsg );
320 : }
321 :
322 : sqlite3_free_table(papszResult);
323 : }
324 : #endif
325 :
326 23 : if (bListAllTables)
327 19 : goto all_tables;
328 :
329 4 : CPLHashSetDestroy(hSet);
330 :
331 4 : return TRUE;
332 : }
333 :
334 : /* -------------------------------------------------------------------- */
335 : /* Otherwise our final resort is to return all tables and views */
336 : /* as non-spatial tables. */
337 : /* -------------------------------------------------------------------- */
338 0 : sqlite3_free( pszErrMsg );
339 :
340 : all_tables:
341 : rc = sqlite3_get_table( hDB,
342 : "SELECT name FROM sqlite_master "
343 : "WHERE type IN ('table','view') "
344 : "UNION ALL "
345 : "SELECT name FROM sqlite_temp_master "
346 : "WHERE type IN ('table','view') "
347 : "ORDER BY 1",
348 : &papszResult, &nRowCount,
349 19 : &nColCount, &pszErrMsg );
350 :
351 19 : if( rc != SQLITE_OK )
352 : {
353 : CPLError( CE_Failure, CPLE_AppDefined,
354 : "Unable to fetch list of tables: %s",
355 0 : pszErrMsg );
356 0 : sqlite3_free( pszErrMsg );
357 0 : CPLHashSetDestroy(hSet);
358 0 : return FALSE;
359 : }
360 :
361 90 : for( iRow = 0; iRow < nRowCount; iRow++ )
362 : {
363 71 : if (CPLHashSetLookup(hSet, papszResult[iRow+1]) == NULL)
364 67 : OpenTable( papszResult[iRow+1] );
365 : }
366 :
367 19 : sqlite3_free_table(papszResult);
368 19 : CPLHashSetDestroy(hSet);
369 :
370 19 : return TRUE;
371 : }
372 :
373 : /************************************************************************/
374 : /* OpenTable() */
375 : /************************************************************************/
376 :
377 104 : int OGRSQLiteDataSource::OpenTable( const char *pszNewName,
378 : const char *pszGeomCol,
379 : OGRwkbGeometryType eGeomType,
380 : const char *pszGeomFormat,
381 : OGRSpatialReference *poSRS, int nSRID,
382 : int bHasSpatialIndex)
383 :
384 : {
385 : /* -------------------------------------------------------------------- */
386 : /* Create the layer object. */
387 : /* -------------------------------------------------------------------- */
388 : OGRSQLiteTableLayer *poLayer;
389 :
390 104 : poLayer = new OGRSQLiteTableLayer( this );
391 :
392 104 : if( poLayer->Initialize( pszNewName, pszGeomCol,
393 : eGeomType, pszGeomFormat,
394 : poSRS, nSRID, bHasSpatialIndex ) )
395 : {
396 0 : delete poLayer;
397 0 : return FALSE;
398 : }
399 :
400 : /* -------------------------------------------------------------------- */
401 : /* Add layer to data source layer list. */
402 : /* -------------------------------------------------------------------- */
403 : papoLayers = (OGRSQLiteLayer **)
404 104 : CPLRealloc( papoLayers, sizeof(OGRSQLiteLayer *) * (nLayers+1) );
405 104 : papoLayers[nLayers++] = poLayer;
406 :
407 104 : return TRUE;
408 : }
409 :
410 : /************************************************************************/
411 : /* TestCapability() */
412 : /************************************************************************/
413 :
414 0 : int OGRSQLiteDataSource::TestCapability( const char * pszCap )
415 :
416 : {
417 0 : if( EQUAL(pszCap,ODsCCreateLayer) )
418 0 : return TRUE;
419 : else
420 0 : return FALSE;
421 : }
422 :
423 : /************************************************************************/
424 : /* GetLayer() */
425 : /************************************************************************/
426 :
427 238 : OGRLayer *OGRSQLiteDataSource::GetLayer( int iLayer )
428 :
429 : {
430 238 : if( iLayer < 0 || iLayer >= nLayers )
431 0 : return NULL;
432 : else
433 238 : return papoLayers[iLayer];
434 : }
435 :
436 : /************************************************************************/
437 : /* ExecuteSQL() */
438 : /************************************************************************/
439 :
440 118 : OGRLayer * OGRSQLiteDataSource::ExecuteSQL( const char *pszSQLCommand,
441 : OGRGeometry *poSpatialFilter,
442 : const char *pszDialect )
443 :
444 : {
445 118 : if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
446 : return OGRDataSource::ExecuteSQL( pszSQLCommand,
447 : poSpatialFilter,
448 0 : pszDialect );
449 :
450 : /* -------------------------------------------------------------------- */
451 : /* Special case DELLAYER: command. */
452 : /* -------------------------------------------------------------------- */
453 118 : if( EQUALN(pszSQLCommand,"DELLAYER:",9) )
454 : {
455 9 : const char *pszLayerName = pszSQLCommand + 9;
456 :
457 18 : while( *pszLayerName == ' ' )
458 0 : pszLayerName++;
459 :
460 9 : DeleteLayer( pszLayerName );
461 9 : return NULL;
462 : }
463 :
464 : /* -------------------------------------------------------------------- */
465 : /* Prepare statement. */
466 : /* -------------------------------------------------------------------- */
467 : int rc;
468 109 : sqlite3_stmt *hSQLStmt = NULL;
469 :
470 : rc = sqlite3_prepare( GetDB(), pszSQLCommand, strlen(pszSQLCommand),
471 109 : &hSQLStmt, NULL );
472 :
473 109 : if( rc != SQLITE_OK )
474 : {
475 : CPLError( CE_Failure, CPLE_AppDefined,
476 : "In ExecuteSQL(): sqlite3_prepare(%s):\n %s",
477 17 : pszSQLCommand, sqlite3_errmsg(GetDB()) );
478 :
479 17 : if( hSQLStmt != NULL )
480 : {
481 0 : sqlite3_finalize( hSQLStmt );
482 : }
483 :
484 17 : return NULL;
485 : }
486 :
487 : /* -------------------------------------------------------------------- */
488 : /* Do we get a resultset? */
489 : /* -------------------------------------------------------------------- */
490 92 : rc = sqlite3_step( hSQLStmt );
491 92 : if( rc != SQLITE_ROW )
492 : {
493 72 : if ( rc != SQLITE_DONE )
494 : {
495 : CPLError( CE_Failure, CPLE_AppDefined,
496 : "In ExecuteSQL(): sqlite3_step(%s):\n %s",
497 0 : pszSQLCommand, sqlite3_errmsg(GetDB()) );
498 : }
499 72 : sqlite3_finalize( hSQLStmt );
500 72 : return NULL;
501 : }
502 :
503 : /* -------------------------------------------------------------------- */
504 : /* Create layer. */
505 : /* -------------------------------------------------------------------- */
506 20 : OGRSQLiteSelectLayer *poLayer = NULL;
507 :
508 20 : poLayer = new OGRSQLiteSelectLayer( this, hSQLStmt );
509 :
510 20 : if( poSpatialFilter != NULL )
511 0 : poLayer->SetSpatialFilter( poSpatialFilter );
512 :
513 20 : return poLayer;
514 : }
515 :
516 : /************************************************************************/
517 : /* ReleaseResultSet() */
518 : /************************************************************************/
519 :
520 20 : void OGRSQLiteDataSource::ReleaseResultSet( OGRLayer * poLayer )
521 :
522 : {
523 20 : delete poLayer;
524 20 : }
525 :
526 : /************************************************************************/
527 : /* CreateLayer() */
528 : /************************************************************************/
529 :
530 : OGRLayer *
531 8 : OGRSQLiteDataSource::CreateLayer( const char * pszLayerNameIn,
532 : OGRSpatialReference *poSRS,
533 : OGRwkbGeometryType eType,
534 : char ** papszOptions )
535 :
536 : {
537 : char *pszLayerName;
538 : const char *pszGeomFormat;
539 :
540 8 : if( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) )
541 8 : pszLayerName = LaunderName( pszLayerNameIn );
542 : else
543 0 : pszLayerName = CPLStrdup( pszLayerNameIn );
544 :
545 8 : pszGeomFormat = CSLFetchNameValue( papszOptions, "FORMAT" );
546 8 : if( pszGeomFormat == NULL )
547 : {
548 5 : if ( !bIsSpatiaLite )
549 4 : pszGeomFormat = "WKB";
550 : else
551 1 : pszGeomFormat = "SpatiaLite";
552 : }
553 :
554 8 : if( !EQUAL(pszGeomFormat,"WKT")
555 : && !EQUAL(pszGeomFormat,"WKB")
556 : && !EQUAL(pszGeomFormat, "SpatiaLite") )
557 : {
558 : CPLError( CE_Failure, CPLE_AppDefined,
559 : "FORMAT=%s not recognised or supported.",
560 0 : pszGeomFormat );
561 0 : return NULL;
562 : }
563 :
564 : /* -------------------------------------------------------------------- */
565 : /* Do we already have this layer? If so, should we blow it */
566 : /* away? */
567 : /* -------------------------------------------------------------------- */
568 : int iLayer;
569 :
570 29 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
571 : {
572 21 : if( EQUAL(pszLayerName,papoLayers[iLayer]->GetLayerDefn()->GetName()) )
573 : {
574 0 : if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != NULL
575 : && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
576 : {
577 0 : DeleteLayer( pszLayerName );
578 : }
579 : else
580 : {
581 : CPLError( CE_Failure, CPLE_AppDefined,
582 : "Layer %s already exists, CreateLayer failed.\n"
583 : "Use the layer creation option OVERWRITE=YES to "
584 : "replace it.",
585 0 : pszLayerName );
586 0 : CPLFree( pszLayerName );
587 0 : return NULL;
588 : }
589 : }
590 : }
591 :
592 : /* -------------------------------------------------------------------- */
593 : /* Try to get the SRS Id of this spatial reference system, */
594 : /* adding to the srs table if needed. */
595 : /* -------------------------------------------------------------------- */
596 8 : int nSRSId = -1;
597 :
598 8 : if( poSRS != NULL )
599 3 : nSRSId = FetchSRSId( poSRS );
600 :
601 : /* -------------------------------------------------------------------- */
602 : /* Create a basic table with the FID. Also include the */
603 : /* geometry if this is not a PostGIS enabled table. */
604 : /* -------------------------------------------------------------------- */
605 : int rc;
606 : char *pszErrMsg;
607 8 : const char *pszGeomCol = NULL;
608 8 : CPLString osCommand;
609 :
610 8 : if( eType == wkbNone )
611 : osCommand.Printf(
612 : "CREATE TABLE '%s' ( OGC_FID INTEGER PRIMARY KEY )",
613 0 : pszLayerName );
614 : else
615 : {
616 8 : if( EQUAL(pszGeomFormat,"WKT") )
617 : {
618 1 : pszGeomCol = "WKT_GEOMETRY";
619 : osCommand.Printf(
620 : "CREATE TABLE '%s' ( "
621 : " OGC_FID INTEGER PRIMARY KEY,"
622 : " %s VARCHAR )",
623 1 : pszLayerName, pszGeomCol );
624 : }
625 : else
626 : {
627 7 : pszGeomCol = "GEOMETRY";
628 : osCommand.Printf(
629 : "CREATE TABLE '%s' ( "
630 : " OGC_FID INTEGER PRIMARY KEY,"
631 : " %s BLOB )",
632 7 : pszLayerName, pszGeomCol );
633 : }
634 : }
635 :
636 : #ifdef DEBUG
637 : CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
638 : #endif
639 :
640 8 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
641 8 : if( rc != SQLITE_OK )
642 : {
643 : CPLError( CE_Failure, CPLE_AppDefined,
644 : "Unable to create table %s: %s",
645 0 : pszLayerName, pszErrMsg );
646 0 : sqlite3_free( pszErrMsg );
647 0 : return FALSE;
648 : }
649 :
650 : /* -------------------------------------------------------------------- */
651 : /* Eventually we should be adding this table to a table of */
652 : /* "geometric layers", capturing the WKT projection, and */
653 : /* perhaps some other housekeeping. */
654 : /* -------------------------------------------------------------------- */
655 8 : if( bHaveGeometryColumns && eType != wkbNone )
656 : {
657 : int nCoordDim;
658 :
659 : /* Sometimes there is an old cruft entry in the geometry_columns
660 : * table if things were not properly cleaned up before. We make
661 : * an effort to clean out such cruft.
662 : */
663 : osCommand.Printf(
664 : "DELETE FROM geometry_columns WHERE f_table_name = '%s'",
665 8 : pszLayerName );
666 :
667 : #ifdef DEBUG
668 : CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
669 : #endif
670 :
671 8 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
672 8 : if( rc != SQLITE_OK )
673 : {
674 0 : sqlite3_free( pszErrMsg );
675 0 : return FALSE;
676 : }
677 :
678 8 : if( eType == wkbFlatten(eType) )
679 8 : nCoordDim = 2;
680 : else
681 0 : nCoordDim = 3;
682 :
683 8 : if( nSRSId > 0 )
684 : {
685 3 : if ( bIsSpatiaLite )
686 : osCommand.Printf(
687 : "INSERT INTO geometry_columns "
688 : "(f_table_name, f_geometry_column, type, "
689 : "coord_dimension, srid, spatial_index_enabled) "
690 : "VALUES ('%s','%s', '%s', %d, %d, 0)",
691 : pszLayerName, pszGeomCol, OGRToSpatiaLiteGeomType(eType),
692 1 : nCoordDim, nSRSId );
693 : else
694 : osCommand.Printf(
695 : "INSERT INTO geometry_columns "
696 : "(f_table_name, f_geometry_column, geometry_format, "
697 : "geometry_type, coord_dimension, srid) VALUES "
698 : "('%s','%s','%s', %d, %d, %d)",
699 : pszLayerName, pszGeomCol, pszGeomFormat,
700 2 : (int) wkbFlatten(eType), nCoordDim, nSRSId );
701 : }
702 : else
703 : {
704 5 : if ( bIsSpatiaLite )
705 : osCommand.Printf(
706 : "INSERT INTO geometry_columns "
707 : "(f_table_name, f_geometry_column, type, "
708 : "coord_dimension, spatial_index_enabled) "
709 : "VALUES ('%s','%s', '%s', %d, 0)",
710 : pszLayerName, pszGeomCol, OGRToSpatiaLiteGeomType(eType),
711 0 : nCoordDim );
712 : else
713 : osCommand.Printf(
714 : "INSERT INTO geometry_columns "
715 : "(f_table_name, f_geometry_column, geometry_format, "
716 : "geometry_type, coord_dimension) VALUES "
717 : "('%s','%s','%s', %d, %d)",
718 : pszLayerName, pszGeomCol, pszGeomFormat,
719 5 : (int) wkbFlatten(eType), nCoordDim );
720 : }
721 :
722 : #ifdef DEBUG
723 : CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
724 : #endif
725 :
726 8 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
727 8 : if( rc != SQLITE_OK )
728 : {
729 : CPLError( CE_Failure, CPLE_AppDefined,
730 : "Unable to add %s table to geometry_columns:\n%s",
731 0 : pszLayerName, pszErrMsg );
732 0 : sqlite3_free( pszErrMsg );
733 0 : return FALSE;
734 : }
735 :
736 : /* -------------------------------------------------------------------- */
737 : /* Create the spatial index. */
738 : /* */
739 : /* We're doing this before we add geometry and record to the table */
740 : /* so this may not be exactly the best way to do it. */
741 : /* -------------------------------------------------------------------- */
742 : #ifdef HAVE_SPATIALITE
743 : /* Only if linked against SpatiaLite and the datasource was created as a SpatiaLite DB */
744 : if ( bIsSpatiaLite && bSpatialiteLoaded )
745 : #else
746 8 : if ( 0 )
747 : #endif
748 : {
749 : const char* pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
750 : if( pszSI == NULL || CSLTestBoolean(pszSI) )
751 : {
752 : osCommand.Printf("SELECT CreateSpatialIndex('%s', '%s')",
753 : pszLayerName, pszGeomCol);
754 :
755 : /* -------------------------------------------------------------------- */
756 : /* Prepare statement. */
757 : /* -------------------------------------------------------------------- */
758 : int rc;
759 : sqlite3_stmt *hSQLStmt = NULL;
760 :
761 : rc = sqlite3_prepare( GetDB(), osCommand, strlen(osCommand),
762 : &hSQLStmt, NULL );
763 :
764 : if( rc != SQLITE_OK )
765 : {
766 : CPLError( CE_Failure, CPLE_AppDefined,
767 : "In CreateLayer(): sqlite3_prepare(%s):\n %s",
768 : osCommand.c_str(), sqlite3_errmsg(GetDB()) );
769 : }
770 : else
771 : {
772 : /* -------------------------------------------------------------------- */
773 : /* Do we get a resultset? */
774 : /* -------------------------------------------------------------------- */
775 : rc = sqlite3_step( hSQLStmt );
776 : if( rc != SQLITE_ROW )
777 : {
778 : if ( rc != SQLITE_DONE )
779 : {
780 : CPLError( CE_Failure, CPLE_AppDefined,
781 : "In CreateLayer(): sqlite3_step(%s):\n %s",
782 : osCommand.c_str(), sqlite3_errmsg(GetDB()) );
783 : }
784 : }
785 : else
786 : {
787 : if (sqlite3_column_count(hSQLStmt) != 1 &&
788 : sqlite3_column_int(hSQLStmt, 0) != 1)
789 : {
790 : CPLError( CE_Failure, CPLE_AppDefined,
791 : "In CreateLayer(): sqlite3_step(%s): did not get expected result",
792 : osCommand.c_str() );
793 : }
794 : }
795 : }
796 :
797 : if( hSQLStmt != NULL )
798 : {
799 : sqlite3_finalize( hSQLStmt );
800 : }
801 : }
802 : }
803 : }
804 :
805 : /* -------------------------------------------------------------------- */
806 : /* Create the layer object. */
807 : /* -------------------------------------------------------------------- */
808 : OGRSQLiteTableLayer *poLayer;
809 :
810 8 : poLayer = new OGRSQLiteTableLayer( this );
811 :
812 : poLayer->Initialize( pszLayerName, pszGeomCol, eType, pszGeomFormat,
813 16 : FetchSRS(nSRSId), nSRSId );
814 :
815 8 : poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
816 :
817 : /* -------------------------------------------------------------------- */
818 : /* Add layer to data source layer list. */
819 : /* -------------------------------------------------------------------- */
820 : papoLayers = (OGRSQLiteLayer **)
821 8 : CPLRealloc( papoLayers, sizeof(OGRSQLiteLayer *) * (nLayers+1) );
822 :
823 8 : papoLayers[nLayers++] = poLayer;
824 :
825 8 : CPLFree( pszLayerName );
826 :
827 8 : return poLayer;
828 : }
829 :
830 : /************************************************************************/
831 : /* LaunderName() */
832 : /************************************************************************/
833 :
834 17 : char *OGRSQLiteDataSource::LaunderName( const char *pszSrcName )
835 :
836 : {
837 17 : char *pszSafeName = CPLStrdup( pszSrcName );
838 : int i;
839 :
840 154 : for( i = 0; pszSafeName[i] != '\0'; i++ )
841 : {
842 137 : pszSafeName[i] = (char) tolower( pszSafeName[i] );
843 137 : if( pszSafeName[i] == '-' || pszSafeName[i] == '#' )
844 0 : pszSafeName[i] = '_';
845 : }
846 :
847 17 : return pszSafeName;
848 : }
849 :
850 : /************************************************************************/
851 : /* DeleteLayer() */
852 : /************************************************************************/
853 :
854 9 : void OGRSQLiteDataSource::DeleteLayer( const char *pszLayerName )
855 :
856 : {
857 : int iLayer;
858 :
859 : /* -------------------------------------------------------------------- */
860 : /* Try to find layer. */
861 : /* -------------------------------------------------------------------- */
862 12 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
863 : {
864 11 : if( EQUAL(pszLayerName,papoLayers[iLayer]->GetLayerDefn()->GetName()) )
865 8 : break;
866 : }
867 :
868 9 : if( iLayer == nLayers )
869 : {
870 : CPLError( CE_Failure, CPLE_AppDefined,
871 : "Attempt to delete layer '%s', but this layer is not known to OGR.",
872 1 : pszLayerName );
873 1 : return;
874 : }
875 :
876 : /* -------------------------------------------------------------------- */
877 : /* Blow away our OGR structures related to the layer. This is */
878 : /* pretty dangerous if anything has a reference to this layer! */
879 : /* -------------------------------------------------------------------- */
880 8 : CPLDebug( "OGR_SQLITE", "DeleteLayer(%s)", pszLayerName );
881 :
882 8 : delete papoLayers[iLayer];
883 : memmove( papoLayers + iLayer, papoLayers + iLayer + 1,
884 8 : sizeof(void *) * (nLayers - iLayer - 1) );
885 8 : nLayers--;
886 :
887 : /* -------------------------------------------------------------------- */
888 : /* Remove from the database. */
889 : /* -------------------------------------------------------------------- */
890 : int rc;
891 : char *pszErrMsg;
892 :
893 : rc = sqlite3_exec( hDB, CPLSPrintf( "DROP TABLE '%s'", pszLayerName ),
894 8 : NULL, NULL, &pszErrMsg );
895 8 : if( rc != SQLITE_OK )
896 : {
897 : CPLError( CE_Failure, CPLE_AppDefined,
898 : "Unable to drop table %s: %s",
899 0 : pszLayerName, pszErrMsg );
900 0 : sqlite3_free( pszErrMsg );
901 0 : return;
902 : }
903 :
904 : /* -------------------------------------------------------------------- */
905 : /* Drop from geometry_columns table. */
906 : /* -------------------------------------------------------------------- */
907 8 : if( bHaveGeometryColumns )
908 : {
909 8 : CPLString osCommand;
910 :
911 : osCommand.Printf(
912 : "DELETE FROM geometry_columns WHERE f_table_name = '%s'",
913 8 : pszLayerName );
914 :
915 8 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
916 8 : if( rc != SQLITE_OK )
917 : {
918 : CPLError( CE_Warning, CPLE_AppDefined,
919 : "Removal from geometry_columns failed.\n%s: %s",
920 0 : osCommand.c_str(), pszErrMsg );
921 0 : sqlite3_free( pszErrMsg );
922 8 : }
923 : }
924 : }
925 :
926 : /************************************************************************/
927 : /* SoftStartTransaction() */
928 : /* */
929 : /* Create a transaction scope. If we already have a */
930 : /* transaction active this isn't a real transaction, but just */
931 : /* an increment to the scope count. */
932 : /************************************************************************/
933 :
934 13 : OGRErr OGRSQLiteDataSource::SoftStartTransaction()
935 :
936 : {
937 13 : nSoftTransactionLevel++;
938 :
939 13 : if( nSoftTransactionLevel == 1 )
940 : {
941 : int rc;
942 : char *pszErrMsg;
943 :
944 : #ifdef DEBUG
945 : CPLDebug( "OGR_SQLITE", "BEGIN Transaction" );
946 : #endif
947 :
948 13 : rc = sqlite3_exec( hDB, "BEGIN", NULL, NULL, &pszErrMsg );
949 13 : if( rc != SQLITE_OK )
950 : {
951 0 : nSoftTransactionLevel--;
952 : CPLError( CE_Failure, CPLE_AppDefined,
953 : "BEGIN transaction failed: %s",
954 0 : pszErrMsg );
955 0 : sqlite3_free( pszErrMsg );
956 0 : return OGRERR_FAILURE;
957 : }
958 : }
959 :
960 13 : return OGRERR_NONE;
961 : }
962 :
963 : /************************************************************************/
964 : /* SoftCommit() */
965 : /* */
966 : /* Commit the current transaction if we are at the outer */
967 : /* scope. */
968 : /************************************************************************/
969 :
970 12 : OGRErr OGRSQLiteDataSource::SoftCommit()
971 :
972 : {
973 12 : if( nSoftTransactionLevel <= 0 )
974 : {
975 0 : CPLDebug( "OGR_SQLITE", "SoftCommit() with no transaction active." );
976 0 : return OGRERR_FAILURE;
977 : }
978 :
979 12 : nSoftTransactionLevel--;
980 :
981 12 : if( nSoftTransactionLevel == 0 )
982 : {
983 : int rc;
984 : char *pszErrMsg;
985 :
986 : #ifdef DEBUG
987 : CPLDebug( "OGR_SQLITE", "COMMIT Transaction" );
988 : #endif
989 :
990 12 : rc = sqlite3_exec( hDB, "COMMIT", NULL, NULL, &pszErrMsg );
991 12 : if( rc != SQLITE_OK )
992 : {
993 : CPLError( CE_Failure, CPLE_AppDefined,
994 : "COMMIT transaction failed: %s",
995 0 : pszErrMsg );
996 0 : sqlite3_free( pszErrMsg );
997 0 : return OGRERR_FAILURE;
998 : }
999 : }
1000 :
1001 12 : return OGRERR_NONE;
1002 : }
1003 :
1004 : /************************************************************************/
1005 : /* SoftRollback() */
1006 : /* */
1007 : /* Force a rollback of the current transaction if there is one, */
1008 : /* even if we are nested several levels deep. */
1009 : /************************************************************************/
1010 :
1011 1 : OGRErr OGRSQLiteDataSource::SoftRollback()
1012 :
1013 : {
1014 1 : if( nSoftTransactionLevel <= 0 )
1015 : {
1016 0 : CPLDebug( "OGR_SQLITE", "SoftRollback() with no transaction active." );
1017 0 : return OGRERR_FAILURE;
1018 : }
1019 :
1020 1 : nSoftTransactionLevel = 0;
1021 :
1022 : int rc;
1023 : char *pszErrMsg;
1024 :
1025 : #ifdef DEBUG
1026 : CPLDebug( "OGR_SQLITE", "ROLLBACK Transaction" );
1027 : #endif
1028 :
1029 1 : rc = sqlite3_exec( hDB, "ROLLBACK", NULL, NULL, &pszErrMsg );
1030 1 : if( rc != SQLITE_OK )
1031 : {
1032 : CPLError( CE_Failure, CPLE_AppDefined,
1033 : "ROLLBACK transaction failed: %s",
1034 0 : pszErrMsg );
1035 0 : sqlite3_free( pszErrMsg );
1036 0 : return OGRERR_FAILURE;
1037 : }
1038 :
1039 1 : return OGRERR_NONE;
1040 : }
1041 :
1042 : /************************************************************************/
1043 : /* FlushSoftTransaction() */
1044 : /* */
1045 : /* Force the unwinding of any active transaction, and it's */
1046 : /* commit. */
1047 : /************************************************************************/
1048 :
1049 0 : OGRErr OGRSQLiteDataSource::FlushSoftTransaction()
1050 :
1051 : {
1052 0 : if( nSoftTransactionLevel <= 0 )
1053 0 : return OGRERR_NONE;
1054 :
1055 0 : nSoftTransactionLevel = 1;
1056 :
1057 0 : return SoftCommit();
1058 : }
1059 :
1060 : /************************************************************************/
1061 : /* FetchSRSId() */
1062 : /* */
1063 : /* Fetch the id corresponding to an SRS, and if not found, add */
1064 : /* it to the table. */
1065 : /************************************************************************/
1066 :
1067 3 : int OGRSQLiteDataSource::FetchSRSId( OGRSpatialReference * poSRS )
1068 :
1069 : {
1070 3 : int nSRSId = -1;
1071 3 : const char *pszAuthorityName, *pszAuthorityCode = NULL;
1072 3 : CPLString osCommand;
1073 : char *pszErrMsg;
1074 : int rc;
1075 : char **papszResult;
1076 : int nRowCount, nColCount;
1077 :
1078 3 : if( poSRS == NULL )
1079 0 : return -1;
1080 :
1081 3 : pszAuthorityName = poSRS->GetAuthorityName(NULL);
1082 :
1083 : /* -------------------------------------------------------------------- */
1084 : /* Check whether the EPSG authority code is already mapped to a */
1085 : /* SRS ID. */
1086 : /* -------------------------------------------------------------------- */
1087 3 : if( pszAuthorityName != NULL && strlen(pszAuthorityName) > 0 )
1088 : {
1089 3 : pszAuthorityCode = poSRS->GetAuthorityCode(NULL);
1090 :
1091 3 : if ( pszAuthorityCode != NULL && strlen(pszAuthorityCode) > 0 )
1092 : {
1093 : // XXX: We are using case insensitive comparison for "auth_name"
1094 : // values, because there are variety of options exist. By default
1095 : // the driver uses 'EPSG' in upper case, but SpatiaLite extension
1096 : // uses 'epsg' in lower case.
1097 : osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE "
1098 : "auth_name = '%s' COLLATE NOCASE AND auth_srid = '%s'",
1099 3 : pszAuthorityName, pszAuthorityCode );
1100 :
1101 : rc = sqlite3_get_table( hDB, osCommand, &papszResult,
1102 3 : &nRowCount, &nColCount, &pszErrMsg );
1103 3 : if( rc != SQLITE_OK )
1104 : {
1105 : /* Retry without COLLATE NOCASE which may not be understood by older sqlite3 */
1106 0 : sqlite3_free( pszErrMsg );
1107 :
1108 : osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE "
1109 : "auth_name = '%s' AND auth_srid = '%s'",
1110 0 : pszAuthorityName, pszAuthorityCode );
1111 :
1112 : rc = sqlite3_get_table( hDB, osCommand, &papszResult,
1113 0 : &nRowCount, &nColCount, &pszErrMsg );
1114 :
1115 : /* Retry in lower case for SpatiaLite */
1116 0 : if( rc != SQLITE_OK )
1117 : {
1118 0 : sqlite3_free( pszErrMsg );
1119 : }
1120 0 : else if ( nRowCount == 0 &&
1121 : strcmp(pszAuthorityName, "EPSG") == 0)
1122 : {
1123 : /* If it's in upper case, look for lower case */
1124 0 : sqlite3_free_table(papszResult);
1125 :
1126 : osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE "
1127 : "auth_name = 'epsg' AND auth_srid = '%s'",
1128 0 : pszAuthorityCode );
1129 :
1130 : rc = sqlite3_get_table( hDB, osCommand, &papszResult,
1131 0 : &nRowCount, &nColCount, &pszErrMsg );
1132 :
1133 0 : if( rc != SQLITE_OK )
1134 : {
1135 0 : sqlite3_free( pszErrMsg );
1136 : }
1137 : }
1138 : }
1139 :
1140 3 : if( rc == SQLITE_OK && nRowCount == 1 )
1141 : {
1142 1 : nSRSId = atoi(papszResult[1]);
1143 1 : sqlite3_free_table(papszResult);
1144 1 : return nSRSId;
1145 : }
1146 2 : sqlite3_free_table(papszResult);
1147 : }
1148 : }
1149 :
1150 : /* -------------------------------------------------------------------- */
1151 : /* Search for existing record using either WKT definition or */
1152 : /* PROJ.4 string (SpatiaLite variant). */
1153 : /* -------------------------------------------------------------------- */
1154 2 : CPLString osSRS;
1155 :
1156 2 : if ( !bIsSpatiaLite )
1157 : {
1158 : /* -------------------------------------------------------------------- */
1159 : /* Translate SRS to WKT. */
1160 : /* -------------------------------------------------------------------- */
1161 1 : char *pszWKT = NULL;
1162 :
1163 1 : if( poSRS->exportToWkt( &pszWKT ) != OGRERR_NONE )
1164 0 : return -1;
1165 :
1166 1 : osSRS = pszWKT;
1167 1 : CPLFree( pszWKT );
1168 1 : pszWKT = NULL;
1169 :
1170 : /* -------------------------------------------------------------------- */
1171 : /* Try to find based on the WKT match. */
1172 : /* -------------------------------------------------------------------- */
1173 : osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE srtext = '%s'",
1174 1 : osSRS.c_str());
1175 :
1176 : rc = sqlite3_get_table( hDB, osCommand, &papszResult,
1177 1 : &nRowCount, &nColCount, &pszErrMsg );
1178 1 : if( rc != SQLITE_OK )
1179 : {
1180 : CPLError( CE_Failure, CPLE_AppDefined,
1181 0 : "Search for existing SRS by WKT failed: %s", pszErrMsg );
1182 0 : sqlite3_free( pszErrMsg );
1183 : }
1184 1 : else if( nRowCount == 1 )
1185 : {
1186 0 : nSRSId = atoi(papszResult[1]);
1187 0 : sqlite3_free_table(papszResult);
1188 0 : return nSRSId;
1189 : }
1190 1 : sqlite3_free_table(papszResult);
1191 : }
1192 :
1193 : /* -------------------------------------------------------------------- */
1194 : /* Handle SpatiaLite flavour of the spatial_ref_sys. */
1195 : /* -------------------------------------------------------------------- */
1196 : else
1197 : {
1198 : /* -------------------------------------------------------------------- */
1199 : /* Translate SRS to PROJ.4 string. */
1200 : /* -------------------------------------------------------------------- */
1201 1 : char *pszProj4 = NULL;
1202 :
1203 1 : if( poSRS->exportToProj4( &pszProj4 ) != OGRERR_NONE )
1204 0 : return -1;
1205 :
1206 1 : osSRS = pszProj4;
1207 1 : CPLFree( pszProj4 );
1208 1 : pszProj4 = NULL;
1209 :
1210 : /* -------------------------------------------------------------------- */
1211 : /* Try to find based on the WKT match. */
1212 : /* -------------------------------------------------------------------- */
1213 : osCommand.Printf(
1214 : "SELECT srid FROM spatial_ref_sys WHERE proj4text = '%s'",
1215 1 : osSRS.c_str());
1216 :
1217 : rc = sqlite3_get_table( hDB, osCommand, &papszResult,
1218 1 : &nRowCount, &nColCount, &pszErrMsg );
1219 1 : if( rc != SQLITE_OK )
1220 : {
1221 : CPLError( CE_Failure, CPLE_AppDefined,
1222 : "Search for existing SRS by PROJ.4 string failed: %s",
1223 0 : pszErrMsg );
1224 0 : sqlite3_free( pszErrMsg );
1225 : }
1226 1 : else if( nRowCount == 1 )
1227 : {
1228 0 : nSRSId = atoi(papszResult[1]);
1229 0 : sqlite3_free_table(papszResult);
1230 0 : return nSRSId;
1231 : }
1232 1 : sqlite3_free_table(papszResult);
1233 : }
1234 :
1235 : /* -------------------------------------------------------------------- */
1236 : /* If the command actually failed, then the metadata table is */
1237 : /* likely missing, so we give up. */
1238 : /* -------------------------------------------------------------------- */
1239 2 : if( rc != SQLITE_OK )
1240 0 : return -1;
1241 :
1242 : /* -------------------------------------------------------------------- */
1243 : /* If we have an authority code try to assign SRS ID the same */
1244 : /* as that code. */
1245 : /* -------------------------------------------------------------------- */
1246 2 : if ( pszAuthorityCode != NULL && strlen(pszAuthorityCode) > 0 )
1247 : {
1248 : osCommand.Printf( "SELECT * FROM spatial_ref_sys WHERE auth_srid='%s'",
1249 2 : pszAuthorityCode );
1250 : rc = sqlite3_get_table( hDB, osCommand, &papszResult,
1251 2 : &nRowCount, &nColCount, &pszErrMsg );
1252 :
1253 2 : if( rc != SQLITE_OK )
1254 : {
1255 : CPLError( CE_Failure, CPLE_AppDefined,
1256 : "exec(SELECT '%s' FROM spatial_ref_sys) failed: %s",
1257 0 : pszAuthorityCode, pszErrMsg );
1258 0 : sqlite3_free( pszErrMsg );
1259 : }
1260 :
1261 : /* -------------------------------------------------------------------- */
1262 : /* If there is no SRS ID with such auth_srid, use it as SRS ID. */
1263 : /* -------------------------------------------------------------------- */
1264 2 : if ( nRowCount < 1 )
1265 2 : nSRSId = atoi(pszAuthorityCode);
1266 2 : sqlite3_free_table(papszResult);
1267 : }
1268 :
1269 : /* -------------------------------------------------------------------- */
1270 : /* Otherwise get the current maximum srid in the srs table. */
1271 : /* -------------------------------------------------------------------- */
1272 2 : if ( nSRSId == -1 )
1273 : {
1274 : rc = sqlite3_get_table( hDB, "SELECT MAX(srid) FROM spatial_ref_sys",
1275 : &papszResult, &nRowCount, &nColCount,
1276 0 : &pszErrMsg );
1277 :
1278 0 : if( rc != SQLITE_OK )
1279 : {
1280 : CPLError( CE_Failure, CPLE_AppDefined,
1281 0 : "SELECT of the maximum SRS ID failed: %s", pszErrMsg );
1282 0 : sqlite3_free( pszErrMsg );
1283 0 : return -1;
1284 : }
1285 :
1286 0 : if ( nRowCount < 1 || !papszResult[1] )
1287 0 : nSRSId = 50000;
1288 : else
1289 0 : nSRSId = atoi(papszResult[1]) + 1; // Insert as the next SRS ID
1290 0 : sqlite3_free_table(papszResult);
1291 : }
1292 :
1293 : /* -------------------------------------------------------------------- */
1294 : /* Try adding the SRS to the SRS table. */
1295 : /* -------------------------------------------------------------------- */
1296 2 : if ( !bIsSpatiaLite )
1297 : {
1298 1 : if( pszAuthorityName != NULL )
1299 : {
1300 : osCommand.Printf(
1301 : "INSERT INTO spatial_ref_sys (srid,srtext,auth_name,auth_srid) "
1302 : " VALUES (%d, '%s', '%s', '%s')",
1303 : nSRSId, osSRS.c_str(),
1304 1 : pszAuthorityName, poSRS->GetAuthorityCode(NULL) );
1305 : }
1306 : else
1307 : {
1308 : osCommand.Printf(
1309 : "INSERT INTO spatial_ref_sys (srid,srtext) "
1310 : " VALUES (%d, '%s')",
1311 0 : nSRSId, osSRS.c_str() );
1312 : }
1313 : }
1314 : else
1315 : {
1316 1 : const char *pszProjCS = poSRS->GetAttrValue("PROJCS");
1317 :
1318 1 : if( pszAuthorityName != NULL )
1319 : {
1320 1 : if ( pszProjCS )
1321 : osCommand.Printf(
1322 : "INSERT INTO spatial_ref_sys "
1323 : "(srid, auth_name, auth_srid, ref_sys_name, proj4text) "
1324 : "VALUES (%d, '%s', '%s', '%s', '%s')",
1325 : nSRSId, pszAuthorityName,
1326 0 : poSRS->GetAuthorityCode(NULL), pszProjCS, osSRS.c_str() );
1327 : else
1328 : osCommand.Printf(
1329 : "INSERT INTO spatial_ref_sys "
1330 : "(srid, auth_name, auth_srid, proj4text) "
1331 : "VALUES (%d, '%s', '%s', '%s')",
1332 : nSRSId, pszAuthorityName,
1333 1 : poSRS->GetAuthorityCode(NULL), osSRS.c_str() );
1334 : }
1335 : else
1336 : {
1337 0 : if ( pszProjCS )
1338 : osCommand.Printf(
1339 : "INSERT INTO spatial_ref_sys "
1340 : "(srid, ref_sys_name, proj4text) VALUES (%d, '%s', '%s')",
1341 0 : nSRSId, pszProjCS, osSRS.c_str() );
1342 : else
1343 : osCommand.Printf(
1344 : "INSERT INTO spatial_ref_sys "
1345 : "(srid, proj4text) VALUES (%d, '%s')",
1346 0 : nSRSId, osSRS.c_str() );
1347 : }
1348 : }
1349 :
1350 2 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
1351 2 : if( rc != SQLITE_OK )
1352 : {
1353 : CPLError( CE_Failure, CPLE_AppDefined,
1354 : "Unable to insert SRID (%s): %s",
1355 0 : osCommand.c_str(), pszErrMsg );
1356 0 : sqlite3_free( pszErrMsg );
1357 0 : return FALSE;
1358 : }
1359 :
1360 2 : return nSRSId;
1361 : }
1362 :
1363 : /************************************************************************/
1364 : /* FetchSRS() */
1365 : /* */
1366 : /* Return a SRS corresponding to a particular id. Note that */
1367 : /* reference counting should be honoured on the returned */
1368 : /* OGRSpatialReference, as handles may be cached. */
1369 : /************************************************************************/
1370 :
1371 45 : OGRSpatialReference *OGRSQLiteDataSource::FetchSRS( int nId )
1372 :
1373 : {
1374 45 : if( nId <= 0 )
1375 29 : return NULL;
1376 :
1377 : /* -------------------------------------------------------------------- */
1378 : /* First, we look through our SRID cache, is it there? */
1379 : /* -------------------------------------------------------------------- */
1380 : int i;
1381 :
1382 16 : for( i = 0; i < nKnownSRID; i++ )
1383 : {
1384 4 : if( panSRID[i] == nId )
1385 4 : return papoSRS[i];
1386 : }
1387 :
1388 : /* -------------------------------------------------------------------- */
1389 : /* Try looking up in spatial_ref_sys table. */
1390 : /* -------------------------------------------------------------------- */
1391 : char *pszErrMsg;
1392 : int rc;
1393 : char **papszResult;
1394 : int nRowCount, nColCount;
1395 12 : CPLString osCommand;
1396 12 : OGRSpatialReference *poSRS = NULL;
1397 :
1398 : osCommand.Printf( "SELECT srtext FROM spatial_ref_sys WHERE srid = %d",
1399 12 : nId );
1400 : rc = sqlite3_get_table( hDB, osCommand,
1401 12 : &papszResult, &nRowCount, &nColCount, &pszErrMsg );
1402 :
1403 12 : if ( rc == SQLITE_OK )
1404 : {
1405 5 : if( nRowCount < 1 )
1406 : {
1407 0 : sqlite3_free_table(papszResult);
1408 0 : return NULL;
1409 : }
1410 :
1411 5 : char** papszRow = papszResult + nColCount;
1412 5 : CPLString osWKT = papszRow[0];
1413 :
1414 : /* -------------------------------------------------------------------- */
1415 : /* Translate into a spatial reference. */
1416 : /* -------------------------------------------------------------------- */
1417 5 : char *pszWKT = (char *) osWKT.c_str();
1418 :
1419 5 : poSRS = new OGRSpatialReference();
1420 10 : if( poSRS->importFromWkt( &pszWKT ) != OGRERR_NONE )
1421 : {
1422 0 : delete poSRS;
1423 0 : poSRS = NULL;
1424 : }
1425 :
1426 5 : sqlite3_free_table(papszResult);
1427 : }
1428 :
1429 : /* -------------------------------------------------------------------- */
1430 : /* Next try SpatiaLite flavour. SpatiaLite uses PROJ.4 strings */
1431 : /* in 'proj4text' column instead of WKT in 'srtext'. */
1432 : /* -------------------------------------------------------------------- */
1433 : else
1434 : {
1435 7 : sqlite3_free( pszErrMsg );
1436 7 : pszErrMsg = NULL;
1437 :
1438 : osCommand.Printf(
1439 7 : "SELECT proj4text, auth_name, auth_srid FROM spatial_ref_sys WHERE srid = %d", nId );
1440 : rc = sqlite3_get_table( hDB, osCommand,
1441 : &papszResult, &nRowCount,
1442 7 : &nColCount, &pszErrMsg );
1443 7 : if ( rc == SQLITE_OK )
1444 : {
1445 7 : if( nRowCount < 1 )
1446 : {
1447 0 : sqlite3_free_table(papszResult);
1448 0 : return NULL;
1449 : }
1450 :
1451 : /* -------------------------------------------------------------------- */
1452 : /* Translate into a spatial reference. */
1453 : /* -------------------------------------------------------------------- */
1454 7 : poSRS = new OGRSpatialReference();
1455 :
1456 7 : char** papszRow = papszResult + nColCount;
1457 :
1458 7 : const char* pszProj4Text = papszRow[0];
1459 7 : const char* pszAuthName = papszRow[1];
1460 7 : int nAuthSRID = atoi(papszRow[2]);
1461 :
1462 : /* Try first from EPSG code */
1463 14 : if (EQUAL(pszAuthName, "EPSG") &&
1464 : poSRS->importFromEPSG( nAuthSRID ) == OGRERR_NONE)
1465 : {
1466 : /* Do nothing */
1467 : }
1468 : /* Then from Proj4 string */
1469 0 : else if( poSRS->importFromProj4( pszProj4Text ) != OGRERR_NONE )
1470 : {
1471 0 : delete poSRS;
1472 0 : poSRS = NULL;
1473 : }
1474 :
1475 7 : sqlite3_free_table(papszResult);
1476 : }
1477 :
1478 : /* -------------------------------------------------------------------- */
1479 : /* No success, report an error. */
1480 : /* -------------------------------------------------------------------- */
1481 : else
1482 : {
1483 : CPLError( CE_Failure, CPLE_AppDefined,
1484 0 : "%s: %s", osCommand.c_str(), pszErrMsg );
1485 0 : sqlite3_free( pszErrMsg );
1486 0 : return NULL;
1487 : }
1488 : }
1489 :
1490 : /* -------------------------------------------------------------------- */
1491 : /* Add to the cache. */
1492 : /* -------------------------------------------------------------------- */
1493 12 : panSRID = (int *) CPLRealloc(panSRID,sizeof(int) * (nKnownSRID+1) );
1494 : papoSRS = (OGRSpatialReference **)
1495 12 : CPLRealloc(papoSRS, sizeof(void*) * (nKnownSRID + 1) );
1496 12 : panSRID[nKnownSRID] = nId;
1497 12 : papoSRS[nKnownSRID] = poSRS;
1498 12 : nKnownSRID++;
1499 :
1500 12 : return poSRS;
1501 : }
|