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