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