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