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