Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: MSSQL Spatial driver
4 : * Purpose: Implements OGRMSSQLSpatialDataSource class..
5 : * Author: Tamas Szekeres, szekerest at gmail.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010, Tamas Szekeres
9 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.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_mssqlspatial.h"
31 :
32 : /************************************************************************/
33 : /* OGRMSSQLSpatialDataSource() */
34 : /************************************************************************/
35 :
36 1 : OGRMSSQLSpatialDataSource::OGRMSSQLSpatialDataSource() : bDSUpdate(false)
37 : {
38 1 : pszName = nullptr;
39 1 : pszCatalog = nullptr;
40 1 : papoLayers = nullptr;
41 1 : nLayers = 0;
42 :
43 1 : poLayerInCopyMode = nullptr;
44 :
45 1 : nGeometryFormat = MSSQLGEOMETRY_NATIVE;
46 1 : pszConnection = nullptr;
47 :
48 1 : sMSSQLVersion.nMajor = 0;
49 1 : sMSSQLVersion.nMinor = 0;
50 1 : sMSSQLVersion.nBuild = 0;
51 1 : sMSSQLVersion.nRevision = 0;
52 :
53 1 : bUseGeometryColumns = CPLTestBool(
54 : CPLGetConfigOption("MSSQLSPATIAL_USE_GEOMETRY_COLUMNS", "YES"));
55 1 : bAlwaysOutputFid =
56 1 : CPLTestBool(CPLGetConfigOption("MSSQLSPATIAL_ALWAYS_OUTPUT_FID", "NO"));
57 1 : bListAllTables =
58 1 : CPLTestBool(CPLGetConfigOption("MSSQLSPATIAL_LIST_ALL_TABLES", "NO"));
59 :
60 : const char *nBCPSizeParam =
61 1 : CPLGetConfigOption("MSSQLSPATIAL_BCP_SIZE", nullptr);
62 1 : if (nBCPSizeParam != nullptr)
63 0 : nBCPSize = atoi(nBCPSizeParam);
64 : else
65 1 : nBCPSize = 1000;
66 : #ifdef MSSQL_BCP_SUPPORTED
67 : bUseCopy = CPLTestBool(CPLGetConfigOption("MSSQLSPATIAL_USE_BCP", "TRUE"));
68 : #else
69 1 : bUseCopy = FALSE;
70 : #endif
71 1 : CPLDebug("MSSQLSpatial", "Use COPY/BCP: %d", bUseCopy);
72 1 : }
73 :
74 : /************************************************************************/
75 : /* ~OGRMSSQLSpatialDataSource() */
76 : /************************************************************************/
77 :
78 2 : OGRMSSQLSpatialDataSource::~OGRMSSQLSpatialDataSource()
79 :
80 : {
81 1 : for (int i = 0; i < nLayers; i++)
82 0 : delete papoLayers[i];
83 :
84 1 : CPLFree(papoLayers);
85 :
86 1 : CPLFree(pszName);
87 1 : CPLFree(pszCatalog);
88 :
89 1 : CPLFree(pszConnection);
90 2 : }
91 :
92 : /************************************************************************/
93 : /* OGRMSSQLDecodeVersionString() */
94 : /************************************************************************/
95 :
96 0 : void OGRMSSQLSpatialDataSource::OGRMSSQLDecodeVersionString(MSSQLVer *psVersion,
97 : const char *pszVer)
98 : {
99 0 : while (*pszVer == ' ')
100 0 : pszVer++;
101 :
102 0 : const char *ptr = pszVer;
103 : // get Version string
104 0 : while (*ptr && *ptr != ' ')
105 0 : ptr++;
106 0 : GUInt32 iLen = static_cast<int>(ptr - pszVer);
107 0 : char szVer[20] = {};
108 0 : if (iLen > sizeof(szVer) - 1)
109 0 : iLen = sizeof(szVer) - 1;
110 0 : strncpy(szVer, pszVer, iLen);
111 0 : szVer[iLen] = '\0';
112 :
113 0 : ptr = pszVer = szVer;
114 :
115 : // get Major number
116 0 : while (*ptr && *ptr != '.')
117 0 : ptr++;
118 0 : iLen = static_cast<int>(ptr - pszVer);
119 0 : char szNum[20] = {};
120 0 : if (iLen > sizeof(szNum) - 1)
121 0 : iLen = sizeof(szNum) - 1;
122 0 : strncpy(szNum, pszVer, iLen);
123 0 : szNum[iLen] = '\0';
124 0 : psVersion->nMajor = atoi(szNum);
125 :
126 0 : if (*ptr == 0)
127 0 : return;
128 0 : pszVer = ++ptr;
129 :
130 : // get Minor number
131 0 : while (*ptr && *ptr != '.')
132 0 : ptr++;
133 0 : iLen = static_cast<int>(ptr - pszVer);
134 0 : if (iLen > sizeof(szNum) - 1)
135 0 : iLen = sizeof(szNum) - 1;
136 0 : strncpy(szNum, pszVer, iLen);
137 0 : szNum[iLen] = '\0';
138 0 : psVersion->nMinor = atoi(szNum);
139 :
140 0 : if (*ptr == 0)
141 0 : return;
142 0 : pszVer = ++ptr;
143 :
144 : // get Build number
145 0 : while (*ptr && *ptr != '.')
146 0 : ptr++;
147 0 : iLen = static_cast<int>(ptr - pszVer);
148 0 : if (iLen > sizeof(szNum) - 1)
149 0 : iLen = sizeof(szNum) - 1;
150 0 : strncpy(szNum, pszVer, iLen);
151 0 : szNum[iLen] = '\0';
152 0 : psVersion->nBuild = atoi(szNum);
153 :
154 0 : if (*ptr == 0)
155 0 : return;
156 0 : pszVer = ++ptr;
157 :
158 : // get Revision number
159 0 : while (*ptr && *ptr != '.')
160 0 : ptr++;
161 0 : iLen = static_cast<int>(ptr - pszVer);
162 0 : if (iLen > sizeof(szNum) - 1)
163 0 : iLen = sizeof(szNum) - 1;
164 0 : strncpy(szNum, pszVer, iLen);
165 0 : szNum[iLen] = '\0';
166 0 : psVersion->nRevision = atoi(szNum);
167 : }
168 :
169 : /************************************************************************/
170 : /* TestCapability() */
171 : /************************************************************************/
172 :
173 0 : int OGRMSSQLSpatialDataSource::TestCapability(const char *pszCap)
174 :
175 : {
176 : #if (ODBCVER >= 0x0300)
177 0 : if (EQUAL(pszCap, ODsCTransactions))
178 0 : return TRUE;
179 : #endif
180 0 : if (EQUAL(pszCap, ODsCCreateLayer) || EQUAL(pszCap, ODsCDeleteLayer))
181 0 : return TRUE;
182 0 : if (EQUAL(pszCap, ODsCRandomLayerWrite))
183 0 : return TRUE;
184 0 : if (EQUAL(pszCap, OLCFastGetExtent))
185 0 : return TRUE;
186 0 : else if (EQUAL(pszCap, ODsCCurveGeometries))
187 0 : return TRUE;
188 0 : else if (EQUAL(pszCap, ODsCMeasuredGeometries))
189 0 : return TRUE;
190 0 : else if (EQUAL(pszCap, ODsCZGeometries))
191 0 : return TRUE;
192 : else
193 0 : return FALSE;
194 : }
195 :
196 : /************************************************************************/
197 : /* GetLayer() */
198 : /************************************************************************/
199 :
200 0 : OGRLayer *OGRMSSQLSpatialDataSource::GetLayer(int iLayer)
201 :
202 : {
203 0 : if (iLayer < 0 || iLayer >= nLayers)
204 0 : return nullptr;
205 : else
206 0 : return papoLayers[iLayer];
207 : }
208 :
209 : /************************************************************************/
210 : /* GetLayerByName() */
211 : /************************************************************************/
212 :
213 0 : OGRLayer *OGRMSSQLSpatialDataSource::GetLayerByName(const char *pszLayerName)
214 :
215 : {
216 0 : if (!pszLayerName)
217 0 : return nullptr;
218 :
219 0 : char *pszTableName = nullptr;
220 0 : char *pszSchemaName = nullptr;
221 :
222 0 : const char *pszDotPos = strstr(pszLayerName, ".");
223 0 : if (pszDotPos != nullptr)
224 : {
225 0 : int length = static_cast<int>(pszDotPos - pszLayerName);
226 0 : pszSchemaName = (char *)CPLMalloc(length + 1);
227 0 : strncpy(pszSchemaName, pszLayerName, length);
228 0 : pszSchemaName[length] = '\0';
229 0 : pszTableName = CPLStrdup(pszDotPos + 1); // skip "."
230 : }
231 : else
232 : {
233 0 : pszSchemaName = CPLStrdup("dbo");
234 0 : pszTableName = CPLStrdup(pszLayerName);
235 : }
236 :
237 0 : for (int iLayer = 0; iLayer < nLayers; iLayer++)
238 : {
239 0 : if (EQUAL(pszTableName, papoLayers[iLayer]->GetTableName()) &&
240 0 : EQUAL(pszSchemaName, papoLayers[iLayer]->GetSchemaName()))
241 : {
242 0 : CPLFree(pszSchemaName);
243 0 : CPLFree(pszTableName);
244 0 : return papoLayers[iLayer];
245 : }
246 : }
247 :
248 0 : CPLFree(pszSchemaName);
249 0 : CPLFree(pszTableName);
250 :
251 0 : return nullptr;
252 : }
253 :
254 : /************************************************************************/
255 : /* DeleteLayer() */
256 : /************************************************************************/
257 :
258 0 : OGRErr OGRMSSQLSpatialDataSource::DeleteLayer(int iLayer)
259 :
260 : {
261 0 : if (iLayer < 0 || iLayer >= nLayers)
262 0 : return OGRERR_FAILURE;
263 :
264 0 : EndCopy();
265 :
266 : /* -------------------------------------------------------------------- */
267 : /* Blow away our OGR structures related to the layer. This is */
268 : /* pretty dangerous if anything has a reference to this layer! */
269 : /* -------------------------------------------------------------------- */
270 0 : const char *pszTableName = papoLayers[iLayer]->GetTableName();
271 0 : const char *pszSchemaName = papoLayers[iLayer]->GetSchemaName();
272 :
273 0 : CPLODBCStatement oStmt(&oSession);
274 0 : if (bUseGeometryColumns)
275 0 : oStmt.Appendf("DELETE FROM geometry_columns WHERE f_table_schema = "
276 : "'%s' AND f_table_name = '%s'\n",
277 : pszSchemaName, pszTableName);
278 0 : oStmt.Appendf("DROP TABLE [%s].[%s]", pszSchemaName, pszTableName);
279 :
280 0 : CPLDebug("MSSQLSpatial", "DeleteLayer(%s)", pszTableName);
281 :
282 0 : papoLayers[iLayer]->SetSpatialIndexFlag(FALSE);
283 :
284 0 : delete papoLayers[iLayer];
285 0 : memmove(papoLayers + iLayer, papoLayers + iLayer + 1,
286 0 : sizeof(void *) * (nLayers - iLayer - 1));
287 0 : nLayers--;
288 :
289 : /* -------------------------------------------------------------------- */
290 : /* Remove from the database. */
291 : /* -------------------------------------------------------------------- */
292 :
293 0 : int bInTransaction = oSession.IsInTransaction();
294 0 : if (!bInTransaction)
295 0 : oSession.BeginTransaction();
296 :
297 0 : if (!oStmt.ExecuteSQL())
298 : {
299 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error deleting layer: %s",
300 : GetSession()->GetLastError());
301 :
302 0 : if (!bInTransaction)
303 0 : oSession.RollbackTransaction();
304 :
305 0 : return OGRERR_FAILURE;
306 : }
307 :
308 0 : if (!bInTransaction)
309 0 : oSession.CommitTransaction();
310 :
311 0 : return OGRERR_NONE;
312 : }
313 :
314 : /************************************************************************/
315 : /* CreateLayer() */
316 : /************************************************************************/
317 :
318 : OGRLayer *
319 0 : OGRMSSQLSpatialDataSource::ICreateLayer(const char *pszLayerName,
320 : const OGRGeomFieldDefn *poGeomFieldDefn,
321 : CSLConstList papszOptions)
322 :
323 : {
324 0 : char *pszTableName = nullptr;
325 0 : char *pszSchemaName = nullptr;
326 0 : const char *pszGeomType = nullptr;
327 0 : const char *pszGeomColumn = nullptr;
328 0 : int nCoordDimension = 3;
329 0 : char *pszFIDColumnName = nullptr;
330 :
331 0 : const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
332 : const auto poSRS =
333 0 : poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
334 :
335 0 : EndCopy();
336 :
337 : /* determine the dimension */
338 0 : if (eType == wkbFlatten(eType))
339 0 : nCoordDimension = 2;
340 :
341 0 : if (CSLFetchNameValue(papszOptions, "DIM") != nullptr)
342 0 : nCoordDimension = atoi(CSLFetchNameValue(papszOptions, "DIM"));
343 :
344 0 : int bExtractSchemaFromLayerName = CPLTestBool(CSLFetchNameValueDef(
345 0 : papszOptions, "EXTRACT_SCHEMA_FROM_LAYER_NAME", "YES"));
346 :
347 : /* MSSQL Schema handling:
348 : Extract schema name from input layer name or passed with -lco SCHEMA.
349 : Set layer name to "schema.table" or to "table" if schema is not
350 : specified
351 : */
352 0 : const char *pszDotPos = strstr(pszLayerName, ".");
353 0 : if (pszDotPos != nullptr && bExtractSchemaFromLayerName)
354 : {
355 0 : int length = static_cast<int>(pszDotPos - pszLayerName);
356 0 : pszSchemaName = (char *)CPLMalloc(length + 1);
357 0 : CPLAssert(pszSchemaName !=
358 : nullptr); /* to make Coverity happy and not believe a
359 : REVERSE_INULL is possible */
360 0 : strncpy(pszSchemaName, pszLayerName, length);
361 0 : pszSchemaName[length] = '\0';
362 :
363 0 : if (CPLFetchBool(papszOptions, "LAUNDER", true))
364 0 : pszTableName = LaunderName(pszDotPos + 1); // skip "."
365 : else
366 0 : pszTableName = CPLStrdup(pszDotPos + 1); // skip "."
367 : }
368 : else
369 : {
370 0 : if (CPLFetchBool(papszOptions, "LAUNDER", TRUE))
371 0 : pszTableName = LaunderName(pszLayerName); // skip "."
372 : else
373 0 : pszTableName = CPLStrdup(pszLayerName); // skip "."
374 : }
375 :
376 0 : if (CSLFetchNameValue(papszOptions, "SCHEMA") != nullptr)
377 : {
378 0 : CPLFree(pszSchemaName);
379 0 : pszSchemaName = CPLStrdup(CSLFetchNameValue(papszOptions, "SCHEMA"));
380 : }
381 :
382 0 : if (pszSchemaName == nullptr)
383 0 : pszSchemaName = CPLStrdup("dbo");
384 :
385 : /* -------------------------------------------------------------------- */
386 : /* Do we already have this layer? If so, should we blow it */
387 : /* away? */
388 : /* -------------------------------------------------------------------- */
389 : int iLayer;
390 :
391 0 : for (iLayer = 0; iLayer < nLayers; iLayer++)
392 : {
393 0 : if (EQUAL(pszTableName, papoLayers[iLayer]->GetTableName()) &&
394 0 : EQUAL(pszSchemaName, papoLayers[iLayer]->GetSchemaName()))
395 : {
396 0 : if (CSLFetchNameValue(papszOptions, "OVERWRITE") != nullptr &&
397 0 : !EQUAL(CSLFetchNameValue(papszOptions, "OVERWRITE"), "NO"))
398 : {
399 0 : CPLFree(pszSchemaName);
400 0 : pszSchemaName = CPLStrdup(papoLayers[iLayer]->GetSchemaName());
401 :
402 0 : DeleteLayer(iLayer);
403 : }
404 : else
405 : {
406 0 : CPLError(CE_Failure, CPLE_AppDefined,
407 : "Layer %s already exists, CreateLayer failed.\n"
408 : "Use the layer creation option OVERWRITE=YES to "
409 : "replace it.",
410 : pszLayerName);
411 :
412 0 : CPLFree(pszSchemaName);
413 0 : CPLFree(pszTableName);
414 0 : return nullptr;
415 : }
416 : }
417 : }
418 :
419 : /* -------------------------------------------------------------------- */
420 : /* Handle the GEOM_TYPE option. */
421 : /* -------------------------------------------------------------------- */
422 0 : if (eType != wkbNone)
423 : {
424 0 : pszGeomType = CSLFetchNameValue(papszOptions, "GEOM_TYPE");
425 :
426 0 : if (!pszGeomType)
427 0 : pszGeomType = "geometry";
428 :
429 0 : if (!EQUAL(pszGeomType, "geometry") && !EQUAL(pszGeomType, "geography"))
430 : {
431 0 : CPLError(CE_Failure, CPLE_AppDefined,
432 : "FORMAT=%s not recognised or supported.", pszGeomType);
433 :
434 0 : CPLFree(pszSchemaName);
435 0 : CPLFree(pszTableName);
436 0 : return nullptr;
437 : }
438 :
439 : /* determine the geometry column name */
440 0 : pszGeomColumn = CSLFetchNameValue(papszOptions, "GEOMETRY_NAME");
441 0 : if (!pszGeomColumn)
442 0 : pszGeomColumn = CSLFetchNameValue(papszOptions, "GEOM_NAME");
443 0 : if (!pszGeomColumn)
444 0 : pszGeomColumn = "ogr_geometry";
445 : }
446 : const bool bGeomNullable =
447 0 : CPLFetchBool(papszOptions, "GEOMETRY_NULLABLE", true);
448 :
449 : /* -------------------------------------------------------------------- */
450 : /* Initialize the metadata tables */
451 : /* -------------------------------------------------------------------- */
452 :
453 0 : if (InitializeMetadataTables() != OGRERR_NONE)
454 : {
455 0 : CPLFree(pszSchemaName);
456 0 : CPLFree(pszTableName);
457 0 : return nullptr;
458 : }
459 :
460 : /* -------------------------------------------------------------------- */
461 : /* Try to get the SRS Id of this spatial reference system, */
462 : /* adding to the srs table if needed. */
463 : /* -------------------------------------------------------------------- */
464 0 : int nSRSId = 0;
465 :
466 0 : if (CSLFetchNameValue(papszOptions, "SRID") != nullptr)
467 0 : nSRSId = atoi(CSLFetchNameValue(papszOptions, "SRID"));
468 :
469 0 : if (nSRSId == 0 && poSRS != nullptr)
470 0 : nSRSId = FetchSRSId(poSRS);
471 :
472 : /* -------------------------------------------------------------------- */
473 : /* Create a new table and create a new entry in the geometry, */
474 : /* geometry_columns metadata table. */
475 : /* -------------------------------------------------------------------- */
476 :
477 0 : CPLODBCStatement oStmt(&oSession);
478 :
479 0 : if (eType != wkbNone && bUseGeometryColumns)
480 : {
481 0 : const char *pszGeometryType = OGRToOGCGeomType(eType);
482 :
483 0 : oStmt.Appendf(
484 : "DELETE FROM geometry_columns WHERE f_table_schema = '%s' "
485 : "AND f_table_name = '%s'\n",
486 : pszSchemaName, pszTableName);
487 :
488 0 : oStmt.Appendf("INSERT INTO [geometry_columns] ([f_table_catalog], "
489 : "[f_table_schema] ,[f_table_name], "
490 : "[f_geometry_column],[coord_dimension],[srid],[geometry_"
491 : "type]) VALUES ('%s', '%s', '%s', '%s', %d, %d, '%s')\n",
492 : pszCatalog, pszSchemaName, pszTableName, pszGeomColumn,
493 : nCoordDimension, nSRSId, pszGeometryType);
494 : }
495 :
496 0 : if (!EQUAL(pszSchemaName, "dbo"))
497 : {
498 : // creating the schema if not exists
499 0 : oStmt.Appendf("IF NOT EXISTS (SELECT name from sys.schemas WHERE name "
500 : "= '%s') EXEC sp_executesql N'CREATE SCHEMA [%s]'\n",
501 : pszSchemaName, pszSchemaName);
502 : }
503 :
504 : /* determine the FID column name */
505 : const char *pszFIDColumnNameIn =
506 0 : CSLFetchNameValueDef(papszOptions, "FID", "ogr_fid");
507 0 : if (CPLFetchBool(papszOptions, "LAUNDER", TRUE))
508 0 : pszFIDColumnName = LaunderName(pszFIDColumnNameIn);
509 : else
510 0 : pszFIDColumnName = CPLStrdup(pszFIDColumnNameIn);
511 :
512 0 : const bool bFID64 = CPLFetchBool(papszOptions, "FID64", FALSE);
513 0 : const char *pszFIDType = bFID64 ? "bigint" : "int";
514 :
515 0 : if (eType == wkbNone)
516 : {
517 0 : oStmt.Appendf(
518 : "CREATE TABLE [%s].[%s] ([%s] [%s] IDENTITY(1,1) NOT NULL, "
519 : "CONSTRAINT [PK_%s] PRIMARY KEY CLUSTERED ([%s] ASC))",
520 : pszSchemaName, pszTableName, pszFIDColumnName, pszFIDType,
521 : pszTableName, pszFIDColumnName);
522 : }
523 : else
524 : {
525 0 : oStmt.Appendf(
526 : "CREATE TABLE [%s].[%s] ([%s] [%s] IDENTITY(1,1) NOT NULL, "
527 : "[%s] [%s] %s, CONSTRAINT [PK_%s] PRIMARY KEY CLUSTERED ([%s] "
528 : "ASC))",
529 : pszSchemaName, pszTableName, pszFIDColumnName, pszFIDType,
530 : pszGeomColumn, pszGeomType, bGeomNullable ? "NULL" : "NOT NULL",
531 : pszTableName, pszFIDColumnName);
532 : }
533 :
534 0 : CPLFree(pszFIDColumnName);
535 :
536 0 : int bInTransaction = oSession.IsInTransaction();
537 0 : if (!bInTransaction)
538 0 : oSession.BeginTransaction();
539 :
540 0 : if (!oStmt.ExecuteSQL())
541 : {
542 0 : CPLError(CE_Failure, CPLE_AppDefined,
543 : "Error creating layer: %s When using the overwrite option and "
544 : "the layer doesn't contain geometry column, you might require "
545 : "to use the MSSQLSPATIAL_LIST_ALL_TABLES config option to get "
546 : "the previous layer deleted before creating the new one.",
547 : GetSession()->GetLastError());
548 :
549 0 : if (!bInTransaction)
550 0 : oSession.RollbackTransaction();
551 :
552 0 : return nullptr;
553 : }
554 :
555 0 : if (!bInTransaction)
556 0 : oSession.CommitTransaction();
557 :
558 : /* -------------------------------------------------------------------- */
559 : /* Create the layer object. */
560 : /* -------------------------------------------------------------------- */
561 : OGRMSSQLSpatialTableLayer *poLayer;
562 :
563 0 : poLayer = new OGRMSSQLSpatialTableLayer(this);
564 :
565 0 : if (bInTransaction)
566 0 : poLayer->SetLayerStatus(MSSQLLAYERSTATUS_INITIAL);
567 : else
568 0 : poLayer->SetLayerStatus(MSSQLLAYERSTATUS_CREATED);
569 :
570 0 : poLayer->SetLaunderFlag(CPLFetchBool(papszOptions, "LAUNDER", true));
571 0 : poLayer->SetPrecisionFlag(CPLFetchBool(papszOptions, "PRECISION", true));
572 :
573 0 : if (bUseCopy)
574 0 : poLayer->SetUseCopy(nBCPSize);
575 :
576 0 : const char *pszSI = CSLFetchNameValue(papszOptions, "SPATIAL_INDEX");
577 0 : int bCreateSpatialIndex = (pszSI == nullptr || CPLTestBool(pszSI));
578 0 : if (pszGeomColumn == nullptr)
579 0 : bCreateSpatialIndex = FALSE;
580 :
581 0 : poLayer->SetSpatialIndexFlag(bCreateSpatialIndex);
582 :
583 : const char *pszUploadGeometryFormat =
584 0 : CSLFetchNameValue(papszOptions, "UPLOAD_GEOM_FORMAT");
585 0 : if (pszUploadGeometryFormat)
586 : {
587 0 : if (STARTS_WITH_CI(pszUploadGeometryFormat, "wkb"))
588 0 : poLayer->SetUploadGeometryFormat(MSSQLGEOMETRY_WKB);
589 0 : else if (STARTS_WITH_CI(pszUploadGeometryFormat, "wkt"))
590 0 : poLayer->SetUploadGeometryFormat(MSSQLGEOMETRY_WKT);
591 : }
592 :
593 0 : char *pszWKT = nullptr;
594 0 : if (poSRS && poSRS->exportToWkt(&pszWKT) != OGRERR_NONE)
595 : {
596 0 : CPLFree(pszWKT);
597 0 : pszWKT = nullptr;
598 : }
599 :
600 0 : if (bFID64)
601 0 : poLayer->SetMetadataItem(OLMD_FID64, "YES");
602 :
603 0 : if (poLayer->Initialize(pszSchemaName, pszTableName, pszGeomColumn,
604 : nCoordDimension, nSRSId, pszWKT,
605 0 : eType) == CE_Failure)
606 : {
607 0 : CPLFree(pszSchemaName);
608 0 : CPLFree(pszTableName);
609 0 : CPLFree(pszWKT);
610 0 : return nullptr;
611 : }
612 :
613 0 : CPLFree(pszSchemaName);
614 0 : CPLFree(pszTableName);
615 0 : CPLFree(pszWKT);
616 :
617 : /* -------------------------------------------------------------------- */
618 : /* Add layer to data source layer list. */
619 : /* -------------------------------------------------------------------- */
620 0 : papoLayers = (OGRMSSQLSpatialTableLayer **)CPLRealloc(
621 0 : papoLayers, sizeof(OGRMSSQLSpatialTableLayer *) * (nLayers + 1));
622 :
623 0 : papoLayers[nLayers++] = poLayer;
624 :
625 0 : return poLayer;
626 : }
627 :
628 : /************************************************************************/
629 : /* OpenTable() */
630 : /************************************************************************/
631 :
632 0 : int OGRMSSQLSpatialDataSource::OpenTable(const char *pszSchemaName,
633 : const char *pszTableName,
634 : const char *pszGeomCol,
635 : int nCoordDimension, int nSRID,
636 : const char *pszSRText,
637 : OGRwkbGeometryType eType, bool bUpdate)
638 : {
639 : /* -------------------------------------------------------------------- */
640 : /* Create the layer object. */
641 : /* -------------------------------------------------------------------- */
642 0 : OGRMSSQLSpatialTableLayer *poLayer = new OGRMSSQLSpatialTableLayer(this);
643 :
644 0 : if (poLayer->Initialize(pszSchemaName, pszTableName, pszGeomCol,
645 0 : nCoordDimension, nSRID, pszSRText, eType))
646 : {
647 0 : delete poLayer;
648 0 : return FALSE;
649 : }
650 0 : poLayer->SetUpdate(bUpdate);
651 :
652 0 : if (bUseCopy)
653 0 : poLayer->SetUseCopy(nBCPSize);
654 :
655 : /* -------------------------------------------------------------------- */
656 : /* Add layer to data source layer list. */
657 : /* -------------------------------------------------------------------- */
658 0 : papoLayers = (OGRMSSQLSpatialTableLayer **)CPLRealloc(
659 0 : papoLayers, sizeof(OGRMSSQLSpatialTableLayer *) * (nLayers + 1));
660 0 : papoLayers[nLayers++] = poLayer;
661 :
662 0 : return TRUE;
663 : }
664 :
665 : /************************************************************************/
666 : /* GetLayerCount() */
667 : /************************************************************************/
668 :
669 0 : int OGRMSSQLSpatialDataSource::GetLayerCount()
670 : {
671 0 : return nLayers;
672 : }
673 :
674 : /************************************************************************/
675 : /* ParseValue() */
676 : /************************************************************************/
677 :
678 529 : int OGRMSSQLSpatialDataSource::ParseValue(char **pszValue, char *pszSource,
679 : const char *pszKey, int nStart,
680 : int nNext, int nTerm, int bRemove)
681 : {
682 529 : int nLen = static_cast<int>(strlen(pszKey));
683 529 : if ((*pszValue) == nullptr && nStart + nLen < nNext &&
684 185 : EQUALN(pszSource + nStart, pszKey, nLen))
685 : {
686 4 : *pszValue =
687 4 : (char *)CPLMalloc(sizeof(char) * (nNext - nStart - nLen + 1));
688 4 : strncpy(*pszValue, pszSource + nStart + nLen, nNext - nStart - nLen);
689 4 : (*pszValue)[nNext - nStart - nLen] = 0;
690 :
691 4 : if (bRemove)
692 : {
693 : // remove the value from the source string
694 0 : if (pszSource[nNext] == ';')
695 0 : memmove(pszSource + nStart, pszSource + nNext + 1,
696 0 : nTerm - nNext);
697 : else
698 0 : memmove(pszSource + nStart, pszSource + nNext,
699 0 : nTerm - nNext + 1);
700 : }
701 4 : return TRUE;
702 : }
703 525 : return FALSE;
704 : }
705 :
706 : /************************************************************************/
707 : /* Open() */
708 : /************************************************************************/
709 :
710 1 : int OGRMSSQLSpatialDataSource::Open(const char *pszNewName, bool bUpdate,
711 : int bTestOpen)
712 :
713 : {
714 1 : CPLAssert(nLayers == 0);
715 :
716 1 : if (!STARTS_WITH_CI(pszNewName, "MSSQL:"))
717 : {
718 0 : if (!bTestOpen)
719 0 : CPLError(CE_Failure, CPLE_AppDefined,
720 : "%s does not conform to MSSSQLSpatial naming convention,"
721 : " MSSQL:*\n",
722 : pszNewName);
723 0 : return FALSE;
724 : }
725 :
726 : /* Determine if the connection string contains specific values */
727 1 : char *pszTableSpec = nullptr;
728 1 : char *pszGeometryFormat = nullptr;
729 1 : char *pszConnectionName = CPLStrdup(pszNewName + 6);
730 1 : char *pszDriver = nullptr;
731 1 : char *pszUID = nullptr;
732 1 : char *pszPWD = nullptr;
733 : int nCurrent, nNext, nTerm;
734 1 : nCurrent = nNext = nTerm = static_cast<int>(strlen(pszConnectionName));
735 :
736 95 : while (nCurrent > 0)
737 : {
738 94 : --nCurrent;
739 94 : if (pszConnectionName[nCurrent] == ';')
740 : {
741 4 : nNext = nCurrent;
742 4 : continue;
743 : }
744 :
745 90 : if (ParseValue(&pszCatalog, pszConnectionName, "database=", nCurrent,
746 90 : nNext, nTerm, FALSE))
747 1 : continue;
748 :
749 89 : if (ParseValue(&pszTableSpec, pszConnectionName, "tables=", nCurrent,
750 89 : nNext, nTerm, TRUE))
751 0 : continue;
752 :
753 89 : if (ParseValue(&pszDriver, pszConnectionName, "driver=", nCurrent,
754 89 : nNext, nTerm, FALSE))
755 1 : continue;
756 :
757 88 : if (ParseValue(&pszUID, pszConnectionName, "uid=", nCurrent, nNext,
758 88 : nTerm, FALSE))
759 1 : continue;
760 :
761 87 : if (ParseValue(&pszPWD, pszConnectionName, "pwd=", nCurrent, nNext,
762 87 : nTerm, FALSE))
763 1 : continue;
764 :
765 86 : if (ParseValue(&pszGeometryFormat, pszConnectionName,
766 86 : "geometryformat=", nCurrent, nNext, nTerm, TRUE))
767 : {
768 0 : if (STARTS_WITH_CI(pszGeometryFormat, "wkbzm"))
769 0 : nGeometryFormat = MSSQLGEOMETRY_WKBZM;
770 0 : else if (STARTS_WITH_CI(pszGeometryFormat, "wkb"))
771 0 : nGeometryFormat = MSSQLGEOMETRY_WKB;
772 0 : else if (STARTS_WITH_CI(pszGeometryFormat, "wkt"))
773 0 : nGeometryFormat = MSSQLGEOMETRY_WKT;
774 0 : else if (STARTS_WITH_CI(pszGeometryFormat, "native"))
775 0 : nGeometryFormat = MSSQLGEOMETRY_NATIVE;
776 : else
777 : {
778 0 : CPLError(CE_Failure, CPLE_AppDefined,
779 : "Invalid geometry type specified: %s,"
780 : " MSSQL:*\n",
781 : pszGeometryFormat);
782 :
783 0 : CPLFree(pszTableSpec);
784 0 : CPLFree(pszGeometryFormat);
785 0 : CPLFree(pszConnectionName);
786 0 : CPLFree(pszDriver);
787 0 : CPLFree(pszUID);
788 0 : CPLFree(pszPWD);
789 0 : return FALSE;
790 : }
791 :
792 0 : CPLFree(pszGeometryFormat);
793 0 : pszGeometryFormat = nullptr;
794 0 : continue;
795 : }
796 : }
797 :
798 : /* Determine if the connection string contains the catalog portion */
799 1 : if (pszCatalog == nullptr)
800 : {
801 0 : CPLError(CE_Failure, CPLE_AppDefined,
802 : "'%s' does not contain the 'database' portion\n", pszNewName);
803 :
804 0 : CPLFree(pszTableSpec);
805 0 : CPLFree(pszGeometryFormat);
806 0 : CPLFree(pszConnectionName);
807 0 : CPLFree(pszDriver);
808 0 : CPLFree(pszUID);
809 0 : CPLFree(pszPWD);
810 0 : return FALSE;
811 : }
812 :
813 1 : pszName = CPLStrdup(pszNewName);
814 :
815 1 : char **papszTableNames = nullptr;
816 1 : char **papszSchemaNames = nullptr;
817 1 : char **papszGeomColumnNames = nullptr;
818 1 : char **papszCoordDimensions = nullptr;
819 1 : char **papszSRIds = nullptr;
820 1 : char **papszSRTexts = nullptr;
821 :
822 : /* Determine if the connection string contains the TABLES portion */
823 1 : if (pszTableSpec != nullptr)
824 : {
825 : char **papszTableList;
826 : int i;
827 :
828 0 : papszTableList = CSLTokenizeString2(pszTableSpec, ",", 0);
829 :
830 0 : for (i = 0; i < CSLCount(papszTableList); i++)
831 : {
832 : char **papszQualifiedParts;
833 :
834 : // Get schema and table name
835 0 : papszQualifiedParts = CSLTokenizeString2(papszTableList[i], ".", 0);
836 :
837 : /* Find the geometry column name if specified */
838 0 : if (CSLCount(papszQualifiedParts) >= 1)
839 : {
840 0 : char *pszGeomColumnName = nullptr;
841 0 : char *pos = strchr(
842 0 : papszQualifiedParts[CSLCount(papszQualifiedParts) - 1],
843 : '(');
844 0 : if (pos != nullptr)
845 : {
846 0 : *pos = '\0';
847 0 : pszGeomColumnName = pos + 1;
848 0 : int len = static_cast<int>(strlen(pszGeomColumnName));
849 0 : if (len > 0)
850 0 : pszGeomColumnName[len - 1] = '\0';
851 : }
852 : papszGeomColumnNames =
853 0 : CSLAddString(papszGeomColumnNames,
854 : pszGeomColumnName ? pszGeomColumnName : "");
855 : }
856 :
857 0 : if (CSLCount(papszQualifiedParts) == 2)
858 : {
859 : papszSchemaNames =
860 0 : CSLAddString(papszSchemaNames, papszQualifiedParts[0]);
861 : papszTableNames =
862 0 : CSLAddString(papszTableNames, papszQualifiedParts[1]);
863 : }
864 0 : else if (CSLCount(papszQualifiedParts) == 1)
865 : {
866 0 : papszSchemaNames = CSLAddString(papszSchemaNames, "dbo");
867 : papszTableNames =
868 0 : CSLAddString(papszTableNames, papszQualifiedParts[0]);
869 : }
870 :
871 0 : CSLDestroy(papszQualifiedParts);
872 : }
873 :
874 0 : CSLDestroy(papszTableList);
875 : }
876 :
877 1 : CPLFree(pszTableSpec);
878 :
879 1 : if (pszDriver == nullptr)
880 : {
881 0 : char *pszConnectionName2 = pszConnectionName;
882 : #if SQLNCLI_VERSION == 11
883 : pszDriver = CPLStrdup("{SQL Server Native Client 11.0}");
884 : #elif SQLNCLI_VERSION == 10
885 : pszDriver = CPLStrdup("{SQL Server Native Client 10.0}");
886 : #elif MSODBCSQL_VERSION == 13
887 : pszDriver = CPLStrdup("{ODBC Driver 13 for SQL Server}");
888 : #elif MSODBCSQL_VERSION == 17
889 : pszDriver = CPLStrdup("{ODBC Driver 17 for SQL Server}");
890 : #elif MSODBCSQL_VERSION == 18
891 : pszDriver = CPLStrdup("{ODBC Driver 18 for SQL Server}");
892 : #else
893 0 : pszDriver = CPLStrdup("{SQL Server}");
894 : #endif
895 0 : pszConnectionName = CPLStrdup(
896 : CPLSPrintf("DRIVER=%s;%s", pszDriver, pszConnectionName2));
897 0 : CPLFree(pszConnectionName2);
898 : }
899 :
900 1 : CPLFree(pszDriver);
901 :
902 1 : if (pszUID == nullptr)
903 : {
904 : const char *pszUIDConst =
905 0 : CPLGetConfigOption("MSSQLSPATIAL_UID", nullptr);
906 0 : if (pszUIDConst)
907 0 : pszUID = CPLStrdup(pszUIDConst);
908 : }
909 1 : if (pszUID != nullptr)
910 : {
911 1 : char *pszConnectionName2 = pszConnectionName;
912 : pszConnectionName =
913 1 : CPLStrdup(CPLSPrintf("%s;UID=%s", pszConnectionName2, pszUID));
914 1 : CPLFree(pszConnectionName2);
915 : }
916 1 : if (pszPWD == nullptr)
917 : {
918 : const char *pszPWDConst =
919 0 : CPLGetConfigOption("MSSQLSPATIAL_PWD", nullptr);
920 0 : if (pszPWDConst)
921 0 : pszPWD = CPLStrdup(pszPWDConst);
922 : }
923 1 : if (pszPWD != nullptr)
924 : {
925 1 : char *pszConnectionName2 = pszConnectionName;
926 : pszConnectionName =
927 1 : CPLStrdup(CPLSPrintf("%s;PWD=%s", pszConnectionName2, pszPWD));
928 1 : CPLFree(pszConnectionName2);
929 : }
930 :
931 1 : CPLFree(pszUID);
932 1 : CPLFree(pszPWD);
933 :
934 : /* Initialize the SQL Server connection. */
935 1 : if (!oSession.EstablishSession(pszConnectionName, "", ""))
936 : {
937 : /* Get a list of the available drivers */
938 : HENV hEnv;
939 1 : if (SQL_SUCCEEDED(SQLAllocEnv(&hEnv)))
940 : {
941 2 : CPLString osDriverList;
942 1 : SQLUSMALLINT direction = SQL_FETCH_FIRST;
943 : SQLSMALLINT driver_ret;
944 : SQLSMALLINT attr_ret;
945 : SQLCHAR attr[256];
946 : SQLCHAR driver[256];
947 1 : while (SQL_SUCCEEDED(SQLDrivers(hEnv, direction, driver,
948 : sizeof(driver), &driver_ret, attr,
949 : sizeof(attr), &attr_ret)))
950 : {
951 0 : direction = SQL_FETCH_NEXT;
952 0 : osDriverList += CPLSPrintf("%s\n", driver);
953 : }
954 :
955 1 : CPLError(CE_Failure, CPLE_AppDefined,
956 : "Unable to initialize connection to the server for %s,\n"
957 : "%s\n"
958 : "Try specifying the driver in the connection string from "
959 : "the list of available drivers:\n"
960 : "%s",
961 : pszNewName, oSession.GetLastError(), osDriverList.c_str());
962 : }
963 : else
964 : {
965 0 : CPLError(CE_Failure, CPLE_AppDefined,
966 : "Unable to initialize connection to the server for %s,\n"
967 : "%s\n",
968 : pszNewName, oSession.GetLastError());
969 : }
970 :
971 1 : if (hEnv != nullptr)
972 1 : SQLFreeEnv(hEnv);
973 :
974 1 : CSLDestroy(papszTableNames);
975 1 : CSLDestroy(papszSchemaNames);
976 1 : CSLDestroy(papszGeomColumnNames);
977 1 : CSLDestroy(papszCoordDimensions);
978 1 : CSLDestroy(papszSRIds);
979 1 : CSLDestroy(papszSRTexts);
980 1 : CPLFree(pszGeometryFormat);
981 1 : CPLFree(pszConnectionName);
982 1 : return FALSE;
983 : }
984 :
985 : /* -------------------------------------------------------------------- */
986 : /* Find out SQLServer version */
987 : /* -------------------------------------------------------------------- */
988 : if (true)
989 : {
990 0 : sMSSQLVersion.nMajor = -1;
991 0 : sMSSQLVersion.nMinor = -1;
992 0 : sMSSQLVersion.nBuild = -1;
993 0 : sMSSQLVersion.nRevision = -1;
994 :
995 0 : CPLODBCStatement oStmt(&oSession);
996 :
997 : /* Use join to make sure the existence of the referred column/table */
998 0 : oStmt.Append(
999 : "SELECT SERVERPROPERTY('ProductVersion') AS ProductVersion;");
1000 :
1001 0 : if (oStmt.ExecuteSQL())
1002 : {
1003 0 : while (oStmt.Fetch())
1004 : {
1005 0 : OGRMSSQLDecodeVersionString(&sMSSQLVersion,
1006 : oStmt.GetColData(0));
1007 : }
1008 : }
1009 : }
1010 :
1011 0 : char **papszTypes = nullptr;
1012 :
1013 : /* read metadata for the specified tables */
1014 0 : if (papszTableNames != nullptr && bUseGeometryColumns)
1015 : {
1016 0 : for (int iTable = 0; papszTableNames[iTable] != nullptr; iTable++)
1017 : {
1018 0 : CPLODBCStatement oStmt(&oSession);
1019 :
1020 : /* Use join to make sure the existence of the referred column/table
1021 : */
1022 0 : oStmt.Appendf(
1023 : "SELECT f_geometry_column, coord_dimension, g.srid, srtext, "
1024 : "geometry_type FROM dbo.geometry_columns g JOIN "
1025 : "INFORMATION_SCHEMA.COLUMNS ON f_table_schema = TABLE_SCHEMA "
1026 : "and f_table_name = TABLE_NAME and f_geometry_column = "
1027 : "COLUMN_NAME left outer join dbo.spatial_ref_sys s on g.srid = "
1028 : "s.srid WHERE f_table_schema = '%s' AND f_table_name = '%s'",
1029 0 : papszSchemaNames[iTable], papszTableNames[iTable]);
1030 :
1031 0 : if (oStmt.ExecuteSQL())
1032 : {
1033 0 : while (oStmt.Fetch())
1034 : {
1035 0 : if (papszGeomColumnNames == nullptr)
1036 0 : papszGeomColumnNames = CSLAddString(
1037 : papszGeomColumnNames, oStmt.GetColData(0));
1038 0 : else if (*papszGeomColumnNames[iTable] == 0)
1039 : {
1040 0 : CPLFree(papszGeomColumnNames[iTable]);
1041 0 : papszGeomColumnNames[iTable] =
1042 0 : CPLStrdup(oStmt.GetColData(0));
1043 : }
1044 :
1045 0 : papszCoordDimensions = CSLAddString(
1046 : papszCoordDimensions, oStmt.GetColData(1, "2"));
1047 : papszSRIds =
1048 0 : CSLAddString(papszSRIds, oStmt.GetColData(2, "0"));
1049 : papszSRTexts =
1050 0 : CSLAddString(papszSRTexts, oStmt.GetColData(3, ""));
1051 0 : papszTypes = CSLAddString(papszTypes,
1052 : oStmt.GetColData(4, "GEOMETRY"));
1053 : }
1054 : }
1055 : else
1056 : {
1057 : /* probably the table is missing at all */
1058 0 : InitializeMetadataTables();
1059 : }
1060 : }
1061 : }
1062 :
1063 : /* if requesting all user database table then this takes priority */
1064 0 : if (papszTableNames == nullptr && bListAllTables)
1065 : {
1066 0 : CPLODBCStatement oStmt(&oSession);
1067 :
1068 0 : oStmt.Append(
1069 : "select sys.schemas.name, sys.schemas.name + '.' + "
1070 : "sys.objects.name, sys.columns.name from sys.columns join "
1071 : "sys.types on sys.columns.system_type_id = "
1072 : "sys.types.system_type_id and sys.columns.user_type_id = "
1073 : "sys.types.user_type_id join sys.objects on sys.objects.object_id "
1074 : "= sys.columns.object_id join sys.schemas on sys.objects.schema_id "
1075 : "= sys.schemas.schema_id where (sys.types.name = 'geometry' or "
1076 : "sys.types.name = 'geography') and (sys.objects.type = 'U' or "
1077 : "sys.objects.type = 'V') union all select sys.schemas.name, "
1078 : "sys.schemas.name + '.' + sys.objects.name, '' from sys.objects "
1079 : "join sys.schemas on sys.objects.schema_id = sys.schemas.schema_id "
1080 : "where not exists (select * from sys.columns sc1 join sys.types on "
1081 : "sc1.system_type_id = sys.types.system_type_id where "
1082 : "(sys.types.name = 'geometry' or sys.types.name = 'geography') and "
1083 : "sys.objects.object_id = sc1.object_id) and (sys.objects.type = "
1084 : "'U' or sys.objects.type = 'V')");
1085 :
1086 0 : if (oStmt.ExecuteSQL())
1087 : {
1088 0 : while (oStmt.Fetch())
1089 : {
1090 : papszSchemaNames =
1091 0 : CSLAddString(papszSchemaNames, oStmt.GetColData(0));
1092 : papszTableNames =
1093 0 : CSLAddString(papszTableNames, oStmt.GetColData(1));
1094 : papszGeomColumnNames =
1095 0 : CSLAddString(papszGeomColumnNames, oStmt.GetColData(2));
1096 : }
1097 : }
1098 : }
1099 :
1100 : /* Determine the available tables if not specified. */
1101 0 : if (papszTableNames == nullptr && bUseGeometryColumns)
1102 : {
1103 0 : CPLODBCStatement oStmt(&oSession);
1104 :
1105 : /* Use join to make sure the existence of the referred column/table */
1106 0 : oStmt.Append("SELECT f_table_schema, f_table_name, f_geometry_column, "
1107 : "coord_dimension, g.srid, srtext, geometry_type FROM "
1108 : "dbo.geometry_columns g JOIN INFORMATION_SCHEMA.COLUMNS "
1109 : "ON f_table_schema = TABLE_SCHEMA and f_table_name = "
1110 : "TABLE_NAME and f_geometry_column = COLUMN_NAME left "
1111 : "outer join dbo.spatial_ref_sys s on g.srid = s.srid");
1112 :
1113 0 : if (oStmt.ExecuteSQL())
1114 : {
1115 0 : while (oStmt.Fetch())
1116 : {
1117 : papszSchemaNames =
1118 0 : CSLAddString(papszSchemaNames, oStmt.GetColData(0, "dbo"));
1119 : papszTableNames =
1120 0 : CSLAddString(papszTableNames, oStmt.GetColData(1));
1121 : papszGeomColumnNames =
1122 0 : CSLAddString(papszGeomColumnNames, oStmt.GetColData(2));
1123 0 : papszCoordDimensions = CSLAddString(papszCoordDimensions,
1124 : oStmt.GetColData(3, "2"));
1125 0 : papszSRIds = CSLAddString(papszSRIds, oStmt.GetColData(4, "0"));
1126 : papszSRTexts =
1127 0 : CSLAddString(papszSRTexts, oStmt.GetColData(5, ""));
1128 : papszTypes =
1129 0 : CSLAddString(papszTypes, oStmt.GetColData(6, "GEOMETRY"));
1130 : }
1131 : }
1132 : else
1133 : {
1134 : /* probably the table is missing at all */
1135 0 : InitializeMetadataTables();
1136 : }
1137 : }
1138 :
1139 : /* Query catalog for tables having geometry columns */
1140 0 : if (papszTableNames == nullptr)
1141 : {
1142 0 : CPLODBCStatement oStmt(&oSession);
1143 :
1144 0 : oStmt.Append(
1145 : "SELECT sys.schemas.name, sys.schemas.name + '.' + "
1146 : "sys.objects.name, sys.columns.name from sys.columns join "
1147 : "sys.types on sys.columns.system_type_id = "
1148 : "sys.types.system_type_id and sys.columns.user_type_id = "
1149 : "sys.types.user_type_id join sys.objects on sys.objects.object_id "
1150 : "= sys.columns.object_id join sys.schemas on sys.objects.schema_id "
1151 : "= sys.schemas.schema_id where (sys.types.name = 'geometry' or "
1152 : "sys.types.name = 'geography') and (sys.objects.type = 'U' or "
1153 : "sys.objects.type = 'V')");
1154 :
1155 0 : if (oStmt.ExecuteSQL())
1156 : {
1157 0 : while (oStmt.Fetch())
1158 : {
1159 : papszSchemaNames =
1160 0 : CSLAddString(papszSchemaNames, oStmt.GetColData(0));
1161 : papszTableNames =
1162 0 : CSLAddString(papszTableNames, oStmt.GetColData(1));
1163 : papszGeomColumnNames =
1164 0 : CSLAddString(papszGeomColumnNames, oStmt.GetColData(2));
1165 : }
1166 : }
1167 : }
1168 :
1169 : int nSRId, nCoordDimension;
1170 : OGRwkbGeometryType eType;
1171 :
1172 0 : for (int iTable = 0;
1173 0 : papszTableNames != nullptr && papszTableNames[iTable] != nullptr;
1174 : iTable++)
1175 : {
1176 0 : if (papszSRIds != nullptr)
1177 0 : nSRId = atoi(papszSRIds[iTable]);
1178 : else
1179 0 : nSRId = 0;
1180 :
1181 0 : if (papszCoordDimensions != nullptr)
1182 0 : nCoordDimension = atoi(papszCoordDimensions[iTable]);
1183 : else
1184 0 : nCoordDimension = 2;
1185 :
1186 0 : if (papszTypes != nullptr)
1187 0 : eType = OGRFromOGCGeomType(papszTypes[iTable]);
1188 : else
1189 0 : eType = wkbUnknown;
1190 :
1191 0 : CPLAssert(papszGeomColumnNames && papszGeomColumnNames[iTable]);
1192 0 : if (strlen(papszGeomColumnNames[iTable]) > 0)
1193 0 : OpenTable(papszSchemaNames[iTable], papszTableNames[iTable],
1194 0 : papszGeomColumnNames[iTable], nCoordDimension, nSRId,
1195 0 : papszSRTexts ? papszSRTexts[iTable] : nullptr, eType,
1196 : bUpdate);
1197 : else
1198 0 : OpenTable(papszSchemaNames[iTable], papszTableNames[iTable],
1199 : nullptr, nCoordDimension, nSRId,
1200 0 : papszSRTexts ? papszSRTexts[iTable] : nullptr, wkbNone,
1201 : bUpdate);
1202 : }
1203 :
1204 0 : CSLDestroy(papszTableNames);
1205 0 : CSLDestroy(papszSchemaNames);
1206 0 : CSLDestroy(papszGeomColumnNames);
1207 0 : CSLDestroy(papszCoordDimensions);
1208 0 : CSLDestroy(papszSRIds);
1209 0 : CSLDestroy(papszSRTexts);
1210 0 : CSLDestroy(papszTypes);
1211 :
1212 0 : CPLFree(pszGeometryFormat);
1213 :
1214 0 : CPLFree(pszConnection);
1215 0 : pszConnection = pszConnectionName;
1216 :
1217 0 : bDSUpdate = bUpdate;
1218 :
1219 0 : return TRUE;
1220 : }
1221 :
1222 : /************************************************************************/
1223 : /* ExecuteSQL() */
1224 : /************************************************************************/
1225 :
1226 0 : OGRLayer *OGRMSSQLSpatialDataSource::ExecuteSQL(const char *pszSQLCommand,
1227 : OGRGeometry *poSpatialFilter,
1228 : const char *pszDialect)
1229 :
1230 : {
1231 : /* -------------------------------------------------------------------- */
1232 : /* Use generic implementation for recognized dialects */
1233 : /* -------------------------------------------------------------------- */
1234 0 : if (IsGenericSQLDialect(pszDialect))
1235 0 : return OGRDataSource::ExecuteSQL(pszSQLCommand, poSpatialFilter,
1236 0 : pszDialect);
1237 :
1238 : /* -------------------------------------------------------------------- */
1239 : /* Special case DELLAYER: command. */
1240 : /* -------------------------------------------------------------------- */
1241 0 : if (STARTS_WITH_CI(pszSQLCommand, "DELLAYER:"))
1242 : {
1243 0 : const char *pszLayerName = pszSQLCommand + 9;
1244 :
1245 0 : while (*pszLayerName == ' ')
1246 0 : pszLayerName++;
1247 :
1248 0 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
1249 :
1250 0 : for (int iLayer = 0; iLayer < nLayers; iLayer++)
1251 : {
1252 0 : if (papoLayers[iLayer] == poLayer)
1253 : {
1254 0 : DeleteLayer(iLayer);
1255 0 : break;
1256 : }
1257 : }
1258 0 : return nullptr;
1259 : }
1260 :
1261 0 : CPLDebug("MSSQLSpatial", "ExecuteSQL(%s) called.", pszSQLCommand);
1262 :
1263 0 : if (STARTS_WITH_CI(pszSQLCommand, "DROP SPATIAL INDEX ON "))
1264 : {
1265 : /* Handle command to drop a spatial index. */
1266 : OGRMSSQLSpatialTableLayer *poLayer =
1267 0 : new OGRMSSQLSpatialTableLayer(this);
1268 :
1269 0 : if (poLayer)
1270 : {
1271 0 : if (poLayer->Initialize(nullptr, pszSQLCommand + 22, nullptr, 0, 0,
1272 0 : nullptr, wkbUnknown) != CE_None)
1273 : {
1274 0 : CPLError(CE_Failure, CPLE_AppDefined,
1275 : "Failed to initialize layer '%s'", pszSQLCommand + 22);
1276 : }
1277 0 : poLayer->DropSpatialIndex();
1278 0 : delete poLayer;
1279 : }
1280 0 : return nullptr;
1281 : }
1282 0 : else if (STARTS_WITH_CI(pszSQLCommand, "CREATE SPATIAL INDEX ON "))
1283 : {
1284 : /* Handle command to create a spatial index. */
1285 : OGRMSSQLSpatialTableLayer *poLayer =
1286 0 : new OGRMSSQLSpatialTableLayer(this);
1287 :
1288 0 : if (poLayer)
1289 : {
1290 0 : if (poLayer->Initialize(nullptr, pszSQLCommand + 24, nullptr, 0, 0,
1291 0 : nullptr, wkbUnknown) != CE_None)
1292 : {
1293 0 : CPLError(CE_Failure, CPLE_AppDefined,
1294 : "Failed to initialize layer '%s'", pszSQLCommand + 24);
1295 : }
1296 0 : poLayer->CreateSpatialIndex();
1297 0 : delete poLayer;
1298 : }
1299 0 : return nullptr;
1300 : }
1301 :
1302 : /* Execute the command natively */
1303 0 : CPLODBCStatement *poStmt = new CPLODBCStatement(&oSession);
1304 0 : poStmt->Append(pszSQLCommand);
1305 :
1306 0 : if (!poStmt->ExecuteSQL())
1307 : {
1308 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", oSession.GetLastError());
1309 0 : delete poStmt;
1310 0 : return nullptr;
1311 : }
1312 :
1313 : /* -------------------------------------------------------------------- */
1314 : /* Are there result columns for this statement? */
1315 : /* -------------------------------------------------------------------- */
1316 0 : if (poStmt->GetColCount() == 0)
1317 : {
1318 0 : delete poStmt;
1319 0 : CPLErrorReset();
1320 0 : return nullptr;
1321 : }
1322 :
1323 : /* -------------------------------------------------------------------- */
1324 : /* Create a results layer. It will take ownership of the */
1325 : /* statement. */
1326 : /* -------------------------------------------------------------------- */
1327 :
1328 : OGRMSSQLSpatialSelectLayer *poLayer =
1329 0 : new OGRMSSQLSpatialSelectLayer(this, poStmt);
1330 :
1331 0 : if (poSpatialFilter != nullptr)
1332 0 : poLayer->SetSpatialFilter(poSpatialFilter);
1333 :
1334 0 : return poLayer;
1335 : }
1336 :
1337 : /************************************************************************/
1338 : /* ReleaseResultSet() */
1339 : /************************************************************************/
1340 :
1341 0 : void OGRMSSQLSpatialDataSource::ReleaseResultSet(OGRLayer *poLayer)
1342 :
1343 : {
1344 0 : delete poLayer;
1345 0 : }
1346 :
1347 : /************************************************************************/
1348 : /* LaunderName() */
1349 : /************************************************************************/
1350 :
1351 0 : char *OGRMSSQLSpatialDataSource::LaunderName(const char *pszSrcName)
1352 :
1353 : {
1354 0 : char *pszSafeName = CPLStrdup(pszSrcName);
1355 : int i;
1356 :
1357 0 : for (i = 0; pszSafeName[i] != '\0'; i++)
1358 : {
1359 0 : pszSafeName[i] =
1360 0 : (char)CPLTolower(static_cast<unsigned char>(pszSafeName[i]));
1361 0 : if (pszSafeName[i] == '-' || pszSafeName[i] == '#')
1362 0 : pszSafeName[i] = '_';
1363 : }
1364 :
1365 0 : return pszSafeName;
1366 : }
1367 :
1368 : /************************************************************************/
1369 : /* InitializeMetadataTables() */
1370 : /* */
1371 : /* Create the metadata tables (SPATIAL_REF_SYS and */
1372 : /* GEOMETRY_COLUMNS). */
1373 : /************************************************************************/
1374 :
1375 0 : OGRErr OGRMSSQLSpatialDataSource::InitializeMetadataTables()
1376 :
1377 : {
1378 0 : if (bUseGeometryColumns)
1379 : {
1380 0 : CPLODBCStatement oStmt(&oSession);
1381 :
1382 0 : oStmt.Append(
1383 : "IF NOT EXISTS (SELECT * FROM sys.objects WHERE "
1384 : "object_id = OBJECT_ID(N'[dbo].[geometry_columns]') AND type in "
1385 : "(N'U')) "
1386 : "CREATE TABLE geometry_columns (f_table_catalog varchar(128) not "
1387 : "null, "
1388 : "f_table_schema varchar(128) not null, f_table_name varchar(256) "
1389 : "not null, "
1390 : "f_geometry_column varchar(256) not null, coord_dimension integer "
1391 : "not null, "
1392 : "srid integer not null, geometry_type varchar(30) not null, "
1393 : "CONSTRAINT geometry_columns_pk PRIMARY KEY (f_table_catalog, "
1394 : "f_table_schema, f_table_name, f_geometry_column));\n");
1395 :
1396 0 : oStmt.Append("IF NOT EXISTS (SELECT * FROM sys.objects "
1397 : "WHERE object_id = OBJECT_ID(N'[dbo].[spatial_ref_sys]') "
1398 : "AND type in (N'U')) "
1399 : "CREATE TABLE spatial_ref_sys (srid integer not null "
1400 : "PRIMARY KEY, auth_name varchar(256), auth_srid integer, "
1401 : "srtext varchar(2048), proj4text varchar(2048))");
1402 :
1403 0 : int bInTransaction = oSession.IsInTransaction();
1404 0 : if (!bInTransaction)
1405 0 : oSession.BeginTransaction();
1406 :
1407 0 : if (!oStmt.ExecuteSQL())
1408 : {
1409 0 : CPLError(CE_Failure, CPLE_AppDefined,
1410 : "Error initializing the metadata tables : %s",
1411 : GetSession()->GetLastError());
1412 :
1413 0 : if (!bInTransaction)
1414 0 : oSession.RollbackTransaction();
1415 :
1416 0 : return OGRERR_FAILURE;
1417 : }
1418 :
1419 0 : if (!bInTransaction)
1420 0 : oSession.CommitTransaction();
1421 : }
1422 :
1423 0 : return OGRERR_NONE;
1424 : }
1425 :
1426 : /************************************************************************/
1427 : /* FetchSRS() */
1428 : /* */
1429 : /* Return a SRS corresponding to a particular id. Note that */
1430 : /* reference counting should be honoured on the returned */
1431 : /* OGRSpatialReference, as handles may be cached. */
1432 : /************************************************************************/
1433 :
1434 0 : OGRSpatialReference *OGRMSSQLSpatialDataSource::FetchSRS(int nId)
1435 :
1436 : {
1437 0 : if (nId <= 0)
1438 0 : return nullptr;
1439 :
1440 : /* -------------------------------------------------------------------- */
1441 : /* First, we look through our SRID cache, is it there? */
1442 : /* -------------------------------------------------------------------- */
1443 0 : auto oIter = m_oSRSCache.find(nId);
1444 0 : if (oIter != m_oSRSCache.end())
1445 : {
1446 0 : return oIter->second.get();
1447 : }
1448 :
1449 0 : EndCopy();
1450 :
1451 : /* -------------------------------------------------------------------- */
1452 : /* Try looking up in spatial_ref_sys table */
1453 : /* -------------------------------------------------------------------- */
1454 0 : if (bUseGeometryColumns)
1455 : {
1456 0 : CPLODBCStatement oStmt(GetSession());
1457 0 : oStmt.Appendf("SELECT srtext FROM spatial_ref_sys WHERE srid = %d",
1458 : nId);
1459 :
1460 0 : if (oStmt.ExecuteSQL() && oStmt.Fetch())
1461 : {
1462 0 : if (oStmt.GetColData(0))
1463 : {
1464 : auto poSRS = std::unique_ptr<OGRSpatialReference,
1465 : OGRSpatialReferenceReleaser>(
1466 0 : new OGRSpatialReference());
1467 0 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1468 0 : const char *pszWKT = oStmt.GetColData(0);
1469 0 : if (poSRS->importFromWkt(pszWKT) == OGRERR_NONE)
1470 : {
1471 : const char *pszAuthorityName =
1472 0 : poSRS->GetAuthorityName(nullptr);
1473 : const char *pszAuthorityCode =
1474 0 : poSRS->GetAuthorityCode(nullptr);
1475 0 : if (pszAuthorityName && pszAuthorityCode &&
1476 0 : EQUAL(pszAuthorityName, "EPSG"))
1477 : {
1478 0 : const int nCode = atoi(pszAuthorityCode);
1479 0 : poSRS->Clear();
1480 0 : poSRS->importFromEPSG(nCode);
1481 : }
1482 :
1483 0 : return AddSRIDToCache(nId, std::move(poSRS));
1484 : }
1485 : }
1486 : }
1487 : }
1488 :
1489 : /* -------------------------------------------------------------------- */
1490 : /* Try looking up the EPSG list */
1491 : /* -------------------------------------------------------------------- */
1492 : auto poSRS =
1493 : std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser>(
1494 0 : new OGRSpatialReference());
1495 0 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1496 0 : if (poSRS->importFromEPSG(nId) == OGRERR_NONE)
1497 : {
1498 0 : return AddSRIDToCache(nId, std::move(poSRS));
1499 : }
1500 :
1501 0 : return nullptr;
1502 : }
1503 :
1504 : /************************************************************************/
1505 : /* AddSRIDToCache() */
1506 : /* */
1507 : /* Note: this will not add a reference on the poSRS object. Make */
1508 : /* sure it is freshly created, or add a reference yourself if not. */
1509 : /************************************************************************/
1510 :
1511 0 : OGRSpatialReference *OGRMSSQLSpatialDataSource::AddSRIDToCache(
1512 : int nId,
1513 : std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser> &&poSRS)
1514 : {
1515 : /* -------------------------------------------------------------------- */
1516 : /* Add to the cache. */
1517 : /* -------------------------------------------------------------------- */
1518 0 : auto oIter = m_oSRSCache.emplace(nId, std::move(poSRS)).first;
1519 0 : return oIter->second.get();
1520 : }
1521 :
1522 : /************************************************************************/
1523 : /* FetchSRSId() */
1524 : /* */
1525 : /* Fetch the id corresponding to an SRS, and if not found, add */
1526 : /* it to the table. */
1527 : /************************************************************************/
1528 :
1529 0 : int OGRMSSQLSpatialDataSource::FetchSRSId(const OGRSpatialReference *poSRS)
1530 :
1531 : {
1532 0 : char *pszWKT = nullptr;
1533 0 : int nSRSId = 0;
1534 : const char *pszAuthorityName;
1535 :
1536 0 : if (poSRS == nullptr)
1537 0 : return 0;
1538 : /* -------------------------------------------------------------------- */
1539 : /* First, we look through our SRID cache, is it there? */
1540 : /* -------------------------------------------------------------------- */
1541 0 : for (const auto &pair : m_oSRSCache)
1542 : {
1543 0 : if (pair.second.get() == poSRS)
1544 0 : return pair.first;
1545 : }
1546 0 : for (const auto &pair : m_oSRSCache)
1547 : {
1548 0 : if (pair.second != nullptr && pair.second->IsSame(poSRS))
1549 0 : return pair.first;
1550 : }
1551 :
1552 0 : OGRSpatialReference oSRS(*poSRS);
1553 : // cppcheck-suppress uselessAssignmentPtrArg
1554 0 : poSRS = nullptr;
1555 :
1556 0 : pszAuthorityName = oSRS.GetAuthorityName(nullptr);
1557 :
1558 0 : if (pszAuthorityName == nullptr || strlen(pszAuthorityName) == 0)
1559 : {
1560 : /* --------------------------------------------------------------------
1561 : */
1562 : /* Try to identify an EPSG code */
1563 : /* --------------------------------------------------------------------
1564 : */
1565 0 : oSRS.AutoIdentifyEPSG();
1566 :
1567 0 : pszAuthorityName = oSRS.GetAuthorityName(nullptr);
1568 0 : if (pszAuthorityName != nullptr && EQUAL(pszAuthorityName, "EPSG"))
1569 : {
1570 0 : const char *pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
1571 0 : if (pszAuthorityCode != nullptr && strlen(pszAuthorityCode) > 0)
1572 : {
1573 : /* Import 'clean' SRS */
1574 0 : oSRS.importFromEPSG(atoi(pszAuthorityCode));
1575 :
1576 0 : pszAuthorityName = oSRS.GetAuthorityName(nullptr);
1577 : }
1578 : }
1579 : }
1580 : /* -------------------------------------------------------------------- */
1581 : /* Check whether the EPSG authority code is already mapped to a */
1582 : /* SRS ID. */
1583 : /* -------------------------------------------------------------------- */
1584 0 : int nAuthorityCode = 0;
1585 0 : if (pszAuthorityName != nullptr && EQUAL(pszAuthorityName, "EPSG"))
1586 : {
1587 : /* For the root authority name 'EPSG', the authority code
1588 : * should always be integral
1589 : */
1590 0 : nAuthorityCode = atoi(oSRS.GetAuthorityCode(nullptr));
1591 :
1592 0 : CPLODBCStatement oStmt(&oSession);
1593 0 : oStmt.Appendf("SELECT srid FROM spatial_ref_sys WHERE "
1594 : "auth_name = '%s' AND auth_srid = %d",
1595 : pszAuthorityName, nAuthorityCode);
1596 :
1597 0 : if (oStmt.ExecuteSQL() && oStmt.Fetch() && oStmt.GetColData(0))
1598 : {
1599 0 : nSRSId = atoi(oStmt.GetColData(0));
1600 0 : if (nSRSId != 0)
1601 : {
1602 : std::unique_ptr<OGRSpatialReference,
1603 : OGRSpatialReferenceReleaser>
1604 0 : poCachedSRS(new OGRSpatialReference(oSRS));
1605 0 : poCachedSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1606 0 : AddSRIDToCache(nSRSId, std::move(poCachedSRS));
1607 : }
1608 0 : return nSRSId;
1609 : }
1610 : }
1611 :
1612 : /* -------------------------------------------------------------------- */
1613 : /* Translate SRS to WKT. */
1614 : /* -------------------------------------------------------------------- */
1615 0 : if (oSRS.exportToWkt(&pszWKT) != OGRERR_NONE)
1616 : {
1617 0 : CPLFree(pszWKT);
1618 0 : return 0;
1619 : }
1620 :
1621 : /* -------------------------------------------------------------------- */
1622 : /* Try to find in the existing table. */
1623 : /* -------------------------------------------------------------------- */
1624 0 : CPLODBCStatement oStmt(&oSession);
1625 :
1626 0 : oStmt.Append("SELECT srid FROM spatial_ref_sys WHERE srtext = ");
1627 0 : OGRMSSQLAppendEscaped(&oStmt, pszWKT);
1628 :
1629 : /* -------------------------------------------------------------------- */
1630 : /* We got it! Return it. */
1631 : /* -------------------------------------------------------------------- */
1632 0 : if (oStmt.ExecuteSQL())
1633 : {
1634 0 : if (oStmt.Fetch() && oStmt.GetColData(0))
1635 : {
1636 0 : nSRSId = atoi(oStmt.GetColData(0));
1637 0 : CPLFree(pszWKT);
1638 0 : return nSRSId;
1639 : }
1640 : }
1641 : else
1642 : {
1643 : /* probably the table is missing at all */
1644 0 : if (InitializeMetadataTables() != OGRERR_NONE)
1645 : {
1646 0 : CPLFree(pszWKT);
1647 0 : return 0;
1648 : }
1649 : }
1650 :
1651 : /* -------------------------------------------------------------------- */
1652 : /* Try adding the SRS to the SRS table. */
1653 : /* -------------------------------------------------------------------- */
1654 0 : char *pszProj4 = nullptr;
1655 0 : if (oSRS.exportToProj4(&pszProj4) != OGRERR_NONE)
1656 : {
1657 0 : CPLFree(pszProj4);
1658 0 : CPLFree(pszWKT);
1659 0 : return 0;
1660 : }
1661 :
1662 : /* -------------------------------------------------------------------- */
1663 : /* Check whether the auth_code can be used as srid. */
1664 : /* -------------------------------------------------------------------- */
1665 0 : nSRSId = nAuthorityCode;
1666 :
1667 0 : oStmt.Clear();
1668 :
1669 0 : int bInTransaction = oSession.IsInTransaction();
1670 0 : if (!bInTransaction)
1671 0 : oSession.BeginTransaction();
1672 :
1673 0 : if (nAuthorityCode > 0)
1674 : {
1675 0 : oStmt.Appendf("SELECT srid FROM spatial_ref_sys where srid = %d",
1676 : nAuthorityCode);
1677 0 : if (oStmt.ExecuteSQL() && oStmt.Fetch())
1678 : {
1679 0 : nSRSId = 0;
1680 : }
1681 : }
1682 :
1683 : /* -------------------------------------------------------------------- */
1684 : /* Get the current maximum srid in the srs table. */
1685 : /* -------------------------------------------------------------------- */
1686 :
1687 0 : if (nSRSId == 0)
1688 : {
1689 0 : oStmt.Clear();
1690 0 : oStmt.Append("SELECT COALESCE(MAX(srid) + 1, 32768) FROM "
1691 : "spatial_ref_sys where srid between 32768 and 65536");
1692 :
1693 0 : if (oStmt.ExecuteSQL() && oStmt.Fetch() && oStmt.GetColData(0))
1694 : {
1695 0 : nSRSId = atoi(oStmt.GetColData(0));
1696 : }
1697 : }
1698 :
1699 0 : if (nSRSId == 0)
1700 : {
1701 : /* unable to allocate srid */
1702 0 : if (!bInTransaction)
1703 0 : oSession.RollbackTransaction();
1704 0 : CPLFree(pszProj4);
1705 0 : CPLFree(pszWKT);
1706 0 : return 0;
1707 : }
1708 :
1709 0 : oStmt.Clear();
1710 0 : if (nAuthorityCode > 0)
1711 : {
1712 0 : oStmt.Appendf("INSERT INTO spatial_ref_sys (srid, auth_srid, "
1713 : "auth_name, srtext, proj4text) "
1714 : "VALUES (%d, %d, ",
1715 : nSRSId, nAuthorityCode);
1716 0 : OGRMSSQLAppendEscaped(&oStmt, pszAuthorityName);
1717 0 : oStmt.Append(", ");
1718 0 : OGRMSSQLAppendEscaped(&oStmt, pszWKT);
1719 0 : oStmt.Append(", ");
1720 0 : OGRMSSQLAppendEscaped(&oStmt, pszProj4);
1721 0 : oStmt.Append(")");
1722 : }
1723 : else
1724 : {
1725 0 : oStmt.Appendf(
1726 : "INSERT INTO spatial_ref_sys (srid,srtext,proj4text) VALUES (%d, ",
1727 : nSRSId);
1728 0 : OGRMSSQLAppendEscaped(&oStmt, pszWKT);
1729 0 : oStmt.Append(", ");
1730 0 : OGRMSSQLAppendEscaped(&oStmt, pszProj4);
1731 0 : oStmt.Append(")");
1732 : }
1733 :
1734 : /* Free everything that was allocated. */
1735 0 : CPLFree(pszProj4);
1736 0 : CPLFree(pszWKT);
1737 :
1738 0 : if (oStmt.ExecuteSQL())
1739 : {
1740 0 : if (!bInTransaction)
1741 0 : oSession.CommitTransaction();
1742 : }
1743 : else
1744 : {
1745 0 : if (!bInTransaction)
1746 0 : oSession.RollbackTransaction();
1747 : }
1748 :
1749 0 : return nSRSId;
1750 : }
1751 :
1752 : /************************************************************************/
1753 : /* StartTransaction() */
1754 : /* */
1755 : /* Should only be called by user code. Not driver internals. */
1756 : /************************************************************************/
1757 :
1758 0 : OGRErr OGRMSSQLSpatialDataSource::StartTransaction(CPL_UNUSED int bForce)
1759 : {
1760 0 : if (!oSession.BeginTransaction())
1761 : {
1762 0 : CPLError(CE_Failure, CPLE_AppDefined, "Failed to start transaction: %s",
1763 : oSession.GetLastError());
1764 0 : return OGRERR_FAILURE;
1765 : }
1766 :
1767 0 : return OGRERR_NONE;
1768 : }
1769 :
1770 : /************************************************************************/
1771 : /* CommitTransaction() */
1772 : /* */
1773 : /* Should only be called by user code. Not driver internals. */
1774 : /************************************************************************/
1775 :
1776 0 : OGRErr OGRMSSQLSpatialDataSource::CommitTransaction()
1777 : {
1778 0 : if (!oSession.CommitTransaction())
1779 : {
1780 0 : CPLError(CE_Failure, CPLE_AppDefined,
1781 : "Failed to commit transaction: %s", oSession.GetLastError());
1782 :
1783 0 : for (int iLayer = 0; iLayer < nLayers; iLayer++)
1784 : {
1785 0 : if (papoLayers[iLayer]->GetLayerStatus() ==
1786 : MSSQLLAYERSTATUS_INITIAL)
1787 0 : papoLayers[iLayer]->SetLayerStatus(MSSQLLAYERSTATUS_DISABLED);
1788 : }
1789 0 : return OGRERR_FAILURE;
1790 : }
1791 :
1792 : /* set the status for the newly created layers */
1793 0 : for (int iLayer = 0; iLayer < nLayers; iLayer++)
1794 : {
1795 0 : if (papoLayers[iLayer]->GetLayerStatus() == MSSQLLAYERSTATUS_INITIAL)
1796 0 : papoLayers[iLayer]->SetLayerStatus(MSSQLLAYERSTATUS_CREATED);
1797 : }
1798 :
1799 0 : return OGRERR_NONE;
1800 : }
1801 :
1802 : /************************************************************************/
1803 : /* RollbackTransaction() */
1804 : /* */
1805 : /* Should only be called by user code. Not driver internals. */
1806 : /************************************************************************/
1807 :
1808 0 : OGRErr OGRMSSQLSpatialDataSource::RollbackTransaction()
1809 : {
1810 : /* set the status for the newly created layers */
1811 0 : for (int iLayer = 0; iLayer < nLayers; iLayer++)
1812 : {
1813 0 : if (papoLayers[iLayer]->GetLayerStatus() == MSSQLLAYERSTATUS_INITIAL)
1814 0 : papoLayers[iLayer]->SetLayerStatus(MSSQLLAYERSTATUS_DISABLED);
1815 : }
1816 :
1817 0 : if (!oSession.RollbackTransaction())
1818 : {
1819 0 : CPLError(CE_Failure, CPLE_AppDefined,
1820 : "Failed to roll back transaction: %s",
1821 : oSession.GetLastError());
1822 0 : return OGRERR_FAILURE;
1823 : }
1824 :
1825 0 : return OGRERR_NONE;
1826 : }
1827 :
1828 : /************************************************************************/
1829 : /* StartCopy() */
1830 : /************************************************************************/
1831 :
1832 0 : void OGRMSSQLSpatialDataSource::StartCopy(
1833 : OGRMSSQLSpatialTableLayer *poMSSQLSpatialLayer)
1834 : {
1835 0 : if (poLayerInCopyMode == poMSSQLSpatialLayer)
1836 0 : return;
1837 0 : EndCopy();
1838 0 : poLayerInCopyMode = poMSSQLSpatialLayer;
1839 0 : poLayerInCopyMode->StartCopy();
1840 : }
1841 :
1842 : /************************************************************************/
1843 : /* EndCopy() */
1844 : /************************************************************************/
1845 :
1846 0 : OGRErr OGRMSSQLSpatialDataSource::EndCopy()
1847 : {
1848 0 : if (poLayerInCopyMode != nullptr)
1849 : {
1850 0 : OGRErr result = poLayerInCopyMode->EndCopy();
1851 0 : poLayerInCopyMode = nullptr;
1852 :
1853 0 : return result;
1854 : }
1855 : else
1856 0 : return OGRERR_NONE;
1857 : }
|