Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: MSSQL Spatial driver
4 : * Purpose: Definition of classes for OGR MSSQL Spatial driver.
5 : * Author: Tamas Szekeres, szekerest at gmail.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010, Tamas Szekeres
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "ogr_mssqlspatial.h"
30 :
31 : /************************************************************************/
32 : /* OGRMSSQLSpatialLayer() */
33 : /************************************************************************/
34 :
35 0 : OGRMSSQLSpatialLayer::OGRMSSQLSpatialLayer(OGRMSSQLSpatialDataSource *poDSIn)
36 0 : : poDS(poDSIn)
37 :
38 : {
39 0 : }
40 :
41 : /************************************************************************/
42 : /* ~OGRMSSQLSpatialLayer() */
43 : /************************************************************************/
44 :
45 0 : OGRMSSQLSpatialLayer::~OGRMSSQLSpatialLayer()
46 :
47 : {
48 0 : if (m_nFeaturesRead > 0 && poFeatureDefn != nullptr)
49 : {
50 0 : CPLDebug("OGR_MSSQLSpatial", "%d features read on layer '%s'.",
51 0 : (int)m_nFeaturesRead, poFeatureDefn->GetName());
52 : }
53 :
54 0 : ClearStatement();
55 :
56 0 : CPLFree(pszGeomColumn);
57 0 : CPLFree(pszFIDColumn);
58 0 : CPLFree(panFieldOrdinals);
59 :
60 0 : if (poFeatureDefn)
61 : {
62 0 : poFeatureDefn->Release();
63 0 : poFeatureDefn = nullptr;
64 : }
65 :
66 0 : if (poSRS)
67 0 : poSRS->Release();
68 0 : }
69 :
70 : /************************************************************************/
71 : /* BuildFeatureDefn() */
72 : /* */
73 : /* Build feature definition from a set of column definitions */
74 : /* set on a statement. Sift out geometry and FID fields. */
75 : /************************************************************************/
76 :
77 0 : void OGRMSSQLSpatialLayer::BuildFeatureDefn(const char *pszLayerName,
78 : CPLODBCStatement *poStmtIn)
79 :
80 : {
81 : bool bShowFidColumn =
82 0 : CPLTestBool(CPLGetConfigOption("MSSQLSPATIAL_SHOW_FID_COLUMN", "NO"));
83 :
84 0 : if (!poFeatureDefn)
85 : {
86 0 : poFeatureDefn = new OGRFeatureDefn(pszLayerName);
87 0 : poFeatureDefn->Reference();
88 : }
89 : else
90 : {
91 0 : for (int iFieldIdx = poFeatureDefn->GetFieldCount() - 1; iFieldIdx >= 0;
92 : --iFieldIdx)
93 : {
94 0 : poFeatureDefn->DeleteFieldDefn(iFieldIdx);
95 : }
96 0 : for (int iFieldIdx = poFeatureDefn->GetGeomFieldCount() - 1;
97 0 : iFieldIdx >= 0; --iFieldIdx)
98 : {
99 0 : poFeatureDefn->DeleteGeomFieldDefn(iFieldIdx);
100 : }
101 0 : poFeatureDefn->SetName(pszLayerName);
102 : }
103 :
104 0 : nRawColumns = poStmtIn->GetColCount();
105 :
106 0 : CPLFree(panFieldOrdinals);
107 0 : panFieldOrdinals = (int *)CPLMalloc(sizeof(int) * nRawColumns);
108 :
109 0 : for (int iCol = 0; iCol < nRawColumns; iCol++)
110 : {
111 0 : if (pszGeomColumn == nullptr)
112 : {
113 : /* need to identify the geometry column */
114 0 : if (EQUAL(poStmtIn->GetColTypeName(iCol), "geometry"))
115 : {
116 0 : nGeomColumnType = MSSQLCOLTYPE_GEOMETRY;
117 0 : pszGeomColumn = CPLStrdup(poStmtIn->GetColName(iCol));
118 0 : if (poFeatureDefn->GetGeomFieldCount() == 1)
119 : {
120 0 : poFeatureDefn->GetGeomFieldDefn(0)->SetNullable(
121 0 : poStmtIn->GetColNullable(iCol));
122 0 : poFeatureDefn->GetGeomFieldDefn(0)->SetName(pszGeomColumn);
123 : }
124 0 : nGeomColumnIndex = iCol;
125 0 : continue;
126 : }
127 0 : else if (EQUAL(poStmtIn->GetColTypeName(iCol), "geography"))
128 : {
129 0 : nGeomColumnType = MSSQLCOLTYPE_GEOGRAPHY;
130 0 : pszGeomColumn = CPLStrdup(poStmtIn->GetColName(iCol));
131 0 : if (poFeatureDefn->GetGeomFieldCount() == 1)
132 : {
133 0 : poFeatureDefn->GetGeomFieldDefn(0)->SetNullable(
134 0 : poStmtIn->GetColNullable(iCol));
135 0 : poFeatureDefn->GetGeomFieldDefn(0)->SetName(pszGeomColumn);
136 : }
137 0 : nGeomColumnIndex = iCol;
138 0 : continue;
139 : }
140 : }
141 : else
142 : {
143 0 : if (EQUAL(poStmtIn->GetColName(iCol), pszGeomColumn))
144 : {
145 0 : if (poFeatureDefn->GetGeomFieldCount() == 1)
146 : {
147 0 : poFeatureDefn->GetGeomFieldDefn(0)->SetNullable(
148 0 : poStmtIn->GetColNullable(iCol));
149 0 : poFeatureDefn->GetGeomFieldDefn(0)->SetName(pszGeomColumn);
150 : }
151 0 : nGeomColumnIndex = iCol;
152 0 : continue;
153 : }
154 : }
155 :
156 0 : if (pszFIDColumn != nullptr)
157 : {
158 0 : if (EQUAL(poStmtIn->GetColName(iCol), pszFIDColumn))
159 : {
160 0 : bool bIntegerFID = false;
161 0 : switch (CPLODBCStatement::GetTypeMapping(
162 0 : poStmtIn->GetColType(iCol)))
163 : {
164 0 : case SQL_C_SSHORT:
165 : case SQL_C_USHORT:
166 : case SQL_C_SLONG:
167 : case SQL_C_ULONG:
168 : case SQL_C_SBIGINT:
169 : case SQL_C_UBIGINT:
170 0 : bIntegerFID = true;
171 0 : break;
172 0 : default:
173 0 : break;
174 : }
175 0 : if (!bIntegerFID)
176 : {
177 0 : CPLDebug(
178 : "MSSQL",
179 : "Ignoring FID column %s as it is of non integer type",
180 : pszFIDColumn);
181 0 : CPLFree(pszFIDColumn);
182 0 : pszFIDColumn = nullptr;
183 : }
184 : else
185 : {
186 0 : if (STARTS_WITH_CI(poStmtIn->GetColTypeName(iCol),
187 : "bigint"))
188 0 : SetMetadataItem(OLMD_FID64, "YES");
189 :
190 0 : if (EQUAL(poStmtIn->GetColTypeName(iCol), "int identity") ||
191 0 : EQUAL(poStmtIn->GetColTypeName(iCol),
192 : "bigint identity"))
193 0 : bIsIdentityFid = TRUE;
194 :
195 0 : nFIDColumnIndex = iCol;
196 :
197 0 : if (!bShowFidColumn)
198 0 : continue;
199 : }
200 : }
201 : }
202 : else
203 : {
204 0 : if (EQUAL(poStmtIn->GetColTypeName(iCol), "int identity"))
205 : {
206 0 : pszFIDColumn = CPLStrdup(poStmtIn->GetColName(iCol));
207 0 : bIsIdentityFid = TRUE;
208 0 : nFIDColumnIndex = iCol;
209 :
210 0 : if (!bShowFidColumn)
211 0 : continue;
212 : }
213 0 : else if (EQUAL(poStmtIn->GetColTypeName(iCol), "bigint identity"))
214 : {
215 0 : pszFIDColumn = CPLStrdup(poStmtIn->GetColName(iCol));
216 0 : bIsIdentityFid = TRUE;
217 0 : SetMetadataItem(OLMD_FID64, "YES");
218 0 : nFIDColumnIndex = iCol;
219 :
220 0 : if (!bShowFidColumn)
221 0 : continue;
222 : }
223 : }
224 :
225 0 : OGRFieldDefn oField(poStmtIn->GetColName(iCol), OFTString);
226 :
227 0 : switch (CPLODBCStatement::GetTypeMapping(poStmtIn->GetColType(iCol)))
228 : {
229 0 : case SQL_C_SSHORT:
230 0 : oField.SetType(OFTInteger);
231 0 : oField.SetSubType(OFSTInt16);
232 0 : break;
233 :
234 0 : case SQL_C_USHORT:
235 : case SQL_C_SLONG:
236 : case SQL_C_ULONG:
237 0 : oField.SetType(OFTInteger);
238 0 : break;
239 :
240 0 : case SQL_C_SBIGINT:
241 : case SQL_C_UBIGINT:
242 0 : oField.SetType(OFTInteger64);
243 0 : break;
244 :
245 0 : case SQL_C_BINARY:
246 0 : oField.SetType(OFTBinary);
247 0 : oField.SetWidth(MAX(0, poStmtIn->GetColSize(iCol)));
248 0 : break;
249 :
250 0 : case SQL_C_NUMERIC:
251 0 : oField.SetType(OFTReal);
252 0 : oField.SetPrecision(poStmtIn->GetColPrecision(iCol));
253 0 : oField.SetWidth(MAX(0, poStmtIn->GetColSize(iCol)));
254 0 : if (oField.GetPrecision() == 0 && oField.GetWidth() <= 9)
255 0 : oField.SetType(OFTInteger);
256 0 : else if (oField.GetPrecision() == 0 && oField.GetWidth() <= 18)
257 0 : oField.SetType(OFTInteger64);
258 0 : break;
259 :
260 0 : case SQL_C_FLOAT:
261 0 : oField.SetType(OFTReal);
262 0 : oField.SetSubType(OFSTFloat32);
263 0 : break;
264 :
265 0 : case SQL_C_DOUBLE:
266 0 : oField.SetType(OFTReal);
267 0 : break;
268 :
269 0 : case SQL_C_DATE:
270 0 : oField.SetType(OFTDate);
271 0 : break;
272 :
273 0 : case SQL_C_TIME:
274 0 : oField.SetType(OFTTime);
275 0 : break;
276 :
277 0 : case SQL_C_TIMESTAMP:
278 0 : oField.SetType(OFTDateTime);
279 0 : break;
280 :
281 0 : case SQL_C_GUID:
282 0 : m_bHasUUIDColumn = true;
283 0 : oField.SetType(OFTString);
284 0 : oField.SetSubType(OFSTUUID);
285 0 : break;
286 :
287 0 : default:
288 0 : oField.SetWidth(MAX(0, poStmtIn->GetColSize(iCol)));
289 : /* leave it as OFTString */;
290 : }
291 :
292 0 : oField.SetNullable(poStmtIn->GetColNullable(iCol));
293 :
294 0 : if (poStmtIn->GetColColumnDef(iCol))
295 : {
296 : /* process default value specification */
297 0 : if (EQUAL(poStmtIn->GetColColumnDef(iCol), "(getdate())"))
298 0 : oField.SetDefault("CURRENT_TIMESTAMP");
299 0 : else if (STARTS_WITH_CI(poStmtIn->GetColColumnDef(iCol),
300 : "(CONVERT([time],getdate()"))
301 0 : oField.SetDefault("CURRENT_TIME");
302 0 : else if (STARTS_WITH_CI(poStmtIn->GetColColumnDef(iCol),
303 : "(CONVERT([date],getdate()"))
304 0 : oField.SetDefault("CURRENT_DATE");
305 : else
306 : {
307 0 : char *pszDefault = CPLStrdup(poStmtIn->GetColColumnDef(iCol));
308 0 : int nLen = static_cast<int>(strlen(pszDefault));
309 0 : if (nLen >= 1 && pszDefault[0] == '(' &&
310 0 : pszDefault[nLen - 1] == ')')
311 : {
312 : // All default values are encapsulated in brackets
313 : // by MSSQL server.
314 0 : if (nLen >= 4 && pszDefault[1] == '(' &&
315 0 : pszDefault[nLen - 2] == ')')
316 : {
317 : /* for numeric values double brackets are used */
318 0 : pszDefault[nLen - 2] = '\0';
319 0 : oField.SetDefault(pszDefault + 2);
320 : }
321 : else
322 : {
323 0 : pszDefault[nLen - 1] = '\0';
324 0 : oField.SetDefault(pszDefault + 1);
325 : }
326 : }
327 : else
328 0 : oField.SetDefault(pszDefault);
329 :
330 0 : CPLFree(pszDefault);
331 : }
332 : }
333 :
334 0 : poFeatureDefn->AddFieldDefn(&oField);
335 0 : panFieldOrdinals[poFeatureDefn->GetFieldCount() - 1] = iCol;
336 : }
337 :
338 : /* -------------------------------------------------------------------- */
339 : /* If we don't already have an FID, check if there is a special */
340 : /* FID named column available. */
341 : /* -------------------------------------------------------------------- */
342 0 : if (pszFIDColumn == nullptr)
343 : {
344 : const char *pszOGR_FID =
345 0 : CPLGetConfigOption("MSSQLSPATIAL_OGR_FID", "OGR_FID");
346 0 : if (poFeatureDefn->GetFieldIndex(pszOGR_FID) != -1)
347 0 : pszFIDColumn = CPLStrdup(pszOGR_FID);
348 : }
349 :
350 0 : if (pszFIDColumn != nullptr)
351 0 : CPLDebug("OGR_MSSQLSpatial", "Using column %s as FID for table %s.",
352 0 : pszFIDColumn, poFeatureDefn->GetName());
353 : else
354 0 : CPLDebug("OGR_MSSQLSpatial", "Table %s has no identified FID column.",
355 0 : poFeatureDefn->GetName());
356 0 : }
357 :
358 : /************************************************************************/
359 : /* ClearStatement() */
360 : /************************************************************************/
361 :
362 0 : void OGRMSSQLSpatialLayer::ClearStatement()
363 :
364 : {
365 0 : if (poStmt != nullptr)
366 : {
367 0 : delete poStmt;
368 0 : poStmt = nullptr;
369 : }
370 0 : }
371 :
372 : /************************************************************************/
373 : /* ResetReading() */
374 : /************************************************************************/
375 :
376 0 : void OGRMSSQLSpatialLayer::ResetReading()
377 :
378 : {
379 0 : if (m_bResetNeeded)
380 : {
381 0 : iNextShapeId = 0;
382 0 : ClearStatement();
383 0 : m_bEOF = false;
384 0 : m_bResetNeeded = false;
385 : }
386 0 : }
387 :
388 : /************************************************************************/
389 : /* GetNextFeature() */
390 : /************************************************************************/
391 :
392 0 : OGRFeature *OGRMSSQLSpatialLayer::GetNextFeature()
393 :
394 : {
395 0 : if (m_bEOF)
396 0 : return nullptr;
397 :
398 : while (true)
399 : {
400 : OGRFeature *poFeature;
401 :
402 0 : poFeature = GetNextRawFeature();
403 0 : if (poFeature == nullptr)
404 : {
405 0 : m_bEOF = true;
406 0 : return nullptr;
407 : }
408 :
409 0 : if ((m_poFilterGeom == nullptr ||
410 0 : FilterGeometry(poFeature->GetGeometryRef())) &&
411 0 : (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
412 0 : return poFeature;
413 :
414 0 : delete poFeature;
415 0 : }
416 : }
417 :
418 : /************************************************************************/
419 : /* GetNextRawFeature() */
420 : /************************************************************************/
421 :
422 0 : OGRFeature *OGRMSSQLSpatialLayer::GetNextRawFeature()
423 :
424 : {
425 0 : m_bResetNeeded = true;
426 0 : if (GetStatement() == nullptr)
427 0 : return nullptr;
428 :
429 : /* -------------------------------------------------------------------- */
430 : /* If we are marked to restart then do so, and fetch a record. */
431 : /* -------------------------------------------------------------------- */
432 0 : if (!poStmt->Fetch())
433 : {
434 0 : delete poStmt;
435 0 : poStmt = nullptr;
436 0 : return nullptr;
437 : }
438 :
439 : /* -------------------------------------------------------------------- */
440 : /* Create a feature from the current result. */
441 : /* -------------------------------------------------------------------- */
442 0 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
443 :
444 : const char *pszFID;
445 0 : if (pszFIDColumn != nullptr && poStmt->GetColId(pszFIDColumn) > -1 &&
446 0 : (pszFID = poStmt->GetColData(poStmt->GetColId(pszFIDColumn))) !=
447 : nullptr)
448 0 : poFeature->SetFID(CPLAtoGIntBig(pszFID));
449 : else
450 0 : poFeature->SetFID(iNextShapeId);
451 :
452 0 : iNextShapeId++;
453 0 : m_nFeaturesRead++;
454 :
455 : /* -------------------------------------------------------------------- */
456 : /* Set the fields. */
457 : /* -------------------------------------------------------------------- */
458 0 : for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++)
459 : {
460 0 : if (poFeatureDefn->GetFieldDefn(iField)->IsIgnored())
461 0 : continue;
462 :
463 0 : int iSrcField = panFieldOrdinals[iField];
464 0 : const char *pszValue = poStmt->GetColData(iSrcField);
465 :
466 0 : if (pszValue == nullptr)
467 0 : poFeature->SetFieldNull(iField);
468 0 : else if (poFeature->GetFieldDefnRef(iField)->GetType() == OFTBinary)
469 0 : poFeature->SetField(iField, poStmt->GetColDataLength(iSrcField),
470 : (GByte *)pszValue);
471 : else
472 0 : poFeature->SetField(iField, pszValue);
473 : }
474 :
475 : /* -------------------------------------------------------------------- */
476 : /* Try to extract a geometry. */
477 : /* -------------------------------------------------------------------- */
478 0 : if (pszGeomColumn != nullptr && !poFeatureDefn->IsGeometryIgnored())
479 : {
480 0 : int iField = poStmt->GetColId(pszGeomColumn);
481 0 : const char *pszGeomText = poStmt->GetColData(iField);
482 0 : OGRGeometry *poGeom = nullptr;
483 0 : OGRErr eErr = OGRERR_NONE;
484 :
485 0 : if (pszGeomText != nullptr)
486 : {
487 0 : int nLength = poStmt->GetColDataLength(iField);
488 :
489 0 : if (nGeomColumnType == MSSQLCOLTYPE_GEOMETRY ||
490 0 : nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY ||
491 0 : nGeomColumnType == MSSQLCOLTYPE_BINARY)
492 : {
493 0 : switch (poDS->GetGeometryFormat())
494 : {
495 0 : case MSSQLGEOMETRY_NATIVE:
496 : {
497 0 : OGRMSSQLGeometryParser oParser(nGeomColumnType);
498 0 : eErr = oParser.ParseSqlGeometry(
499 : (unsigned char *)pszGeomText, nLength, &poGeom);
500 0 : nSRSId = oParser.GetSRSId();
501 : }
502 0 : break;
503 0 : case MSSQLGEOMETRY_WKB:
504 : case MSSQLGEOMETRY_WKBZM:
505 0 : eErr = OGRGeometryFactory::createFromWkb(
506 : pszGeomText, nullptr, &poGeom, nLength);
507 0 : break;
508 0 : case MSSQLGEOMETRY_WKT:
509 0 : eErr = OGRGeometryFactory::createFromWkt(
510 : pszGeomText, nullptr, &poGeom);
511 0 : break;
512 0 : }
513 : }
514 0 : else if (nGeomColumnType == MSSQLCOLTYPE_TEXT)
515 : {
516 0 : eErr = OGRGeometryFactory::createFromWkt(pszGeomText, nullptr,
517 : &poGeom);
518 : }
519 : }
520 :
521 0 : if (eErr != OGRERR_NONE)
522 : {
523 : const char *pszMessage;
524 :
525 0 : switch (eErr)
526 : {
527 0 : case OGRERR_NOT_ENOUGH_DATA:
528 0 : pszMessage = "Not enough data to deserialize";
529 0 : break;
530 0 : case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
531 0 : pszMessage = "Unsupported geometry type";
532 0 : break;
533 0 : case OGRERR_CORRUPT_DATA:
534 0 : pszMessage = "Corrupt data";
535 0 : break;
536 0 : default:
537 0 : pszMessage = "Unrecognized error";
538 : }
539 0 : CPLError(CE_Failure, CPLE_AppDefined, "GetNextRawFeature(): %s",
540 : pszMessage);
541 : }
542 :
543 0 : if (poGeom != nullptr)
544 : {
545 0 : if (GetSpatialRef())
546 0 : poGeom->assignSpatialReference(poSRS);
547 :
548 0 : poFeature->SetGeometryDirectly(poGeom);
549 : }
550 : }
551 :
552 0 : return poFeature;
553 : }
554 :
555 : /************************************************************************/
556 : /* GetFeature() */
557 : /************************************************************************/
558 :
559 0 : OGRFeature *OGRMSSQLSpatialLayer::GetFeature(GIntBig nFeatureId)
560 :
561 : {
562 : /* This should be implemented directly! */
563 :
564 0 : return OGRLayer::GetFeature(nFeatureId);
565 : }
566 :
567 : /************************************************************************/
568 : /* TestCapability() */
569 : /************************************************************************/
570 :
571 0 : int OGRMSSQLSpatialLayer::TestCapability(CPL_UNUSED const char *pszCap)
572 : {
573 0 : return FALSE;
574 : }
575 :
576 : /************************************************************************/
577 : /* StartTransaction() */
578 : /************************************************************************/
579 :
580 0 : OGRErr OGRMSSQLSpatialLayer::StartTransaction()
581 :
582 : {
583 0 : if (!poDS->GetSession()->BeginTransaction())
584 : {
585 0 : CPLError(CE_Failure, CPLE_AppDefined, "Failed to start transaction: %s",
586 0 : poDS->GetSession()->GetLastError());
587 0 : return OGRERR_FAILURE;
588 : }
589 0 : return OGRERR_NONE;
590 : }
591 :
592 : /************************************************************************/
593 : /* CommitTransaction() */
594 : /************************************************************************/
595 :
596 0 : OGRErr OGRMSSQLSpatialLayer::CommitTransaction()
597 :
598 : {
599 0 : if (!poDS->GetSession()->CommitTransaction())
600 : {
601 0 : CPLError(CE_Failure, CPLE_AppDefined,
602 : "Failed to commit transaction: %s",
603 0 : poDS->GetSession()->GetLastError());
604 0 : return OGRERR_FAILURE;
605 : }
606 0 : return OGRERR_NONE;
607 : }
608 :
609 : /************************************************************************/
610 : /* RollbackTransaction() */
611 : /************************************************************************/
612 :
613 0 : OGRErr OGRMSSQLSpatialLayer::RollbackTransaction()
614 :
615 : {
616 0 : if (!poDS->GetSession()->RollbackTransaction())
617 : {
618 0 : CPLError(CE_Failure, CPLE_AppDefined,
619 : "Failed to roll back transaction: %s",
620 0 : poDS->GetSession()->GetLastError());
621 0 : return OGRERR_FAILURE;
622 : }
623 0 : return OGRERR_NONE;
624 : }
625 :
626 : /************************************************************************/
627 : /* GetSpatialRef() */
628 : /************************************************************************/
629 :
630 0 : OGRSpatialReference *OGRMSSQLSpatialLayer::GetSpatialRef()
631 :
632 : {
633 0 : if (poSRS == nullptr && nSRSId > 0)
634 : {
635 0 : poSRS = poDS->FetchSRS(nSRSId);
636 0 : if (poSRS != nullptr)
637 0 : poSRS->Reference();
638 : else
639 0 : nSRSId = 0;
640 : }
641 :
642 0 : return poSRS;
643 : }
644 :
645 : /************************************************************************/
646 : /* GetFIDColumn() */
647 : /************************************************************************/
648 :
649 0 : const char *OGRMSSQLSpatialLayer::GetFIDColumn()
650 :
651 : {
652 0 : GetLayerDefn();
653 :
654 0 : if (pszFIDColumn != nullptr)
655 0 : return pszFIDColumn;
656 : else
657 0 : return "";
658 : }
659 :
660 : /************************************************************************/
661 : /* GetGeometryColumn() */
662 : /************************************************************************/
663 :
664 0 : const char *OGRMSSQLSpatialLayer::GetGeometryColumn()
665 :
666 : {
667 0 : GetLayerDefn();
668 :
669 0 : if (pszGeomColumn != nullptr)
670 0 : return pszGeomColumn;
671 : else
672 0 : return "";
673 : }
674 :
675 : /************************************************************************/
676 : /* GByteArrayToHexString() */
677 : /************************************************************************/
678 :
679 0 : char *OGRMSSQLSpatialLayer::GByteArrayToHexString(const GByte *pabyData,
680 : int nLen)
681 : {
682 : char *pszTextBuf;
683 :
684 0 : const size_t nTextBufLen = nLen * 2 + 3;
685 0 : pszTextBuf = (char *)CPLMalloc(nTextBufLen);
686 :
687 0 : int iSrc, iDst = 0;
688 :
689 0 : for (iSrc = 0; iSrc < nLen; iSrc++)
690 : {
691 0 : if (iSrc == 0)
692 : {
693 0 : snprintf(pszTextBuf + iDst, nTextBufLen - iDst, "0x%02x",
694 0 : pabyData[iSrc]);
695 0 : iDst += 4;
696 : }
697 : else
698 : {
699 0 : snprintf(pszTextBuf + iDst, nTextBufLen - iDst, "%02x",
700 0 : pabyData[iSrc]);
701 0 : iDst += 2;
702 : }
703 : }
704 0 : pszTextBuf[iDst] = 0;
705 :
706 0 : return pszTextBuf;
707 : }
708 :
709 : /************************************************************************/
710 : /* GetDataset() */
711 : /************************************************************************/
712 :
713 0 : GDALDataset *OGRMSSQLSpatialLayer::GetDataset()
714 : {
715 0 : return poDS;
716 : }
|