1 /******************************************************************************
2  * $Id: ogr_mssqlspatial.h d4f8ce3534e7f16fb3eb0eed97b7cb301828ccd3 2021-03-28 15:45:02 +0200 Even Rouault $
3  *
4  * Project:  MSSQL Spatial driver
5  * Purpose:  Definition of classes for OGR MSSQL Spatial driver.
6  * Author:   Tamas Szekeres, szekerest at gmail.com
7  *
8  ******************************************************************************
9  * Copyright (c) 2010, Tamas Szekeres
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  ****************************************************************************/
29 
30 #ifndef OGR_MSSQLSPATIAL_H_INCLUDED
31 #define OGR_MSSQLSPATIAL_H_INCLUDED
32 
33 #include "ogrsf_frmts.h"
34 #include "cpl_odbc.h"
35 #include "cpl_error.h"
36 
37 #ifdef SQLNCLI_VERSION
38 #include <sqlncli.h>
39 #endif
40 #ifdef MSODBCSQL_VERSION
41 #include <msodbcsql.h>
42 #endif
43 
44 class OGRMSSQLSpatialDataSource;
45 
46 /* layer status */
47 #define MSSQLLAYERSTATUS_ORIGINAL  0
48 #define MSSQLLAYERSTATUS_INITIAL 1
49 #define MSSQLLAYERSTATUS_CREATED 2
50 #define MSSQLLAYERSTATUS_DISABLED 3
51 
52 /* geometry format to transfer geometry column */
53 #define MSSQLGEOMETRY_NATIVE 0
54 #define MSSQLGEOMETRY_WKB 1
55 #define MSSQLGEOMETRY_WKT 2
56 #define MSSQLGEOMETRY_WKBZM 3  /* SQL Server 2012 */
57 
58 /* geometry column types */
59 #define MSSQLCOLTYPE_GEOMETRY  0
60 #define MSSQLCOLTYPE_GEOGRAPHY 1
61 #define MSSQLCOLTYPE_BINARY 2
62 #define MSSQLCOLTYPE_TEXT 3
63 
64 /* sqlgeometry constants */
65 
66 #define VA_KATMAI 0x01
67 #define VA_DENALI 0x02
68 
69 #define SP_NONE 0
70 #define SP_HASZVALUES 1
71 #define SP_HASMVALUES 2
72 #define SP_ISVALID 4
73 #define SP_ISSINGLEPOINT 8
74 #define SP_ISSINGLELINESEGMENT 0x10
75 #define SP_ISLARGERTHANAHEMISPHERE 0x20
76 
77 #define ST_UNKNOWN 0
78 #define ST_POINT 1
79 #define ST_LINESTRING 2
80 #define ST_POLYGON 3
81 #define ST_MULTIPOINT 4
82 #define ST_MULTILINESTRING 5
83 #define ST_MULTIPOLYGON 6
84 #define ST_GEOMETRYCOLLECTION 7
85 #define ST_CIRCULARSTRING 8
86 #define ST_COMPOUNDCURVE 9
87 #define ST_CURVEPOLYGON 10
88 #define ST_FULLGLOBE 11
89 
90 #define FA_INTERIORRING 0x00
91 #define FA_STROKE 0x01
92 #define FA_EXTERIORRING 0x02
93 
94 #define FA_NONE 0x00
95 #define FA_LINE 0x01
96 #define FA_ARC 0x02
97 #define FA_CURVE 0x03
98 
99 #define SMT_LINE 0
100 #define SMT_ARC 1
101 #define SMT_FIRSTLINE 2
102 #define SMT_FIRSTARC 3
103 
104 /************************************************************************/
105 /*                         OGRMSSQLAppendEscaped( )                     */
106 /************************************************************************/
107 
108 void OGRMSSQLAppendEscaped( CPLODBCStatement* poStatement, const char* pszStrValue);
109 
110 /************************************************************************/
111 /*                           OGRMSSQLGeometryParser                     */
112 /************************************************************************/
113 
114 class OGRMSSQLGeometryValidator
115 {
116 protected:
117     bool bIsValid;
118     OGRGeometry*    poValidGeometry;
119     OGRGeometry*    poOriginalGeometry;
120     int             nGeomColumnType;
121 
122 public:
123     explicit         OGRMSSQLGeometryValidator(OGRGeometry* poGeom, int nGeomColumnType);
124                     ~OGRMSSQLGeometryValidator();
125 
126     bool            IsValidLatLon(double longitude, double latitude);
127     bool            IsValidCircularZ(double z1, double z2);
128     bool            IsValidPolygonRingCount(const OGRCurve* poGeom);
129     bool            IsValidPolygonRingClosed(const OGRCurve* poGeom);
130     bool            IsValid(const OGRPoint* poGeom);
131     bool            IsValid(const OGRMultiPoint* poGeom);
132     bool            IsValid(const OGRCircularString* poGeom);
133     bool            IsValid(const OGRSimpleCurve* poGeom);
134     bool            IsValid(const OGRCompoundCurve* poGeom);
135     bool            IsValid(const OGRMultiLineString* poGeom);
136     bool            IsValid(const OGRCurvePolygon* poGeom);
137     bool            IsValid(const OGRMultiPolygon* poGeom);
138     bool            IsValid(const OGRGeometryCollection* poGeom);
139     bool            IsValid(const OGRGeometry* poGeom);
140     void            MakeValid(OGRPoint* poGeom);
141     void            MakeValid(OGRMultiPoint* poGeom);
142     void            MakeValid(OGRCircularString* poGeom);
143     void            MakeValid(OGRSimpleCurve* poGeom);
144     void            MakeValid(OGRCompoundCurve* poGeom);
145     void            MakeValid(OGRMultiLineString* poGeom);
146     void            MakeValid(OGRPolygon* poGeom);
147     void            MakeValid(OGRCurvePolygon* poGeom);
148     void            MakeValid(OGRMultiPolygon* poGeom);
149     void            MakeValid(OGRGeometryCollection* poGeom);
150     void            MakeValid(OGRGeometry* poGeom);
151     bool            ValidateGeometry(OGRGeometry* poGeom);
152 
153     OGRGeometry*    GetValidGeometryRef();
IsValid()154     bool            IsValid() { return bIsValid; }
155 };
156 
157 /************************************************************************/
158 /*                           OGRMSSQLGeometryParser                     */
159 /************************************************************************/
160 
161 class OGRMSSQLGeometryParser
162 {
163 protected:
164     unsigned char* pszData;
165     /* version information */
166     char chVersion;
167     /* serialization properties */
168     char chProps;
169     /* point array */
170     int nPointSize;
171     int nPointPos;
172     int nNumPoints;
173     /* figure array */
174     int nFigurePos;
175     int nNumFigures;
176     /* shape array */
177     int nShapePos;
178     int nNumShapes;
179     /* segmenttype array */
180     int nSegmentPos;
181     int nNumSegments;
182     int iSegment;
183     int nSRSId;
184     /* geometry or geography */
185     int nColType;
186 
187 protected:
188     OGRPoint*           ReadPoint(int iFigure);
189     OGRMultiPoint*      ReadMultiPoint(int iShape);
190     OGRErr              ReadSimpleCurve(OGRSimpleCurve* poCurve, int iPoint, int iNextPoint);
191     OGRLineString*      ReadLineString(int iFigure);
192     OGRLinearRing*      ReadLinearRing(int iFigure);
193     OGRMultiLineString* ReadMultiLineString(int iShape);
194     OGRPolygon*         ReadPolygon(int iShape);
195     OGRMultiPolygon*    ReadMultiPolygon(int iShape);
196     OGRGeometryCollection* ReadGeometryCollection(int iShape);
197     OGRCircularString*  ReadCircularString(int iFigure);
198     OGRCompoundCurve*   ReadCompoundCurve(int iFigure);
199     void AddCurveSegment(OGRCompoundCurve* poCompoundCurve,
200         OGRSimpleCurve* poCurve, int iPoint, int iNextPoint);
201     OGRCurvePolygon*    ReadCurvePolygon(int iShape);
202 
203 public:
204     explicit            OGRMSSQLGeometryParser( int nGeomColumnType );
205     OGRErr              ParseSqlGeometry(unsigned char* pszInput, int nLen,
206                                                         OGRGeometry **poGeom);
GetSRSId()207     int                 GetSRSId() { return nSRSId; }
208 };
209 
210 /************************************************************************/
211 /*                           OGRMSSQLGeometryWriter                     */
212 /************************************************************************/
213 
214 class OGRMSSQLGeometryWriter
215 {
216 protected:
217     OGRGeometry *poGeom2;
218     unsigned char* pszData;
219     int nLen;
220     /* version information */
221     char chVersion;
222     /* serialization properties */
223     char chProps;
224     /* point array */
225     int nPointSize;
226     int nPointPos;
227     int nNumPoints;
228     int iPoint;
229     /* figure array */
230     int nFigurePos;
231     int nNumFigures;
232     int iFigure;
233     /* shape array */
234     int nShapePos;
235     int nNumShapes;
236     int iShape;
237     /* segmenttype array */
238     int nSegmentPos;
239     int nNumSegments;
240     int iSegment;
241     int nSRSId;
242     /* geometry or geography */
243     int nColType;
244 
245 protected:
246     void             WritePoint(OGRPoint* poGeom);
247     void             WritePoint(double x, double y);
248     void             WritePoint(double x, double y, double z);
249     void             WritePoint(double x, double y, double z, double m);
250     void             WriteSimpleCurve(OGRSimpleCurve* poGeom);
251     void             WriteSimpleCurve(OGRSimpleCurve* poGeom, int iStartIndex);
252     void             WriteSimpleCurve(OGRSimpleCurve* poGeom, int iStartIndex, int nCount);
253     void             WriteCompoundCurve(OGRCompoundCurve* poGeom);
254     void             WriteCurve(OGRCurve* poGeom);
255     void             WritePolygon(OGRPolygon* poGeom);
256     void             WriteCurvePolygon(OGRCurvePolygon* poGeom);
257     void             WriteGeometryCollection(OGRGeometryCollection* poGeom, int iParent);
258     void             WriteGeometry(OGRGeometry* poGeom, int iParent);
259     void             TrackGeometry(OGRGeometry* poGeom);
260 
261 public:
262                      OGRMSSQLGeometryWriter(OGRGeometry *poGeometry, int nGeomColumnType, int nSRS);
263     OGRErr           WriteSqlGeometry(unsigned char* pszBuffer, int nBufLen);
GetDataLen()264     int              GetDataLen() { return nLen; }
265 };
266 
267 /************************************************************************/
268 /*                             OGRMSSQLSpatialLayer                     */
269 /************************************************************************/
270 
271 class OGRMSSQLSpatialLayer CPL_NON_FINAL: public OGRLayer
272 {
273     protected:
274     OGRFeatureDefn     *poFeatureDefn = nullptr;
275     int                 nRawColumns = 0;
276 
277     CPLODBCStatement   *poStmt = nullptr;
278     bool                m_bEOF = false;
279     bool                m_bResetNeeded = false;
280 
281     // Layer spatial reference system, and srid.
282     OGRSpatialReference *poSRS = nullptr;
283     int                 nSRSId = 0;
284 
285     GIntBig             iNextShapeId = 0;
286 
287     OGRMSSQLSpatialDataSource    *poDS = nullptr;
288 
289     int                nGeomColumnType = -1;
290     char               *pszGeomColumn = nullptr;
291     int                nGeomColumnIndex = -1;
292     char               *pszFIDColumn = nullptr;
293     int                nFIDColumnIndex = -1;
294 
295     int                bIsIdentityFid = FALSE;
296 
297     int                nLayerStatus = MSSQLLAYERSTATUS_ORIGINAL;
298 
299     int                *panFieldOrdinals = nullptr;
300 
301     CPLErr              BuildFeatureDefn( const char *pszLayerName,
302                                           CPLODBCStatement *poStmt );
303 
GetStatement()304     virtual CPLODBCStatement *  GetStatement() { return poStmt; }
305     void                ClearStatement();
306     OGRFeature         *GetNextRawFeature();
307 
308   public:
309                         OGRMSSQLSpatialLayer();
310     virtual             ~OGRMSSQLSpatialLayer();
311 
312     virtual void        ResetReading() override;
313     virtual OGRFeature *GetNextFeature() override;
314 
315     virtual OGRFeature *GetFeature( GIntBig nFeatureId ) override;
316 
GetLayerDefn()317     virtual OGRFeatureDefn *GetLayerDefn() override { return poFeatureDefn; }
318 
319     virtual OGRSpatialReference *GetSpatialRef() override;
320 
321     virtual OGRErr     StartTransaction() override;
322     virtual OGRErr     CommitTransaction() override;
323     virtual OGRErr     RollbackTransaction() override;
324 
325     virtual const char *GetFIDColumn() override;
326     virtual const char *GetGeometryColumn() override;
327 
328     virtual int         TestCapability( const char * ) override;
329     char*               GByteArrayToHexString( const GByte* pabyData, int nLen);
330 
SetLayerStatus(int nStatus)331     void               SetLayerStatus( int nStatus ) { nLayerStatus = nStatus; }
GetLayerStatus()332     int                GetLayerStatus() { return nLayerStatus; }
333 };
334 
335 /************************************************************************/
336 /*                       OGRMSSQLSpatialTableLayer                      */
337 /************************************************************************/
338 
339 typedef union {
340     struct {
341         int     iIndicator;
342         int     Value;
343     } Integer;
344 
345     struct {
346         int     iIndicator;
347         GIntBig     Value;
348     } Integer64;
349 
350     struct {
351         int     iIndicator;
352         double  Value;
353     } Float;
354 
355     struct {
356         SQLLEN  nSize;
357         char* pData[8000];
358     } VarChar;
359 
360     struct {
361         SQLLEN  nSize;
362         GByte*  pData;
363     } RawData;
364 
365 } BCPData;
366 
367 class OGRMSSQLSpatialTableLayer final: public OGRMSSQLSpatialLayer
368 {
369     bool                bUpdateAccess = true;
370     bool                bUseGeometryValidation = false;
371     int                 bLaunderColumnNames = FALSE;
372     int                 bPreservePrecision = FALSE;
373     int                 bNeedSpatialIndex = FALSE;
374     int                 bUseCopy = FALSE;
375     int                 nBCPSize = 1000;
376 
377 #ifdef SQL_SS_UDT
378     int                 nUploadGeometryFormat = MSSQLGEOMETRY_NATIVE;
379 #else
380     int                 nUploadGeometryFormat = MSSQLGEOMETRY_WKB;
381 #endif
382 
383     char                *pszQuery = nullptr;
384 
385     SQLHANDLE           hEnvBCP = nullptr;
386 #ifdef MSSQL_BCP_SUPPORTED
387     SQLHANDLE           hDBCBCP = nullptr;
388     int                 nBCPCount = 0;
389     BCPData             **papstBindBuffer = nullptr;
390 
391     int                 bIdentityInsert = FALSE;
392 #endif
393 
394     CPLODBCStatement* BuildStatement(const char* pszColumns);
395 
396     CPLString BuildFields();
397 
398     virtual CPLODBCStatement *  GetStatement() override;
399 
400     char               *pszTableName = nullptr;
401     char               *pszLayerName = nullptr;
402     char               *pszSchemaName = nullptr;
403 
404     OGRwkbGeometryType eGeomType = wkbNone;
405 
406   public:
407     explicit            OGRMSSQLSpatialTableLayer( OGRMSSQLSpatialDataSource * );
408                         virtual ~OGRMSSQLSpatialTableLayer();
409 
410     CPLErr              Initialize( const char *pszSchema,
411                                     const char *pszTableName,
412                                     const char *pszGeomCol,
413                                     int nCoordDimension,
414                                     int nSRId,
415                                     const char *pszSRText,
416                                     OGRwkbGeometryType eType);
417 
418     OGRErr              CreateSpatialIndex();
419     void                DropSpatialIndex();
420 
GetExtent(OGREnvelope * psExtent,int bForce)421     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce) override { return GetExtent(0, psExtent, bForce); }
422     virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) override;
423 
424     virtual GIntBig     GetFeatureCount( int ) override;
425 
426     virtual OGRFeatureDefn *GetLayerDefn() override;
427 
428     virtual const char* GetName() override;
429 
430     virtual OGRErr      SetAttributeFilter( const char * ) override;
431 
432     virtual OGRErr      ISetFeature( OGRFeature *poFeature ) override;
433     virtual OGRErr      DeleteFeature( GIntBig nFID ) override;
434     virtual OGRErr      ICreateFeature( OGRFeature *poFeature ) override;
435 
GetTableName()436     const char*         GetTableName() { return pszTableName; }
GetLayerName()437     const char*         GetLayerName() { return pszLayerName; }
GetSchemaName()438     const char*         GetSchemaName() { return pszSchemaName; }
439 
440     virtual OGRErr      CreateField( OGRFieldDefn *poField,
441                                      int bApproxOK = TRUE ) override;
442 
443     virtual OGRFeature *GetFeature( GIntBig nFeatureId ) override;
444 
445     virtual int         TestCapability( const char * ) override;
446 
SetLaunderFlag(int bFlag)447     void                SetLaunderFlag( int bFlag )
448                                 { bLaunderColumnNames = bFlag; }
SetPrecisionFlag(int bFlag)449     void                SetPrecisionFlag( int bFlag )
450                                 { bPreservePrecision = bFlag; }
SetSpatialIndexFlag(int bFlag)451     void                SetSpatialIndexFlag( int bFlag )
452                                 { bNeedSpatialIndex = bFlag; }
SetUploadGeometryFormat(int nGeometryFormat)453     void                SetUploadGeometryFormat( int nGeometryFormat )
454                                 { nUploadGeometryFormat = nGeometryFormat; }
455     void                AppendFieldValue(CPLODBCStatement *poStatement,
456                                        OGRFeature* poFeature, int i, int *bind_num, void **bind_buffer);
457 
458     int                 FetchSRSId();
459 
SetUseCopy(int bcpSize)460     void                SetUseCopy(int bcpSize) { bUseCopy = TRUE; nBCPSize = bcpSize; }
SetUpdate(bool bFlag)461     void                SetUpdate(bool bFlag) { bUpdateAccess = bFlag; }
462 
463     // cppcheck-suppress functionStatic
464     OGRErr              StartCopy();
465     // cppcheck-suppress functionStatic
466     OGRErr              EndCopy();
467 
468     int                 Failed( int nRetCode );
469 #ifdef MSSQL_BCP_SUPPORTED
470     OGRErr              CreateFeatureBCP( OGRFeature *poFeature );
471     int                 Failed2( int nRetCode );
472     int                 InitBCP( const char* pszDSN );
473     void                CloseBCP();
474 #endif
475 };
476 
477 /************************************************************************/
478 /*                      OGRMSSQLSpatialSelectLayer                      */
479 /************************************************************************/
480 
481 class OGRMSSQLSpatialSelectLayer final: public OGRMSSQLSpatialLayer
482 {
483     char                *pszBaseStatement;
484 
485     virtual CPLODBCStatement *  GetStatement() override;
486 
487   public:
488                         OGRMSSQLSpatialSelectLayer( OGRMSSQLSpatialDataSource *,
489                                            CPLODBCStatement * );
490                         virtual ~OGRMSSQLSpatialSelectLayer();
491 
492     virtual GIntBig     GetFeatureCount( int ) override;
493 
494     virtual OGRFeature *GetFeature( GIntBig nFeatureId ) override;
495 
496     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE) override;
GetExtent(int iGeomField,OGREnvelope * psExtent,int bForce)497     virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) override
498                 { return OGRLayer::GetExtent(iGeomField, psExtent, bForce); }
499 
500     virtual int         TestCapability( const char * ) override;
501 };
502 
503 /************************************************************************/
504 /*                           OGRODBCDataSource                          */
505 /************************************************************************/
506 
507 class OGRMSSQLSpatialDataSource final: public OGRDataSource
508 {
509     typedef struct
510     {
511         int nMajor;
512         int nMinor;
513         int nBuild;
514         int nRevision;
515     } MSSQLVer;
516 
517     OGRMSSQLSpatialTableLayer    **papoLayers;
518     int                 nLayers;
519 
520     char               *pszName;
521 
522     char               *pszCatalog;
523 
524     bool                bDSUpdate;
525     CPLODBCSession      oSession;
526 
527     int                 nGeometryFormat;
528 
529     int                 bUseGeometryColumns;
530     bool                bAlwaysOutputFid;
531 
532     int                 bListAllTables;
533 
534     int                 nBCPSize;
535     int                 bUseCopy;
536 
537     // We maintain a list of known SRID to reduce the number of trips to
538     // the database to get SRSes.
539     int                 nKnownSRID;
540     int                *panSRID;
541     OGRSpatialReference **papoSRS;
542 
543     OGRMSSQLSpatialTableLayer *poLayerInCopyMode;
544 
545     static void               OGRMSSQLDecodeVersionString(MSSQLVer* psVersion, const char* pszVer);
546 
547     char                *pszConnection;
548 
549 public:
550     MSSQLVer            sMSSQLVersion;
551 
552                         OGRMSSQLSpatialDataSource();
553                         virtual ~OGRMSSQLSpatialDataSource();
554 
GetCatalog()555     const char          *GetCatalog() { return pszCatalog; }
556 
557     static int                 ParseValue(char** pszValue, char* pszSource, const char* pszKey,
558                                   int nStart, int nNext, int nTerm, int bRemove);
559 
560     int                 Open( const char *, bool bUpdate, int bTestOpen );
561     int                 OpenTable( const char *pszSchemaName, const char *pszTableName,
562                                    const char *pszGeomCol,int nCoordDimension,
563                                    int nSRID, const char *pszSRText,
564                                    OGRwkbGeometryType eType, bool bUpdate );
565 
GetName()566     const char          *GetName() override { return pszName; }
567     int                 GetLayerCount() override;
568     OGRLayer            *GetLayer( int ) override;
569     OGRLayer            *GetLayerByName( const char* pszLayerName ) override;
570 
GetGeometryFormat()571     int                 GetGeometryFormat() { return nGeometryFormat; }
UseGeometryColumns()572     int                 UseGeometryColumns() { return bUseGeometryColumns; }
AlwaysOutputFid()573     bool                AlwaysOutputFid() { return bAlwaysOutputFid; }
574 
575     virtual OGRErr       DeleteLayer( int iLayer ) override;
576     virtual OGRLayer    *ICreateLayer( const char *,
577                                       OGRSpatialReference * = nullptr,
578                                       OGRwkbGeometryType = wkbUnknown,
579                                       char ** = nullptr ) override;
580 
581     int                 TestCapability( const char * ) override;
582 
583     virtual OGRLayer *  ExecuteSQL( const char *pszSQLCommand,
584                                     OGRGeometry *poSpatialFilter,
585                                     const char *pszDialect ) override;
586     virtual void        ReleaseResultSet( OGRLayer * poLayer ) override;
587 
588     char                *LaunderName( const char *pszSrcName );
589     OGRErr              InitializeMetadataTables();
590 
591     OGRSpatialReference* FetchSRS( int nId );
592     int                 FetchSRSId( OGRSpatialReference * poSRS );
593 
594     OGRErr              StartTransaction(CPL_UNUSED int bForce) override;
595     OGRErr              CommitTransaction() override;
596     OGRErr              RollbackTransaction() override;
597 
598     // Internal use
GetSession()599     CPLODBCSession     *GetSession() { return &oSession; }
GetConnectionString()600     const char         *GetConnectionString() { return pszConnection; }
601 
602     void                StartCopy(OGRMSSQLSpatialTableLayer *poMSSQLSpatialLayer);
603     OGRErr              EndCopy();
604 };
605 
606 /************************************************************************/
607 /*                        OGRMSSQLSpatialDriver                         */
608 /************************************************************************/
609 
610 class OGRMSSQLSpatialDriver final: public OGRSFDriver
611 {
612   public:
613     virtual ~OGRMSSQLSpatialDriver();
614 
615     const char *GetName() override;
616     OGRDataSource *Open( const char *, int ) override;
617 
618     virtual OGRDataSource *CreateDataSource( const char *pszName,
619                                              char ** = nullptr ) override;
620 
621     int                 TestCapability( const char * ) override;
622 };
623 
624 #endif /* ndef OGR_MSSQLSPATIAL_H_INCLUDED */
625