/src/gdal/ogr/ogrsf_frmts/vfk/vfkdatablocksqlite.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | VFKDataBlockSQLite::VFKDataBlockSQLite(const char *pszName, |
29 | | const IVFKReader *poReader) |
30 | 10.3k | : IVFKDataBlock(pszName, poReader), m_hStmt(nullptr) |
31 | 10.3k | { |
32 | 10.3k | } |
33 | | |
34 | | /*! |
35 | | \brief Load geometry (point layers) |
36 | | |
37 | | \return number of invalid features |
38 | | */ |
39 | | int VFKDataBlockSQLite::LoadGeometryPoint() |
40 | 498 | { |
41 | 498 | if (LoadGeometryFromDB()) /* try to load geometry from DB */ |
42 | 97 | return 0; |
43 | | |
44 | 401 | const bool bSkipInvalid = EQUAL(m_pszName, "OB") || |
45 | 401 | EQUAL(m_pszName, "OP") || |
46 | 401 | EQUAL(m_pszName, "OBBP"); |
47 | | |
48 | 401 | CPLString osSQL; |
49 | 401 | osSQL.Printf("SELECT SOURADNICE_Y,SOURADNICE_X,%s,rowid FROM %s", |
50 | 401 | FID_COLUMN, m_pszName); |
51 | | |
52 | 401 | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
53 | 401 | sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str()); |
54 | | |
55 | 401 | if (poReader->IsSpatial()) |
56 | 401 | poReader->ExecuteSQL("BEGIN"); |
57 | | |
58 | 401 | int nGeometries = 0; |
59 | 401 | int nInvalid = 0; |
60 | 11.3k | while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE) |
61 | 10.9k | { |
62 | | /* read values */ |
63 | 10.9k | const double x = |
64 | 10.9k | -1.0 * sqlite3_column_double( |
65 | 10.9k | hStmt, 0); /* S-JTSK coordinate system expected */ |
66 | 10.9k | const double y = -1.0 * sqlite3_column_double(hStmt, 1); |
67 | 10.9k | const GIntBig iFID = sqlite3_column_int64(hStmt, 2); |
68 | 10.9k | const int rowId = sqlite3_column_int(hStmt, 3); |
69 | | |
70 | 10.9k | VFKFeatureSQLite *poFeature = |
71 | 10.9k | dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1)); |
72 | 10.9k | if (poFeature == nullptr || poFeature->GetFID() != iFID) |
73 | 26 | { |
74 | 26 | continue; |
75 | 26 | } |
76 | | |
77 | | /* create geometry */ |
78 | 10.9k | OGRPoint pt(x, y); |
79 | 10.9k | if (!poFeature->SetGeometry(&pt)) |
80 | 1.63k | { |
81 | 1.63k | nInvalid++; |
82 | 1.63k | continue; |
83 | 1.63k | } |
84 | | |
85 | | /* store also geometry in DB */ |
86 | 9.29k | if (poReader->IsSpatial() && |
87 | 9.29k | SaveGeometryToDB(&pt, rowId) != OGRERR_FAILURE) |
88 | 9.29k | nGeometries++; |
89 | 9.29k | } |
90 | | |
91 | | /* update number of geometries in VFK_DB_TABLE table */ |
92 | 401 | UpdateVfkBlocks(nGeometries); |
93 | | |
94 | 401 | if (poReader->IsSpatial()) |
95 | 401 | poReader->ExecuteSQL("COMMIT"); |
96 | | |
97 | 401 | return bSkipInvalid ? 0 : nInvalid; |
98 | 498 | } |
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 | | bool VFKDataBlockSQLite::SetGeometryLineString(VFKFeatureSQLite *poLine, |
111 | | OGRLineString *oOGRLine, |
112 | | bool &bValid, const char *ftype, |
113 | | std::vector<int> &rowIdFeat, |
114 | | int &nGeometries) |
115 | 5.24k | { |
116 | 5.24k | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
117 | | |
118 | 5.24k | oOGRLine->setCoordinateDimension(2); /* force 2D */ |
119 | | |
120 | | /* check also VFK validity */ |
121 | 5.24k | if (bValid) |
122 | 2.91k | { |
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 | 2.91k | const int npoints = oOGRLine->getNumPoints(); |
134 | 2.91k | if (EQUAL(ftype, "3") && npoints > 2) |
135 | 1 | { |
136 | | /* be less pedantic, just inform user about data |
137 | | * inconsistency |
138 | | |
139 | | bValid = false; |
140 | | */ |
141 | 1 | CPLDebug("OGR-VFK", |
142 | 1 | "Line (fid=" CPL_FRMT_GIB |
143 | 1 | ") defined by more than two vertices", |
144 | 1 | poLine->GetFID()); |
145 | 1 | } |
146 | 2.90k | else if (EQUAL(ftype, "11") && npoints < 2) |
147 | 0 | { |
148 | 0 | bValid = false; |
149 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
150 | 0 | "Curve (fid=" CPL_FRMT_GIB |
151 | 0 | ") defined by less than two vertices", |
152 | 0 | poLine->GetFID()); |
153 | 0 | } |
154 | 2.90k | else if (EQUAL(ftype, "15") && npoints != 3) |
155 | 0 | { |
156 | 0 | bValid = false; |
157 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
158 | 0 | "Circle (fid=" CPL_FRMT_GIB |
159 | 0 | ") defined by invalid number of vertices (%d)", |
160 | 0 | poLine->GetFID(), oOGRLine->getNumPoints()); |
161 | 0 | } |
162 | 2.90k | else if (strlen(ftype) > 2 && STARTS_WITH_CI(ftype, "15") && |
163 | 2.90k | npoints != 1) |
164 | 0 | { |
165 | 0 | bValid = false; |
166 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
167 | 0 | "Circle (fid=" CPL_FRMT_GIB |
168 | 0 | ") defined by invalid number of vertices (%d)", |
169 | 0 | poLine->GetFID(), oOGRLine->getNumPoints()); |
170 | 0 | } |
171 | 2.90k | else if (EQUAL(ftype, "16") && npoints != 3) |
172 | 130 | { |
173 | 130 | bValid = false; |
174 | 130 | CPLError(CE_Warning, CPLE_AppDefined, |
175 | 130 | "Arc (fid=" CPL_FRMT_GIB |
176 | 130 | ") defined by invalid number of vertices (%d)", |
177 | 130 | poLine->GetFID(), oOGRLine->getNumPoints()); |
178 | 130 | } |
179 | 2.91k | } |
180 | | |
181 | | /* set geometry (NULL for invalid features) */ |
182 | 5.24k | if (bValid) |
183 | 2.78k | { |
184 | 2.78k | if (!poLine->SetGeometry(oOGRLine, ftype)) |
185 | 2.63k | { |
186 | 2.63k | bValid = false; |
187 | 2.63k | } |
188 | 2.78k | } |
189 | 2.46k | else |
190 | 2.46k | { |
191 | 2.46k | poLine->SetGeometry(nullptr); |
192 | 2.46k | } |
193 | | |
194 | | /* update fid column */ |
195 | 5.24k | UpdateFID(poLine->GetFID(), rowIdFeat); |
196 | | |
197 | | /* store also geometry in DB */ |
198 | 5.24k | CPLAssert(!rowIdFeat.empty()); |
199 | 5.24k | if (bValid && poReader->IsSpatial() && |
200 | 5.24k | SaveGeometryToDB(poLine->GetGeometry(), rowIdFeat[0]) != OGRERR_FAILURE) |
201 | 149 | { |
202 | 149 | nGeometries++; |
203 | 149 | } |
204 | | |
205 | 5.24k | rowIdFeat.clear(); |
206 | 5.24k | oOGRLine->empty(); /* restore line */ |
207 | | |
208 | 5.24k | return bValid; |
209 | 5.24k | } |
210 | | |
211 | | /*! |
212 | | \brief Load geometry (linestring SBP layer) |
213 | | |
214 | | \return number of invalid features |
215 | | */ |
216 | | int VFKDataBlockSQLite::LoadGeometryLineStringSBP() |
217 | 342 | { |
218 | 342 | int nInvalid = 0; |
219 | | |
220 | 342 | VFKDataBlockSQLite *poDataBlockPoints = |
221 | 342 | cpl::down_cast<VFKDataBlockSQLite *>(m_poReader->GetDataBlock("SOBR")); |
222 | 342 | if (nullptr == poDataBlockPoints) |
223 | 125 | { |
224 | 125 | CPLError(CE_Failure, CPLE_FileIO, "Data block %s not found.\n", |
225 | 125 | m_pszName); |
226 | 125 | return nInvalid; |
227 | 125 | } |
228 | | |
229 | 217 | int nGeometries = 0; |
230 | 217 | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
231 | | |
232 | 217 | poDataBlockPoints->LoadGeometry(); |
233 | | |
234 | 217 | if (LoadGeometryFromDB()) /* try to load geometry from DB */ |
235 | 34 | return 0; |
236 | | |
237 | 183 | CPLString osSQL; |
238 | 183 | osSQL.Printf("UPDATE %s SET %s = -1", m_pszName, FID_COLUMN); |
239 | 183 | poReader->ExecuteSQL(osSQL.c_str()); |
240 | 183 | bool bValid = true; |
241 | 183 | int iIdx = 0; |
242 | | |
243 | 183 | VFKFeatureSQLite *poLine = nullptr; |
244 | | |
245 | 549 | for (int i = 0; i < 2; i++) |
246 | 366 | { |
247 | | /* first collect linestrings related to HP, OB, DPM and ZVB |
248 | | then collect rest of linestrings */ |
249 | 366 | if (i == 0) |
250 | 183 | osSQL.Printf( |
251 | 183 | "SELECT BP_ID,PORADOVE_CISLO_BODU,PARAMETRY_SPOJENI,_rowid_ " |
252 | 183 | "FROM '%s' WHERE " |
253 | 183 | "HP_ID IS NOT NULL OR OB_ID IS NOT NULL OR DPM_ID IS NOT NULL " |
254 | 183 | "OR ZVB_ID IS NOT NULL " |
255 | 183 | "ORDER BY HP_ID,OB_ID,DPM_ID,ZVB_ID,PORADOVE_CISLO_BODU", |
256 | 183 | m_pszName); |
257 | 183 | else |
258 | 183 | osSQL.Printf( |
259 | 183 | "SELECT BP_ID,PORADOVE_CISLO_BODU,PARAMETRY_SPOJENI,_rowid_ " |
260 | 183 | "FROM '%s' WHERE " |
261 | 183 | "OB_ID IS NULL AND HP_ID IS NULL AND DPM_ID IS NULL AND ZVB_ID " |
262 | 183 | "IS NULL " |
263 | 183 | "ORDER BY ID,PORADOVE_CISLO_BODU", |
264 | 183 | m_pszName); |
265 | | |
266 | 366 | sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str()); |
267 | | |
268 | 366 | if (poReader->IsSpatial()) |
269 | 366 | poReader->ExecuteSQL("BEGIN"); |
270 | | |
271 | 366 | std::vector<int> rowIdFeat; |
272 | 366 | CPLString osFType; |
273 | 366 | OGRLineString oOGRLine; |
274 | | |
275 | 11.0k | while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE) |
276 | 10.7k | { |
277 | | // read values |
278 | 10.7k | const GUIntBig id = sqlite3_column_int64(hStmt, 0); |
279 | 10.7k | const GUIntBig ipcb = sqlite3_column_int64(hStmt, 1); |
280 | 10.7k | const char *pszFType = |
281 | 10.7k | reinterpret_cast<const char *>(sqlite3_column_text(hStmt, 2)); |
282 | 10.7k | int rowId = sqlite3_column_int(hStmt, 3); |
283 | | |
284 | 10.7k | if (ipcb == 1) |
285 | 5.25k | { |
286 | 5.25k | VFKFeatureSQLite *poFeature = |
287 | 5.25k | cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(iIdx)); |
288 | 5.25k | if (poFeature == nullptr) |
289 | 11 | { |
290 | 11 | CPLError(CE_Failure, CPLE_AppDefined, |
291 | 11 | "Cannot retrieve feature %d", iIdx); |
292 | 11 | sqlite3_finalize(hStmt); |
293 | 11 | break; |
294 | 11 | } |
295 | 5.24k | poFeature->SetRowId(rowId); |
296 | | |
297 | | /* set geometry & reset */ |
298 | 5.24k | if (poLine && !SetGeometryLineString(poLine, &oOGRLine, bValid, |
299 | 5.15k | osFType.c_str(), rowIdFeat, |
300 | 5.15k | nGeometries)) |
301 | 5.02k | { |
302 | 5.02k | nInvalid++; |
303 | 5.02k | } |
304 | | |
305 | 5.24k | bValid = true; |
306 | 5.24k | poLine = poFeature; |
307 | 5.24k | osFType = pszFType ? pszFType : ""; |
308 | 5.24k | iIdx++; |
309 | 5.24k | } |
310 | | |
311 | 10.7k | VFKFeatureSQLite *poPoint = cpl::down_cast<VFKFeatureSQLite *>( |
312 | 10.7k | poDataBlockPoints->GetFeature("ID", id)); |
313 | 10.7k | if (poPoint) |
314 | 6.24k | { |
315 | 6.24k | const OGRGeometry *pt = poPoint->GetGeometry(); |
316 | 6.24k | if (pt) |
317 | 5.53k | { |
318 | 5.53k | oOGRLine.addPoint(pt->toPoint()); |
319 | 5.53k | } |
320 | 709 | else |
321 | 709 | { |
322 | 709 | CPLDebug("OGR-VFK", |
323 | 709 | "Geometry (point ID = " CPL_FRMT_GUIB |
324 | 709 | ") not valid", |
325 | 709 | id); |
326 | 709 | bValid = false; |
327 | 709 | } |
328 | 6.24k | } |
329 | 4.47k | else |
330 | 4.47k | { |
331 | 4.47k | CPLDebug("OGR-VFK", |
332 | 4.47k | "Point ID = " CPL_FRMT_GUIB " not found (rowid = %d)", |
333 | 4.47k | id, rowId); |
334 | 4.47k | bValid = false; |
335 | 4.47k | } |
336 | | |
337 | | /* add vertex to the linestring */ |
338 | 10.7k | rowIdFeat.push_back(rowId); |
339 | 10.7k | } |
340 | | |
341 | | /* add last line */ |
342 | 366 | if (poLine && |
343 | 366 | !SetGeometryLineString(poLine, &oOGRLine, bValid, osFType.c_str(), |
344 | 92 | rowIdFeat, nGeometries)) |
345 | 70 | { |
346 | 70 | nInvalid++; |
347 | 70 | } |
348 | 366 | poLine = nullptr; |
349 | | |
350 | 366 | if (poReader->IsSpatial()) |
351 | 366 | poReader->ExecuteSQL("COMMIT"); |
352 | 366 | } |
353 | | |
354 | | /* update number of geometries in VFK_DB_TABLE table */ |
355 | 183 | UpdateVfkBlocks(nGeometries); |
356 | | |
357 | 183 | return nInvalid; |
358 | 217 | } |
359 | | |
360 | | /*! |
361 | | \brief Load geometry (linestring HP/DPM/ZVB layer) |
362 | | |
363 | | \return number of invalid features |
364 | | */ |
365 | | int VFKDataBlockSQLite::LoadGeometryLineStringHP() |
366 | 294 | { |
367 | 294 | int nInvalid = 0; |
368 | 294 | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
369 | | |
370 | 294 | VFKDataBlockSQLite *poDataBlockLines = |
371 | 294 | cpl::down_cast<VFKDataBlockSQLite *>(m_poReader->GetDataBlock("SBP")); |
372 | 294 | if (nullptr == poDataBlockLines) |
373 | 188 | { |
374 | 188 | CPLError(CE_Failure, CPLE_FileIO, "Data block %s not found.", |
375 | 188 | m_pszName); |
376 | 188 | return nInvalid; |
377 | 188 | } |
378 | | |
379 | 106 | poDataBlockLines->LoadGeometry(); |
380 | | |
381 | 106 | if (LoadGeometryFromDB()) /* try to load geometry from DB */ |
382 | 8 | return 0; |
383 | | |
384 | 98 | CPLString osColumn; |
385 | 98 | osColumn.Printf("%s_ID", m_pszName); |
386 | 98 | const char *vrColumn[2] = {osColumn.c_str(), "PORADOVE_CISLO_BODU"}; |
387 | | |
388 | 98 | GUIntBig vrValue[2] = {0, 1}; // Reduce to first segment. |
389 | | |
390 | 98 | CPLString osSQL; |
391 | 98 | osSQL.Printf("SELECT ID,%s,rowid FROM %s", FID_COLUMN, m_pszName); |
392 | | /* TODO: handle points in DPM */ |
393 | 98 | if (EQUAL(m_pszName, "DPM")) |
394 | 13 | osSQL += " WHERE SOURADNICE_X IS NULL"; |
395 | 98 | sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str()); |
396 | | |
397 | 98 | if (poReader->IsSpatial()) |
398 | 98 | poReader->ExecuteSQL("BEGIN"); |
399 | | |
400 | 98 | int nGeometries = 0; |
401 | | |
402 | 2.23k | while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE) |
403 | 2.14k | { |
404 | | /* read values */ |
405 | 2.14k | vrValue[0] = sqlite3_column_int64(hStmt, 0); |
406 | 2.14k | const GIntBig iFID = sqlite3_column_int64(hStmt, 1); |
407 | 2.14k | const int rowId = sqlite3_column_int(hStmt, 2); |
408 | | |
409 | 2.14k | VFKFeatureSQLite *poFeature = |
410 | 2.14k | cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1)); |
411 | 2.14k | if (poFeature == nullptr || poFeature->GetFID() != iFID) |
412 | 11 | { |
413 | 11 | continue; |
414 | 11 | } |
415 | | |
416 | 2.13k | VFKFeatureSQLite *poLine = |
417 | 2.13k | poDataBlockLines->GetFeature(vrColumn, vrValue, 2, TRUE); |
418 | | |
419 | 2.13k | const OGRGeometry *poOgrGeometry = |
420 | 2.13k | poLine ? poLine->GetGeometry() : nullptr; |
421 | 2.13k | if (!poOgrGeometry || !poFeature->SetGeometry(poOgrGeometry)) |
422 | 1.74k | { |
423 | 1.74k | CPLDebug("OGR-VFK", |
424 | 1.74k | "VFKDataBlockSQLite::LoadGeometryLineStringHP(): name=%s " |
425 | 1.74k | "fid=" CPL_FRMT_GIB " " |
426 | 1.74k | "id=" CPL_FRMT_GUIB " -> %s geometry", |
427 | 1.74k | m_pszName, iFID, vrValue[0], |
428 | 1.74k | poOgrGeometry ? "invalid" : "empty"); |
429 | 1.74k | nInvalid++; |
430 | 1.74k | continue; |
431 | 1.74k | } |
432 | | |
433 | | /* store also geometry in DB */ |
434 | 382 | if (poReader->IsSpatial() && |
435 | 382 | SaveGeometryToDB(poOgrGeometry, rowId) != OGRERR_FAILURE) |
436 | 382 | nGeometries++; |
437 | 382 | } |
438 | | |
439 | | /* update number of geometries in VFK_DB_TABLE table */ |
440 | 98 | UpdateVfkBlocks(nGeometries); |
441 | | |
442 | 98 | if (poReader->IsSpatial()) |
443 | 98 | poReader->ExecuteSQL("COMMIT"); |
444 | | |
445 | 98 | return nInvalid; |
446 | 106 | } |
447 | | |
448 | | /*! |
449 | | \brief Load geometry (polygon BUD/PAR layers) |
450 | | |
451 | | \return number of invalid features |
452 | | */ |
453 | | int VFKDataBlockSQLite::LoadGeometryPolygon() |
454 | 98 | { |
455 | 98 | #ifndef HAVE_GEOS |
456 | | |
457 | 98 | CPLError(CE_Warning, CPLE_NotSupported, |
458 | 98 | "GEOS support not enabled. Unable to build geometry for %s.", |
459 | 98 | m_pszName); |
460 | 98 | return -1; |
461 | | |
462 | | #else |
463 | | |
464 | | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
465 | | |
466 | | VFKDataBlockSQLite *poDataBlockLines1 = nullptr; |
467 | | VFKDataBlockSQLite *poDataBlockLines2 = nullptr; |
468 | | bool bIsPar = false; |
469 | | if (EQUAL(m_pszName, "PAR")) |
470 | | { |
471 | | poDataBlockLines1 = cpl::down_cast<VFKDataBlockSQLite *>( |
472 | | m_poReader->GetDataBlock("HP")); |
473 | | poDataBlockLines2 = poDataBlockLines1; |
474 | | bIsPar = true; |
475 | | } |
476 | | else |
477 | | { |
478 | | poDataBlockLines1 = cpl::down_cast<VFKDataBlockSQLite *>( |
479 | | m_poReader->GetDataBlock("OB")); |
480 | | poDataBlockLines2 = cpl::down_cast<VFKDataBlockSQLite *>( |
481 | | m_poReader->GetDataBlock("SBP")); |
482 | | bIsPar = false; |
483 | | } |
484 | | if (nullptr == poDataBlockLines1) |
485 | | { |
486 | | CPLError(CE_Warning, CPLE_FileIO, |
487 | | "Data block %s not found. Unable to build geometry for %s.", |
488 | | bIsPar ? "HP" : "OB", m_pszName); |
489 | | return -1; |
490 | | } |
491 | | if (nullptr == poDataBlockLines2) |
492 | | { |
493 | | CPLError(CE_Warning, CPLE_FileIO, |
494 | | "Data block %s not found. Unable to build geometry for %s.", |
495 | | "SBP", m_pszName); |
496 | | return -1; |
497 | | } |
498 | | |
499 | | poDataBlockLines1->LoadGeometry(); |
500 | | poDataBlockLines2->LoadGeometry(); |
501 | | |
502 | | if (LoadGeometryFromDB()) // Try to load geometry from DB. |
503 | | return 0; |
504 | | |
505 | | const char *vrColumn[2] = {nullptr, nullptr}; |
506 | | GUIntBig vrValue[2] = {0, 0}; |
507 | | if (bIsPar) |
508 | | { |
509 | | vrColumn[0] = "PAR_ID_1"; |
510 | | vrColumn[1] = "PAR_ID_2"; |
511 | | } |
512 | | else |
513 | | { |
514 | | vrColumn[0] = "OB_ID"; |
515 | | vrColumn[1] = "PORADOVE_CISLO_BODU"; |
516 | | vrValue[1] = 1; |
517 | | } |
518 | | |
519 | | CPLString osSQL; |
520 | | osSQL.Printf("SELECT ID,%s,rowid FROM %s", FID_COLUMN, m_pszName); |
521 | | sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str()); |
522 | | |
523 | | if (poReader->IsSpatial()) |
524 | | poReader->ExecuteSQL("BEGIN"); |
525 | | |
526 | | int nInvalidNoLines = 0; |
527 | | int nInvalidNoRings = 0; |
528 | | int nGeometries = 0; |
529 | | |
530 | | while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE) |
531 | | { |
532 | | /* read values */ |
533 | | const GUIntBig id = sqlite3_column_int64(hStmt, 0); |
534 | | const long iFID = static_cast<long>(sqlite3_column_int64(hStmt, 1)); |
535 | | const int rowId = sqlite3_column_int(hStmt, 2); |
536 | | |
537 | | VFKFeatureSQLite *poFeature = |
538 | | cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1)); |
539 | | if (poFeature == nullptr || poFeature->GetFID() != iFID) |
540 | | { |
541 | | continue; |
542 | | } |
543 | | |
544 | | /* collect boundary lines */ |
545 | | VFKFeatureSQLiteList poLineList; |
546 | | if (bIsPar) |
547 | | { |
548 | | vrValue[0] = vrValue[1] = id; |
549 | | poLineList = poDataBlockLines1->GetFeatures(vrColumn, vrValue, 2); |
550 | | } |
551 | | else |
552 | | { |
553 | | osSQL.Printf("SELECT ID FROM %s WHERE BUD_ID = " CPL_FRMT_GUIB, |
554 | | poDataBlockLines1->GetName(), id); |
555 | | if (poReader->IsSpatial()) |
556 | | { |
557 | | CPLString osColumn; |
558 | | |
559 | | osColumn.Printf(" AND %s IS NULL", GEOM_COLUMN); |
560 | | osSQL += osColumn; |
561 | | } |
562 | | sqlite3_stmt *hStmtOb = poReader->PrepareStatement(osSQL.c_str()); |
563 | | |
564 | | while (poReader->ExecuteSQL(hStmtOb) == OGRERR_NONE) |
565 | | { |
566 | | const GUIntBig idOb = sqlite3_column_int64(hStmtOb, 0); |
567 | | vrValue[0] = idOb; |
568 | | VFKFeatureSQLite *poLineSbp = |
569 | | poDataBlockLines2->GetFeature(vrColumn, vrValue, 2); |
570 | | if (poLineSbp) |
571 | | poLineList.push_back(poLineSbp); |
572 | | } |
573 | | } |
574 | | if (poLineList.empty()) |
575 | | { |
576 | | CPLDebug("OGR-VFK", "%s: no lines to polygonize (fid = %ld)", |
577 | | m_pszName, iFID); |
578 | | nInvalidNoLines++; |
579 | | continue; |
580 | | } |
581 | | |
582 | | OGRMultiLineString oMultiLine; |
583 | | for (VFKFeatureSQLite *poLineFeature : poLineList) |
584 | | { |
585 | | const OGRGeometry *poLineGeom = poLineFeature->GetGeometry(); |
586 | | if (poLineGeom) |
587 | | { |
588 | | oMultiLine.addGeometry(poLineGeom); |
589 | | } |
590 | | } |
591 | | |
592 | | /* polygonize using GEOSBuildArea() */ |
593 | | auto poPolygonGeom = |
594 | | std::unique_ptr<OGRGeometry>(oMultiLine.BuildArea()); |
595 | | /* only Polygons are allowed in VFK, in particular, no MultiPolygons */ |
596 | | if (!poPolygonGeom || poPolygonGeom->IsEmpty() || |
597 | | wkbFlatten(poPolygonGeom->getGeometryType()) != wkbPolygon) |
598 | | { |
599 | | CPLDebug("OGR-VFK", "%s: unable to polygonize (fid = %ld)", |
600 | | m_pszName, iFID); |
601 | | nInvalidNoRings++; |
602 | | continue; |
603 | | } |
604 | | |
605 | | /* set polygon */ |
606 | | poPolygonGeom->setCoordinateDimension(2); /* force 2D */ |
607 | | if (!poFeature->SetGeometry(poPolygonGeom.get())) |
608 | | { |
609 | | nInvalidNoRings++; |
610 | | continue; |
611 | | } |
612 | | |
613 | | /* store also geometry in DB */ |
614 | | if (poReader->IsSpatial() && |
615 | | SaveGeometryToDB(poPolygonGeom.get(), rowId) != OGRERR_FAILURE) |
616 | | nGeometries++; |
617 | | } |
618 | | |
619 | | CPLDebug("OGR-VFK", "%s: nolines = %d norings = %d", m_pszName, |
620 | | nInvalidNoLines, nInvalidNoRings); |
621 | | |
622 | | /* update number of geometries in VFK_DB_TABLE table */ |
623 | | UpdateVfkBlocks(nGeometries); |
624 | | |
625 | | if (poReader->IsSpatial()) |
626 | | poReader->ExecuteSQL("COMMIT"); |
627 | | |
628 | | return nInvalidNoLines + nInvalidNoRings; |
629 | | #endif // HAVE_GEOS |
630 | 98 | } |
631 | | |
632 | | /*! |
633 | | \brief Get feature by FID |
634 | | |
635 | | Modifies next feature id. |
636 | | |
637 | | \param nFID feature id |
638 | | |
639 | | \return pointer to feature definition or NULL on failure (not found) |
640 | | */ |
641 | | IVFKFeature *VFKDataBlockSQLite::GetFeature(GIntBig nFID) |
642 | 0 | { |
643 | 0 | if (m_nFeatureCount < 0) |
644 | 0 | { |
645 | 0 | m_poReader->ReadDataRecords(this); |
646 | 0 | } |
647 | |
|
648 | 0 | if (nFID < 1 || nFID > m_nFeatureCount) |
649 | 0 | return nullptr; |
650 | | |
651 | 0 | if (m_bGeometryPerBlock && !m_bGeometry) |
652 | 0 | { |
653 | 0 | LoadGeometry(); |
654 | 0 | } |
655 | |
|
656 | 0 | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
657 | |
|
658 | 0 | CPLString osSQL; |
659 | 0 | osSQL.Printf("SELECT rowid FROM %s WHERE %s = " CPL_FRMT_GIB, m_pszName, |
660 | 0 | FID_COLUMN, nFID); |
661 | 0 | if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG")) |
662 | 0 | { |
663 | 0 | osSQL += " AND PORADOVE_CISLO_BODU = 1"; |
664 | 0 | } |
665 | 0 | sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str()); |
666 | |
|
667 | 0 | int rowId = -1; |
668 | 0 | if (poReader->ExecuteSQL(hStmt) == OGRERR_NONE) |
669 | 0 | { |
670 | 0 | rowId = sqlite3_column_int(hStmt, 0); |
671 | 0 | } |
672 | 0 | sqlite3_finalize(hStmt); |
673 | |
|
674 | 0 | return GetFeatureByIndex(rowId - 1); |
675 | 0 | } |
676 | | |
677 | | /*! |
678 | | \brief Get first found feature based on its property |
679 | | |
680 | | \param column property name |
681 | | \param value property value |
682 | | \param bGeom True to check also geometry != NULL |
683 | | |
684 | | \return pointer to feature definition or NULL on failure (not found) |
685 | | */ |
686 | | VFKFeatureSQLite *VFKDataBlockSQLite::GetFeature(const char *column, |
687 | | GUIntBig value, bool bGeom) |
688 | 10.7k | { |
689 | 10.7k | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
690 | | |
691 | 10.7k | CPLString osSQL; |
692 | 10.7k | osSQL.Printf("SELECT %s from %s WHERE %s = " CPL_FRMT_GUIB, FID_COLUMN, |
693 | 10.7k | m_pszName, column, value); |
694 | 10.7k | if (bGeom) |
695 | 0 | { |
696 | 0 | CPLString osColumn; |
697 | |
|
698 | 0 | osColumn.Printf(" AND %s IS NOT NULL", GEOM_COLUMN); |
699 | 0 | osSQL += osColumn; |
700 | 0 | } |
701 | | |
702 | 10.7k | sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str()); |
703 | 10.7k | if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE) |
704 | 4.46k | return nullptr; |
705 | | |
706 | 6.25k | const int idx = sqlite3_column_int(hStmt, 0) - 1; |
707 | 6.25k | sqlite3_finalize(hStmt); |
708 | | |
709 | 6.25k | if (idx < 0 || idx >= m_nFeatureCount) // ? assert |
710 | 17 | return nullptr; |
711 | | |
712 | 6.24k | return cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(idx)); |
713 | 6.25k | } |
714 | | |
715 | | /*! |
716 | | \brief Get first found feature based on its properties (AND) |
717 | | |
718 | | \param column array of property names |
719 | | \param value array of property values |
720 | | \param num number of array items |
721 | | \param bGeom True to check also geometry != NULL |
722 | | |
723 | | \return pointer to feature definition or NULL on failure (not found) |
724 | | */ |
725 | | VFKFeatureSQLite *VFKDataBlockSQLite::GetFeature(const char **column, |
726 | | GUIntBig *value, int num, |
727 | | bool bGeom) |
728 | 2.13k | { |
729 | 2.13k | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
730 | | |
731 | 2.13k | CPLString osSQL; |
732 | 2.13k | osSQL.Printf("SELECT %s FROM %s WHERE ", FID_COLUMN, m_pszName); |
733 | | |
734 | 2.13k | CPLString osItem; |
735 | 6.39k | for (int i = 0; i < num; i++) |
736 | 4.26k | { |
737 | 4.26k | if (i > 0) |
738 | 2.13k | osItem.Printf(" AND %s = " CPL_FRMT_GUIB, column[i], value[i]); |
739 | 2.13k | else |
740 | 2.13k | osItem.Printf("%s = " CPL_FRMT_GUIB, column[i], value[i]); |
741 | 4.26k | osSQL += osItem; |
742 | 4.26k | } |
743 | 2.13k | if (bGeom) |
744 | 2.13k | { |
745 | 2.13k | osItem.Printf(" AND %s IS NOT NULL", GEOM_COLUMN); |
746 | 2.13k | osSQL += osItem; |
747 | 2.13k | } |
748 | | |
749 | 2.13k | sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str()); |
750 | 2.13k | if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE) |
751 | 1.74k | return nullptr; |
752 | | |
753 | 382 | int idx = sqlite3_column_int(hStmt, 0) - 1; /* rowid starts at 1 */ |
754 | 382 | sqlite3_finalize(hStmt); |
755 | | |
756 | 382 | if (idx < 0 || idx >= m_nFeatureCount) // ? assert |
757 | 0 | return nullptr; |
758 | | |
759 | 382 | return cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(idx)); |
760 | 382 | } |
761 | | |
762 | | /*! |
763 | | \brief Get features based on properties |
764 | | |
765 | | \param column array of property names |
766 | | \param value array of property values |
767 | | \param num number of array items |
768 | | |
769 | | \return list of features |
770 | | */ |
771 | | VFKFeatureSQLiteList VFKDataBlockSQLite::GetFeatures(const char **column, |
772 | | GUIntBig *value, int num) |
773 | 0 | { |
774 | 0 | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
775 | |
|
776 | 0 | CPLString osItem; |
777 | 0 | CPLString osSQL; |
778 | 0 | osSQL.Printf("SELECT rowid from %s WHERE ", m_pszName); |
779 | 0 | for (int i = 0; i < num; i++) |
780 | 0 | { |
781 | 0 | if (i > 0) |
782 | 0 | osItem.Printf(" OR %s = " CPL_FRMT_GUIB, column[i], value[i]); |
783 | 0 | else |
784 | 0 | osItem.Printf("%s = " CPL_FRMT_GUIB, column[i], value[i]); |
785 | 0 | osSQL += osItem; |
786 | 0 | } |
787 | 0 | osSQL += " ORDER BY "; |
788 | 0 | osSQL += FID_COLUMN; |
789 | |
|
790 | 0 | VFKFeatureSQLiteList fList; |
791 | |
|
792 | 0 | sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str()); |
793 | 0 | while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE) |
794 | 0 | { |
795 | 0 | const int iRowId = sqlite3_column_int(hStmt, 0); |
796 | 0 | VFKFeatureSQLite *poFeature = |
797 | 0 | dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(iRowId - 1)); |
798 | 0 | if (poFeature == nullptr) |
799 | 0 | { |
800 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Cannot retrieve feature %d", |
801 | 0 | iRowId); |
802 | 0 | sqlite3_finalize(hStmt); |
803 | 0 | return VFKFeatureSQLiteList(); |
804 | 0 | } |
805 | 0 | fList.push_back(poFeature); |
806 | 0 | } |
807 | | |
808 | 0 | return fList; |
809 | 0 | } |
810 | | |
811 | | /*! |
812 | | \brief Save geometry to DB (as WKB) |
813 | | |
814 | | \param poGeom pointer to OGRGeometry to be saved |
815 | | \param iRowId row id to update |
816 | | |
817 | | \return OGRERR_NONE on success otherwise OGRERR_FAILURE |
818 | | */ |
819 | | OGRErr VFKDataBlockSQLite::SaveGeometryToDB(const OGRGeometry *poGeom, |
820 | | int iRowId) |
821 | 9.83k | { |
822 | 9.83k | int rc; |
823 | 9.83k | CPLString osSQL; |
824 | | |
825 | 9.83k | sqlite3_stmt *hStmt = nullptr; |
826 | | |
827 | 9.83k | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
828 | | |
829 | | /* check if geometry column exists (see SUPPRESS_GEOMETRY open |
830 | | option) */ |
831 | 9.83k | if (AddGeometryColumn() != OGRERR_NONE) |
832 | 0 | return OGRERR_FAILURE; |
833 | | |
834 | 9.83k | if (poGeom) |
835 | 9.83k | { |
836 | 9.83k | const size_t nWKBLen = poGeom->WkbSize(); |
837 | 9.83k | if (nWKBLen > static_cast<size_t>(std::numeric_limits<int>::max())) |
838 | 0 | { |
839 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Too large geometry"); |
840 | 0 | return OGRERR_FAILURE; |
841 | 0 | } |
842 | 9.83k | GByte *pabyWKB = (GByte *)VSI_MALLOC_VERBOSE(nWKBLen); |
843 | 9.83k | if (pabyWKB) |
844 | 9.83k | { |
845 | 9.83k | poGeom->exportToWkb(wkbNDR, pabyWKB); |
846 | | |
847 | 9.83k | osSQL.Printf("UPDATE %s SET %s = ? WHERE rowid = %d", m_pszName, |
848 | 9.83k | GEOM_COLUMN, iRowId); |
849 | 9.83k | hStmt = poReader->PrepareStatement(osSQL.c_str()); |
850 | | |
851 | 9.83k | rc = sqlite3_bind_blob(hStmt, 1, pabyWKB, static_cast<int>(nWKBLen), |
852 | 9.83k | CPLFree); |
853 | 9.83k | if (rc != SQLITE_OK) |
854 | 0 | { |
855 | 0 | sqlite3_finalize(hStmt); |
856 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
857 | 0 | "Storing geometry in DB failed"); |
858 | 0 | return OGRERR_FAILURE; |
859 | 0 | } |
860 | 9.83k | } |
861 | 9.83k | } |
862 | 0 | else |
863 | 0 | { /* invalid */ |
864 | 0 | osSQL.Printf("UPDATE %s SET %s = NULL WHERE rowid = %d", m_pszName, |
865 | 0 | GEOM_COLUMN, iRowId); |
866 | 0 | hStmt = poReader->PrepareStatement(osSQL.c_str()); |
867 | 0 | } |
868 | | |
869 | 9.83k | return poReader->ExecuteSQL(hStmt); /* calls sqlite3_finalize() */ |
870 | 9.83k | } |
871 | | |
872 | | /*! |
873 | | \brief Load geometry from DB |
874 | | |
875 | | \return true if geometry successfully loaded otherwise false |
876 | | */ |
877 | | bool VFKDataBlockSQLite::LoadGeometryFromDB() |
878 | 821 | { |
879 | 821 | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
880 | | |
881 | 821 | if (!poReader->IsSpatial()) /* check if DB is spatial */ |
882 | 0 | return false; |
883 | | |
884 | 821 | CPLString osSQL; |
885 | 821 | osSQL.Printf("SELECT num_geometries FROM %s WHERE table_name = '%s'", |
886 | 821 | VFK_DB_TABLE, m_pszName); |
887 | 821 | sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str()); |
888 | 821 | if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE) |
889 | 59 | return false; |
890 | 762 | const int nGeometries = sqlite3_column_int(hStmt, 0); |
891 | 762 | sqlite3_finalize(hStmt); |
892 | | |
893 | 762 | if (nGeometries < 1) |
894 | 623 | return false; |
895 | | |
896 | 139 | const bool bSkipInvalid = EQUAL(m_pszName, "OB") || |
897 | 139 | EQUAL(m_pszName, "OP") || |
898 | 139 | EQUAL(m_pszName, "OBBP"); |
899 | | |
900 | | /* load geometry from DB */ |
901 | 139 | osSQL.Printf("SELECT %s,rowid,%s FROM %s ", GEOM_COLUMN, FID_COLUMN, |
902 | 139 | m_pszName); |
903 | 139 | if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG")) |
904 | 34 | osSQL += "WHERE PORADOVE_CISLO_BODU = 1 "; |
905 | 139 | osSQL += "ORDER BY "; |
906 | 139 | osSQL += FID_COLUMN; |
907 | 139 | hStmt = poReader->PrepareStatement(osSQL.c_str()); |
908 | | |
909 | 139 | int rowId = 0; |
910 | 139 | int nInvalid = 0; |
911 | 139 | int nGeometriesCount = 0; |
912 | | |
913 | 6.12k | while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE) |
914 | 5.98k | { |
915 | 5.98k | rowId++; // =sqlite3_column_int(hStmt, 1); |
916 | 5.98k | const GIntBig iFID = sqlite3_column_int64(hStmt, 2); |
917 | 5.98k | VFKFeatureSQLite *poFeature = |
918 | 5.98k | dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1)); |
919 | 5.98k | if (poFeature == nullptr || poFeature->GetFID() != iFID) |
920 | 701 | { |
921 | 701 | continue; |
922 | 701 | } |
923 | | |
924 | | // read geometry from DB |
925 | 5.28k | const int nBytes = sqlite3_column_bytes(hStmt, 0); |
926 | 5.28k | OGRGeometry *poGeometry = nullptr; |
927 | 5.28k | if (nBytes > 0 && OGRGeometryFactory::createFromWkb( |
928 | 2.54k | sqlite3_column_blob(hStmt, 0), nullptr, |
929 | 2.54k | &poGeometry, nBytes) == OGRERR_NONE) |
930 | 2.54k | { |
931 | 2.54k | nGeometriesCount++; |
932 | 2.54k | if (!poFeature->SetGeometry(poGeometry)) |
933 | 0 | { |
934 | 0 | nInvalid++; |
935 | 0 | } |
936 | 2.54k | delete poGeometry; |
937 | 2.54k | } |
938 | 2.74k | else |
939 | 2.74k | { |
940 | 2.74k | nInvalid++; |
941 | 2.74k | } |
942 | 5.28k | } |
943 | | |
944 | 139 | CPLDebug("OGR-VFK", "%s: %d geometries loaded from DB", m_pszName, |
945 | 139 | nGeometriesCount); |
946 | | |
947 | 139 | if (nGeometriesCount != nGeometries) |
948 | 33 | { |
949 | 33 | CPLError(CE_Warning, CPLE_AppDefined, |
950 | 33 | "%s: %d geometries loaded (should be %d)", m_pszName, |
951 | 33 | nGeometriesCount, nGeometries); |
952 | 33 | } |
953 | | |
954 | 139 | if (nInvalid > 0 && !bSkipInvalid) |
955 | 101 | { |
956 | 101 | CPLError(CE_Warning, CPLE_AppDefined, |
957 | 101 | "%s: %d features with invalid or empty geometry", m_pszName, |
958 | 101 | nInvalid); |
959 | 101 | } |
960 | | |
961 | 139 | return true; |
962 | 762 | } |
963 | | |
964 | | /*! |
965 | | \brief Update VFK_DB_TABLE table |
966 | | |
967 | | \param nGeometries number of geometries to update |
968 | | */ |
969 | | void VFKDataBlockSQLite::UpdateVfkBlocks(int nGeometries) |
970 | 682 | { |
971 | 682 | CPLString osSQL; |
972 | | |
973 | 682 | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
974 | | |
975 | | /* update number of features in VFK_DB_TABLE table */ |
976 | 682 | const int nFeatCount = (int)GetFeatureCount(); |
977 | 682 | if (nFeatCount > 0) |
978 | 231 | { |
979 | 231 | osSQL.Printf("UPDATE %s SET num_features = %d WHERE table_name = '%s'", |
980 | 231 | VFK_DB_TABLE, nFeatCount, m_pszName); |
981 | 231 | poReader->ExecuteSQL(osSQL.c_str()); |
982 | 231 | } |
983 | | |
984 | | /* update number of geometries in VFK_DB_TABLE table */ |
985 | 682 | if (nGeometries > 0) |
986 | 132 | { |
987 | 132 | CPLDebug("OGR-VFK", |
988 | 132 | "VFKDataBlockSQLite::UpdateVfkBlocks(): name=%s -> " |
989 | 132 | "%d geometries saved to internal DB", |
990 | 132 | m_pszName, nGeometries); |
991 | | |
992 | 132 | osSQL.Printf( |
993 | 132 | "UPDATE %s SET num_geometries = %d WHERE table_name = '%s'", |
994 | 132 | VFK_DB_TABLE, nGeometries, m_pszName); |
995 | 132 | poReader->ExecuteSQL(osSQL.c_str()); |
996 | 132 | } |
997 | 682 | } |
998 | | |
999 | | /*! |
1000 | | \brief Update feature id (see SBP) |
1001 | | |
1002 | | \param iFID feature id to set up |
1003 | | \param rowId list of rows to update |
1004 | | */ |
1005 | | void VFKDataBlockSQLite::UpdateFID(GIntBig iFID, const std::vector<int> &rowId) |
1006 | 5.24k | { |
1007 | 5.24k | CPLString osSQL, osValue; |
1008 | 5.24k | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
1009 | | |
1010 | | /* update number of geometries in VFK_DB_TABLE table */ |
1011 | 5.24k | osSQL.Printf("UPDATE %s SET %s = " CPL_FRMT_GIB " WHERE rowid IN (", |
1012 | 5.24k | m_pszName, FID_COLUMN, iFID); |
1013 | 15.9k | for (size_t i = 0; i < rowId.size(); i++) |
1014 | 10.7k | { |
1015 | 10.7k | if (i > 0) |
1016 | 5.47k | osValue.Printf(",%d", rowId[i]); |
1017 | 5.24k | else |
1018 | 5.24k | osValue.Printf("%d", rowId[i]); |
1019 | 10.7k | osSQL += osValue; |
1020 | 10.7k | } |
1021 | 5.24k | osSQL += ")"; |
1022 | | |
1023 | 5.24k | poReader->ExecuteSQL(osSQL.c_str()); |
1024 | 5.24k | } |
1025 | | |
1026 | | /*! |
1027 | | \brief Check is ring is closed |
1028 | | |
1029 | | \param poRing pointer to OGRLinearRing to check |
1030 | | |
1031 | | \return true if closed otherwise false |
1032 | | */ |
1033 | | bool VFKDataBlockSQLite::IsRingClosed(const OGRLinearRing *poRing) |
1034 | 0 | { |
1035 | 0 | const int nPoints = poRing->getNumPoints(); |
1036 | 0 | if (nPoints < 3) |
1037 | 0 | return false; |
1038 | | |
1039 | 0 | if (poRing->getX(0) == poRing->getX(nPoints - 1) && |
1040 | 0 | poRing->getY(0) == poRing->getY(nPoints - 1)) |
1041 | 0 | return true; |
1042 | | |
1043 | 0 | return false; |
1044 | 0 | } |
1045 | | |
1046 | | /*! |
1047 | | \brief Get primary key |
1048 | | |
1049 | | \return property name or NULL |
1050 | | */ |
1051 | | const char *VFKDataBlockSQLite::GetKey() const |
1052 | 858 | { |
1053 | 858 | if (GetPropertyCount() > 1) |
1054 | 649 | { |
1055 | 649 | const VFKPropertyDefn *poPropDefn = GetProperty(0); |
1056 | 649 | const char *pszKey = poPropDefn->GetName(); |
1057 | 649 | if (EQUAL(pszKey, "ID")) |
1058 | 604 | return pszKey; |
1059 | 649 | } |
1060 | | |
1061 | 254 | return nullptr; |
1062 | 858 | } |
1063 | | |
1064 | | /*! |
1065 | | \brief Get geometry SQL type (for geometry_columns table) |
1066 | | |
1067 | | \return geometry_type as integer |
1068 | | */ |
1069 | | int VFKDataBlockSQLite::GetGeometrySQLType() const |
1070 | 2.34k | { |
1071 | 2.34k | if (m_nGeometryType == wkbPolygon) |
1072 | 52 | return 3; |
1073 | 2.29k | else if (m_nGeometryType == wkbLineString) |
1074 | 178 | return 2; |
1075 | 2.11k | else if (m_nGeometryType == wkbPoint) |
1076 | 208 | return 1; |
1077 | | |
1078 | 1.90k | return 0; /* unknown geometry type */ |
1079 | 2.34k | } |
1080 | | |
1081 | | /*! |
1082 | | \brief Add geometry column into table if not exists |
1083 | | |
1084 | | \return OGRERR_NONE on success otherwise OGRERR_FAILURE |
1085 | | */ |
1086 | | OGRErr VFKDataBlockSQLite::AddGeometryColumn() const |
1087 | 10.3k | { |
1088 | 10.3k | CPLString osSQL; |
1089 | | |
1090 | 10.3k | VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader); |
1091 | | |
1092 | 10.3k | osSQL.Printf("SELECT %s FROM %s LIMIT 0", GEOM_COLUMN, m_pszName); |
1093 | 10.3k | if (poReader->ExecuteSQL(osSQL.c_str(), CE_None) == OGRERR_FAILURE) |
1094 | 151 | { |
1095 | | /* query failed, we assume that geometry column not exists */ |
1096 | 151 | osSQL.Printf("ALTER TABLE %s ADD COLUMN %s blob", m_pszName, |
1097 | 151 | GEOM_COLUMN); |
1098 | 151 | return poReader->ExecuteSQL(osSQL.c_str()); |
1099 | 151 | } |
1100 | | |
1101 | 10.1k | return OGRERR_NONE; |
1102 | 10.3k | } |
1103 | | |
1104 | | /*! |
1105 | | \brief Load feature properties |
1106 | | |
1107 | | Used for sequential access, see OGRVFKLayer:GetNextFeature(). |
1108 | | |
1109 | | \return OGRERR_NONE on success otherwise OGRERR_FAILURE |
1110 | | */ |
1111 | | OGRErr VFKDataBlockSQLite::LoadProperties() |
1112 | 5.64k | { |
1113 | 5.64k | CPLString osSQL; |
1114 | | |
1115 | 5.64k | if (m_hStmt) |
1116 | 0 | sqlite3_finalize(m_hStmt); |
1117 | | |
1118 | 5.64k | osSQL.Printf("SELECT * FROM %s", // TODO: where |
1119 | 5.64k | m_pszName); |
1120 | 5.64k | if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG")) |
1121 | 205 | osSQL += " WHERE PORADOVE_CISLO_BODU = 1"; |
1122 | | |
1123 | 5.64k | m_hStmt = cpl::down_cast<VFKReaderSQLite *>(m_poReader) |
1124 | 5.64k | ->PrepareStatement(osSQL.c_str()); |
1125 | | |
1126 | 5.64k | if (m_hStmt == nullptr) |
1127 | 4.11k | return OGRERR_FAILURE; |
1128 | | |
1129 | 1.52k | return OGRERR_NONE; |
1130 | 5.64k | } |
1131 | | |
1132 | | /* |
1133 | | \brief Clean feature properties for a next run |
1134 | | |
1135 | | \return OGRERR_NONE on success otherwise OGRERR_FAILURE |
1136 | | */ |
1137 | | OGRErr VFKDataBlockSQLite::CleanProperties() |
1138 | 16.0k | { |
1139 | 16.0k | if (m_hStmt) |
1140 | 1.52k | { |
1141 | 1.52k | if (sqlite3_finalize(m_hStmt) != SQLITE_OK) |
1142 | 0 | { |
1143 | 0 | m_hStmt = nullptr; |
1144 | 0 | return OGRERR_FAILURE; |
1145 | 0 | } |
1146 | 1.52k | m_hStmt = nullptr; |
1147 | 1.52k | } |
1148 | | |
1149 | 16.0k | return OGRERR_NONE; |
1150 | 16.0k | } |