OpenCPN Partial API docs
Loading...
Searching...
No Matches
navobj_db_util.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2026 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 **************************************************************************/
17
24#include "model/navobj_db.h"
27
28// Schema migration 0->1 Helper functions
29int getUserVersion(sqlite3* db) {
30 sqlite3_stmt* stmt = nullptr;
31 int version = 0;
32
33 const char* sql = "PRAGMA user_version;";
34
35 int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
36 if (rc != SQLITE_OK) {
37 return 0; // or throw, depending on your error policy
38 }
39
40 rc = sqlite3_step(stmt);
41 if (rc == SQLITE_ROW) {
42 version = sqlite3_column_int(stmt, 0);
43 }
44
45 sqlite3_finalize(stmt);
46 return version;
47}
48
49void setUserVersion(sqlite3* db, int v) {
50 std::string sql = "PRAGMA user_version = " + std::to_string(v) + ";";
51
52 char* errMsg = nullptr;
53 int rc = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errMsg);
54
55 if (rc != SQLITE_OK) {
56 std::string err = errMsg ? errMsg : "Failed to set user_version";
57 sqlite3_free(errMsg);
58 throw std::runtime_error(err);
59 }
60}
61
62inline bool columnInPrimaryKey(sqlite3* db, const std::string& table,
63 const std::string& column) {
64 std::string sql = "PRAGMA table_info(" + table + ");";
65 sqlite3_stmt* stmt;
66
67 if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
68 return false;
69
70 bool found = false;
71
72 while (sqlite3_step(stmt) == SQLITE_ROW) {
73 std::string name =
74 reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
75 int pk = sqlite3_column_int(stmt, 5);
76
77 if (name == column && pk > 0) {
78 found = true;
79 break;
80 }
81 }
82
83 sqlite3_finalize(stmt);
84 return found;
85}
86
87bool needsMigration_0_1(sqlite3* db) {
88 int version = getUserVersion(db);
89 if (version < 1) {
90 // Verify really version 0
91 bool hasRouteGuid =
92 columnInPrimaryKey(db, "routepoints_link", "route_guid");
93 bool hasPointGuid =
94 columnInPrimaryKey(db, "routepoints_link", "point_guid");
95 bool hasPointOrder =
96 columnInPrimaryKey(db, "routepoints_link", "point_order");
97 return hasRouteGuid && hasPointGuid && !hasPointOrder;
98 }
99 return false;
100}
101
102// Utility functions for performing database schema updates, to be applied in
103// succession.
104
105std::string SchemaUpdate_0_1(sqlite3* db, wxFrame* frame) {
106 bool rv = true;
107
108 if (needsMigration_0_1(db)) {
109 // Configure and execute migrator for 0->1 migration
110 DbMigrator migrator(db);
111 migrator.addMigration(1, [](sqlite3* db) {
112 char* errMsg = nullptr;
113
114 const char* sql = R"(
115 CREATE TABLE routepoints_link_new (
116 route_guid TEXT,
117 point_guid TEXT,
118 point_order INTEGER,
119 PRIMARY KEY (route_guid, point_order),
120 FOREIGN KEY (route_guid) REFERENCES routes(guid) ON DELETE CASCADE
121 );
122
123 INSERT INTO routepoints_link_new
124 SELECT t.*
125 FROM routepoints_link t
126 WHERE rowid = (
127 SELECT MIN(rowid)
128 FROM routepoints_link t2
129 WHERE t.route_guid = t2.route_guid
130 AND t.point_order = t2.point_order
131 );
132
133 DROP TABLE routepoints_link;
134
135 ALTER TABLE routepoints_link_new RENAME TO routepoints_link;
136 )";
137
138 if (sqlite3_exec(db, sql, nullptr, nullptr, &errMsg) != SQLITE_OK) {
139 std::string err = errMsg ? errMsg : "";
140 sqlite3_free(errMsg);
141 throw std::runtime_error(err);
142 }
143 });
144
145 try {
146 migrator.migrate();
147 } catch (const std::runtime_error& e) {
148 // Known errors you threw (e.g., SQLite issues)
149 return (std::string("Migration 0->1 failed: ") + e.what());
150 } catch (const std::exception& e) {
151 // Any other standard exception
152 return (std::string("Unexpected error on migration 0->1: ") + e.what());
153 } catch (...) {
154 // Truly unknown (rare, but good safety net)
155 return ("Unknown non-standard exception during migration");
156 }
157 }
158
159 return "";
160}
MySQL based storage for routes, tracks, etc.
MySQL schema update facility.
navobj_db_util.h – MySQL support utilities