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 : const OGRFeatureDefn *OGRSQLiteViewLayer::GetLayerDefn() const
88 : {
89 31 : if (!m_poFeatureDefn)
90 : {
91 4 : const_cast<OGRSQLiteViewLayer *>(this)->BuildLayerDefn();
92 : }
93 31 : return m_poFeatureDefn;
94 : }
95 :
96 : /************************************************************************/
97 : /* BuildLayerDefn() */
98 : /************************************************************************/
99 :
100 4 : void OGRSQLiteViewLayer::BuildLayerDefn()
101 : {
102 4 : EstablishFeatureDefn();
103 :
104 4 : if (m_poFeatureDefn == nullptr)
105 : {
106 0 : m_bLayerDefnError = true;
107 :
108 0 : m_poFeatureDefn = new OGRSQLiteFeatureDefn(m_pszViewName);
109 0 : m_poFeatureDefn->Reference();
110 : }
111 4 : }
112 :
113 : /************************************************************************/
114 : /* GetUnderlyingLayer() */
115 : /************************************************************************/
116 :
117 4 : OGRSQLiteLayer *OGRSQLiteViewLayer::GetUnderlyingLayer()
118 : {
119 4 : if (m_poUnderlyingLayer == nullptr)
120 : {
121 4 : if (strchr(m_osUnderlyingTableName, '(') == nullptr)
122 : {
123 4 : CPLString osNewUnderlyingTableName;
124 : osNewUnderlyingTableName.Printf(
125 : "%s(%s)", m_osUnderlyingTableName.c_str(),
126 4 : m_osUnderlyingGeometryColumn.c_str());
127 4 : m_poUnderlyingLayer = cpl::down_cast<OGRSQLiteLayer *>(
128 4 : m_poDS->GetLayerByNameNotVisible(osNewUnderlyingTableName));
129 : }
130 4 : if (m_poUnderlyingLayer == nullptr)
131 0 : m_poUnderlyingLayer = cpl::down_cast<OGRSQLiteLayer *>(
132 0 : m_poDS->GetLayerByNameNotVisible(m_osUnderlyingTableName));
133 : }
134 4 : return m_poUnderlyingLayer;
135 : }
136 :
137 : /************************************************************************/
138 : /* GetGeomType() */
139 : /************************************************************************/
140 :
141 3 : OGRwkbGeometryType OGRSQLiteViewLayer::GetGeomType() const
142 : {
143 3 : if (m_poFeatureDefn)
144 3 : return m_poFeatureDefn->GetGeomType();
145 :
146 : 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 : }
153 :
154 : /************************************************************************/
155 : /* EstablishFeatureDefn() */
156 : /************************************************************************/
157 :
158 4 : CPLErr OGRSQLiteViewLayer::EstablishFeatureDefn()
159 : {
160 4 : sqlite3 *hDB = m_poDS->GetDB();
161 4 : sqlite3_stmt *hColStmt = nullptr;
162 :
163 4 : OGRSQLiteLayer *l_m_poUnderlyingLayer = GetUnderlyingLayer();
164 4 : if (l_m_poUnderlyingLayer == nullptr)
165 : {
166 0 : CPLError(CE_Failure, CPLE_AppDefined,
167 : "Cannot find underlying layer %s for view %s",
168 : m_osUnderlyingTableName.c_str(), m_pszViewName);
169 0 : return CE_Failure;
170 : }
171 4 : if (!l_m_poUnderlyingLayer->IsTableLayer())
172 : {
173 0 : CPLError(CE_Failure, CPLE_AppDefined,
174 : "Underlying layer %s for view %s is not a regular table",
175 : m_osUnderlyingTableName.c_str(), m_pszViewName);
176 0 : return CE_Failure;
177 : }
178 :
179 : int nUnderlyingLayerGeomFieldIndex =
180 8 : l_m_poUnderlyingLayer->GetLayerDefn()->GetGeomFieldIndex(
181 4 : m_osUnderlyingGeometryColumn);
182 4 : if (nUnderlyingLayerGeomFieldIndex < 0)
183 : {
184 0 : CPLError(CE_Failure, CPLE_AppDefined,
185 : "Underlying layer %s for view %s has not expected geometry "
186 : "column name %s",
187 : m_osUnderlyingTableName.c_str(), m_pszViewName,
188 : m_osUnderlyingGeometryColumn.c_str());
189 0 : return CE_Failure;
190 : }
191 :
192 4 : m_bHasSpatialIndex =
193 4 : l_m_poUnderlyingLayer->HasSpatialIndex(nUnderlyingLayerGeomFieldIndex);
194 :
195 : /* -------------------------------------------------------------------- */
196 : /* Get the column definitions for this table. */
197 : /* -------------------------------------------------------------------- */
198 4 : hColStmt = nullptr;
199 4 : const char *pszSQL = CPLSPrintf("SELECT \"%s\", * FROM '%s' LIMIT 1",
200 8 : SQLEscapeName(m_pszFIDColumn).c_str(),
201 : m_pszEscapedTableName);
202 :
203 4 : int rc = sqlite3_prepare_v2(hDB, pszSQL, -1, &hColStmt, nullptr);
204 4 : if (rc != SQLITE_OK)
205 : {
206 0 : CPLError(CE_Failure, CPLE_AppDefined,
207 : "Unable to query table %s for column definitions : %s.",
208 : m_pszViewName, sqlite3_errmsg(hDB));
209 :
210 0 : return CE_Failure;
211 : }
212 :
213 4 : rc = sqlite3_step(hColStmt);
214 4 : if (rc != SQLITE_DONE && rc != SQLITE_ROW)
215 : {
216 0 : CPLError(CE_Failure, CPLE_AppDefined,
217 : "In Initialize(): sqlite3_step(%s):\n %s", pszSQL,
218 : sqlite3_errmsg(hDB));
219 0 : sqlite3_finalize(hColStmt);
220 0 : return CE_Failure;
221 : }
222 :
223 : /* -------------------------------------------------------------------- */
224 : /* Collect the rest of the fields. */
225 : /* -------------------------------------------------------------------- */
226 8 : std::set<CPLString> aosGeomCols;
227 4 : std::set<CPLString> aosIgnoredCols;
228 4 : aosGeomCols.insert(m_osGeomColumn);
229 4 : BuildFeatureDefn(m_pszViewName, false, hColStmt, &aosGeomCols,
230 : aosIgnoredCols);
231 4 : sqlite3_finalize(hColStmt);
232 :
233 : /* -------------------------------------------------------------------- */
234 : /* Set the properties of the geometry column. */
235 : /* -------------------------------------------------------------------- */
236 4 : if (m_poFeatureDefn->GetGeomFieldCount() != 0)
237 : {
238 : OGRSQLiteGeomFieldDefn *poSrcGeomFieldDefn =
239 4 : l_m_poUnderlyingLayer->myGetLayerDefn()->myGetGeomFieldDefn(
240 : nUnderlyingLayerGeomFieldIndex);
241 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
242 4 : m_poFeatureDefn->myGetGeomFieldDefn(0);
243 4 : poGeomFieldDefn->SetType(poSrcGeomFieldDefn->GetType());
244 4 : poGeomFieldDefn->SetSpatialRef(poSrcGeomFieldDefn->GetSpatialRef());
245 4 : poGeomFieldDefn->m_nSRSId = poSrcGeomFieldDefn->m_nSRSId;
246 4 : poGeomFieldDefn->m_eGeomFormat = m_eGeomFormat;
247 : }
248 :
249 4 : return CE_None;
250 : }
251 :
252 : /************************************************************************/
253 : /* ResetStatement() */
254 : /************************************************************************/
255 :
256 4 : OGRErr OGRSQLiteViewLayer::ResetStatement()
257 :
258 : {
259 8 : CPLString osSQL;
260 :
261 4 : ClearStatement();
262 :
263 4 : m_iNextShapeId = 0;
264 :
265 : osSQL.Printf("SELECT \"%s\", * FROM '%s' %s",
266 4 : SQLEscapeName(m_pszFIDColumn).c_str(), m_pszEscapedTableName,
267 4 : m_osWHERE.c_str());
268 :
269 : const int rc =
270 4 : sqlite3_prepare_v2(m_poDS->GetDB(), osSQL,
271 4 : static_cast<int>(osSQL.size()), &m_hStmt, nullptr);
272 :
273 4 : if (rc == SQLITE_OK)
274 : {
275 4 : return OGRERR_NONE;
276 : }
277 :
278 0 : CPLError(CE_Failure, CPLE_AppDefined,
279 : "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 : }
284 :
285 : /************************************************************************/
286 : /* GetNextFeature() */
287 : /************************************************************************/
288 :
289 4 : OGRFeature *OGRSQLiteViewLayer::GetNextFeature()
290 :
291 : {
292 4 : if (HasLayerDefnError())
293 0 : return nullptr;
294 :
295 4 : return OGRSQLiteLayer::GetNextFeature();
296 : }
297 :
298 : /************************************************************************/
299 : /* GetFeature() */
300 : /************************************************************************/
301 :
302 3 : OGRFeature *OGRSQLiteViewLayer::GetFeature(GIntBig nFeatureId)
303 :
304 : {
305 3 : 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 3 : 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 6 : CPLString osSQL;
319 :
320 3 : ClearStatement();
321 :
322 3 : m_iNextShapeId = nFeatureId;
323 :
324 : osSQL.Printf("SELECT \"%s\", * FROM '%s' WHERE \"%s\" = " CPL_FRMT_GIB,
325 3 : SQLEscapeName(m_pszFIDColumn).c_str(), m_pszEscapedTableName,
326 6 : SQLEscapeName(m_pszFIDColumn).c_str(), nFeatureId);
327 :
328 3 : CPLDebug("OGR_SQLITE", "exec(%s)", osSQL.c_str());
329 :
330 : const int rc =
331 3 : sqlite3_prepare_v2(m_poDS->GetDB(), osSQL,
332 3 : static_cast<int>(osSQL.size()), &m_hStmt, nullptr);
333 3 : if (rc != SQLITE_OK)
334 : {
335 0 : CPLError(CE_Failure, CPLE_AppDefined,
336 : "In GetFeature(): sqlite3_prepare_v2(%s):\n %s",
337 0 : osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB()));
338 :
339 0 : return nullptr;
340 : }
341 : /* -------------------------------------------------------------------- */
342 : /* Get the feature if possible. */
343 : /* -------------------------------------------------------------------- */
344 3 : OGRFeature *poFeature = GetNextRawFeature();
345 :
346 3 : ResetReading();
347 :
348 3 : return poFeature;
349 : }
350 :
351 : /************************************************************************/
352 : /* SetAttributeFilter() */
353 : /************************************************************************/
354 :
355 2 : OGRErr OGRSQLiteViewLayer::SetAttributeFilter(const char *pszQuery)
356 :
357 : {
358 2 : if (pszQuery == nullptr)
359 0 : m_osQuery = "";
360 : else
361 2 : m_osQuery = pszQuery;
362 :
363 2 : BuildWhere();
364 :
365 2 : ResetReading();
366 :
367 2 : return OGRERR_NONE;
368 : }
369 :
370 : /************************************************************************/
371 : /* ISetSpatialFilter() */
372 : /************************************************************************/
373 :
374 4 : OGRErr OGRSQLiteViewLayer::ISetSpatialFilter(int, const OGRGeometry *poGeomIn)
375 :
376 : {
377 4 : if (InstallFilter(poGeomIn))
378 : {
379 4 : BuildWhere();
380 :
381 4 : ResetReading();
382 : }
383 4 : return OGRERR_NONE;
384 : }
385 :
386 : /************************************************************************/
387 : /* GetSpatialWhere() */
388 : /************************************************************************/
389 :
390 6 : CPLString OGRSQLiteViewLayer::GetSpatialWhere(int iGeomCol,
391 : OGRGeometry *poFilterGeom)
392 : {
393 12 : if (HasLayerDefnError() || m_poFeatureDefn == nullptr || iGeomCol < 0 ||
394 6 : iGeomCol >= m_poFeatureDefn->GetGeomFieldCount())
395 0 : return "";
396 :
397 6 : if (poFilterGeom != nullptr && m_bHasSpatialIndex)
398 : {
399 3 : OGREnvelope sEnvelope;
400 :
401 3 : poFilterGeom->getEnvelope(&sEnvelope);
402 :
403 : /* We first check that the spatial index table exists */
404 3 : if (!m_bHasCheckedSpatialIndexTable)
405 : {
406 3 : m_bHasCheckedSpatialIndexTable = true;
407 3 : char **papszResult = nullptr;
408 3 : int nRowCount = 0;
409 3 : int nColCount = 0;
410 3 : char *pszErrMsg = nullptr;
411 :
412 6 : CPLString osSQL;
413 : osSQL.Printf(
414 : "SELECT name FROM sqlite_master "
415 : "WHERE name='idx_%s_%s'",
416 : m_pszEscapedUnderlyingTableName,
417 3 : SQLEscapeLiteral(m_osUnderlyingGeometryColumn).c_str());
418 :
419 : int rc =
420 3 : sqlite3_get_table(m_poDS->GetDB(), osSQL.c_str(), &papszResult,
421 : &nRowCount, &nColCount, &pszErrMsg);
422 :
423 3 : if (rc != SQLITE_OK)
424 : {
425 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error: %s", pszErrMsg);
426 0 : sqlite3_free(pszErrMsg);
427 0 : m_bHasSpatialIndex = false;
428 : }
429 : else
430 : {
431 3 : if (nRowCount != 1)
432 : {
433 1 : m_bHasSpatialIndex = false;
434 : }
435 :
436 3 : sqlite3_free_table(papszResult);
437 : }
438 : }
439 :
440 3 : if (m_bHasSpatialIndex)
441 : {
442 : return FormatSpatialFilterFromRTree(
443 : poFilterGeom,
444 2 : CPLSPrintf("\"%s\"", SQLEscapeName(m_pszFIDColumn).c_str()),
445 2 : m_pszEscapedUnderlyingTableName,
446 6 : SQLEscapeLiteral(m_osUnderlyingGeometryColumn).c_str());
447 : }
448 : else
449 : {
450 1 : CPLDebug("SQLITE",
451 : "Count not find idx_%s_%s layer. Disabling spatial index",
452 : m_pszEscapedUnderlyingTableName,
453 : m_osUnderlyingGeometryColumn.c_str());
454 : }
455 : }
456 :
457 4 : if (poFilterGeom != nullptr && m_poDS->IsSpatialiteLoaded())
458 : {
459 : return FormatSpatialFilterFromMBR(
460 : poFilterGeom,
461 4 : SQLEscapeName(
462 2 : m_poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef())
463 2 : .c_str());
464 : }
465 :
466 2 : return "";
467 : }
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 6 : void OGRSQLiteViewLayer::BuildWhere()
477 :
478 : {
479 6 : m_osWHERE = "";
480 :
481 : CPLString osSpatialWHERE =
482 12 : GetSpatialWhere(m_iGeomFieldFilter, m_poFilterGeom);
483 6 : if (!osSpatialWHERE.empty())
484 : {
485 4 : m_osWHERE = "WHERE ";
486 4 : m_osWHERE += osSpatialWHERE;
487 : }
488 :
489 6 : if (!m_osQuery.empty())
490 : {
491 4 : if (m_osWHERE.empty())
492 : {
493 2 : m_osWHERE = "WHERE ";
494 2 : m_osWHERE += m_osQuery;
495 : }
496 : else
497 : {
498 2 : m_osWHERE += " AND (";
499 2 : m_osWHERE += m_osQuery;
500 2 : m_osWHERE += ")";
501 : }
502 : }
503 6 : }
504 :
505 : /************************************************************************/
506 : /* TestCapability() */
507 : /************************************************************************/
508 :
509 3 : int OGRSQLiteViewLayer::TestCapability(const char *pszCap) const
510 :
511 : {
512 3 : if (HasLayerDefnError())
513 0 : return FALSE;
514 :
515 3 : if (EQUAL(pszCap, OLCFastFeatureCount))
516 3 : return m_poFilterGeom == nullptr || m_osGeomColumn.empty() ||
517 3 : m_bHasSpatialIndex;
518 :
519 0 : else if (EQUAL(pszCap, OLCFastSpatialFilter))
520 0 : return m_bHasSpatialIndex;
521 :
522 : else
523 0 : return OGRSQLiteLayer::TestCapability(pszCap);
524 : }
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 3 : GIntBig OGRSQLiteViewLayer::GetFeatureCount(int bForce)
536 :
537 : {
538 3 : if (HasLayerDefnError())
539 0 : return 0;
540 :
541 3 : if (!TestCapability(OLCFastFeatureCount))
542 0 : return OGRSQLiteLayer::GetFeatureCount(bForce);
543 :
544 : /* -------------------------------------------------------------------- */
545 : /* Form count SQL. */
546 : /* -------------------------------------------------------------------- */
547 3 : const char *pszSQL = CPLSPrintf("SELECT count(*) FROM '%s' %s",
548 : m_pszEscapedTableName, m_osWHERE.c_str());
549 :
550 : /* -------------------------------------------------------------------- */
551 : /* Execute. */
552 : /* -------------------------------------------------------------------- */
553 : char **papszResult, *pszErrMsg;
554 : int nRowCount, nColCount;
555 3 : int nResult = -1;
556 :
557 3 : if (sqlite3_get_table(m_poDS->GetDB(), pszSQL, &papszResult, &nColCount,
558 3 : &nRowCount, &pszErrMsg) != SQLITE_OK)
559 0 : return -1;
560 :
561 3 : if (nRowCount == 1 && nColCount == 1)
562 3 : nResult = atoi(papszResult[1]);
563 :
564 3 : sqlite3_free_table(papszResult);
565 :
566 3 : return nResult;
567 : }
|