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 : if (m_eGeomFormat != OSGF_None)
247 4 : poGeomFieldDefn->m_eGeomFormat = m_eGeomFormat;
248 : }
249 :
250 4 : return CE_None;
251 : }
252 :
253 : /************************************************************************/
254 : /* ResetStatement() */
255 : /************************************************************************/
256 :
257 4 : OGRErr OGRSQLiteViewLayer::ResetStatement()
258 :
259 : {
260 8 : CPLString osSQL;
261 :
262 4 : ClearStatement();
263 :
264 4 : m_iNextShapeId = 0;
265 :
266 : osSQL.Printf("SELECT \"%s\", * FROM '%s' %s",
267 4 : SQLEscapeName(m_pszFIDColumn).c_str(), m_pszEscapedTableName,
268 4 : m_osWHERE.c_str());
269 :
270 : const int rc =
271 4 : sqlite3_prepare_v2(m_poDS->GetDB(), osSQL,
272 4 : static_cast<int>(osSQL.size()), &m_hStmt, nullptr);
273 :
274 4 : if (rc == SQLITE_OK)
275 : {
276 4 : return OGRERR_NONE;
277 : }
278 :
279 0 : CPLError(CE_Failure, CPLE_AppDefined,
280 : "In ResetStatement(): sqlite3_prepare_v2(%s):\n %s",
281 0 : osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB()));
282 0 : m_hStmt = nullptr;
283 0 : return OGRERR_FAILURE;
284 : }
285 :
286 : /************************************************************************/
287 : /* GetNextFeature() */
288 : /************************************************************************/
289 :
290 4 : OGRFeature *OGRSQLiteViewLayer::GetNextFeature()
291 :
292 : {
293 4 : if (HasLayerDefnError())
294 0 : return nullptr;
295 :
296 4 : return OGRSQLiteLayer::GetNextFeature();
297 : }
298 :
299 : /************************************************************************/
300 : /* GetFeature() */
301 : /************************************************************************/
302 :
303 3 : OGRFeature *OGRSQLiteViewLayer::GetFeature(GIntBig nFeatureId)
304 :
305 : {
306 3 : if (HasLayerDefnError())
307 0 : return nullptr;
308 :
309 : /* -------------------------------------------------------------------- */
310 : /* If we don't have an explicit FID column, just read through */
311 : /* the result set iteratively to find our target. */
312 : /* -------------------------------------------------------------------- */
313 3 : if (m_pszFIDColumn == nullptr)
314 0 : return OGRSQLiteLayer::GetFeature(nFeatureId);
315 :
316 : /* -------------------------------------------------------------------- */
317 : /* Setup explicit query statement to fetch the record we want. */
318 : /* -------------------------------------------------------------------- */
319 6 : CPLString osSQL;
320 :
321 3 : ClearStatement();
322 :
323 3 : m_iNextShapeId = nFeatureId;
324 :
325 : osSQL.Printf("SELECT \"%s\", * FROM '%s' WHERE \"%s\" = " CPL_FRMT_GIB,
326 3 : SQLEscapeName(m_pszFIDColumn).c_str(), m_pszEscapedTableName,
327 6 : SQLEscapeName(m_pszFIDColumn).c_str(), nFeatureId);
328 :
329 3 : CPLDebug("OGR_SQLITE", "exec(%s)", osSQL.c_str());
330 :
331 : const int rc =
332 3 : sqlite3_prepare_v2(m_poDS->GetDB(), osSQL,
333 3 : static_cast<int>(osSQL.size()), &m_hStmt, nullptr);
334 3 : if (rc != SQLITE_OK)
335 : {
336 0 : CPLError(CE_Failure, CPLE_AppDefined,
337 : "In GetFeature(): sqlite3_prepare_v2(%s):\n %s",
338 0 : osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB()));
339 :
340 0 : return nullptr;
341 : }
342 : /* -------------------------------------------------------------------- */
343 : /* Get the feature if possible. */
344 : /* -------------------------------------------------------------------- */
345 3 : OGRFeature *poFeature = GetNextRawFeature();
346 :
347 3 : ResetReading();
348 :
349 3 : return poFeature;
350 : }
351 :
352 : /************************************************************************/
353 : /* SetAttributeFilter() */
354 : /************************************************************************/
355 :
356 2 : OGRErr OGRSQLiteViewLayer::SetAttributeFilter(const char *pszQuery)
357 :
358 : {
359 2 : if (pszQuery == nullptr)
360 0 : m_osQuery = "";
361 : else
362 2 : m_osQuery = pszQuery;
363 :
364 2 : BuildWhere();
365 :
366 2 : ResetReading();
367 :
368 2 : return OGRERR_NONE;
369 : }
370 :
371 : /************************************************************************/
372 : /* ISetSpatialFilter() */
373 : /************************************************************************/
374 :
375 4 : OGRErr OGRSQLiteViewLayer::ISetSpatialFilter(int, const OGRGeometry *poGeomIn)
376 :
377 : {
378 4 : if (InstallFilter(poGeomIn))
379 : {
380 4 : BuildWhere();
381 :
382 4 : ResetReading();
383 : }
384 4 : return OGRERR_NONE;
385 : }
386 :
387 : /************************************************************************/
388 : /* GetSpatialWhere() */
389 : /************************************************************************/
390 :
391 6 : CPLString OGRSQLiteViewLayer::GetSpatialWhere(int iGeomCol,
392 : OGRGeometry *poFilterGeom)
393 : {
394 12 : if (HasLayerDefnError() || m_poFeatureDefn == nullptr || iGeomCol < 0 ||
395 6 : iGeomCol >= m_poFeatureDefn->GetGeomFieldCount())
396 0 : return "";
397 :
398 6 : if (poFilterGeom != nullptr && m_bHasSpatialIndex)
399 : {
400 3 : OGREnvelope sEnvelope;
401 :
402 3 : poFilterGeom->getEnvelope(&sEnvelope);
403 :
404 : /* We first check that the spatial index table exists */
405 3 : if (!m_bHasCheckedSpatialIndexTable)
406 : {
407 3 : m_bHasCheckedSpatialIndexTable = true;
408 3 : char **papszResult = nullptr;
409 3 : int nRowCount = 0;
410 3 : int nColCount = 0;
411 3 : char *pszErrMsg = nullptr;
412 :
413 6 : CPLString osSQL;
414 : osSQL.Printf(
415 : "SELECT name FROM sqlite_master "
416 : "WHERE name='idx_%s_%s'",
417 : m_pszEscapedUnderlyingTableName,
418 3 : SQLEscapeLiteral(m_osUnderlyingGeometryColumn).c_str());
419 :
420 : int rc =
421 3 : sqlite3_get_table(m_poDS->GetDB(), osSQL.c_str(), &papszResult,
422 : &nRowCount, &nColCount, &pszErrMsg);
423 :
424 3 : if (rc != SQLITE_OK)
425 : {
426 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error: %s", pszErrMsg);
427 0 : sqlite3_free(pszErrMsg);
428 0 : m_bHasSpatialIndex = false;
429 : }
430 : else
431 : {
432 3 : if (nRowCount != 1)
433 : {
434 1 : m_bHasSpatialIndex = false;
435 : }
436 :
437 3 : sqlite3_free_table(papszResult);
438 : }
439 : }
440 :
441 3 : if (m_bHasSpatialIndex)
442 : {
443 : return FormatSpatialFilterFromRTree(
444 : poFilterGeom,
445 2 : CPLSPrintf("\"%s\"", SQLEscapeName(m_pszFIDColumn).c_str()),
446 2 : m_pszEscapedUnderlyingTableName,
447 6 : SQLEscapeLiteral(m_osUnderlyingGeometryColumn).c_str());
448 : }
449 : else
450 : {
451 1 : CPLDebug("SQLITE",
452 : "Count not find idx_%s_%s layer. Disabling spatial index",
453 : m_pszEscapedUnderlyingTableName,
454 : m_osUnderlyingGeometryColumn.c_str());
455 : }
456 : }
457 :
458 4 : if (poFilterGeom != nullptr && m_poDS->IsSpatialiteLoaded())
459 : {
460 : return FormatSpatialFilterFromMBR(
461 : poFilterGeom,
462 4 : SQLEscapeName(
463 2 : m_poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef())
464 2 : .c_str());
465 : }
466 :
467 2 : return "";
468 : }
469 :
470 : /************************************************************************/
471 : /* BuildWhere() */
472 : /* */
473 : /* Build the WHERE statement appropriate to the current set of */
474 : /* criteria (spatial and attribute queries). */
475 : /************************************************************************/
476 :
477 6 : void OGRSQLiteViewLayer::BuildWhere()
478 :
479 : {
480 6 : m_osWHERE = "";
481 :
482 : CPLString osSpatialWHERE =
483 12 : GetSpatialWhere(m_iGeomFieldFilter, m_poFilterGeom);
484 6 : if (!osSpatialWHERE.empty())
485 : {
486 4 : m_osWHERE = "WHERE ";
487 4 : m_osWHERE += osSpatialWHERE;
488 : }
489 :
490 6 : if (!m_osQuery.empty())
491 : {
492 4 : if (m_osWHERE.empty())
493 : {
494 2 : m_osWHERE = "WHERE ";
495 2 : m_osWHERE += m_osQuery;
496 : }
497 : else
498 : {
499 2 : m_osWHERE += " AND (";
500 2 : m_osWHERE += m_osQuery;
501 2 : m_osWHERE += ")";
502 : }
503 : }
504 6 : }
505 :
506 : /************************************************************************/
507 : /* TestCapability() */
508 : /************************************************************************/
509 :
510 3 : int OGRSQLiteViewLayer::TestCapability(const char *pszCap) const
511 :
512 : {
513 3 : if (HasLayerDefnError())
514 0 : return FALSE;
515 :
516 3 : if (EQUAL(pszCap, OLCFastFeatureCount))
517 3 : return m_poFilterGeom == nullptr || m_osGeomColumn.empty() ||
518 3 : m_bHasSpatialIndex;
519 :
520 0 : else if (EQUAL(pszCap, OLCFastSpatialFilter))
521 0 : return m_bHasSpatialIndex;
522 :
523 : else
524 0 : return OGRSQLiteLayer::TestCapability(pszCap);
525 : }
526 :
527 : /************************************************************************/
528 : /* GetFeatureCount() */
529 : /* */
530 : /* If a spatial filter is in effect, we turn control over to */
531 : /* the generic counter. Otherwise we return the total count. */
532 : /* Eventually we should consider implementing a more efficient */
533 : /* way of counting features matching a spatial query. */
534 : /************************************************************************/
535 :
536 3 : GIntBig OGRSQLiteViewLayer::GetFeatureCount(int bForce)
537 :
538 : {
539 3 : if (HasLayerDefnError())
540 0 : return 0;
541 :
542 3 : if (!TestCapability(OLCFastFeatureCount))
543 0 : return OGRSQLiteLayer::GetFeatureCount(bForce);
544 :
545 : /* -------------------------------------------------------------------- */
546 : /* Form count SQL. */
547 : /* -------------------------------------------------------------------- */
548 3 : const char *pszSQL = CPLSPrintf("SELECT count(*) FROM '%s' %s",
549 : m_pszEscapedTableName, m_osWHERE.c_str());
550 :
551 : /* -------------------------------------------------------------------- */
552 : /* Execute. */
553 : /* -------------------------------------------------------------------- */
554 : char **papszResult, *pszErrMsg;
555 : int nRowCount, nColCount;
556 3 : int nResult = -1;
557 :
558 3 : if (sqlite3_get_table(m_poDS->GetDB(), pszSQL, &papszResult, &nColCount,
559 3 : &nRowCount, &pszErrMsg) != SQLITE_OK)
560 0 : return -1;
561 :
562 3 : if (nRowCount == 1 && nColCount == 1)
563 3 : nResult = atoi(papszResult[1]);
564 :
565 3 : sqlite3_free_table(papszResult);
566 :
567 3 : return nResult;
568 : }
|