1 : /******************************************************************************
2 : * $Id: ogrmssqlspatialdatasource.cpp 25690 2013-02-26 11:51:12Z tamas $
3 : *
4 : * Project: MSSQL Spatial driver
5 : * Purpose: Implements OGRMSSQLSpatialDataSource class..
6 : * Author: Tamas Szekeres, szekerest at gmail.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Tamas Szekeres
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_mssqlspatial.h"
31 :
32 : CPL_CVSID("$Id: ogrmssqlspatialdatasource.cpp 25690 2013-02-26 11:51:12Z tamas $");
33 :
34 : /************************************************************************/
35 : /* OGRMSSQLSpatialDataSource() */
36 : /************************************************************************/
37 :
38 0 : OGRMSSQLSpatialDataSource::OGRMSSQLSpatialDataSource()
39 :
40 : {
41 0 : pszName = NULL;
42 0 : pszCatalog = NULL;
43 0 : papoLayers = NULL;
44 0 : nLayers = 0;
45 :
46 0 : nKnownSRID = 0;
47 0 : panSRID = NULL;
48 0 : papoSRS = NULL;
49 :
50 0 : nGeometryFormat = MSSQLGEOMETRY_NATIVE;
51 :
52 0 : bUseGeometryColumns = CSLTestBoolean(CPLGetConfigOption("MSSQLSPATIAL_USE_GEOMETRY_COLUMNS", "YES"));
53 0 : }
54 :
55 : /************************************************************************/
56 : /* ~OGRMSSQLSpatialDataSource() */
57 : /************************************************************************/
58 :
59 0 : OGRMSSQLSpatialDataSource::~OGRMSSQLSpatialDataSource()
60 :
61 : {
62 : int i;
63 :
64 0 : CPLFree( pszName );
65 0 : CPLFree( pszCatalog );
66 :
67 0 : for( i = 0; i < nLayers; i++ )
68 0 : delete papoLayers[i];
69 :
70 0 : CPLFree( papoLayers );
71 :
72 0 : for( i = 0; i < nKnownSRID; i++ )
73 : {
74 0 : if( papoSRS[i] != NULL )
75 0 : papoSRS[i]->Release();
76 : }
77 0 : CPLFree( panSRID );
78 0 : CPLFree( papoSRS );
79 0 : }
80 :
81 : /************************************************************************/
82 : /* TestCapability() */
83 : /************************************************************************/
84 :
85 0 : int OGRMSSQLSpatialDataSource::TestCapability( const char * pszCap )
86 :
87 : {
88 0 : if( EQUAL(pszCap,ODsCCreateLayer) || EQUAL(pszCap,ODsCDeleteLayer) )
89 0 : return TRUE;
90 : else
91 0 : return FALSE;
92 : }
93 :
94 : /************************************************************************/
95 : /* GetLayer() */
96 : /************************************************************************/
97 :
98 0 : OGRLayer *OGRMSSQLSpatialDataSource::GetLayer( int iLayer )
99 :
100 : {
101 0 : if( iLayer < 0 || iLayer >= nLayers )
102 0 : return NULL;
103 : else
104 0 : return papoLayers[iLayer];
105 : }
106 :
107 : /************************************************************************/
108 : /* DeleteLayer() */
109 : /************************************************************************/
110 :
111 0 : int OGRMSSQLSpatialDataSource::DeleteLayer( int iLayer )
112 :
113 : {
114 0 : if( iLayer < 0 || iLayer >= nLayers )
115 0 : return OGRERR_FAILURE;
116 :
117 : /* -------------------------------------------------------------------- */
118 : /* Blow away our OGR structures related to the layer. This is */
119 : /* pretty dangerous if anything has a reference to this layer! */
120 : /* -------------------------------------------------------------------- */
121 0 : const char* pszLayerName = papoLayers[iLayer]->GetTableName();
122 0 : const char* pszSchemaName = papoLayers[iLayer]->GetSchemaName();
123 :
124 0 : CPLODBCStatement oStmt( &oSession );
125 0 : if (bUseGeometryColumns)
126 : oStmt.Appendf( "DELETE FROM geometry_columns WHERE f_table_schema = '%s' AND f_table_name = '%s'\n",
127 0 : pszSchemaName, pszLayerName );
128 0 : oStmt.Appendf("DROP TABLE [%s].[%s]", pszSchemaName, pszLayerName );
129 :
130 0 : CPLDebug( "MSSQLSpatial", "DeleteLayer(%s)", pszLayerName );
131 :
132 0 : delete papoLayers[iLayer];
133 : memmove( papoLayers + iLayer, papoLayers + iLayer + 1,
134 0 : sizeof(void *) * (nLayers - iLayer - 1) );
135 0 : nLayers--;
136 :
137 0 : if ( strlen(pszLayerName) == 0 )
138 0 : return OGRERR_NONE;
139 :
140 : /* -------------------------------------------------------------------- */
141 : /* Remove from the database. */
142 : /* -------------------------------------------------------------------- */
143 :
144 0 : oSession.BeginTransaction();
145 :
146 0 : if( !oStmt.ExecuteSQL() )
147 : {
148 : CPLError( CE_Failure, CPLE_AppDefined,
149 0 : "Error deleting layer: %s", GetSession()->GetLastError() );
150 :
151 0 : return OGRERR_FAILURE;
152 : }
153 :
154 0 : oSession.CommitTransaction();
155 :
156 0 : return OGRERR_NONE;
157 : }
158 :
159 : /************************************************************************/
160 : /* CreateLayer() */
161 : /************************************************************************/
162 :
163 0 : OGRLayer * OGRMSSQLSpatialDataSource::CreateLayer( const char * pszLayerName,
164 : OGRSpatialReference *poSRS,
165 : OGRwkbGeometryType eType,
166 : char ** papszOptions )
167 :
168 : {
169 0 : char *pszTableName = NULL;
170 0 : char *pszSchemaName = NULL;
171 0 : const char *pszGeomType = NULL;
172 0 : const char *pszGeomColumn = NULL;
173 0 : int nCoordDimension = 3;
174 :
175 : /* determine the dimension */
176 0 : if( eType == wkbFlatten(eType) )
177 0 : nCoordDimension = 2;
178 :
179 0 : if( CSLFetchNameValue( papszOptions, "DIM") != NULL )
180 0 : nCoordDimension = atoi(CSLFetchNameValue( papszOptions, "DIM"));
181 :
182 : /* MSSQL Schema handling:
183 : Extract schema name from input layer name or passed with -lco SCHEMA.
184 : Set layer name to "schema.table" or to "table" if schema is not
185 : specified
186 : */
187 0 : const char* pszDotPos = strstr(pszLayerName,".");
188 0 : if ( pszDotPos != NULL )
189 : {
190 0 : int length = pszDotPos - pszLayerName;
191 0 : pszSchemaName = (char*)CPLMalloc(length+1);
192 0 : strncpy(pszSchemaName, pszLayerName, length);
193 0 : pszSchemaName[length] = '\0';
194 :
195 0 : if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
196 0 : pszTableName = LaunderName( pszDotPos + 1 ); //skip "."
197 : else
198 0 : pszTableName = CPLStrdup( pszDotPos + 1 ); //skip "."
199 : }
200 : else
201 : {
202 0 : pszSchemaName = NULL;
203 0 : if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
204 0 : pszTableName = LaunderName( pszLayerName ); //skip "."
205 : else
206 0 : pszTableName = CPLStrdup( pszLayerName ); //skip "."
207 : }
208 :
209 0 : if( CSLFetchNameValue( papszOptions, "SCHEMA" ) != NULL )
210 : {
211 0 : CPLFree(pszSchemaName);
212 0 : pszSchemaName = CPLStrdup(CSLFetchNameValue( papszOptions, "SCHEMA" ));
213 : }
214 :
215 0 : if (pszSchemaName == NULL)
216 0 : pszSchemaName = CPLStrdup("dbo");
217 :
218 : /* -------------------------------------------------------------------- */
219 : /* Do we already have this layer? If so, should we blow it */
220 : /* away? */
221 : /* -------------------------------------------------------------------- */
222 : int iLayer;
223 :
224 0 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
225 : {
226 0 : if( EQUAL(pszLayerName,papoLayers[iLayer]->GetTableName()) )
227 : {
228 0 : if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != NULL
229 : && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
230 : {
231 0 : if (!pszSchemaName)
232 0 : pszSchemaName = CPLStrdup(papoLayers[iLayer]->GetSchemaName());
233 :
234 0 : DeleteLayer( iLayer );
235 : }
236 : else
237 : {
238 : CPLError( CE_Failure, CPLE_AppDefined,
239 : "Layer %s already exists, CreateLayer failed.\n"
240 : "Use the layer creation option OVERWRITE=YES to "
241 : "replace it.",
242 0 : pszLayerName );
243 :
244 0 : CPLFree( pszSchemaName );
245 0 : CPLFree( pszTableName );
246 0 : return NULL;
247 : }
248 : }
249 : }
250 :
251 : /* -------------------------------------------------------------------- */
252 : /* Handle the GEOM_TYPE option. */
253 : /* -------------------------------------------------------------------- */
254 0 : pszGeomType = CSLFetchNameValue( papszOptions, "GEOM_TYPE" );
255 :
256 0 : if( !pszGeomType )
257 0 : pszGeomType = "geometry";
258 :
259 0 : if( !EQUAL(pszGeomType, "geometry")
260 : && !EQUAL(pszGeomType, "geography"))
261 : {
262 : CPLError( CE_Failure, CPLE_AppDefined,
263 : "FORMAT=%s not recognised or supported.",
264 0 : pszGeomType );
265 :
266 0 : CPLFree( pszSchemaName );
267 0 : CPLFree( pszTableName );
268 0 : return NULL;
269 : }
270 :
271 : /* determine the geometry column name */
272 0 : pszGeomColumn = CSLFetchNameValue( papszOptions, "GEOM_NAME");
273 0 : if (!pszGeomColumn)
274 0 : pszGeomColumn = "ogr_geometry";
275 :
276 : /* -------------------------------------------------------------------- */
277 : /* Initialize the metadata tables */
278 : /* -------------------------------------------------------------------- */
279 :
280 0 : if (InitializeMetadataTables() != OGRERR_NONE)
281 : {
282 0 : CPLFree( pszSchemaName );
283 0 : CPLFree( pszTableName );
284 0 : return NULL;
285 : }
286 :
287 : /* -------------------------------------------------------------------- */
288 : /* Try to get the SRS Id of this spatial reference system, */
289 : /* adding to the srs table if needed. */
290 : /* -------------------------------------------------------------------- */
291 0 : int nSRSId = 0;
292 :
293 0 : if( CSLFetchNameValue( papszOptions, "SRID") != NULL )
294 0 : nSRSId = atoi(CSLFetchNameValue( papszOptions, "SRID"));
295 :
296 0 : if( nSRSId == 0 && poSRS != NULL )
297 0 : nSRSId = FetchSRSId( poSRS );
298 :
299 : /* -------------------------------------------------------------------- */
300 : /* Create a new table and create a new entry in the geometry, */
301 : /* geometry_columns metadata table. */
302 : /* -------------------------------------------------------------------- */
303 :
304 0 : if( eType != wkbNone )
305 : {
306 0 : const char *pszGeometryType = OGRToOGCGeomType(eType);
307 :
308 0 : CPLODBCStatement oStmt( &oSession );
309 :
310 0 : if (bUseGeometryColumns)
311 : {
312 : oStmt.Appendf( "DELETE FROM geometry_columns WHERE f_table_schema = '%s' "
313 0 : "AND f_table_name = '%s'\n", pszSchemaName, pszTableName );
314 :
315 : oStmt.Appendf("INSERT INTO [geometry_columns] ([f_table_catalog], [f_table_schema] ,[f_table_name], "
316 : "[f_geometry_column],[coord_dimension],[srid],[geometry_type]) VALUES ('%s', '%s', '%s', '%s', %d, %d, '%s')\n",
317 0 : pszCatalog, pszSchemaName, pszTableName, pszGeomColumn, nCoordDimension, nSRSId, pszGeometryType );
318 : }
319 :
320 : oStmt.Appendf("CREATE TABLE [%s].[%s] ([ogr_fid] [int] IDENTITY(1,1) NOT NULL, "
321 : "[%s] [%s] NULL, CONSTRAINT [PK_%s] PRIMARY KEY CLUSTERED ([ogr_fid] ASC))",
322 0 : pszSchemaName, pszTableName, pszGeomColumn, pszGeomType, pszTableName);
323 :
324 0 : oSession.BeginTransaction();
325 :
326 0 : if( !oStmt.ExecuteSQL() )
327 : {
328 : CPLError( CE_Failure, CPLE_AppDefined,
329 0 : "Error creating layer: %s", GetSession()->GetLastError() );
330 :
331 0 : return NULL;
332 : }
333 :
334 0 : oSession.CommitTransaction();
335 : }
336 :
337 : /* -------------------------------------------------------------------- */
338 : /* Create the layer object. */
339 : /* -------------------------------------------------------------------- */
340 : OGRMSSQLSpatialTableLayer *poLayer;
341 :
342 0 : poLayer = new OGRMSSQLSpatialTableLayer( this );
343 :
344 0 : poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
345 0 : poLayer->SetPrecisionFlag( CSLFetchBoolean(papszOptions,"PRECISION",TRUE));
346 :
347 0 : if (poLayer->Initialize(pszSchemaName, pszTableName, pszGeomColumn, nCoordDimension, nSRSId, eType) == OGRERR_FAILURE)
348 : {
349 0 : CPLFree( pszSchemaName );
350 0 : CPLFree( pszTableName );
351 0 : return NULL;
352 : }
353 :
354 0 : CPLFree( pszSchemaName );
355 0 : CPLFree( pszTableName );
356 :
357 : /* -------------------------------------------------------------------- */
358 : /* Add layer to data source layer list. */
359 : /* -------------------------------------------------------------------- */
360 : papoLayers = (OGRMSSQLSpatialTableLayer **)
361 0 : CPLRealloc( papoLayers, sizeof(OGRMSSQLSpatialTableLayer *) * (nLayers+1) );
362 :
363 0 : papoLayers[nLayers++] = poLayer;
364 :
365 :
366 0 : return poLayer;
367 : }
368 :
369 : /************************************************************************/
370 : /* OpenTable() */
371 : /************************************************************************/
372 :
373 0 : int OGRMSSQLSpatialDataSource::OpenTable( const char *pszSchemaName, const char *pszTableName,
374 : const char *pszGeomCol, int nCoordDimension,
375 : int nSRID, OGRwkbGeometryType eType, int bUpdate )
376 :
377 : {
378 : /* -------------------------------------------------------------------- */
379 : /* Create the layer object. */
380 : /* -------------------------------------------------------------------- */
381 0 : OGRMSSQLSpatialTableLayer *poLayer = new OGRMSSQLSpatialTableLayer( this );
382 :
383 0 : if( poLayer->Initialize( pszSchemaName, pszTableName, pszGeomCol, nCoordDimension, nSRID, eType ) )
384 : {
385 0 : delete poLayer;
386 0 : return FALSE;
387 : }
388 :
389 : /* -------------------------------------------------------------------- */
390 : /* Add layer to data source layer list. */
391 : /* -------------------------------------------------------------------- */
392 : papoLayers = (OGRMSSQLSpatialTableLayer **)
393 0 : CPLRealloc( papoLayers, sizeof(OGRMSSQLSpatialTableLayer *) * (nLayers+1) );
394 0 : papoLayers[nLayers++] = poLayer;
395 :
396 0 : return TRUE;
397 : }
398 :
399 :
400 : /************************************************************************/
401 : /* GetLayerCount() */
402 : /************************************************************************/
403 :
404 0 : int OGRMSSQLSpatialDataSource::GetLayerCount()
405 : {
406 0 : return nLayers;
407 : }
408 :
409 : /************************************************************************/
410 : /* ParseValue() */
411 : /************************************************************************/
412 :
413 0 : int OGRMSSQLSpatialDataSource::ParseValue(char** pszValue, char* pszSource, const char* pszKey, int nStart, int nNext, int nTerm, int bRemove)
414 : {
415 0 : int nLen = strlen(pszKey);
416 0 : if ((*pszValue) == NULL && nStart + nLen < nNext &&
417 : EQUALN(pszSource + nStart, pszKey, nLen))
418 : {
419 0 : *pszValue = (char*)CPLMalloc( sizeof(char) * (nNext - nStart - nLen + 1) );
420 0 : if (*pszValue)
421 0 : strncpy(*pszValue, pszSource + nStart + nLen, nNext - nStart - nLen);
422 0 : (*pszValue)[nNext - nStart - nLen] = 0;
423 :
424 0 : if (bRemove)
425 : {
426 : // remove the value from the source string
427 0 : if (pszSource[nNext] == ';')
428 0 : memmove( pszSource + nStart, pszSource + nNext + 1, nTerm - nNext);
429 : else
430 0 : memmove( pszSource + nStart, pszSource + nNext, nTerm - nNext + 1);
431 : }
432 0 : return TRUE;
433 : }
434 0 : return FALSE;
435 : }
436 :
437 :
438 : /************************************************************************/
439 : /* Open() */
440 : /************************************************************************/
441 :
442 0 : int OGRMSSQLSpatialDataSource::Open( const char * pszNewName, int bUpdate,
443 : int bTestOpen )
444 :
445 : {
446 0 : CPLAssert( nLayers == 0 );
447 :
448 0 : if( !EQUALN(pszNewName,"MSSQL:",6) )
449 : {
450 0 : if( !bTestOpen )
451 : CPLError( CE_Failure, CPLE_AppDefined,
452 : "%s does not conform to MSSSQLSpatial naming convention,"
453 0 : " MSSQL:*\n", pszNewName );
454 0 : return FALSE;
455 : }
456 :
457 : /* Determine if the connection string contains specific values */
458 0 : char* pszTableSpec = NULL;
459 0 : char* pszGeometryFormat = NULL;
460 0 : char* pszConnectionName = CPLStrdup(pszNewName + 6);
461 0 : char* pszDriver = NULL;
462 : int nCurrent, nNext, nTerm;
463 0 : nCurrent = nNext = nTerm = strlen(pszConnectionName);
464 :
465 0 : while (nCurrent > 0)
466 : {
467 0 : --nCurrent;
468 0 : if (pszConnectionName[nCurrent] == ';')
469 : {
470 0 : nNext = nCurrent;
471 0 : continue;
472 : }
473 :
474 0 : if (ParseValue(&pszCatalog, pszConnectionName, "database=",
475 : nCurrent, nNext, nTerm, FALSE))
476 0 : continue;
477 :
478 0 : if (ParseValue(&pszTableSpec, pszConnectionName, "tables=",
479 : nCurrent, nNext, nTerm, TRUE))
480 0 : continue;
481 :
482 0 : if (ParseValue(&pszDriver, pszConnectionName, "driver=",
483 : nCurrent, nNext, nTerm, FALSE))
484 0 : continue;
485 :
486 0 : if (ParseValue(&pszGeometryFormat, pszConnectionName,
487 : "geometryformat=", nCurrent, nNext, nTerm, TRUE))
488 : {
489 0 : if (EQUALN(pszGeometryFormat,"wkbzm",5))
490 0 : nGeometryFormat = MSSQLGEOMETRY_WKBZM;
491 0 : else if (EQUALN(pszGeometryFormat, "wkb",3))
492 0 : nGeometryFormat = MSSQLGEOMETRY_WKB;
493 0 : else if (EQUALN(pszGeometryFormat,"wkt",3))
494 0 : nGeometryFormat = MSSQLGEOMETRY_WKT;
495 0 : else if (EQUALN(pszGeometryFormat,"native",6))
496 0 : nGeometryFormat = MSSQLGEOMETRY_NATIVE;
497 : else
498 : {
499 : CPLError( CE_Failure, CPLE_AppDefined,
500 : "Invalid geometry type specified: %s,"
501 0 : " MSSQL:*\n", pszGeometryFormat );
502 :
503 0 : CPLFree(pszTableSpec);
504 0 : CPLFree(pszGeometryFormat);
505 0 : CPLFree(pszConnectionName);
506 0 : CPLFree(pszDriver);
507 0 : return FALSE;
508 : }
509 :
510 0 : CPLFree(pszGeometryFormat);
511 0 : pszGeometryFormat = NULL;
512 0 : continue;
513 : }
514 : }
515 :
516 : /* Determine if the connection string contains the catalog portion */
517 0 : if( pszCatalog == NULL )
518 : {
519 : CPLError( CE_Failure, CPLE_AppDefined,
520 0 : "'%s' does not contain the 'database' portion\n", pszNewName );
521 :
522 0 : CPLFree(pszTableSpec);
523 0 : CPLFree(pszGeometryFormat);
524 0 : CPLFree(pszConnectionName);
525 0 : CPLFree(pszDriver);
526 0 : return FALSE;
527 : }
528 :
529 0 : pszName = CPLStrdup(pszNewName);
530 :
531 0 : char **papszTableNames=NULL;
532 0 : char **papszSchemaNames=NULL;
533 0 : char **papszGeomColumnNames=NULL;
534 0 : char **papszCoordDimensions=NULL;
535 0 : char **papszSRIds=NULL;
536 :
537 : /* Determine if the connection string contains the TABLES portion */
538 0 : if( pszTableSpec != NULL )
539 : {
540 : char **papszTableList;
541 : int i;
542 :
543 0 : papszTableList = CSLTokenizeString2( pszTableSpec, ",", 0 );
544 :
545 0 : for( i = 0; i < CSLCount(papszTableList); i++ )
546 : {
547 : char **papszQualifiedParts;
548 :
549 : // Get schema and table name
550 0 : papszQualifiedParts = CSLTokenizeString2( papszTableList[i],
551 0 : ".", 0 );
552 :
553 : /* Find the geometry column name if specified */
554 0 : if( CSLCount( papszQualifiedParts ) >= 1 )
555 : {
556 0 : char* pszGeomColumnName = NULL;
557 0 : char* pos = strchr(papszQualifiedParts[CSLCount( papszQualifiedParts ) - 1], '(');
558 0 : if (pos != NULL)
559 : {
560 0 : *pos = '\0';
561 0 : pszGeomColumnName = pos+1;
562 0 : int len = strlen(pszGeomColumnName);
563 0 : if (len > 0)
564 0 : pszGeomColumnName[len - 1] = '\0';
565 : }
566 : papszGeomColumnNames = CSLAddString( papszGeomColumnNames,
567 0 : pszGeomColumnName ? pszGeomColumnName : "");
568 : }
569 :
570 0 : if( CSLCount( papszQualifiedParts ) == 2 )
571 : {
572 : papszSchemaNames = CSLAddString( papszSchemaNames,
573 0 : papszQualifiedParts[0] );
574 : papszTableNames = CSLAddString( papszTableNames,
575 0 : papszQualifiedParts[1] );
576 : }
577 0 : else if( CSLCount( papszQualifiedParts ) == 1 )
578 : {
579 0 : papszSchemaNames = CSLAddString( papszSchemaNames, "dbo");
580 : papszTableNames = CSLAddString( papszTableNames,
581 0 : papszQualifiedParts[0] );
582 : }
583 :
584 0 : CSLDestroy(papszQualifiedParts);
585 : }
586 :
587 0 : CSLDestroy(papszTableList);
588 : }
589 :
590 0 : CPLFree(pszTableSpec);
591 :
592 : /* Initialize the SQL Server connection. */
593 : int nResult;
594 0 : if ( pszDriver != NULL )
595 : {
596 : /* driver has been specified */
597 0 : CPLDebug( "OGR_MSSQLSpatial", "EstablishSession(Connection:\"%s\")", pszConnectionName);
598 0 : nResult = oSession.EstablishSession( pszConnectionName, "", "" );
599 : }
600 : else
601 : {
602 : /* no driver has been specified, defautls to SQL Server */
603 0 : CPLDebug( "OGR_MSSQLSpatial", "EstablishSession(Connection:\"%s\")", pszConnectionName);
604 0 : nResult = oSession.EstablishSession( CPLSPrintf("DRIVER=SQL Server;%s", pszConnectionName), "", "" );
605 : }
606 :
607 0 : CPLFree(pszDriver);
608 :
609 0 : if( !nResult )
610 : {
611 : CPLError( CE_Failure, CPLE_AppDefined,
612 : "Unable to initialize connection to the server for %s,\n"
613 0 : "%s", pszNewName, oSession.GetLastError() );
614 :
615 0 : CSLDestroy( papszTableNames );
616 0 : CSLDestroy( papszSchemaNames );
617 0 : CSLDestroy( papszGeomColumnNames );
618 0 : CSLDestroy( papszCoordDimensions );
619 0 : CSLDestroy( papszSRIds );
620 0 : CPLFree(pszGeometryFormat);
621 0 : CPLFree(pszConnectionName);
622 0 : return FALSE;
623 : }
624 :
625 0 : char** papszTypes = NULL;
626 :
627 : /* Determine the available tables if not specified. */
628 0 : if (papszTableNames == NULL && bUseGeometryColumns)
629 : {
630 0 : CPLODBCStatement oStmt( &oSession );
631 :
632 0 : oStmt.Append( "SELECT f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, geometry_type FROM dbo.geometry_columns");
633 :
634 0 : if( oStmt.ExecuteSQL() )
635 : {
636 0 : while( oStmt.Fetch() )
637 : {
638 : papszSchemaNames =
639 0 : CSLAddString( papszSchemaNames, oStmt.GetColData(0) );
640 : papszTableNames =
641 0 : CSLAddString( papszTableNames, oStmt.GetColData(1) );
642 : papszGeomColumnNames =
643 0 : CSLAddString( papszGeomColumnNames, oStmt.GetColData(2) );
644 : papszCoordDimensions =
645 0 : CSLAddString( papszCoordDimensions, oStmt.GetColData(3) );
646 : papszSRIds =
647 0 : CSLAddString( papszSRIds, oStmt.GetColData(4) );
648 : papszTypes =
649 0 : CSLAddString( papszTypes, oStmt.GetColData(5) );
650 : }
651 : }
652 : else
653 0 : bUseGeometryColumns = FALSE;
654 : }
655 :
656 : /* Query catalog for tables having geometry columns */
657 0 : if (papszTableNames == NULL)
658 : {
659 0 : CPLODBCStatement oStmt( &oSession );
660 :
661 0 : oStmt.Append( "SELECT sys.schemas.name, sys.schemas.name + '.' + sys.objects.name, sys.columns.name from sys.columns join sys.types on sys.columns.system_type_id = sys.types.system_type_id and sys.columns.user_type_id = sys.types.user_type_id join sys.objects on sys.objects.object_id = sys.columns.object_id join sys.schemas on sys.objects.schema_id = sys.schemas.schema_id where (sys.types.name = 'geometry' or sys.types.name = 'geography') and (sys.objects.type = 'U' or sys.objects.type = 'V')");
662 :
663 0 : if( oStmt.ExecuteSQL() )
664 : {
665 0 : while( oStmt.Fetch() )
666 : {
667 : papszSchemaNames =
668 0 : CSLAddString( papszSchemaNames, oStmt.GetColData(0) );
669 : papszTableNames =
670 0 : CSLAddString( papszTableNames, oStmt.GetColData(1) );
671 : papszGeomColumnNames =
672 0 : CSLAddString( papszGeomColumnNames, oStmt.GetColData(2) );
673 : }
674 0 : }
675 : }
676 :
677 : int nSRId, nCoordDimension;
678 : OGRwkbGeometryType eType;
679 :
680 0 : for( int iTable = 0;
681 0 : papszTableNames != NULL && papszTableNames[iTable] != NULL;
682 : iTable++ )
683 : {
684 0 : if (papszSRIds != NULL)
685 0 : nSRId = atoi(papszSRIds[iTable]);
686 : else
687 0 : nSRId = -1;
688 :
689 0 : if (papszCoordDimensions != NULL)
690 0 : nCoordDimension = atoi(papszCoordDimensions[iTable]);
691 : else
692 0 : nCoordDimension = 2;
693 :
694 0 : if (papszTypes != NULL)
695 0 : eType = OGRFromOGCGeomType(papszTypes[iTable]);
696 : else
697 0 : eType = wkbUnknown;
698 :
699 0 : if( strlen(papszGeomColumnNames[iTable]) > 0 )
700 0 : OpenTable( papszSchemaNames[iTable], papszTableNames[iTable], papszGeomColumnNames[iTable],
701 0 : nCoordDimension, nSRId, eType, bUpdate );
702 : else
703 0 : OpenTable( papszSchemaNames[iTable], papszTableNames[iTable], NULL,
704 0 : nCoordDimension, nSRId, eType, bUpdate );
705 : }
706 :
707 0 : CSLDestroy( papszTableNames );
708 0 : CSLDestroy( papszSchemaNames );
709 0 : CSLDestroy( papszGeomColumnNames );
710 0 : CSLDestroy( papszCoordDimensions );
711 0 : CSLDestroy( papszSRIds );
712 0 : CSLDestroy( papszTypes );
713 :
714 0 : CPLFree(pszGeometryFormat);
715 0 : CPLFree(pszConnectionName);
716 :
717 0 : bDSUpdate = bUpdate;
718 :
719 0 : return TRUE;
720 : }
721 :
722 : /************************************************************************/
723 : /* ExecuteSQL() */
724 : /************************************************************************/
725 :
726 0 : OGRLayer * OGRMSSQLSpatialDataSource::ExecuteSQL( const char *pszSQLCommand,
727 : OGRGeometry *poSpatialFilter,
728 : const char *pszDialect )
729 :
730 : {
731 : /* -------------------------------------------------------------------- */
732 : /* Use generic imlplementation for OGRSQL dialect. */
733 : /* -------------------------------------------------------------------- */
734 0 : if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
735 : return OGRDataSource::ExecuteSQL( pszSQLCommand,
736 : poSpatialFilter,
737 0 : pszDialect );
738 :
739 : /* -------------------------------------------------------------------- */
740 : /* Special case DELLAYER: command. */
741 : /* -------------------------------------------------------------------- */
742 0 : if( EQUALN(pszSQLCommand,"DELLAYER:",9) )
743 : {
744 0 : const char *pszLayerName = pszSQLCommand + 9;
745 :
746 0 : while( *pszLayerName == ' ' )
747 0 : pszLayerName++;
748 :
749 0 : for( int iLayer = 0; iLayer < nLayers; iLayer++ )
750 : {
751 0 : if( EQUAL(papoLayers[iLayer]->GetName(),
752 : pszLayerName ))
753 : {
754 0 : DeleteLayer( iLayer );
755 0 : break;
756 : }
757 : }
758 0 : return NULL;
759 : }
760 :
761 0 : CPLDebug( "MSSQLSpatial", "ExecuteSQL(%s) called.", pszSQLCommand );
762 :
763 0 : if( EQUALN(pszSQLCommand, "DROP SPATIAL INDEX ON ", 22) )
764 : {
765 : /* Handle command to drop a spatial index. */
766 0 : OGRMSSQLSpatialTableLayer *poLayer = new OGRMSSQLSpatialTableLayer( this );
767 :
768 0 : if (poLayer)
769 : {
770 0 : if( poLayer->Initialize( "dbo", pszSQLCommand + 22, NULL, 0, 0, wkbUnknown ) != CE_None )
771 : {
772 : CPLError( CE_Failure, CPLE_AppDefined,
773 0 : "Failed to initialize layer '%s'", pszSQLCommand + 22 );
774 : }
775 0 : poLayer->DropSpatialIndex();
776 0 : delete poLayer;
777 : }
778 0 : return NULL;
779 : }
780 0 : else if( EQUALN(pszSQLCommand, "CREATE SPATIAL INDEX ON ", 24) )
781 : {
782 : /* Handle command to create a spatial index. */
783 0 : OGRMSSQLSpatialTableLayer *poLayer = new OGRMSSQLSpatialTableLayer( this );
784 :
785 0 : if (poLayer)
786 : {
787 0 : if( poLayer->Initialize( "dbo", pszSQLCommand + 24, NULL, 0, 0, wkbUnknown ) != CE_None )
788 : {
789 : CPLError( CE_Failure, CPLE_AppDefined,
790 0 : "Failed to initialize layer '%s'", pszSQLCommand + 24 );
791 : }
792 0 : poLayer->CreateSpatialIndex();
793 0 : delete poLayer;
794 : }
795 0 : return NULL;
796 : }
797 :
798 : /* Execute the command natively */
799 0 : CPLODBCStatement *poStmt = new CPLODBCStatement( &oSession );
800 0 : poStmt->Append( pszSQLCommand );
801 :
802 0 : if( !poStmt->ExecuteSQL() )
803 : {
804 : CPLError( CE_Failure, CPLE_AppDefined,
805 0 : "%s", oSession.GetLastError() );
806 0 : delete poStmt;
807 0 : return NULL;
808 : }
809 :
810 : /* -------------------------------------------------------------------- */
811 : /* Are there result columns for this statement? */
812 : /* -------------------------------------------------------------------- */
813 0 : if( poStmt->GetColCount() == 0 )
814 : {
815 0 : delete poStmt;
816 0 : CPLErrorReset();
817 0 : return NULL;
818 : }
819 :
820 : /* -------------------------------------------------------------------- */
821 : /* Create a results layer. It will take ownership of the */
822 : /* statement. */
823 : /* -------------------------------------------------------------------- */
824 :
825 0 : OGRMSSQLSpatialSelectLayer *poLayer = NULL;
826 :
827 0 : poLayer = new OGRMSSQLSpatialSelectLayer( this, poStmt );
828 :
829 0 : if( poSpatialFilter != NULL )
830 0 : poLayer->SetSpatialFilter( poSpatialFilter );
831 :
832 0 : return poLayer;
833 : }
834 :
835 : /************************************************************************/
836 : /* ReleaseResultSet() */
837 : /************************************************************************/
838 :
839 0 : void OGRMSSQLSpatialDataSource::ReleaseResultSet( OGRLayer * poLayer )
840 :
841 : {
842 0 : delete poLayer;
843 0 : }
844 :
845 : /************************************************************************/
846 : /* LaunderName() */
847 : /************************************************************************/
848 :
849 0 : char *OGRMSSQLSpatialDataSource::LaunderName( const char *pszSrcName )
850 :
851 : {
852 0 : char *pszSafeName = CPLStrdup( pszSrcName );
853 : int i;
854 :
855 0 : for( i = 0; pszSafeName[i] != '\0'; i++ )
856 : {
857 0 : pszSafeName[i] = (char) tolower( pszSafeName[i] );
858 0 : if( pszSafeName[i] == '-' || pszSafeName[i] == '#' )
859 0 : pszSafeName[i] = '_';
860 : }
861 :
862 0 : return pszSafeName;
863 : }
864 :
865 : /************************************************************************/
866 : /* InitializeMetadataTables() */
867 : /* */
868 : /* Create the metadata tables (SPATIAL_REF_SYS and */
869 : /* GEOMETRY_COLUMNS). */
870 : /************************************************************************/
871 :
872 0 : OGRErr OGRMSSQLSpatialDataSource::InitializeMetadataTables()
873 :
874 : {
875 0 : if (bUseGeometryColumns)
876 : {
877 0 : CPLODBCStatement oStmt( &oSession );
878 :
879 : oStmt.Append( "IF NOT EXISTS (SELECT * FROM sys.objects WHERE "
880 : "object_id = OBJECT_ID(N'[dbo].[geometry_columns]') AND type in (N'U')) "
881 : "CREATE TABLE geometry_columns (f_table_catalog varchar(128) not null, "
882 : "f_table_schema varchar(128) not null, f_table_name varchar(256) not null, "
883 : "f_geometry_column varchar(256) not null, coord_dimension integer not null, "
884 : "srid integer not null, geometry_type varchar(30) not null, "
885 : "CONSTRAINT geometry_columns_pk PRIMARY KEY (f_table_catalog, "
886 0 : "f_table_schema, f_table_name, f_geometry_column));\n" );
887 :
888 : oStmt.Append( "IF NOT EXISTS (SELECT * FROM sys.objects "
889 : "WHERE object_id = OBJECT_ID(N'[dbo].[spatial_ref_sys]') AND type in (N'U')) "
890 : "CREATE TABLE spatial_ref_sys (srid integer not null "
891 0 : "PRIMARY KEY, auth_name varchar(256), auth_srid integer, srtext varchar(2048), proj4text varchar(2048))" );
892 :
893 0 : oSession.BeginTransaction();
894 :
895 0 : if( !oStmt.ExecuteSQL() )
896 : {
897 : CPLError( CE_Failure, CPLE_AppDefined,
898 0 : "Error initializing the metadata tables : %s", GetSession()->GetLastError() );
899 0 : return OGRERR_FAILURE;
900 : }
901 :
902 0 : oSession.CommitTransaction();
903 : }
904 :
905 0 : return OGRERR_NONE;
906 : }
907 :
908 :
909 : /************************************************************************/
910 : /* FetchSRS() */
911 : /* */
912 : /* Return a SRS corresponding to a particular id. Note that */
913 : /* reference counting should be honoured on the returned */
914 : /* OGRSpatialReference, as handles may be cached. */
915 : /************************************************************************/
916 :
917 0 : OGRSpatialReference *OGRMSSQLSpatialDataSource::FetchSRS( int nId )
918 :
919 : {
920 0 : if( nId <= 0 )
921 0 : return NULL;
922 :
923 : /* -------------------------------------------------------------------- */
924 : /* First, we look through our SRID cache, is it there? */
925 : /* -------------------------------------------------------------------- */
926 : int i;
927 :
928 0 : for( i = 0; i < nKnownSRID; i++ )
929 : {
930 0 : if( panSRID[i] == nId )
931 0 : return papoSRS[i];
932 : }
933 :
934 0 : OGRSpatialReference *poSRS = NULL;
935 :
936 : /* -------------------------------------------------------------------- */
937 : /* Try looking up in spatial_ref_sys table */
938 : /* -------------------------------------------------------------------- */
939 0 : if (bUseGeometryColumns)
940 : {
941 0 : CPLODBCStatement oStmt( GetSession() );
942 0 : oStmt.Appendf( "SELECT srtext FROM spatial_ref_sys WHERE srid = %d", nId );
943 :
944 0 : if( oStmt.ExecuteSQL() && oStmt.Fetch() )
945 : {
946 0 : if ( oStmt.GetColData( 0 ) )
947 : {
948 0 : poSRS = new OGRSpatialReference();
949 0 : char* pszWKT = (char*)oStmt.GetColData( 0 );
950 0 : if( poSRS->importFromWkt( &pszWKT ) != OGRERR_NONE )
951 : {
952 0 : delete poSRS;
953 0 : poSRS = NULL;
954 : }
955 : }
956 0 : }
957 : }
958 :
959 : /* -------------------------------------------------------------------- */
960 : /* Try looking up the EPSG list */
961 : /* -------------------------------------------------------------------- */
962 0 : if (!poSRS)
963 : {
964 0 : poSRS = new OGRSpatialReference();
965 0 : if( poSRS->importFromEPSG( nId ) != OGRERR_NONE )
966 : {
967 0 : delete poSRS;
968 0 : poSRS = NULL;
969 : }
970 : }
971 :
972 : /* -------------------------------------------------------------------- */
973 : /* Add to the cache. */
974 : /* -------------------------------------------------------------------- */
975 0 : if (poSRS)
976 : {
977 0 : panSRID = (int *) CPLRealloc(panSRID,sizeof(int) * (nKnownSRID+1) );
978 : papoSRS = (OGRSpatialReference **)
979 0 : CPLRealloc(papoSRS, sizeof(void*) * (nKnownSRID + 1) );
980 0 : panSRID[nKnownSRID] = nId;
981 0 : papoSRS[nKnownSRID] = poSRS;
982 0 : nKnownSRID++;
983 : }
984 :
985 0 : return poSRS;
986 : }
987 :
988 : /************************************************************************/
989 : /* FetchSRSId() */
990 : /* */
991 : /* Fetch the id corresponding to an SRS, and if not found, add */
992 : /* it to the table. */
993 : /************************************************************************/
994 :
995 0 : int OGRMSSQLSpatialDataSource::FetchSRSId( OGRSpatialReference * poSRS)
996 :
997 : {
998 0 : char *pszWKT = NULL;
999 0 : int nSRSId = 0;
1000 : const char* pszAuthorityName;
1001 :
1002 0 : if( poSRS == NULL )
1003 0 : return 0;
1004 :
1005 0 : OGRSpatialReference oSRS(*poSRS);
1006 0 : poSRS = NULL;
1007 :
1008 0 : pszAuthorityName = oSRS.GetAuthorityName(NULL);
1009 :
1010 0 : if( pszAuthorityName == NULL || strlen(pszAuthorityName) == 0 )
1011 : {
1012 : /* -------------------------------------------------------------------- */
1013 : /* Try to identify an EPSG code */
1014 : /* -------------------------------------------------------------------- */
1015 0 : oSRS.AutoIdentifyEPSG();
1016 :
1017 0 : pszAuthorityName = oSRS.GetAuthorityName(NULL);
1018 0 : if (pszAuthorityName != NULL && EQUAL(pszAuthorityName, "EPSG"))
1019 : {
1020 0 : const char* pszAuthorityCode = oSRS.GetAuthorityCode(NULL);
1021 0 : if ( pszAuthorityCode != NULL && strlen(pszAuthorityCode) > 0 )
1022 : {
1023 : /* Import 'clean' SRS */
1024 0 : oSRS.importFromEPSG( atoi(pszAuthorityCode) );
1025 :
1026 0 : pszAuthorityName = oSRS.GetAuthorityName(NULL);
1027 : }
1028 : }
1029 : }
1030 : /* -------------------------------------------------------------------- */
1031 : /* Check whether the EPSG authority code is already mapped to a */
1032 : /* SRS ID. */
1033 : /* -------------------------------------------------------------------- */
1034 0 : int nAuthorityCode = 0;
1035 0 : if( pszAuthorityName != NULL && EQUAL( pszAuthorityName, "EPSG" ) )
1036 : {
1037 : /* For the root authority name 'EPSG', the authority code
1038 : * should always be integral
1039 : */
1040 0 : nAuthorityCode = atoi( oSRS.GetAuthorityCode(NULL) );
1041 :
1042 0 : CPLODBCStatement oStmt( &oSession );
1043 : oStmt.Appendf("SELECT srid FROM spatial_ref_sys WHERE "
1044 : "auth_name = '%s' AND auth_srid = %d",
1045 : pszAuthorityName,
1046 0 : nAuthorityCode );
1047 :
1048 0 : if( oStmt.ExecuteSQL() && oStmt.Fetch() && oStmt.GetColData( 0 ) )
1049 : {
1050 0 : nSRSId = atoi(oStmt.GetColData( 0 ));
1051 0 : return nSRSId;
1052 0 : }
1053 : }
1054 :
1055 : /* -------------------------------------------------------------------- */
1056 : /* Translate SRS to WKT. */
1057 : /* -------------------------------------------------------------------- */
1058 0 : if( oSRS.exportToWkt( &pszWKT ) != OGRERR_NONE )
1059 : {
1060 0 : CPLFree(pszWKT);
1061 0 : return 0;
1062 : }
1063 :
1064 : /* -------------------------------------------------------------------- */
1065 : /* Try to find in the existing table. */
1066 : /* -------------------------------------------------------------------- */
1067 0 : CPLODBCStatement oStmt( &oSession );
1068 :
1069 0 : oStmt.Append( "SELECT srid FROM spatial_ref_sys WHERE srtext = ");
1070 0 : OGRMSSQLAppendEscaped(&oStmt, pszWKT);
1071 :
1072 : /* -------------------------------------------------------------------- */
1073 : /* We got it! Return it. */
1074 : /* -------------------------------------------------------------------- */
1075 0 : if( oStmt.ExecuteSQL() )
1076 : {
1077 0 : if ( oStmt.Fetch() && oStmt.GetColData( 0 ) )
1078 : {
1079 0 : nSRSId = atoi(oStmt.GetColData( 0 ));
1080 0 : CPLFree(pszWKT);
1081 0 : return nSRSId;
1082 : }
1083 : }
1084 : else
1085 : {
1086 : /* probably the table is missing at all */
1087 0 : if( InitializeMetadataTables() != OGRERR_NONE )
1088 : {
1089 0 : CPLFree(pszWKT);
1090 0 : return 0;
1091 : }
1092 : }
1093 :
1094 : /* -------------------------------------------------------------------- */
1095 : /* Try adding the SRS to the SRS table. */
1096 : /* -------------------------------------------------------------------- */
1097 0 : char *pszProj4 = NULL;
1098 0 : if( oSRS.exportToProj4( &pszProj4 ) != OGRERR_NONE )
1099 : {
1100 0 : CPLFree( pszProj4 );
1101 0 : CPLFree(pszWKT);
1102 0 : return 0;
1103 : }
1104 :
1105 : /* -------------------------------------------------------------------- */
1106 : /* Check whether the auth_code can be used as srid. */
1107 : /* -------------------------------------------------------------------- */
1108 0 : nSRSId = nAuthorityCode;
1109 :
1110 0 : oStmt.Clear();
1111 0 : oSession.BeginTransaction();
1112 0 : if (nAuthorityCode > 0)
1113 : {
1114 0 : oStmt.Appendf("SELECT srid FROM spatial_ref_sys where srid = %d", nAuthorityCode);
1115 0 : if ( oStmt.ExecuteSQL() && oStmt.Fetch())
1116 : {
1117 0 : nSRSId = 0;
1118 : }
1119 : }
1120 :
1121 : /* -------------------------------------------------------------------- */
1122 : /* Get the current maximum srid in the srs table. */
1123 : /* -------------------------------------------------------------------- */
1124 :
1125 0 : if (nSRSId == 0)
1126 : {
1127 0 : oStmt.Clear();
1128 0 : oStmt.Append("SELECT COALESCE(MAX(srid) + 1, 32768) FROM spatial_ref_sys where srid between 32768 and 65536");
1129 :
1130 0 : if ( oStmt.ExecuteSQL() && oStmt.Fetch() && oStmt.GetColData( 0 ) )
1131 : {
1132 0 : nSRSId = atoi(oStmt.GetColData( 0 ));
1133 : }
1134 : }
1135 :
1136 0 : if (nSRSId == 0)
1137 : {
1138 : /* unable to allocate srid */
1139 0 : oSession.RollbackTransaction();
1140 0 : CPLFree( pszProj4 );
1141 0 : CPLFree(pszWKT);
1142 0 : return 0;
1143 : }
1144 :
1145 0 : oStmt.Clear();
1146 0 : if( nAuthorityCode > 0 )
1147 : {
1148 : oStmt.Appendf(
1149 : "INSERT INTO spatial_ref_sys (srid, auth_srid, auth_name, srtext, proj4text) "
1150 0 : "VALUES (%d, %d, ", nSRSId, nAuthorityCode );
1151 0 : OGRMSSQLAppendEscaped(&oStmt, pszAuthorityName);
1152 0 : oStmt.Append(", ");
1153 0 : OGRMSSQLAppendEscaped(&oStmt, pszWKT);
1154 0 : oStmt.Append(", ");
1155 0 : OGRMSSQLAppendEscaped(&oStmt, pszProj4);
1156 0 : oStmt.Append(")");
1157 : }
1158 : else
1159 : {
1160 : oStmt.Appendf(
1161 0 : "INSERT INTO spatial_ref_sys (srid,srtext,proj4text) VALUES (%d, ", nSRSId);
1162 0 : OGRMSSQLAppendEscaped(&oStmt, pszWKT);
1163 0 : oStmt.Append(", ");
1164 0 : OGRMSSQLAppendEscaped(&oStmt, pszProj4);
1165 0 : oStmt.Append(")");
1166 : }
1167 :
1168 : /* Free everything that was allocated. */
1169 0 : CPLFree( pszProj4 );
1170 0 : CPLFree( pszWKT);
1171 :
1172 0 : if ( oStmt.ExecuteSQL() )
1173 0 : oSession.CommitTransaction();
1174 : else
1175 0 : oSession.RollbackTransaction();
1176 :
1177 0 : return nSRSId;
1178 : }
1179 :
|