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