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(), (SQLSMALLINT)(iColumn + 1), 53 : SQL_DESC_TABLE_NAME, szTableName, 54 : sizeof(szTableName), &nTableNameLength, nullptr); 55 : 56 0 : if (nTableNameLength > 0) 57 : { 58 : OGRLayer *poBaseLayer = 59 0 : poDS->GetLayerByName((const char *)szTableName); 60 0 : if (poBaseLayer != nullptr && 61 0 : EQUAL(poBaseLayer->GetGeometryColumn(), 62 : poStmt->GetColName(iColumn))) 63 : { 64 0 : nGeomColumnType = MSSQLCOLTYPE_BINARY; 65 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iColumn)); 66 : /* copy spatial reference */ 67 0 : if (!poSRS && poBaseLayer->GetSpatialRef()) 68 0 : poSRS = poBaseLayer->GetSpatialRef()->Clone(); 69 0 : break; 70 : } 71 : } 72 0 : else if (iImageCol == -1) 73 0 : iImageCol = iColumn; 74 : } 75 0 : else if (EQUAL(poStmt->GetColTypeName(iColumn), "geometry")) 76 : { 77 0 : nGeomColumnType = MSSQLCOLTYPE_GEOMETRY; 78 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iColumn)); 79 0 : break; 80 : } 81 0 : else if (EQUAL(poStmt->GetColTypeName(iColumn), "geography")) 82 : { 83 0 : nGeomColumnType = MSSQLCOLTYPE_GEOGRAPHY; 84 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iColumn)); 85 0 : break; 86 : } 87 0 : else if (EQUAL(poStmt->GetColTypeName(iColumn), "udt")) 88 : { 89 : SQLCHAR szUDTTypeName[256]; 90 0 : SQLSMALLINT nUDTTypeNameLength = 0; 91 : 92 0 : SQLColAttribute(poStmt->GetStatement(), (SQLSMALLINT)(iColumn + 1), 93 : SQL_CA_SS_UDT_TYPE_NAME, szUDTTypeName, 94 : sizeof(szUDTTypeName), &nUDTTypeNameLength, 95 : nullptr); 96 : 97 : // For some reason on unixODBC, a UCS2 string is returned 98 0 : if (EQUAL((char *)szUDTTypeName, "geometry") || 99 0 : (nUDTTypeNameLength == 16 && 100 0 : memcmp(szUDTTypeName, "g\0e\0o\0m\0e\0t\0r\0y", 16) == 0)) 101 : { 102 0 : nGeomColumnType = MSSQLCOLTYPE_GEOMETRY; 103 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iColumn)); 104 : } 105 0 : else if (EQUAL((char *)szUDTTypeName, "geography") || 106 0 : (nUDTTypeNameLength == 18 && 107 0 : memcmp(szUDTTypeName, "g\0e\0o\0g\0r\0a\0p\0h\0y", 18) == 108 : 0)) 109 : { 110 0 : nGeomColumnType = MSSQLCOLTYPE_GEOGRAPHY; 111 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iColumn)); 112 : } 113 0 : break; 114 : } 115 : } 116 : 117 0 : if (pszGeomColumn == nullptr && iImageCol >= 0) 118 : { 119 : /* set the image col as geometry column as the last resort */ 120 0 : nGeomColumnType = MSSQLCOLTYPE_BINARY; 121 0 : pszGeomColumn = CPLStrdup(poStmt->GetColName(iImageCol)); 122 : } 123 : 124 0 : BuildFeatureDefn("SELECT", poStmt); 125 : 126 0 : if (GetSpatialRef() && poFeatureDefn->GetGeomFieldCount() == 1) 127 0 : poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS); 128 0 : } 129 : 130 : /************************************************************************/ 131 : /* ~OGRMSSQLSpatialSelectLayer() */ 132 : /************************************************************************/ 133 : 134 0 : OGRMSSQLSpatialSelectLayer::~OGRMSSQLSpatialSelectLayer() 135 : 136 : { 137 0 : CPLFree(pszBaseStatement); 138 0 : } 139 : 140 : /************************************************************************/ 141 : /* GetStatement() */ 142 : /************************************************************************/ 143 : 144 0 : CPLODBCStatement *OGRMSSQLSpatialSelectLayer::GetStatement() 145 : 146 : { 147 0 : if (poStmt == nullptr) 148 : { 149 0 : CPLDebug("OGR_MSSQLSpatial", "Recreating statement."); 150 0 : poStmt = new CPLODBCStatement(poDS->GetSession()); 151 0 : poStmt->Append(pszBaseStatement); 152 : 153 0 : if (!poStmt->ExecuteSQL()) 154 : { 155 0 : delete poStmt; 156 0 : poStmt = nullptr; 157 : } 158 : } 159 : 160 0 : return poStmt; 161 : } 162 : 163 : /************************************************************************/ 164 : /* GetFeature() */ 165 : /************************************************************************/ 166 : 167 0 : OGRFeature *OGRMSSQLSpatialSelectLayer::GetFeature(GIntBig nFeatureId) 168 : 169 : { 170 0 : return OGRMSSQLSpatialLayer::GetFeature(nFeatureId); 171 : } 172 : 173 : /************************************************************************/ 174 : /* TestCapability() */ 175 : /************************************************************************/ 176 : 177 0 : int OGRMSSQLSpatialSelectLayer::TestCapability(const char *pszCap) 178 : 179 : { 180 0 : return OGRMSSQLSpatialLayer::TestCapability(pszCap); 181 : } 182 : 183 : /************************************************************************/ 184 : /* GetExtent() */ 185 : /* */ 186 : /* Since SELECT layers currently cannot ever have geometry, we */ 187 : /* can optimize the GetExtent() method! */ 188 : /************************************************************************/ 189 : 190 0 : OGRErr OGRMSSQLSpatialSelectLayer::GetExtent(OGREnvelope *, int) 191 : 192 : { 193 0 : return OGRERR_FAILURE; 194 : } 195 : 196 : /************************************************************************/ 197 : /* GetFeatureCount() */ 198 : /* */ 199 : /* If a spatial filter is in effect, we turn control over to */ 200 : /* the generic counter. Otherwise we return the total count. */ 201 : /* Eventually we should consider implementing a more efficient */ 202 : /* way of counting features matching a spatial query. */ 203 : /************************************************************************/ 204 : 205 0 : GIntBig OGRMSSQLSpatialSelectLayer::GetFeatureCount(int bForce) 206 : 207 : { 208 0 : return OGRMSSQLSpatialLayer::GetFeatureCount(bForce); 209 : }