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