/src/gdal/ogr/ogrsf_frmts/sqlite/ogrsqliteviewlayer.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: Implements OGRSQLiteViewLayer class, access to an existing |
5 | | *spatialite view. Author: Even Rouault, <even dot rouault at spatialys.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "cpl_port.h" |
14 | | #include "ogr_sqlite.h" |
15 | | #include "ogrsqliteutility.h" |
16 | | |
17 | | #include <cstdlib> |
18 | | #include <cstring> |
19 | | #include <set> |
20 | | #include <string> |
21 | | |
22 | | #include "cpl_conv.h" |
23 | | #include "cpl_error.h" |
24 | | #include "cpl_string.h" |
25 | | #include "ogr_core.h" |
26 | | #include "ogr_feature.h" |
27 | | #include "ogr_geometry.h" |
28 | | #include "sqlite3.h" |
29 | | |
30 | | /************************************************************************/ |
31 | | /* OGRSQLiteViewLayer() */ |
32 | | /************************************************************************/ |
33 | | |
34 | | OGRSQLiteViewLayer::OGRSQLiteViewLayer(OGRSQLiteDataSource *poDSIn) |
35 | 0 | : OGRSQLiteLayer(poDSIn) |
36 | 0 | { |
37 | 0 | } |
38 | | |
39 | | /************************************************************************/ |
40 | | /* ~OGRSQLiteViewLayer() */ |
41 | | /************************************************************************/ |
42 | | |
43 | | OGRSQLiteViewLayer::~OGRSQLiteViewLayer() |
44 | | |
45 | 0 | { |
46 | 0 | ClearStatement(); |
47 | 0 | CPLFree(m_pszViewName); |
48 | 0 | CPLFree(m_pszEscapedTableName); |
49 | 0 | CPLFree(m_pszEscapedUnderlyingTableName); |
50 | 0 | } |
51 | | |
52 | | /************************************************************************/ |
53 | | /* Initialize() */ |
54 | | /************************************************************************/ |
55 | | |
56 | | CPLErr OGRSQLiteViewLayer::Initialize(const char *pszViewNameIn, |
57 | | const char *pszViewGeometry, |
58 | | const char *pszViewRowid, |
59 | | const char *pszUnderlyingTableName, |
60 | | const char *pszUnderlyingGeometryColumn) |
61 | | |
62 | 0 | { |
63 | 0 | m_pszViewName = CPLStrdup(pszViewNameIn); |
64 | 0 | SetDescription(m_pszViewName); |
65 | |
|
66 | 0 | m_osGeomColumn = pszViewGeometry; |
67 | 0 | m_eGeomFormat = OSGF_SpatiaLite; |
68 | |
|
69 | 0 | CPLFree(m_pszFIDColumn); |
70 | 0 | m_pszFIDColumn = CPLStrdup(pszViewRowid); |
71 | |
|
72 | 0 | m_osUnderlyingTableName = pszUnderlyingTableName; |
73 | 0 | m_osUnderlyingGeometryColumn = pszUnderlyingGeometryColumn; |
74 | 0 | m_poUnderlyingLayer = nullptr; |
75 | |
|
76 | 0 | m_pszEscapedTableName = CPLStrdup(SQLEscapeLiteral(m_pszViewName)); |
77 | 0 | m_pszEscapedUnderlyingTableName = |
78 | 0 | CPLStrdup(SQLEscapeLiteral(pszUnderlyingTableName)); |
79 | |
|
80 | 0 | return CE_None; |
81 | 0 | } |
82 | | |
83 | | /************************************************************************/ |
84 | | /* GetLayerDefn() */ |
85 | | /************************************************************************/ |
86 | | |
87 | | const OGRFeatureDefn *OGRSQLiteViewLayer::GetLayerDefn() const |
88 | 0 | { |
89 | 0 | if (!m_poFeatureDefn) |
90 | 0 | { |
91 | 0 | const_cast<OGRSQLiteViewLayer *>(this)->BuildLayerDefn(); |
92 | 0 | } |
93 | 0 | return m_poFeatureDefn; |
94 | 0 | } |
95 | | |
96 | | /************************************************************************/ |
97 | | /* BuildLayerDefn() */ |
98 | | /************************************************************************/ |
99 | | |
100 | | void OGRSQLiteViewLayer::BuildLayerDefn() |
101 | 0 | { |
102 | 0 | EstablishFeatureDefn(); |
103 | |
|
104 | 0 | if (m_poFeatureDefn == nullptr) |
105 | 0 | { |
106 | 0 | m_bLayerDefnError = true; |
107 | |
|
108 | 0 | m_poFeatureDefn = new OGRSQLiteFeatureDefn(m_pszViewName); |
109 | 0 | m_poFeatureDefn->Reference(); |
110 | 0 | } |
111 | 0 | } |
112 | | |
113 | | /************************************************************************/ |
114 | | /* GetUnderlyingLayer() */ |
115 | | /************************************************************************/ |
116 | | |
117 | | OGRSQLiteLayer *OGRSQLiteViewLayer::GetUnderlyingLayer() |
118 | 0 | { |
119 | 0 | if (m_poUnderlyingLayer == nullptr) |
120 | 0 | { |
121 | 0 | if (strchr(m_osUnderlyingTableName, '(') == nullptr) |
122 | 0 | { |
123 | 0 | CPLString osNewUnderlyingTableName; |
124 | 0 | osNewUnderlyingTableName.Printf( |
125 | 0 | "%s(%s)", m_osUnderlyingTableName.c_str(), |
126 | 0 | m_osUnderlyingGeometryColumn.c_str()); |
127 | 0 | m_poUnderlyingLayer = cpl::down_cast<OGRSQLiteLayer *>( |
128 | 0 | m_poDS->GetLayerByNameNotVisible(osNewUnderlyingTableName)); |
129 | 0 | } |
130 | 0 | if (m_poUnderlyingLayer == nullptr) |
131 | 0 | m_poUnderlyingLayer = cpl::down_cast<OGRSQLiteLayer *>( |
132 | 0 | m_poDS->GetLayerByNameNotVisible(m_osUnderlyingTableName)); |
133 | 0 | } |
134 | 0 | return m_poUnderlyingLayer; |
135 | 0 | } |
136 | | |
137 | | /************************************************************************/ |
138 | | /* GetGeomType() */ |
139 | | /************************************************************************/ |
140 | | |
141 | | OGRwkbGeometryType OGRSQLiteViewLayer::GetGeomType() const |
142 | 0 | { |
143 | 0 | if (m_poFeatureDefn) |
144 | 0 | return m_poFeatureDefn->GetGeomType(); |
145 | | |
146 | 0 | OGRSQLiteLayer *l_m_poUnderlyingLayer = |
147 | 0 | const_cast<OGRSQLiteViewLayer *>(this)->GetUnderlyingLayer(); |
148 | 0 | if (l_m_poUnderlyingLayer) |
149 | 0 | return l_m_poUnderlyingLayer->GetGeomType(); |
150 | | |
151 | 0 | return wkbUnknown; |
152 | 0 | } |
153 | | |
154 | | /************************************************************************/ |
155 | | /* EstablishFeatureDefn() */ |
156 | | /************************************************************************/ |
157 | | |
158 | | CPLErr OGRSQLiteViewLayer::EstablishFeatureDefn() |
159 | 0 | { |
160 | 0 | sqlite3 *hDB = m_poDS->GetDB(); |
161 | 0 | sqlite3_stmt *hColStmt = nullptr; |
162 | |
|
163 | 0 | OGRSQLiteLayer *l_m_poUnderlyingLayer = GetUnderlyingLayer(); |
164 | 0 | if (l_m_poUnderlyingLayer == nullptr) |
165 | 0 | { |
166 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
167 | 0 | "Cannot find underlying layer %s for view %s", |
168 | 0 | m_osUnderlyingTableName.c_str(), m_pszViewName); |
169 | 0 | return CE_Failure; |
170 | 0 | } |
171 | 0 | if (!l_m_poUnderlyingLayer->IsTableLayer()) |
172 | 0 | { |
173 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
174 | 0 | "Underlying layer %s for view %s is not a regular table", |
175 | 0 | m_osUnderlyingTableName.c_str(), m_pszViewName); |
176 | 0 | return CE_Failure; |
177 | 0 | } |
178 | | |
179 | 0 | int nUnderlyingLayerGeomFieldIndex = |
180 | 0 | l_m_poUnderlyingLayer->GetLayerDefn()->GetGeomFieldIndex( |
181 | 0 | m_osUnderlyingGeometryColumn); |
182 | 0 | if (nUnderlyingLayerGeomFieldIndex < 0) |
183 | 0 | { |
184 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
185 | 0 | "Underlying layer %s for view %s has not expected geometry " |
186 | 0 | "column name %s", |
187 | 0 | m_osUnderlyingTableName.c_str(), m_pszViewName, |
188 | 0 | m_osUnderlyingGeometryColumn.c_str()); |
189 | 0 | return CE_Failure; |
190 | 0 | } |
191 | | |
192 | 0 | m_bHasSpatialIndex = |
193 | 0 | l_m_poUnderlyingLayer->HasSpatialIndex(nUnderlyingLayerGeomFieldIndex); |
194 | | |
195 | | /* -------------------------------------------------------------------- */ |
196 | | /* Get the column definitions for this table. */ |
197 | | /* -------------------------------------------------------------------- */ |
198 | 0 | hColStmt = nullptr; |
199 | 0 | const char *pszSQL = CPLSPrintf("SELECT \"%s\", * FROM '%s' LIMIT 1", |
200 | 0 | SQLEscapeName(m_pszFIDColumn).c_str(), |
201 | 0 | m_pszEscapedTableName); |
202 | |
|
203 | 0 | int rc = sqlite3_prepare_v2(hDB, pszSQL, -1, &hColStmt, nullptr); |
204 | 0 | if (rc != SQLITE_OK) |
205 | 0 | { |
206 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
207 | 0 | "Unable to query table %s for column definitions : %s.", |
208 | 0 | m_pszViewName, sqlite3_errmsg(hDB)); |
209 | |
|
210 | 0 | return CE_Failure; |
211 | 0 | } |
212 | | |
213 | 0 | rc = sqlite3_step(hColStmt); |
214 | 0 | if (rc != SQLITE_DONE && rc != SQLITE_ROW) |
215 | 0 | { |
216 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
217 | 0 | "In Initialize(): sqlite3_step(%s):\n %s", pszSQL, |
218 | 0 | sqlite3_errmsg(hDB)); |
219 | 0 | sqlite3_finalize(hColStmt); |
220 | 0 | return CE_Failure; |
221 | 0 | } |
222 | | |
223 | | /* -------------------------------------------------------------------- */ |
224 | | /* Collect the rest of the fields. */ |
225 | | /* -------------------------------------------------------------------- */ |
226 | 0 | std::set<CPLString> aosGeomCols; |
227 | 0 | std::set<CPLString> aosIgnoredCols; |
228 | 0 | aosGeomCols.insert(m_osGeomColumn); |
229 | 0 | BuildFeatureDefn(m_pszViewName, false, hColStmt, &aosGeomCols, |
230 | 0 | aosIgnoredCols); |
231 | 0 | sqlite3_finalize(hColStmt); |
232 | | |
233 | | /* -------------------------------------------------------------------- */ |
234 | | /* Set the properties of the geometry column. */ |
235 | | /* -------------------------------------------------------------------- */ |
236 | 0 | if (m_poFeatureDefn->GetGeomFieldCount() != 0) |
237 | 0 | { |
238 | 0 | OGRSQLiteGeomFieldDefn *poSrcGeomFieldDefn = |
239 | 0 | l_m_poUnderlyingLayer->myGetLayerDefn()->myGetGeomFieldDefn( |
240 | 0 | nUnderlyingLayerGeomFieldIndex); |
241 | 0 | OGRSQLiteGeomFieldDefn *poGeomFieldDefn = |
242 | 0 | m_poFeatureDefn->myGetGeomFieldDefn(0); |
243 | 0 | poGeomFieldDefn->SetType(poSrcGeomFieldDefn->GetType()); |
244 | 0 | poGeomFieldDefn->SetSpatialRef(poSrcGeomFieldDefn->GetSpatialRef()); |
245 | 0 | poGeomFieldDefn->m_nSRSId = poSrcGeomFieldDefn->m_nSRSId; |
246 | 0 | poGeomFieldDefn->m_eGeomFormat = m_eGeomFormat; |
247 | 0 | } |
248 | |
|
249 | 0 | return CE_None; |
250 | 0 | } |
251 | | |
252 | | /************************************************************************/ |
253 | | /* ResetStatement() */ |
254 | | /************************************************************************/ |
255 | | |
256 | | OGRErr OGRSQLiteViewLayer::ResetStatement() |
257 | | |
258 | 0 | { |
259 | 0 | CPLString osSQL; |
260 | |
|
261 | 0 | ClearStatement(); |
262 | |
|
263 | 0 | m_iNextShapeId = 0; |
264 | |
|
265 | 0 | osSQL.Printf("SELECT \"%s\", * FROM '%s' %s", |
266 | 0 | SQLEscapeName(m_pszFIDColumn).c_str(), m_pszEscapedTableName, |
267 | 0 | m_osWHERE.c_str()); |
268 | |
|
269 | 0 | const int rc = |
270 | 0 | sqlite3_prepare_v2(m_poDS->GetDB(), osSQL, |
271 | 0 | static_cast<int>(osSQL.size()), &m_hStmt, nullptr); |
272 | |
|
273 | 0 | if (rc == SQLITE_OK) |
274 | 0 | { |
275 | 0 | return OGRERR_NONE; |
276 | 0 | } |
277 | | |
278 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
279 | 0 | "In ResetStatement(): sqlite3_prepare_v2(%s):\n %s", |
280 | 0 | osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB())); |
281 | 0 | m_hStmt = nullptr; |
282 | 0 | return OGRERR_FAILURE; |
283 | 0 | } |
284 | | |
285 | | /************************************************************************/ |
286 | | /* GetNextFeature() */ |
287 | | /************************************************************************/ |
288 | | |
289 | | OGRFeature *OGRSQLiteViewLayer::GetNextFeature() |
290 | | |
291 | 0 | { |
292 | 0 | if (HasLayerDefnError()) |
293 | 0 | return nullptr; |
294 | | |
295 | 0 | return OGRSQLiteLayer::GetNextFeature(); |
296 | 0 | } |
297 | | |
298 | | /************************************************************************/ |
299 | | /* GetFeature() */ |
300 | | /************************************************************************/ |
301 | | |
302 | | OGRFeature *OGRSQLiteViewLayer::GetFeature(GIntBig nFeatureId) |
303 | | |
304 | 0 | { |
305 | 0 | if (HasLayerDefnError()) |
306 | 0 | return nullptr; |
307 | | |
308 | | /* -------------------------------------------------------------------- */ |
309 | | /* If we don't have an explicit FID column, just read through */ |
310 | | /* the result set iteratively to find our target. */ |
311 | | /* -------------------------------------------------------------------- */ |
312 | 0 | if (m_pszFIDColumn == nullptr) |
313 | 0 | return OGRSQLiteLayer::GetFeature(nFeatureId); |
314 | | |
315 | | /* -------------------------------------------------------------------- */ |
316 | | /* Setup explicit query statement to fetch the record we want. */ |
317 | | /* -------------------------------------------------------------------- */ |
318 | 0 | CPLString osSQL; |
319 | |
|
320 | 0 | ClearStatement(); |
321 | |
|
322 | 0 | m_iNextShapeId = nFeatureId; |
323 | |
|
324 | 0 | osSQL.Printf("SELECT \"%s\", * FROM '%s' WHERE \"%s\" = " CPL_FRMT_GIB, |
325 | 0 | SQLEscapeName(m_pszFIDColumn).c_str(), m_pszEscapedTableName, |
326 | 0 | SQLEscapeName(m_pszFIDColumn).c_str(), nFeatureId); |
327 | |
|
328 | 0 | CPLDebug("OGR_SQLITE", "exec(%s)", osSQL.c_str()); |
329 | |
|
330 | 0 | const int rc = |
331 | 0 | sqlite3_prepare_v2(m_poDS->GetDB(), osSQL, |
332 | 0 | static_cast<int>(osSQL.size()), &m_hStmt, nullptr); |
333 | 0 | if (rc != SQLITE_OK) |
334 | 0 | { |
335 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
336 | 0 | "In GetFeature(): sqlite3_prepare_v2(%s):\n %s", |
337 | 0 | osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB())); |
338 | |
|
339 | 0 | return nullptr; |
340 | 0 | } |
341 | | /* -------------------------------------------------------------------- */ |
342 | | /* Get the feature if possible. */ |
343 | | /* -------------------------------------------------------------------- */ |
344 | 0 | OGRFeature *poFeature = GetNextRawFeature(); |
345 | |
|
346 | 0 | ResetReading(); |
347 | |
|
348 | 0 | return poFeature; |
349 | 0 | } |
350 | | |
351 | | /************************************************************************/ |
352 | | /* SetAttributeFilter() */ |
353 | | /************************************************************************/ |
354 | | |
355 | | OGRErr OGRSQLiteViewLayer::SetAttributeFilter(const char *pszQuery) |
356 | | |
357 | 0 | { |
358 | 0 | if (pszQuery == nullptr) |
359 | 0 | m_osQuery = ""; |
360 | 0 | else |
361 | 0 | m_osQuery = pszQuery; |
362 | |
|
363 | 0 | BuildWhere(); |
364 | |
|
365 | 0 | ResetReading(); |
366 | |
|
367 | 0 | return OGRERR_NONE; |
368 | 0 | } |
369 | | |
370 | | /************************************************************************/ |
371 | | /* ISetSpatialFilter() */ |
372 | | /************************************************************************/ |
373 | | |
374 | | OGRErr OGRSQLiteViewLayer::ISetSpatialFilter(int, const OGRGeometry *poGeomIn) |
375 | | |
376 | 0 | { |
377 | 0 | if (InstallFilter(poGeomIn)) |
378 | 0 | { |
379 | 0 | BuildWhere(); |
380 | |
|
381 | 0 | ResetReading(); |
382 | 0 | } |
383 | 0 | return OGRERR_NONE; |
384 | 0 | } |
385 | | |
386 | | /************************************************************************/ |
387 | | /* GetSpatialWhere() */ |
388 | | /************************************************************************/ |
389 | | |
390 | | CPLString OGRSQLiteViewLayer::GetSpatialWhere(int iGeomCol, |
391 | | OGRGeometry *poFilterGeom) |
392 | 0 | { |
393 | 0 | if (HasLayerDefnError() || m_poFeatureDefn == nullptr || iGeomCol < 0 || |
394 | 0 | iGeomCol >= m_poFeatureDefn->GetGeomFieldCount()) |
395 | 0 | return ""; |
396 | | |
397 | 0 | if (poFilterGeom != nullptr && m_bHasSpatialIndex) |
398 | 0 | { |
399 | 0 | OGREnvelope sEnvelope; |
400 | |
|
401 | 0 | poFilterGeom->getEnvelope(&sEnvelope); |
402 | | |
403 | | /* We first check that the spatial index table exists */ |
404 | 0 | if (!m_bHasCheckedSpatialIndexTable) |
405 | 0 | { |
406 | 0 | m_bHasCheckedSpatialIndexTable = true; |
407 | 0 | char **papszResult = nullptr; |
408 | 0 | int nRowCount = 0; |
409 | 0 | int nColCount = 0; |
410 | 0 | char *pszErrMsg = nullptr; |
411 | |
|
412 | 0 | CPLString osSQL; |
413 | 0 | osSQL.Printf( |
414 | 0 | "SELECT name FROM sqlite_master " |
415 | 0 | "WHERE name='idx_%s_%s'", |
416 | 0 | m_pszEscapedUnderlyingTableName, |
417 | 0 | SQLEscapeLiteral(m_osUnderlyingGeometryColumn).c_str()); |
418 | |
|
419 | 0 | int rc = |
420 | 0 | sqlite3_get_table(m_poDS->GetDB(), osSQL.c_str(), &papszResult, |
421 | 0 | &nRowCount, &nColCount, &pszErrMsg); |
422 | |
|
423 | 0 | if (rc != SQLITE_OK) |
424 | 0 | { |
425 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Error: %s", pszErrMsg); |
426 | 0 | sqlite3_free(pszErrMsg); |
427 | 0 | m_bHasSpatialIndex = false; |
428 | 0 | } |
429 | 0 | else |
430 | 0 | { |
431 | 0 | if (nRowCount != 1) |
432 | 0 | { |
433 | 0 | m_bHasSpatialIndex = false; |
434 | 0 | } |
435 | |
|
436 | 0 | sqlite3_free_table(papszResult); |
437 | 0 | } |
438 | 0 | } |
439 | |
|
440 | 0 | if (m_bHasSpatialIndex) |
441 | 0 | { |
442 | 0 | return FormatSpatialFilterFromRTree( |
443 | 0 | poFilterGeom, |
444 | 0 | CPLSPrintf("\"%s\"", SQLEscapeName(m_pszFIDColumn).c_str()), |
445 | 0 | m_pszEscapedUnderlyingTableName, |
446 | 0 | SQLEscapeLiteral(m_osUnderlyingGeometryColumn).c_str()); |
447 | 0 | } |
448 | 0 | else |
449 | 0 | { |
450 | 0 | CPLDebug("SQLITE", |
451 | 0 | "Count not find idx_%s_%s layer. Disabling spatial index", |
452 | 0 | m_pszEscapedUnderlyingTableName, |
453 | 0 | m_osUnderlyingGeometryColumn.c_str()); |
454 | 0 | } |
455 | 0 | } |
456 | | |
457 | 0 | if (poFilterGeom != nullptr && m_poDS->IsSpatialiteLoaded()) |
458 | 0 | { |
459 | 0 | return FormatSpatialFilterFromMBR( |
460 | 0 | poFilterGeom, |
461 | 0 | SQLEscapeName( |
462 | 0 | m_poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef()) |
463 | 0 | .c_str()); |
464 | 0 | } |
465 | | |
466 | 0 | return ""; |
467 | 0 | } |
468 | | |
469 | | /************************************************************************/ |
470 | | /* BuildWhere() */ |
471 | | /* */ |
472 | | /* Build the WHERE statement appropriate to the current set of */ |
473 | | /* criteria (spatial and attribute queries). */ |
474 | | /************************************************************************/ |
475 | | |
476 | | void OGRSQLiteViewLayer::BuildWhere() |
477 | | |
478 | 0 | { |
479 | 0 | m_osWHERE = ""; |
480 | |
|
481 | 0 | CPLString osSpatialWHERE = |
482 | 0 | GetSpatialWhere(m_iGeomFieldFilter, m_poFilterGeom); |
483 | 0 | if (!osSpatialWHERE.empty()) |
484 | 0 | { |
485 | 0 | m_osWHERE = "WHERE "; |
486 | 0 | m_osWHERE += osSpatialWHERE; |
487 | 0 | } |
488 | |
|
489 | 0 | if (!m_osQuery.empty()) |
490 | 0 | { |
491 | 0 | if (m_osWHERE.empty()) |
492 | 0 | { |
493 | 0 | m_osWHERE = "WHERE "; |
494 | 0 | m_osWHERE += m_osQuery; |
495 | 0 | } |
496 | 0 | else |
497 | 0 | { |
498 | 0 | m_osWHERE += " AND ("; |
499 | 0 | m_osWHERE += m_osQuery; |
500 | 0 | m_osWHERE += ")"; |
501 | 0 | } |
502 | 0 | } |
503 | 0 | } |
504 | | |
505 | | /************************************************************************/ |
506 | | /* TestCapability() */ |
507 | | /************************************************************************/ |
508 | | |
509 | | int OGRSQLiteViewLayer::TestCapability(const char *pszCap) const |
510 | | |
511 | 0 | { |
512 | 0 | if (HasLayerDefnError()) |
513 | 0 | return FALSE; |
514 | | |
515 | 0 | if (EQUAL(pszCap, OLCFastFeatureCount)) |
516 | 0 | return m_poFilterGeom == nullptr || m_osGeomColumn.empty() || |
517 | 0 | m_bHasSpatialIndex; |
518 | | |
519 | 0 | else if (EQUAL(pszCap, OLCFastSpatialFilter)) |
520 | 0 | return m_bHasSpatialIndex; |
521 | | |
522 | 0 | else |
523 | 0 | return OGRSQLiteLayer::TestCapability(pszCap); |
524 | 0 | } |
525 | | |
526 | | /************************************************************************/ |
527 | | /* GetFeatureCount() */ |
528 | | /* */ |
529 | | /* If a spatial filter is in effect, we turn control over to */ |
530 | | /* the generic counter. Otherwise we return the total count. */ |
531 | | /* Eventually we should consider implementing a more efficient */ |
532 | | /* way of counting features matching a spatial query. */ |
533 | | /************************************************************************/ |
534 | | |
535 | | GIntBig OGRSQLiteViewLayer::GetFeatureCount(int bForce) |
536 | | |
537 | 0 | { |
538 | 0 | if (HasLayerDefnError()) |
539 | 0 | return 0; |
540 | | |
541 | 0 | if (!TestCapability(OLCFastFeatureCount)) |
542 | 0 | return OGRSQLiteLayer::GetFeatureCount(bForce); |
543 | | |
544 | | /* -------------------------------------------------------------------- */ |
545 | | /* Form count SQL. */ |
546 | | /* -------------------------------------------------------------------- */ |
547 | 0 | const char *pszSQL = CPLSPrintf("SELECT count(*) FROM '%s' %s", |
548 | 0 | m_pszEscapedTableName, m_osWHERE.c_str()); |
549 | | |
550 | | /* -------------------------------------------------------------------- */ |
551 | | /* Execute. */ |
552 | | /* -------------------------------------------------------------------- */ |
553 | 0 | char **papszResult, *pszErrMsg; |
554 | 0 | int nRowCount, nColCount; |
555 | 0 | int nResult = -1; |
556 | |
|
557 | 0 | if (sqlite3_get_table(m_poDS->GetDB(), pszSQL, &papszResult, &nColCount, |
558 | 0 | &nRowCount, &pszErrMsg) != SQLITE_OK) |
559 | 0 | return -1; |
560 | | |
561 | 0 | if (nRowCount == 1 && nColCount == 1) |
562 | 0 | nResult = atoi(papszResult[1]); |
563 | |
|
564 | 0 | sqlite3_free_table(papszResult); |
565 | |
|
566 | 0 | return nResult; |
567 | 0 | } |