Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: MSSQL Spatial driver 4 : * Purpose: Implements OGRMSSQLSpatialSelectLayer class, layer access to the 5 : *results of a SELECT statement executed via ExecuteSQL(). Author: Tamas 6 : *Szekeres, szekerest at gmail.com 7 : * 8 : ****************************************************************************** 9 : * Copyright (c) 2010, Tamas Szekeres 10 : * 11 : * SPDX-License-Identifier: MIT 12 : ****************************************************************************/ 13 : 14 : #include "cpl_conv.h" 15 : #include "ogr_mssqlspatial.h" 16 : 17 : // SQL_CA_SS_UDT_TYPE_NAME not defined in unixODBC headers 18 : #ifndef SQL_CA_SS_BASE 19 : #define SQL_CA_SS_BASE 1200 20 : #endif 21 : 22 : #ifndef SQL_CA_SS_UDT_TYPE_NAME 23 : #define SQL_CA_SS_UDT_TYPE_NAME (SQL_CA_SS_BASE + 20) 24 : #endif 25 : 26 : /************************************************************************/ 27 : /* OGRMSSQLSpatialSelectLayer() */ 28 : /************************************************************************/ 29 : 30 0 : OGRMSSQLSpatialSelectLayer::OGRMSSQLSpatialSelectLayer( 31 0 : OGRMSSQLSpatialDataSource *poDSIn, CPLODBCStatement *poStmtIn) 32 0 : : OGRMSSQLSpatialLayer(poDSIn) 33 : 34 : { 35 0 : iNextShapeId = 0; 36 0 : nSRSId = 0; 37 0 : poFeatureDefn = nullptr; 38 : 39 0 : poStmt = poStmtIn; 40 0 : pszBaseStatement = CPLStrdup(poStmtIn->GetCommand()); 41 : 42 : /* identify the geometry column */ 43 0 : pszGeomColumn = nullptr; 44 0 : int iImageCol = -1; 45 0 : for (int iColumn = 0; iColumn < poStmt->GetColCount(); iColumn++) 46 : { 47 0 : if (EQUAL(poStmt->GetColTypeName(iColumn), "image")) 48 : { 49 : SQLCHAR szTableName[256]; 50 0 : SQLSMALLINT nTableNameLength = 0; 51 : 52 0 : SQLColAttribute(poStmt->GetStatement(), 53 0 : static_cast<SQLSMALLINT>(iColumn + 1), 54 : SQL_DESC_TABLE_NAME, szTableName, 55 : sizeof(szTableName), &nTableNameLength, nullptr); 56 : 57 0 : if (nTableNameLength > 0) 58 : { 59 : OGRLayer *poBaseLayer = 60 0 : poDS->GetLayerByName(reinterpret_cast<char *>(szTableName)); 61 0 : if (poBaseLayer != nullptr && 62 0 : EQUAL(poBaseLayer->GetGeometryColumn(), 63 : poStmt->GetColName(iColumn))) 64 : { 65 0 : nGeomColumnType = MSSQLCOLTYPE_BINARY; 66 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iColumn)); 67 : /* copy spatial reference */ 68 0 : if (!poSRS && poBaseLayer->GetSpatialRef()) 69 0 : poSRS = poBaseLayer->GetSpatialRef()->Clone(); 70 0 : break; 71 : } 72 : } 73 0 : else if (iImageCol == -1) 74 0 : iImageCol = iColumn; 75 : } 76 0 : else if (EQUAL(poStmt->GetColTypeName(iColumn), "geometry")) 77 : { 78 0 : nGeomColumnType = MSSQLCOLTYPE_GEOMETRY; 79 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iColumn)); 80 0 : break; 81 : } 82 0 : else if (EQUAL(poStmt->GetColTypeName(iColumn), "geography")) 83 : { 84 0 : nGeomColumnType = MSSQLCOLTYPE_GEOGRAPHY; 85 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iColumn)); 86 0 : break; 87 : } 88 0 : else if (EQUAL(poStmt->GetColTypeName(iColumn), "udt")) 89 : { 90 : SQLCHAR szUDTTypeName[256]; 91 0 : SQLSMALLINT nUDTTypeNameLength = 0; 92 : 93 0 : SQLColAttribute( 94 0 : poStmt->GetStatement(), static_cast<SQLSMALLINT>(iColumn + 1), 95 : SQL_CA_SS_UDT_TYPE_NAME, szUDTTypeName, sizeof(szUDTTypeName), 96 : &nUDTTypeNameLength, nullptr); 97 : 98 : // For some reason on unixODBC, a UCS2 string is returned 99 0 : if (EQUAL(reinterpret_cast<char *>(szUDTTypeName), "geometry") || 100 0 : (nUDTTypeNameLength == 16 && 101 0 : memcmp(szUDTTypeName, "g\0e\0o\0m\0e\0t\0r\0y", 16) == 0)) 102 : { 103 0 : nGeomColumnType = MSSQLCOLTYPE_GEOMETRY; 104 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iColumn)); 105 : } 106 0 : else if (EQUAL(reinterpret_cast<char *>(szUDTTypeName), 107 0 : "geography") || 108 0 : (nUDTTypeNameLength == 18 && 109 0 : memcmp(szUDTTypeName, "g\0e\0o\0g\0r\0a\0p\0h\0y", 18) == 110 : 0)) 111 : { 112 0 : nGeomColumnType = MSSQLCOLTYPE_GEOGRAPHY; 113 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iColumn)); 114 : } 115 0 : break; 116 : } 117 : } 118 : 119 0 : if (pszGeomColumn == nullptr && iImageCol >= 0) 120 : { 121 : /* set the image col as geometry column as the last resort */ 122 0 : nGeomColumnType = MSSQLCOLTYPE_BINARY; 123 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iImageCol)); 124 : } 125 : 126 0 : BuildFeatureDefn("SELECT", poStmt); 127 : 128 0 : if (GetSpatialRef() && poFeatureDefn->GetGeomFieldCount() == 1) 129 0 : poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS); 130 0 : } 131 : 132 : /************************************************************************/ 133 : /* ~OGRMSSQLSpatialSelectLayer() */ 134 : /************************************************************************/ 135 : 136 0 : OGRMSSQLSpatialSelectLayer::~OGRMSSQLSpatialSelectLayer() 137 : 138 : { 139 0 : CPLFree(pszBaseStatement); 140 0 : } 141 : 142 : /************************************************************************/ 143 : /* GetStatement() */ 144 : /************************************************************************/ 145 : 146 0 : CPLODBCStatement *OGRMSSQLSpatialSelectLayer::GetStatement() 147 : 148 : { 149 0 : if (poStmt == nullptr) 150 : { 151 0 : CPLDebug("OGR_MSSQLSpatial", "Recreating statement."); 152 0 : poStmt = new CPLODBCStatement(poDS->GetSession()); 153 0 : poStmt->Append(pszBaseStatement); 154 : 155 0 : if (!poStmt->ExecuteSQL()) 156 : { 157 0 : delete poStmt; 158 0 : poStmt = nullptr; 159 : } 160 : } 161 : 162 0 : return poStmt; 163 : } 164 : 165 : /************************************************************************/ 166 : /* GetFeature() */ 167 : /************************************************************************/ 168 : 169 0 : OGRFeature *OGRMSSQLSpatialSelectLayer::GetFeature(GIntBig nFeatureId) 170 : 171 : { 172 0 : return OGRMSSQLSpatialLayer::GetFeature(nFeatureId); 173 : } 174 : 175 : /************************************************************************/ 176 : /* TestCapability() */ 177 : /************************************************************************/ 178 : 179 0 : int OGRMSSQLSpatialSelectLayer::TestCapability(const char *pszCap) 180 : 181 : { 182 0 : return OGRMSSQLSpatialLayer::TestCapability(pszCap); 183 : } 184 : 185 : /************************************************************************/ 186 : /* GetFeatureCount() */ 187 : /* */ 188 : /* If a spatial filter is in effect, we turn control over to */ 189 : /* the generic counter. Otherwise we return the total count. */ 190 : /* Eventually we should consider implementing a more efficient */ 191 : /* way of counting features matching a spatial query. */ 192 : /************************************************************************/ 193 : 194 0 : GIntBig OGRMSSQLSpatialSelectLayer::GetFeatureCount(int bForce) 195 : 196 : { 197 0 : return OGRMSSQLSpatialLayer::GetFeatureCount(bForce); 198 : }