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