Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: VFK Reader - Data block definition (SQLite)
4 : * Purpose: Implements VFKDataBlockSQLite
5 : * Author: Martin Landa, landa.martin gmail.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2012-2014, Martin Landa <landa.martin gmail.com>
9 : * Copyright (c) 2012-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person
12 : * obtaining a copy of this software and associated documentation
13 : * files (the "Software"), to deal in the Software without
14 : * restriction, including without limitation the rights to use, copy,
15 : * modify, merge, publish, distribute, sublicense, and/or sell copies
16 : * of the Software, and to permit persons to whom the Software is
17 : * furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be
20 : * included in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
26 : * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 : * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28 : * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 : * SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include <algorithm>
33 : #include <limits>
34 : #include <map>
35 : #include <utility>
36 :
37 : #include "vfkreader.h"
38 : #include "vfkreaderp.h"
39 :
40 : #include "cpl_conv.h"
41 : #include "cpl_error.h"
42 :
43 : /*!
44 : \brief VFKDataBlockSQLite constructor
45 : */
46 976 : VFKDataBlockSQLite::VFKDataBlockSQLite(const char *pszName,
47 976 : const IVFKReader *poReader)
48 976 : : IVFKDataBlock(pszName, poReader), m_hStmt(nullptr)
49 : {
50 976 : }
51 :
52 : /*!
53 : \brief Load geometry (point layers)
54 :
55 : \return number of invalid features
56 : */
57 90 : int VFKDataBlockSQLite::LoadGeometryPoint()
58 : {
59 90 : if (LoadGeometryFromDB()) /* try to load geometry from DB */
60 1 : return 0;
61 :
62 252 : const bool bSkipInvalid = EQUAL(m_pszName, "OB") ||
63 148 : EQUAL(m_pszName, "OP") ||
64 59 : EQUAL(m_pszName, "OBBP");
65 :
66 89 : CPLString osSQL;
67 : osSQL.Printf("SELECT SOURADNICE_Y,SOURADNICE_X,%s,rowid FROM %s",
68 89 : FID_COLUMN, m_pszName);
69 :
70 89 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
71 89 : sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
72 :
73 89 : if (poReader->IsSpatial())
74 89 : poReader->ExecuteSQL("BEGIN");
75 :
76 89 : int nGeometries = 0;
77 89 : int nInvalid = 0;
78 271 : while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
79 : {
80 : /* read values */
81 : const double x =
82 182 : -1.0 * sqlite3_column_double(
83 182 : hStmt, 0); /* S-JTSK coordinate system expected */
84 182 : const double y = -1.0 * sqlite3_column_double(hStmt, 1);
85 182 : const GIntBig iFID = sqlite3_column_int64(hStmt, 2);
86 182 : const int rowId = sqlite3_column_int(hStmt, 3);
87 :
88 : VFKFeatureSQLite *poFeature =
89 182 : dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1));
90 182 : if (poFeature == nullptr || poFeature->GetFID() != iFID)
91 : {
92 0 : continue;
93 : }
94 :
95 : /* create geometry */
96 182 : OGRPoint pt(x, y);
97 182 : if (!poFeature->SetGeometry(&pt))
98 : {
99 0 : nInvalid++;
100 0 : continue;
101 : }
102 :
103 : /* store also geometry in DB */
104 364 : if (poReader->IsSpatial() &&
105 182 : SaveGeometryToDB(&pt, rowId) != OGRERR_FAILURE)
106 182 : nGeometries++;
107 : }
108 :
109 : /* update number of geometries in VFK_DB_TABLE table */
110 89 : UpdateVfkBlocks(nGeometries);
111 :
112 89 : if (poReader->IsSpatial())
113 89 : poReader->ExecuteSQL("COMMIT");
114 :
115 89 : return bSkipInvalid ? 0 : nInvalid;
116 : }
117 :
118 : /*!
119 : \brief Set geometry for linestrings
120 :
121 : \param poLine VFK feature
122 : \param oOGRLine line geometry
123 : \param[in,out] bValid true when feature's geometry is valid
124 : \param ftype geometry VFK type
125 : \param[in,out] rowIdFeat list of row ids which forms linestring
126 : \param[in,out] nGeometries number of features with valid geometry
127 : */
128 196 : bool VFKDataBlockSQLite::SetGeometryLineString(VFKFeatureSQLite *poLine,
129 : OGRLineString *oOGRLine,
130 : bool &bValid, const char *ftype,
131 : std::vector<int> &rowIdFeat,
132 : int &nGeometries)
133 : {
134 196 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
135 :
136 196 : oOGRLine->setCoordinateDimension(2); /* force 2D */
137 :
138 : /* check also VFK validity */
139 196 : if (bValid)
140 : {
141 : /* Feature types
142 :
143 : - '3' - line (2 points)
144 : - '4' - linestring (at least 2 points)
145 : - '11' - curve (at least 2 points)
146 : - '15' - circle (3 points)
147 : - '15 r' - circle (center point & radius)
148 : - '16' - arc (3 points)
149 : */
150 :
151 196 : const int npoints = oOGRLine->getNumPoints();
152 196 : if (EQUAL(ftype, "3") && npoints > 2)
153 : {
154 : /* be less pedantic, just inform user about data
155 : * inconsistency
156 :
157 : bValid = false;
158 : */
159 0 : CPLDebug("OGR-VFK",
160 : "Line (fid=" CPL_FRMT_GIB
161 : ") defined by more than two vertices",
162 : poLine->GetFID());
163 : }
164 196 : else if (EQUAL(ftype, "11") && npoints < 2)
165 : {
166 0 : bValid = false;
167 0 : CPLError(CE_Warning, CPLE_AppDefined,
168 : "Curve (fid=" CPL_FRMT_GIB
169 : ") defined by less than two vertices",
170 : poLine->GetFID());
171 : }
172 196 : else if (EQUAL(ftype, "15") && npoints != 3)
173 : {
174 0 : bValid = false;
175 0 : CPLError(CE_Warning, CPLE_AppDefined,
176 : "Circle (fid=" CPL_FRMT_GIB
177 : ") defined by invalid number of vertices (%d)",
178 0 : poLine->GetFID(), oOGRLine->getNumPoints());
179 : }
180 196 : else if (strlen(ftype) > 2 && STARTS_WITH_CI(ftype, "15") &&
181 : npoints != 1)
182 : {
183 0 : bValid = false;
184 0 : CPLError(CE_Warning, CPLE_AppDefined,
185 : "Circle (fid=" CPL_FRMT_GIB
186 : ") defined by invalid number of vertices (%d)",
187 0 : poLine->GetFID(), oOGRLine->getNumPoints());
188 : }
189 196 : else if (EQUAL(ftype, "16") && npoints != 3)
190 : {
191 0 : bValid = false;
192 0 : CPLError(CE_Warning, CPLE_AppDefined,
193 : "Arc (fid=" CPL_FRMT_GIB
194 : ") defined by invalid number of vertices (%d)",
195 0 : poLine->GetFID(), oOGRLine->getNumPoints());
196 : }
197 : }
198 :
199 : /* set geometry (NULL for invalid features) */
200 196 : if (bValid)
201 : {
202 196 : if (!poLine->SetGeometry(oOGRLine, ftype))
203 : {
204 0 : bValid = false;
205 : }
206 : }
207 : else
208 : {
209 0 : poLine->SetGeometry(nullptr);
210 : }
211 :
212 : /* update fid column */
213 196 : UpdateFID(poLine->GetFID(), rowIdFeat);
214 :
215 : /* store also geometry in DB */
216 196 : CPLAssert(!rowIdFeat.empty());
217 392 : if (bValid && poReader->IsSpatial() &&
218 196 : SaveGeometryToDB(poLine->GetGeometry(), rowIdFeat[0]) != OGRERR_FAILURE)
219 : {
220 196 : nGeometries++;
221 : }
222 :
223 196 : rowIdFeat.clear();
224 196 : oOGRLine->empty(); /* restore line */
225 :
226 196 : return bValid;
227 : }
228 :
229 : /*!
230 : \brief Load geometry (linestring SBP layer)
231 :
232 : \return number of invalid features
233 : */
234 15 : int VFKDataBlockSQLite::LoadGeometryLineStringSBP()
235 : {
236 15 : int nInvalid = 0;
237 :
238 : VFKDataBlockSQLite *poDataBlockPoints =
239 15 : (VFKDataBlockSQLite *)m_poReader->GetDataBlock("SOBR");
240 15 : if (nullptr == poDataBlockPoints)
241 : {
242 0 : CPLError(CE_Failure, CPLE_FileIO, "Data block %s not found.\n",
243 : m_pszName);
244 0 : return nInvalid;
245 : }
246 :
247 15 : int nGeometries = 0;
248 15 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
249 :
250 15 : poDataBlockPoints->LoadGeometry();
251 :
252 15 : if (LoadGeometryFromDB()) /* try to load geometry from DB */
253 1 : return 0;
254 :
255 14 : CPLString osSQL;
256 14 : osSQL.Printf("UPDATE %s SET %s = -1", m_pszName, FID_COLUMN);
257 14 : poReader->ExecuteSQL(osSQL.c_str());
258 14 : bool bValid = true;
259 14 : int iIdx = 0;
260 :
261 14 : VFKFeatureSQLite *poLine = nullptr;
262 :
263 42 : for (int i = 0; i < 2; i++)
264 : {
265 : /* first collect linestrings related to HP, OB, DPM and ZVB
266 : then collect rest of linestrings */
267 28 : if (i == 0)
268 : osSQL.Printf(
269 : "SELECT BP_ID,PORADOVE_CISLO_BODU,PARAMETRY_SPOJENI,_rowid_ "
270 : "FROM '%s' WHERE "
271 : "HP_ID IS NOT NULL OR OB_ID IS NOT NULL OR DPM_ID IS NOT NULL "
272 : "OR ZVB_ID IS NOT NULL "
273 : "ORDER BY HP_ID,OB_ID,DPM_ID,ZVB_ID,PORADOVE_CISLO_BODU",
274 14 : m_pszName);
275 : else
276 : osSQL.Printf(
277 : "SELECT BP_ID,PORADOVE_CISLO_BODU,PARAMETRY_SPOJENI,_rowid_ "
278 : "FROM '%s' WHERE "
279 : "OB_ID IS NULL AND HP_ID IS NULL AND DPM_ID IS NULL AND ZVB_ID "
280 : "IS NULL "
281 : "ORDER BY ID,PORADOVE_CISLO_BODU",
282 14 : m_pszName);
283 :
284 28 : sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
285 :
286 28 : if (poReader->IsSpatial())
287 28 : poReader->ExecuteSQL("BEGIN");
288 :
289 56 : std::vector<int> rowIdFeat;
290 56 : CPLString osFType;
291 56 : OGRLineString oOGRLine;
292 :
293 434 : while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
294 : {
295 : // read values
296 406 : const GUIntBig id = sqlite3_column_int64(hStmt, 0);
297 406 : const GUIntBig ipcb = sqlite3_column_int64(hStmt, 1);
298 : const char *pszFType =
299 406 : reinterpret_cast<const char *>(sqlite3_column_text(hStmt, 2));
300 406 : int rowId = sqlite3_column_int(hStmt, 3);
301 :
302 406 : if (ipcb == 1)
303 : {
304 : VFKFeatureSQLite *poFeature =
305 196 : (VFKFeatureSQLite *)GetFeatureByIndex(iIdx);
306 196 : if (poFeature == nullptr)
307 : {
308 0 : CPLError(CE_Failure, CPLE_AppDefined,
309 : "Cannot retrieve feature %d", iIdx);
310 0 : sqlite3_finalize(hStmt);
311 0 : break;
312 : }
313 196 : poFeature->SetRowId(rowId);
314 :
315 : /* set geometry & reset */
316 196 : if (poLine && !SetGeometryLineString(poLine, &oOGRLine, bValid,
317 : osFType.c_str(), rowIdFeat,
318 : nGeometries))
319 : {
320 0 : nInvalid++;
321 : }
322 :
323 196 : bValid = true;
324 196 : poLine = poFeature;
325 196 : osFType = pszFType ? pszFType : "";
326 196 : iIdx++;
327 : }
328 :
329 : VFKFeatureSQLite *poPoint =
330 406 : (VFKFeatureSQLite *)poDataBlockPoints->GetFeature("ID", id);
331 406 : if (poPoint)
332 : {
333 406 : const OGRGeometry *pt = poPoint->GetGeometry();
334 406 : if (pt)
335 : {
336 406 : oOGRLine.addPoint(pt->toPoint());
337 : }
338 : else
339 : {
340 0 : CPLDebug("OGR-VFK",
341 : "Geometry (point ID = " CPL_FRMT_GUIB
342 : ") not valid",
343 : id);
344 0 : bValid = false;
345 : }
346 : }
347 : else
348 : {
349 0 : CPLDebug("OGR-VFK",
350 : "Point ID = " CPL_FRMT_GUIB " not found (rowid = %d)",
351 : id, rowId);
352 0 : bValid = false;
353 : }
354 :
355 : /* add vertex to the linestring */
356 406 : rowIdFeat.push_back(rowId);
357 : }
358 :
359 : /* add last line */
360 42 : if (poLine &&
361 14 : !SetGeometryLineString(poLine, &oOGRLine, bValid, osFType.c_str(),
362 : rowIdFeat, nGeometries))
363 : {
364 0 : nInvalid++;
365 : }
366 28 : poLine = nullptr;
367 :
368 28 : if (poReader->IsSpatial())
369 28 : poReader->ExecuteSQL("COMMIT");
370 : }
371 :
372 : /* update number of geometries in VFK_DB_TABLE table */
373 14 : UpdateVfkBlocks(nGeometries);
374 :
375 14 : return nInvalid;
376 : }
377 :
378 : /*!
379 : \brief Load geometry (linestring HP/DPM/ZVB layer)
380 :
381 : \return number of invalid features
382 : */
383 45 : int VFKDataBlockSQLite::LoadGeometryLineStringHP()
384 : {
385 45 : int nInvalid = 0;
386 45 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
387 :
388 : VFKDataBlockSQLite *poDataBlockLines =
389 45 : (VFKDataBlockSQLite *)m_poReader->GetDataBlock("SBP");
390 45 : if (nullptr == poDataBlockLines)
391 : {
392 0 : CPLError(CE_Failure, CPLE_FileIO, "Data block %s not found.",
393 : m_pszName);
394 0 : return nInvalid;
395 : }
396 :
397 45 : poDataBlockLines->LoadGeometry();
398 :
399 45 : if (LoadGeometryFromDB()) /* try to load geometry from DB */
400 1 : return 0;
401 :
402 88 : CPLString osColumn;
403 44 : osColumn.Printf("%s_ID", m_pszName);
404 44 : const char *vrColumn[2] = {osColumn.c_str(), "PORADOVE_CISLO_BODU"};
405 :
406 44 : GUIntBig vrValue[2] = {0, 1}; // Reduce to first segment.
407 :
408 44 : CPLString osSQL;
409 44 : osSQL.Printf("SELECT ID,%s,rowid FROM %s", FID_COLUMN, m_pszName);
410 : /* TODO: handle points in DPM */
411 44 : if (EQUAL(m_pszName, "DPM"))
412 15 : osSQL += " WHERE SOURADNICE_X IS NULL";
413 44 : sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
414 :
415 44 : if (poReader->IsSpatial())
416 44 : poReader->ExecuteSQL("BEGIN");
417 :
418 44 : int nGeometries = 0;
419 :
420 226 : while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
421 : {
422 : /* read values */
423 182 : vrValue[0] = sqlite3_column_int64(hStmt, 0);
424 182 : const GIntBig iFID = sqlite3_column_int64(hStmt, 1);
425 182 : const int rowId = sqlite3_column_int(hStmt, 2);
426 :
427 : VFKFeatureSQLite *poFeature =
428 182 : (VFKFeatureSQLite *)GetFeatureByIndex(rowId - 1);
429 182 : if (poFeature == nullptr || poFeature->GetFID() != iFID)
430 : {
431 0 : continue;
432 : }
433 :
434 : VFKFeatureSQLite *poLine =
435 182 : poDataBlockLines->GetFeature(vrColumn, vrValue, 2, TRUE);
436 :
437 : const OGRGeometry *poOgrGeometry =
438 182 : poLine ? poLine->GetGeometry() : nullptr;
439 182 : if (!poOgrGeometry || !poFeature->SetGeometry(poOgrGeometry))
440 : {
441 0 : CPLDebug("OGR-VFK",
442 : "VFKDataBlockSQLite::LoadGeometryLineStringHP(): name=%s "
443 : "fid=" CPL_FRMT_GIB " "
444 : "id=" CPL_FRMT_GUIB " -> %s geometry",
445 : m_pszName, iFID, vrValue[0],
446 : poOgrGeometry ? "invalid" : "empty");
447 0 : nInvalid++;
448 0 : continue;
449 : }
450 :
451 : /* store also geometry in DB */
452 364 : if (poReader->IsSpatial() &&
453 182 : SaveGeometryToDB(poOgrGeometry, rowId) != OGRERR_FAILURE)
454 182 : nGeometries++;
455 : }
456 :
457 : /* update number of geometries in VFK_DB_TABLE table */
458 44 : UpdateVfkBlocks(nGeometries);
459 :
460 44 : if (poReader->IsSpatial())
461 44 : poReader->ExecuteSQL("COMMIT");
462 :
463 44 : return nInvalid;
464 : }
465 :
466 : /*!
467 : \brief Load geometry (polygon BUD/PAR layers)
468 :
469 : \return number of invalid features
470 : */
471 30 : int VFKDataBlockSQLite::LoadGeometryPolygon()
472 : {
473 30 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
474 :
475 30 : VFKDataBlockSQLite *poDataBlockLines1 = nullptr;
476 30 : VFKDataBlockSQLite *poDataBlockLines2 = nullptr;
477 30 : bool bIsPar = false;
478 30 : if (EQUAL(m_pszName, "PAR"))
479 : {
480 : poDataBlockLines1 =
481 15 : (VFKDataBlockSQLite *)m_poReader->GetDataBlock("HP");
482 15 : poDataBlockLines2 = poDataBlockLines1;
483 15 : bIsPar = true;
484 : }
485 : else
486 : {
487 : poDataBlockLines1 =
488 15 : (VFKDataBlockSQLite *)m_poReader->GetDataBlock("OB");
489 : poDataBlockLines2 =
490 15 : (VFKDataBlockSQLite *)m_poReader->GetDataBlock("SBP");
491 15 : bIsPar = false;
492 : }
493 30 : if (nullptr == poDataBlockLines1)
494 : {
495 0 : CPLError(CE_Warning, CPLE_FileIO,
496 : "Data block %s not found. Unable to build geometry for %s.",
497 : bIsPar ? "HP" : "OB", m_pszName);
498 0 : return -1;
499 : }
500 30 : if (nullptr == poDataBlockLines2)
501 : {
502 0 : CPLError(CE_Warning, CPLE_FileIO,
503 : "Data block %s not found. Unable to build geometry for %s.",
504 : "SBP", m_pszName);
505 0 : return -1;
506 : }
507 :
508 30 : poDataBlockLines1->LoadGeometry();
509 30 : poDataBlockLines2->LoadGeometry();
510 :
511 30 : if (LoadGeometryFromDB()) // Try to load geometry from DB.
512 1 : return 0;
513 :
514 29 : const char *vrColumn[2] = {nullptr, nullptr};
515 29 : GUIntBig vrValue[2] = {0, 0};
516 29 : if (bIsPar)
517 : {
518 14 : vrColumn[0] = "PAR_ID_1";
519 14 : vrColumn[1] = "PAR_ID_2";
520 : }
521 : else
522 : {
523 15 : vrColumn[0] = "OB_ID";
524 15 : vrColumn[1] = "PORADOVE_CISLO_BODU";
525 15 : vrValue[1] = 1;
526 : }
527 :
528 58 : CPLString osSQL;
529 29 : osSQL.Printf("SELECT ID,%s,rowid FROM %s", FID_COLUMN, m_pszName);
530 29 : sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
531 :
532 29 : if (poReader->IsSpatial())
533 29 : poReader->ExecuteSQL("BEGIN");
534 :
535 58 : VFKFeatureSQLiteList poLineList;
536 : /* first is to be considered as exterior */
537 58 : PointListArray poRingList;
538 58 : std::vector<OGRLinearRing *> poLinearRingList;
539 29 : OGRPolygon ogrPolygon;
540 29 : int nInvalidNoLines = 0;
541 29 : int nInvalidNoRings = 0;
542 29 : int nGeometries = 0;
543 :
544 43 : while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
545 : {
546 : /* read values */
547 14 : const GUIntBig id = sqlite3_column_int64(hStmt, 0);
548 14 : const long iFID = static_cast<long>(sqlite3_column_int64(hStmt, 1));
549 14 : const int rowId = sqlite3_column_int(hStmt, 2);
550 :
551 : VFKFeatureSQLite *poFeature =
552 14 : (VFKFeatureSQLite *)GetFeatureByIndex(rowId - 1);
553 14 : if (poFeature == nullptr || poFeature->GetFID() != iFID)
554 : {
555 0 : continue;
556 : }
557 :
558 14 : if (bIsPar)
559 : {
560 14 : vrValue[0] = vrValue[1] = id;
561 14 : poLineList = poDataBlockLines1->GetFeatures(vrColumn, vrValue, 2);
562 : }
563 : else
564 : {
565 : // std::vector<VFKFeatureSQLite *> poLineListOb;
566 :
567 : osSQL.Printf("SELECT ID FROM %s WHERE BUD_ID = " CPL_FRMT_GUIB,
568 0 : poDataBlockLines1->GetName(), id);
569 0 : if (poReader->IsSpatial())
570 : {
571 0 : CPLString osColumn;
572 :
573 0 : osColumn.Printf(" AND %s IS NULL", GEOM_COLUMN);
574 0 : osSQL += osColumn;
575 : }
576 0 : sqlite3_stmt *hStmtOb = poReader->PrepareStatement(osSQL.c_str());
577 :
578 0 : while (poReader->ExecuteSQL(hStmtOb) == OGRERR_NONE)
579 : {
580 0 : const GUIntBig idOb = sqlite3_column_int64(hStmtOb, 0);
581 0 : vrValue[0] = idOb;
582 : VFKFeatureSQLite *poLineSbp =
583 0 : poDataBlockLines2->GetFeature(vrColumn, vrValue, 2);
584 0 : if (poLineSbp)
585 0 : poLineList.push_back(poLineSbp);
586 : }
587 : }
588 14 : size_t nLines = poLineList.size();
589 14 : if (nLines < 1)
590 : {
591 0 : CPLDebug(
592 : "OGR-VFK",
593 : "%s: unable to collect rings for polygon fid = %ld (no lines)",
594 : m_pszName, iFID);
595 0 : nInvalidNoLines++;
596 0 : continue;
597 : }
598 :
599 : /* clear */
600 14 : ogrPolygon.empty();
601 :
602 : /* free ring list */
603 14 : for (PointListArray::iterator iRing = poRingList.begin(),
604 14 : eRing = poRingList.end();
605 14 : iRing != eRing; ++iRing)
606 : {
607 0 : delete (*iRing);
608 0 : *iRing = nullptr;
609 : }
610 14 : poRingList.clear();
611 :
612 : /* collect rings from lines */
613 : #if 1
614 : // Fast version using a map to identify quickly a ring from its end
615 : // point.
616 14 : std::map<std::pair<double, double>, PointList *> oMapEndRing;
617 28 : while (!poLineList.empty())
618 : {
619 14 : auto pGeom = poLineList.front()->GetGeometry();
620 14 : if (pGeom)
621 : {
622 14 : auto poLine = pGeom->toLineString();
623 14 : if (poLine == nullptr || poLine->getNumPoints() < 2)
624 0 : continue;
625 14 : poLineList.erase(poLineList.begin());
626 14 : PointList *poList = new PointList();
627 14 : FillPointList(poList, poLine);
628 14 : poRingList.emplace_back(poList);
629 28 : OGRPoint oFirst, oLast;
630 14 : poLine->StartPoint(&oFirst);
631 14 : poLine->EndPoint(&oLast);
632 14 : oMapEndRing[std::pair<double, double>(oLast.getX(),
633 28 : oLast.getY())] = poList;
634 :
635 14 : bool bWorkDone = true;
636 182 : while (bWorkDone && (*poList).front() != (*poList).back())
637 : {
638 168 : bWorkDone = false;
639 700 : for (auto oIter = poLineList.begin();
640 1232 : oIter != poLineList.end(); ++oIter)
641 : {
642 700 : const auto &oCandidate = *oIter;
643 700 : auto poCandidateGeom = oCandidate->GetGeometry();
644 700 : if (poCandidateGeom == nullptr)
645 0 : continue;
646 700 : poLine = poCandidateGeom->toLineString();
647 700 : if (poLine == nullptr || poLine->getNumPoints() < 2)
648 0 : continue;
649 700 : poLine->StartPoint(&oFirst);
650 700 : poLine->EndPoint(&oLast);
651 : // MER = MapEndRing
652 : auto oIterMER =
653 0 : oMapEndRing.find(std::pair<double, double>(
654 700 : oFirst.getX(), oFirst.getY()));
655 700 : if (oIterMER != oMapEndRing.end())
656 : {
657 126 : auto ring = oIterMER->second;
658 252 : PointList oList;
659 126 : FillPointList(&oList, poLine);
660 : /* forward, skip first point */
661 252 : ring->insert(ring->end(), oList.begin() + 1,
662 378 : oList.end());
663 126 : poLineList.erase(oIter);
664 126 : oMapEndRing.erase(oIterMER);
665 0 : oMapEndRing[std::pair<double, double>(
666 126 : oLast.getX(), oLast.getY())] = poList;
667 126 : bWorkDone = true;
668 126 : break;
669 : }
670 0 : oIterMER = oMapEndRing.find(std::pair<double, double>(
671 574 : oLast.getX(), oLast.getY()));
672 574 : if (oIterMER != oMapEndRing.end())
673 : {
674 42 : auto ring = oIterMER->second;
675 84 : PointList oList;
676 42 : FillPointList(&oList, poLine);
677 : /* backward, skip first point */
678 42 : ring->insert(ring->end(), oList.rbegin() + 1,
679 84 : oList.rend());
680 42 : poLineList.erase(oIter);
681 42 : oMapEndRing.erase(oIterMER);
682 0 : oMapEndRing[std::pair<double, double>(
683 42 : oFirst.getX(), oFirst.getY())] = ring;
684 42 : bWorkDone = true;
685 42 : break;
686 : }
687 : }
688 : }
689 : }
690 : }
691 : #else
692 : bool bFound = false;
693 : int nCount = 0;
694 : const int nCountMax = static_cast<int>(nLines) * 2;
695 : while (!poLineList.empty() && nCount < nCountMax)
696 : {
697 : bool bNewRing = !bFound;
698 : bFound = false;
699 : int i = 1;
700 : for (VFKFeatureSQLiteList::iterator iHp = poLineList.begin(),
701 : eHp = poLineList.end();
702 : iHp != eHp; ++iHp, ++i)
703 : {
704 : auto pGeom = (*iHp)->GetGeometry();
705 : if (pGeom && AppendLineToRing(&poRingList,
706 : pGeom->toLineString(), bNewRing))
707 : {
708 : bFound = true;
709 : poLineList.erase(iHp);
710 : break;
711 : }
712 : }
713 : nCount++;
714 : }
715 : #endif
716 14 : CPLDebug("OGR-VFK", "%s: fid = %ld nlines = %d -> nrings = %d",
717 14 : m_pszName, iFID, (int)nLines, (int)poRingList.size());
718 :
719 14 : if (!poLineList.empty())
720 : {
721 0 : CPLDebug("OGR-VFK",
722 : "%s: unable to collect rings for polygon fid = %ld",
723 : m_pszName, iFID);
724 0 : nInvalidNoRings++;
725 0 : continue;
726 : }
727 :
728 : /* build rings */
729 14 : poLinearRingList.clear();
730 14 : OGRLinearRing *poOgrRing = nullptr;
731 28 : for (PointListArray::const_iterator iRing = poRingList.begin(),
732 14 : eRing = poRingList.end();
733 42 : iRing != eRing; ++iRing)
734 : {
735 14 : PointList *poList = *iRing;
736 :
737 14 : poLinearRingList.push_back(new OGRLinearRing());
738 14 : poOgrRing = poLinearRingList.back();
739 14 : CPLAssert(nullptr != poOgrRing);
740 :
741 210 : for (PointList::iterator iPoint = poList->begin(),
742 14 : ePoint = poList->end();
743 406 : iPoint != ePoint; ++iPoint)
744 : {
745 196 : OGRPoint *poPoint = &(*iPoint);
746 196 : poOgrRing->addPoint(poPoint);
747 : }
748 : }
749 :
750 : /* find exterior ring */
751 14 : if (poLinearRingList.size() > 1)
752 : {
753 0 : std::vector<OGRLinearRing *>::iterator exteriorRing;
754 :
755 0 : exteriorRing = poLinearRingList.begin();
756 0 : double dMaxArea = -1.0;
757 0 : for (std::vector<OGRLinearRing *>::iterator
758 0 : iRing = poLinearRingList.begin(),
759 0 : eRing = poLinearRingList.end();
760 0 : iRing != eRing; ++iRing)
761 : {
762 0 : poOgrRing = *iRing;
763 0 : if (!IsRingClosed(poOgrRing))
764 0 : continue; /* skip unclosed rings */
765 :
766 0 : const double dArea = poOgrRing->get_Area();
767 0 : if (dArea > dMaxArea)
768 : {
769 0 : dMaxArea = dArea;
770 0 : exteriorRing = iRing;
771 : }
772 : }
773 0 : if (exteriorRing != poLinearRingList.begin())
774 : {
775 0 : std::swap(*poLinearRingList.begin(), *exteriorRing);
776 : }
777 : }
778 :
779 : /* build polygon from rings */
780 14 : int nBridges = 0;
781 14 : for (std::vector<OGRLinearRing *>::iterator
782 14 : iRing = poLinearRingList.begin(),
783 14 : eRing = poLinearRingList.end();
784 28 : iRing != eRing; ++iRing)
785 : {
786 14 : poOgrRing = *iRing;
787 :
788 : /* check if ring is closed */
789 14 : if (IsRingClosed(poOgrRing))
790 : {
791 14 : ogrPolygon.addRing(poOgrRing);
792 : }
793 : else
794 : {
795 0 : if (poOgrRing->getNumPoints() == 2)
796 : {
797 0 : CPLDebug("OGR-VFK",
798 : "%s: Polygon (fid = %ld) bridge removed",
799 : m_pszName, iFID);
800 0 : nBridges++;
801 : }
802 : else
803 : {
804 0 : CPLDebug("OGR-VFK",
805 : "%s: Polygon (fid = %ld) unclosed ring skipped",
806 : m_pszName, iFID);
807 : }
808 : }
809 14 : delete poOgrRing;
810 14 : *iRing = nullptr;
811 : }
812 :
813 : /* set polygon */
814 14 : ogrPolygon.setCoordinateDimension(2); /* force 2D */
815 14 : if (ogrPolygon.getNumInteriorRings() + nBridges !=
816 28 : (int)poLinearRingList.size() - 1 ||
817 14 : !poFeature->SetGeometry(&ogrPolygon))
818 : {
819 0 : nInvalidNoRings++;
820 0 : continue;
821 : }
822 :
823 : /* store also geometry in DB */
824 28 : if (poReader->IsSpatial() &&
825 14 : SaveGeometryToDB(&ogrPolygon, rowId) != OGRERR_FAILURE)
826 14 : nGeometries++;
827 : }
828 :
829 : /* free ring list */
830 43 : for (PointListArray::iterator iRing = poRingList.begin(),
831 29 : eRing = poRingList.end();
832 43 : iRing != eRing; ++iRing)
833 : {
834 14 : delete (*iRing);
835 14 : *iRing = nullptr;
836 : }
837 :
838 29 : CPLDebug("OGR-VFK", "%s: nolines = %d norings = %d", m_pszName,
839 : nInvalidNoLines, nInvalidNoRings);
840 :
841 : /* update number of geometries in VFK_DB_TABLE table */
842 29 : UpdateVfkBlocks(nGeometries);
843 :
844 29 : if (poReader->IsSpatial())
845 29 : poReader->ExecuteSQL("COMMIT");
846 :
847 29 : return nInvalidNoLines + nInvalidNoRings;
848 : }
849 :
850 : /*!
851 : \brief Get feature by FID
852 :
853 : Modifies next feature id.
854 :
855 : \param nFID feature id
856 :
857 : \return pointer to feature definition or NULL on failure (not found)
858 : */
859 0 : IVFKFeature *VFKDataBlockSQLite::GetFeature(GIntBig nFID)
860 : {
861 0 : if (m_nFeatureCount < 0)
862 : {
863 0 : m_poReader->ReadDataRecords(this);
864 : }
865 :
866 0 : if (nFID < 1 || nFID > m_nFeatureCount)
867 0 : return nullptr;
868 :
869 0 : if (m_bGeometryPerBlock && !m_bGeometry)
870 : {
871 0 : LoadGeometry();
872 : }
873 :
874 0 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
875 :
876 0 : CPLString osSQL;
877 : osSQL.Printf("SELECT rowid FROM %s WHERE %s = " CPL_FRMT_GIB, m_pszName,
878 0 : FID_COLUMN, nFID);
879 0 : if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG"))
880 : {
881 0 : osSQL += " AND PORADOVE_CISLO_BODU = 1";
882 : }
883 0 : sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
884 :
885 0 : int rowId = -1;
886 0 : if (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
887 : {
888 0 : rowId = sqlite3_column_int(hStmt, 0);
889 : }
890 0 : sqlite3_finalize(hStmt);
891 :
892 0 : return GetFeatureByIndex(rowId - 1);
893 : }
894 :
895 : /*!
896 : \brief Get first found feature based on its property
897 :
898 : \param column property name
899 : \param value property value
900 : \param bGeom True to check also geometry != NULL
901 :
902 : \return pointer to feature definition or NULL on failure (not found)
903 : */
904 406 : VFKFeatureSQLite *VFKDataBlockSQLite::GetFeature(const char *column,
905 : GUIntBig value, bool bGeom)
906 : {
907 406 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
908 :
909 812 : CPLString osSQL;
910 : osSQL.Printf("SELECT %s from %s WHERE %s = " CPL_FRMT_GUIB, FID_COLUMN,
911 406 : m_pszName, column, value);
912 406 : if (bGeom)
913 : {
914 0 : CPLString osColumn;
915 :
916 0 : osColumn.Printf(" AND %s IS NOT NULL", GEOM_COLUMN);
917 0 : osSQL += osColumn;
918 : }
919 :
920 406 : sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
921 406 : if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
922 0 : return nullptr;
923 :
924 406 : const int idx = sqlite3_column_int(hStmt, 0) - 1;
925 406 : sqlite3_finalize(hStmt);
926 :
927 406 : if (idx < 0 || idx >= m_nFeatureCount) // ? assert
928 0 : return nullptr;
929 :
930 406 : return (VFKFeatureSQLite *)GetFeatureByIndex(idx);
931 : }
932 :
933 : /*!
934 : \brief Get first found feature based on its properties (AND)
935 :
936 : \param column array of property names
937 : \param value array of property values
938 : \param num number of array items
939 : \param bGeom True to check also geometry != NULL
940 :
941 : \return pointer to feature definition or NULL on failure (not found)
942 : */
943 182 : VFKFeatureSQLite *VFKDataBlockSQLite::GetFeature(const char **column,
944 : GUIntBig *value, int num,
945 : bool bGeom)
946 : {
947 182 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
948 :
949 364 : CPLString osSQL;
950 182 : osSQL.Printf("SELECT %s FROM %s WHERE ", FID_COLUMN, m_pszName);
951 :
952 364 : CPLString osItem;
953 546 : for (int i = 0; i < num; i++)
954 : {
955 364 : if (i > 0)
956 182 : osItem.Printf(" AND %s = " CPL_FRMT_GUIB, column[i], value[i]);
957 : else
958 182 : osItem.Printf("%s = " CPL_FRMT_GUIB, column[i], value[i]);
959 364 : osSQL += osItem;
960 : }
961 182 : if (bGeom)
962 : {
963 182 : osItem.Printf(" AND %s IS NOT NULL", GEOM_COLUMN);
964 182 : osSQL += osItem;
965 : }
966 :
967 182 : sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
968 182 : if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
969 0 : return nullptr;
970 :
971 182 : int idx = sqlite3_column_int(hStmt, 0) - 1; /* rowid starts at 1 */
972 182 : sqlite3_finalize(hStmt);
973 :
974 182 : if (idx < 0 || idx >= m_nFeatureCount) // ? assert
975 0 : return nullptr;
976 :
977 182 : return (VFKFeatureSQLite *)GetFeatureByIndex(idx);
978 : }
979 :
980 : /*!
981 : \brief Get features based on properties
982 :
983 : \param column array of property names
984 : \param value array of property values
985 : \param num number of array items
986 :
987 : \return list of features
988 : */
989 14 : VFKFeatureSQLiteList VFKDataBlockSQLite::GetFeatures(const char **column,
990 : GUIntBig *value, int num)
991 : {
992 14 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
993 :
994 28 : CPLString osItem;
995 28 : CPLString osSQL;
996 14 : osSQL.Printf("SELECT rowid from %s WHERE ", m_pszName);
997 42 : for (int i = 0; i < num; i++)
998 : {
999 28 : if (i > 0)
1000 14 : osItem.Printf(" OR %s = " CPL_FRMT_GUIB, column[i], value[i]);
1001 : else
1002 14 : osItem.Printf("%s = " CPL_FRMT_GUIB, column[i], value[i]);
1003 28 : osSQL += osItem;
1004 : }
1005 14 : osSQL += " ORDER BY ";
1006 14 : osSQL += FID_COLUMN;
1007 :
1008 28 : VFKFeatureSQLiteList fList;
1009 :
1010 14 : sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
1011 196 : while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
1012 : {
1013 182 : const int iRowId = sqlite3_column_int(hStmt, 0);
1014 : VFKFeatureSQLite *poFeature =
1015 182 : dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(iRowId - 1));
1016 182 : if (poFeature == nullptr)
1017 : {
1018 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot retrieve feature %d",
1019 : iRowId);
1020 0 : sqlite3_finalize(hStmt);
1021 0 : return VFKFeatureSQLiteList();
1022 : }
1023 182 : fList.push_back(poFeature);
1024 : }
1025 :
1026 14 : return fList;
1027 : }
1028 :
1029 : /*!
1030 : \brief Save geometry to DB (as WKB)
1031 :
1032 : \param poGeom pointer to OGRGeometry to be saved
1033 : \param iRowId row id to update
1034 :
1035 : \return OGRERR_NONE on success otherwise OGRERR_FAILURE
1036 : */
1037 574 : OGRErr VFKDataBlockSQLite::SaveGeometryToDB(const OGRGeometry *poGeom,
1038 : int iRowId)
1039 : {
1040 : int rc;
1041 1148 : CPLString osSQL;
1042 :
1043 574 : sqlite3_stmt *hStmt = nullptr;
1044 :
1045 574 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
1046 :
1047 : /* check if geometry column exists (see SUPPRESS_GEOMETRY open
1048 : option) */
1049 574 : if (AddGeometryColumn() != OGRERR_NONE)
1050 0 : return OGRERR_FAILURE;
1051 :
1052 574 : if (poGeom)
1053 : {
1054 574 : const size_t nWKBLen = poGeom->WkbSize();
1055 574 : if (nWKBLen > static_cast<size_t>(std::numeric_limits<int>::max()))
1056 : {
1057 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too large geometry");
1058 0 : return OGRERR_FAILURE;
1059 : }
1060 574 : GByte *pabyWKB = (GByte *)VSI_MALLOC_VERBOSE(nWKBLen);
1061 574 : if (pabyWKB)
1062 : {
1063 574 : poGeom->exportToWkb(wkbNDR, pabyWKB);
1064 :
1065 : osSQL.Printf("UPDATE %s SET %s = ? WHERE rowid = %d", m_pszName,
1066 574 : GEOM_COLUMN, iRowId);
1067 574 : hStmt = poReader->PrepareStatement(osSQL.c_str());
1068 :
1069 574 : rc = sqlite3_bind_blob(hStmt, 1, pabyWKB, static_cast<int>(nWKBLen),
1070 : CPLFree);
1071 574 : if (rc != SQLITE_OK)
1072 : {
1073 0 : sqlite3_finalize(hStmt);
1074 0 : CPLError(CE_Failure, CPLE_AppDefined,
1075 : "Storing geometry in DB failed");
1076 0 : return OGRERR_FAILURE;
1077 : }
1078 : }
1079 : }
1080 : else
1081 : { /* invalid */
1082 : osSQL.Printf("UPDATE %s SET %s = NULL WHERE rowid = %d", m_pszName,
1083 0 : GEOM_COLUMN, iRowId);
1084 0 : hStmt = poReader->PrepareStatement(osSQL.c_str());
1085 : }
1086 :
1087 574 : return poReader->ExecuteSQL(hStmt); /* calls sqlite3_finalize() */
1088 : }
1089 :
1090 : /*!
1091 : \brief Load geometry from DB
1092 :
1093 : \return true if geometry successfully loaded otherwise false
1094 : */
1095 180 : bool VFKDataBlockSQLite::LoadGeometryFromDB()
1096 : {
1097 180 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
1098 :
1099 180 : if (!poReader->IsSpatial()) /* check if DB is spatial */
1100 0 : return false;
1101 :
1102 360 : CPLString osSQL;
1103 : osSQL.Printf("SELECT num_geometries FROM %s WHERE table_name = '%s'",
1104 180 : VFK_DB_TABLE, m_pszName);
1105 180 : sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
1106 180 : if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
1107 0 : return false;
1108 180 : const int nGeometries = sqlite3_column_int(hStmt, 0);
1109 180 : sqlite3_finalize(hStmt);
1110 :
1111 180 : if (nGeometries < 1)
1112 176 : return false;
1113 :
1114 12 : const bool bSkipInvalid = EQUAL(m_pszName, "OB") ||
1115 8 : EQUAL(m_pszName, "OP") ||
1116 4 : EQUAL(m_pszName, "OBBP");
1117 :
1118 : /* load geometry from DB */
1119 : osSQL.Printf("SELECT %s,rowid,%s FROM %s ", GEOM_COLUMN, FID_COLUMN,
1120 4 : m_pszName);
1121 4 : if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG"))
1122 1 : osSQL += "WHERE PORADOVE_CISLO_BODU = 1 ";
1123 4 : osSQL += "ORDER BY ";
1124 4 : osSQL += FID_COLUMN;
1125 4 : hStmt = poReader->PrepareStatement(osSQL.c_str());
1126 :
1127 4 : int rowId = 0;
1128 4 : int nInvalid = 0;
1129 4 : int nGeometriesCount = 0;
1130 :
1131 45 : while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
1132 : {
1133 41 : rowId++; // =sqlite3_column_int(hStmt, 1);
1134 41 : const GIntBig iFID = sqlite3_column_int64(hStmt, 2);
1135 : VFKFeatureSQLite *poFeature =
1136 41 : dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1));
1137 41 : if (poFeature == nullptr || poFeature->GetFID() != iFID)
1138 : {
1139 0 : continue;
1140 : }
1141 :
1142 : // read geometry from DB
1143 41 : const int nBytes = sqlite3_column_bytes(hStmt, 0);
1144 41 : OGRGeometry *poGeometry = nullptr;
1145 41 : if (nBytes > 0 && OGRGeometryFactory::createFromWkb(
1146 : sqlite3_column_blob(hStmt, 0), nullptr,
1147 : &poGeometry, nBytes) == OGRERR_NONE)
1148 : {
1149 41 : nGeometriesCount++;
1150 41 : if (!poFeature->SetGeometry(poGeometry))
1151 : {
1152 0 : nInvalid++;
1153 : }
1154 41 : delete poGeometry;
1155 : }
1156 : else
1157 : {
1158 0 : nInvalid++;
1159 : }
1160 : }
1161 :
1162 4 : CPLDebug("OGR-VFK", "%s: %d geometries loaded from DB", m_pszName,
1163 : nGeometriesCount);
1164 :
1165 4 : if (nGeometriesCount != nGeometries)
1166 : {
1167 0 : CPLError(CE_Warning, CPLE_AppDefined,
1168 : "%s: %d geometries loaded (should be %d)", m_pszName,
1169 : nGeometriesCount, nGeometries);
1170 : }
1171 :
1172 4 : if (nInvalid > 0 && !bSkipInvalid)
1173 : {
1174 0 : CPLError(CE_Warning, CPLE_AppDefined,
1175 : "%s: %d features with invalid or empty geometry", m_pszName,
1176 : nInvalid);
1177 : }
1178 :
1179 4 : return true;
1180 : }
1181 :
1182 : /*!
1183 : \brief Update VFK_DB_TABLE table
1184 :
1185 : \param nGeometries number of geometries to update
1186 : */
1187 176 : void VFKDataBlockSQLite::UpdateVfkBlocks(int nGeometries)
1188 : {
1189 352 : CPLString osSQL;
1190 :
1191 176 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
1192 :
1193 : /* update number of features in VFK_DB_TABLE table */
1194 176 : const int nFeatCount = (int)GetFeatureCount();
1195 176 : if (nFeatCount > 0)
1196 : {
1197 : osSQL.Printf("UPDATE %s SET num_features = %d WHERE table_name = '%s'",
1198 56 : VFK_DB_TABLE, nFeatCount, m_pszName);
1199 56 : poReader->ExecuteSQL(osSQL.c_str());
1200 : }
1201 :
1202 : /* update number of geometries in VFK_DB_TABLE table */
1203 176 : if (nGeometries > 0)
1204 : {
1205 56 : CPLDebug("OGR-VFK",
1206 : "VFKDataBlockSQLite::UpdateVfkBlocks(): name=%s -> "
1207 : "%d geometries saved to internal DB",
1208 : m_pszName, nGeometries);
1209 :
1210 : osSQL.Printf(
1211 : "UPDATE %s SET num_geometries = %d WHERE table_name = '%s'",
1212 56 : VFK_DB_TABLE, nGeometries, m_pszName);
1213 56 : poReader->ExecuteSQL(osSQL.c_str());
1214 : }
1215 176 : }
1216 :
1217 : /*!
1218 : \brief Update feature id (see SBP)
1219 :
1220 : \param iFID feature id to set up
1221 : \param rowId list of rows to update
1222 : */
1223 196 : void VFKDataBlockSQLite::UpdateFID(GIntBig iFID, const std::vector<int> &rowId)
1224 : {
1225 392 : CPLString osSQL, osValue;
1226 196 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
1227 :
1228 : /* update number of geometries in VFK_DB_TABLE table */
1229 : osSQL.Printf("UPDATE %s SET %s = " CPL_FRMT_GIB " WHERE rowid IN (",
1230 196 : m_pszName, FID_COLUMN, iFID);
1231 602 : for (size_t i = 0; i < rowId.size(); i++)
1232 : {
1233 406 : if (i > 0)
1234 210 : osValue.Printf(",%d", rowId[i]);
1235 : else
1236 196 : osValue.Printf("%d", rowId[i]);
1237 406 : osSQL += osValue;
1238 : }
1239 196 : osSQL += ")";
1240 :
1241 196 : poReader->ExecuteSQL(osSQL.c_str());
1242 196 : }
1243 :
1244 : /*!
1245 : \brief Check is ring is closed
1246 :
1247 : \param poRing pointer to OGRLinearRing to check
1248 :
1249 : \return true if closed otherwise false
1250 : */
1251 14 : bool VFKDataBlockSQLite::IsRingClosed(const OGRLinearRing *poRing)
1252 : {
1253 14 : const int nPoints = poRing->getNumPoints();
1254 14 : if (nPoints < 3)
1255 0 : return false;
1256 :
1257 28 : if (poRing->getX(0) == poRing->getX(nPoints - 1) &&
1258 14 : poRing->getY(0) == poRing->getY(nPoints - 1))
1259 14 : return true;
1260 :
1261 0 : return false;
1262 : }
1263 :
1264 : /*!
1265 : \brief Get primary key
1266 :
1267 : \return property name or NULL
1268 : */
1269 168 : const char *VFKDataBlockSQLite::GetKey() const
1270 : {
1271 168 : if (GetPropertyCount() > 1)
1272 : {
1273 168 : const VFKPropertyDefn *poPropDefn = GetProperty(0);
1274 168 : const char *pszKey = poPropDefn->GetName();
1275 168 : if (EQUAL(pszKey, "ID"))
1276 168 : return pszKey;
1277 : }
1278 :
1279 0 : return nullptr;
1280 : }
1281 :
1282 : /*!
1283 : \brief Get geometry SQL type (for geometry_columns table)
1284 :
1285 : \return geometry_type as integer
1286 : */
1287 915 : int VFKDataBlockSQLite::GetGeometrySQLType() const
1288 : {
1289 915 : if (m_nGeometryType == wkbPolygon)
1290 28 : return 3;
1291 887 : else if (m_nGeometryType == wkbLineString)
1292 56 : return 2;
1293 831 : else if (m_nGeometryType == wkbPoint)
1294 84 : return 1;
1295 :
1296 747 : return 0; /* unknown geometry type */
1297 : }
1298 :
1299 : /*!
1300 : \brief Add geometry column into table if not exists
1301 :
1302 : \return OGRERR_NONE on success otherwise OGRERR_FAILURE
1303 : */
1304 586 : OGRErr VFKDataBlockSQLite::AddGeometryColumn() const
1305 : {
1306 1172 : CPLString osSQL;
1307 :
1308 586 : VFKReaderSQLite *poReader = (VFKReaderSQLite *)m_poReader;
1309 :
1310 586 : osSQL.Printf("SELECT %s FROM %s LIMIT 0", GEOM_COLUMN, m_pszName);
1311 586 : if (poReader->ExecuteSQL(osSQL.c_str(), CE_None) == OGRERR_FAILURE)
1312 : {
1313 : /* query failed, we assume that geometry column not exists */
1314 0 : osSQL.Printf("ALTER TABLE %s ADD COLUMN %s blob", m_pszName,
1315 0 : GEOM_COLUMN);
1316 0 : return poReader->ExecuteSQL(osSQL.c_str());
1317 : }
1318 :
1319 586 : return OGRERR_NONE;
1320 : }
1321 :
1322 : /*!
1323 : \brief Load feature properties
1324 :
1325 : Used for sequential access, see OGRVFKLayer:GetNextFeature().
1326 :
1327 : \return OGRERR_NONE on success otherwise OGRERR_FAILURE
1328 : */
1329 4 : OGRErr VFKDataBlockSQLite::LoadProperties()
1330 : {
1331 8 : CPLString osSQL;
1332 :
1333 4 : if (m_hStmt)
1334 0 : sqlite3_finalize(m_hStmt);
1335 :
1336 : osSQL.Printf("SELECT * FROM %s", // TODO: where
1337 4 : m_pszName);
1338 4 : if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG"))
1339 0 : osSQL += " WHERE PORADOVE_CISLO_BODU = 1";
1340 :
1341 4 : m_hStmt = ((VFKReaderSQLite *)m_poReader)->PrepareStatement(osSQL.c_str());
1342 :
1343 4 : if (m_hStmt == nullptr)
1344 0 : return OGRERR_FAILURE;
1345 :
1346 4 : return OGRERR_NONE;
1347 : }
1348 :
1349 : /*
1350 : \brief Clean feature properties for a next run
1351 :
1352 : \return OGRERR_NONE on success otherwise OGRERR_FAILURE
1353 : */
1354 979 : OGRErr VFKDataBlockSQLite::CleanProperties()
1355 : {
1356 979 : if (m_hStmt)
1357 : {
1358 4 : if (sqlite3_finalize(m_hStmt) != SQLITE_OK)
1359 : {
1360 0 : m_hStmt = nullptr;
1361 0 : return OGRERR_FAILURE;
1362 : }
1363 4 : m_hStmt = nullptr;
1364 : }
1365 :
1366 979 : return OGRERR_NONE;
1367 : }
|