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