# include "config.h"
#endif
-// to ensure compatability between sqlite3_int64 and PositionedID,
-// force the type used by sqlite to match PositionedID explicitly
-#define SQLITE_INT64_TYPE int64_t
-#define SQLITE_UINT64_TYPE uint64_t
-
#include "NavDataCache.hxx"
// std
// boost
#include <boost/foreach.hpp>
-#include "sqlite3.h"
+
+#ifdef SYSTEM_SQLITE
+// the standard sqlite3.h doesn't give a way to set SQLITE_UINT64_TYPE,
+// so we have to hope sizeof(int64_t) matches sizeof(sqlite3_int64).
+// otherwise things will go bad quickly.
+ #include "sqlite3.h"
+#else
+// to ensure compatability between sqlite3_int64 and PositionedID,
+// force the type used by sqlite to match PositionedID explicitly
+#define SQLITE_INT64_TYPE int64_t
+#define SQLITE_UINT64_TYPE uint64_t
+
+ #include "fg_sqlite3.h"
+#endif
// SimGear
+#include <simgear/sg_inlines.h>
#include <simgear/structure/exception.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/bucket/newbucket.hxx>
#include <simgear/threads/SGGuard.hxx>
#include <Main/globals.hxx>
+#include <Main/fg_props.hxx>
+#include <Main/options.hxx>
#include "markerbeacon.hxx"
#include "navrecord.hxx"
#include <Airports/airport.hxx>
#include "poidb.hxx"
#include <Airports/parking.hxx>
#include <Airports/gnnode.hxx>
+#include "CacheSchema.h"
using std::string;
namespace {
const int MAX_RETRIES = 10;
-const int SCHEMA_VERSION = 8;
-const int CACHE_SIZE_KBYTES= 16000;
+
+const int CACHE_SIZE_KBYTES= 32 * 1024;
// bind a std::string to a sqlite statement. The std::string must live the
// entire duration of the statement execution - do not pass a temporary
outer(o),
db(NULL),
path(p),
+ readOnly(false),
cacheHits(0),
cacheMisses(0),
transactionLevel(0),
void init()
{
SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache at:" << path);
- sqlite3_open_v2(path.c_str(), &db,
- SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
-
+
+ readOnly = fgGetBool("/sim/fghome-readonly", false);
+
+ int openFlags = readOnly ? SQLITE_OPEN_READONLY :
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
+ // see http://code.google.com/p/flightgear-bugs/issues/detail?id=1055
+ // for the UTF8 / path logic here
+ std::string pathUtf8 = simgear::strutils::convertWindowsLocal8BitToUtf8(path.str());
+ sqlite3_open_v2(pathUtf8.c_str(), &db, openFlags, NULL);
sqlite3_stmt_ptr checkTables =
prepare("SELECT count(*) FROM sqlite_master WHERE name='properties'");
execSelect(checkTables);
bool didCreate = false;
- if (sqlite3_column_int(checkTables, 0) == 0) {
+ if (!readOnly && (sqlite3_column_int(checkTables, 0) == 0)) {
SG_LOG(SG_NAVCACHE, SG_INFO, "will create tables");
initTables();
didCreate = true;
SG_LOG(SG_NAVCACHE, SG_INFO, "NavDataCache integrity check took:" << st.elapsedMSec());
finalize(stmt);
}
+
+ bool isCachedFileModified(const SGPath& path, bool verbose);
void callSqlite(int result, const string& sql)
{
execSelect(stmt);
reset(stmt);
}
-
+
void initTables()
{
- runSQL("CREATE TABLE properties ("
- "key VARCHAR,"
- "value VARCHAR"
- ")");
-
- runSQL("CREATE TABLE stat_cache ("
- "path VARCHAR unique,"
- "stamp INT"
- ")");
-
- runSQL("CREATE TABLE positioned ("
- "type INT,"
- "ident VARCHAR collate nocase,"
- "name VARCHAR collate nocase,"
- "airport INT64,"
- "lon FLOAT,"
- "lat FLOAT,"
- "elev_m FLOAT,"
- "octree_node INT,"
- "cart_x FLOAT,"
- "cart_y FLOAT,"
- "cart_z FLOAT"
- ")");
-
- runSQL("CREATE INDEX pos_octree ON positioned(octree_node)");
- runSQL("CREATE INDEX pos_ident ON positioned(ident collate nocase)");
- runSQL("CREATE INDEX pos_name ON positioned(name collate nocase)");
- // allow efficient querying of 'all ATIS at this airport' or
- // 'all towers at this airport'
- runSQL("CREATE INDEX pos_apt_type ON positioned(airport, type)");
-
- runSQL("CREATE TABLE airport ("
- "has_metar BOOL"
- ")"
- );
-
- runSQL("CREATE TABLE comm ("
- "freq_khz INT,"
- "range_nm INT"
- ")"
- );
-
- runSQL("CREATE INDEX comm_freq ON comm(freq_khz)");
-
- runSQL("CREATE TABLE runway ("
- "heading FLOAT,"
- "length_ft FLOAT,"
- "width_m FLOAT,"
- "surface INT,"
- "displaced_threshold FLOAT,"
- "stopway FLOAT,"
- "reciprocal INT64,"
- "ils INT64"
- ")"
- );
-
- runSQL("CREATE TABLE navaid ("
- "freq INT,"
- "range_nm INT,"
- "multiuse FLOAT,"
- "runway INT64,"
- "colocated INT64"
- ")"
- );
-
- runSQL("CREATE INDEX navaid_freq ON navaid(freq)");
-
- runSQL("CREATE TABLE octree (children INT)");
-
- runSQL("CREATE TABLE airway ("
- "ident VARCHAR collate nocase,"
- "network INT" // high-level or low-level
- ")");
-
- runSQL("CREATE INDEX airway_ident ON airway(ident)");
-
- runSQL("CREATE TABLE airway_edge ("
- "network INT,"
- "airway INT64,"
- "a INT64,"
- "b INT64"
- ")");
-
- runSQL("CREATE INDEX airway_edge_from ON airway_edge(a)");
-
- runSQL("CREATE TABLE taxi_node ("
- "hold_type INT,"
- "on_runway BOOL,"
- "pushback BOOL"
- ")");
-
- runSQL("CREATE TABLE parking ("
- "heading FLOAT,"
- "radius INT,"
- "gate_type VARCHAR,"
- "airlines VARCHAR,"
- "pushback INT64"
- ")");
-
- runSQL("CREATE TABLE groundnet_edge ("
- "airport INT64,"
- "a INT64,"
- "b INT64"
- ")");
-
- runSQL("CREATE INDEX groundnet_edge_airport ON groundnet_edge(airport)");
- runSQL("CREATE INDEX groundnet_edge_from ON groundnet_edge(a)");
+ string_list commands = simgear::strutils::split(SCHEMA_SQL, ";");
+ BOOST_FOREACH(std::string sql, commands) {
+ if (sql.empty()) {
+ continue;
+ }
+
+ runSQL(sql);
+ } // of commands in scheme loop
}
void prepareQueries()
setRunwayReciprocal = prepare("UPDATE runway SET reciprocal=?2 WHERE rowid=?1");
setRunwayILS = prepare("UPDATE runway SET ils=?2 WHERE rowid=?1");
- updateRunwayThreshold = prepare("UPDATE runway SET heading=?2, displaced_threshold=?3, stopway=?4 WHERE rowid=?1");
+ setNavaidColocated = prepare("UPDATE navaid SET colocated=?2 WHERE rowid=?1");
insertPositionedQuery = prepare("INSERT INTO positioned "
"(type, ident, name, airport, lon, lat, elev_m, octree_node, "
insertAirport = prepare("INSERT INTO airport (rowid, has_metar) VALUES (?, ?)");
insertNavaid = prepare("INSERT INTO navaid (rowid, freq, range_nm, multiuse, runway, colocated)"
" VALUES (?1, ?2, ?3, ?4, ?5, ?6)");
- updateILS = prepare("UPDATE navaid SET multiuse=?2 WHERE rowid=?1");
insertCommStation = prepare("INSERT INTO comm (rowid, freq_khz, range_nm)"
" VALUES (?, ?, ?)");
sqlite3_bind_int(searchAirports, 2, FGPositioned::AIRPORT);
sqlite3_bind_int(searchAirports, 3, FGPositioned::SEAPORT);
+ getAllAirports = prepare("SELECT ident, name FROM positioned WHERE type>=?1 AND type <=?2");
+ sqlite3_bind_int(getAllAirports, 1, FGPositioned::AIRPORT);
+ sqlite3_bind_int(getAllAirports, 2, FGPositioned::SEAPORT);
+
+
getAirportItemByIdent = prepare("SELECT rowid FROM positioned WHERE airport=?1 AND ident=?2 AND type=?3");
findAirportRunway = prepare("SELECT airport, rowid FROM positioned WHERE ident=?2 AND type=?3 AND airport="
}
- FGPositioned* loadById(sqlite_int64 rowId);
+ FGPositioned* loadById(sqlite_int64 rowId, sqlite3_int64& aptId);
FGAirport* loadAirport(sqlite_int64 rowId,
FGPositioned::Type ty,
}
int rangeNm = sqlite3_column_int(loadNavaid, 0),
- freq = sqlite3_column_int(loadNavaid, 1);
+ freq = sqlite3_column_int(loadNavaid, 1);
double mulituse = sqlite3_column_double(loadNavaid, 2);
- //sqlite3_int64 colocated = sqlite3_column_int64(loadNavaid, 4);
+ PositionedID colocated = sqlite3_column_int64(loadNavaid, 4);
reset(loadNavaid);
-
- return new FGNavRecord(rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway);
+
+ FGNavRecord* n =
+ (ty == FGPositioned::MOBILE_TACAN)
+ ? new FGMobileNavRecord
+ (rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway)
+ : new FGNavRecord
+ (rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway);
+
+ if (colocated)
+ n->setColocatedDME(colocated);
+
+ return n;
}
FGPositioned* loadParking(sqlite3_int64 rowId,
NavDataCache* outer;
sqlite3* db;
SGPath path;
-
+ bool readOnly;
+
/// the actual cache of ID -> instances. This holds an owning reference,
/// so once items are in the cache they will never be deleted until
/// the cache drops its reference
sqlite3_stmt_ptr insertPositionedQuery, insertAirport, insertTower, insertRunway,
insertCommStation, insertNavaid;
- sqlite3_stmt_ptr setAirportMetar, setRunwayReciprocal, setRunwayILS,
- setAirportPos, updateRunwayThreshold, updateILS;
+ sqlite3_stmt_ptr setAirportMetar, setRunwayReciprocal, setRunwayILS, setNavaidColocated,
+ setAirportPos;
sqlite3_stmt_ptr removePOIQuery;
sqlite3_stmt_ptr findClosestWithIdent;
sqlite3_stmt_ptr getOctreeChildren, insertOctree, updateOctreeChildren,
getOctreeLeafChildren;
- sqlite3_stmt_ptr searchAirports;
+ sqlite3_stmt_ptr searchAirports, getAllAirports;
sqlite3_stmt_ptr findCommByFreq, findNavsByFreq,
findNavsByFreqNoPos, findNavaidForRunway;
sqlite3_stmt_ptr getAirportItems, getAirportItemByIdent;
std::auto_ptr<RebuildThread> rebuilder;
};
- //////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
-FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid)
+FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid,
+ sqlite3_int64& aptId)
{
sqlite3_bind_int64(loadPositioned, 1, rowid);
assert(rowid == sqlite3_column_int64(loadPositioned, 0));
FGPositioned::Type ty = (FGPositioned::Type) sqlite3_column_int(loadPositioned, 1);
+ PositionedID prowid = static_cast<PositionedID>(rowid);
string ident = (char*) sqlite3_column_text(loadPositioned, 2);
string name = (char*) sqlite3_column_text(loadPositioned, 3);
- sqlite3_int64 aptId = sqlite3_column_int64(loadPositioned, 4);
+ aptId = sqlite3_column_int64(loadPositioned, 4);
double lon = sqlite3_column_double(loadPositioned, 5);
double lat = sqlite3_column_double(loadPositioned, 6);
double elev = sqlite3_column_double(loadPositioned, 7);
return loadAirport(rowid, ty, ident, name, pos);
case FGPositioned::TOWER:
- return new AirportTower(rowid, aptId, ident, pos);
+ return new AirportTower(prowid, aptId, ident, pos);
case FGPositioned::RUNWAY:
case FGPositioned::HELIPAD:
case FGPositioned::DME:
case FGPositioned::TACAN:
case FGPositioned::MOBILE_TACAN:
- {
- if (aptId > 0) {
- FGAirport* apt = FGPositioned::loadById<FGAirport>(aptId);
- if (apt->validateILSData()) {
- SG_LOG(SG_NAVCACHE, SG_INFO, "re-loaded ILS data for " << apt->ident());
- // queried data above is probably invalid, force us to go around again
- // (the next time through, validateILSData will return false)
- return outer->loadById(rowid);
- }
- }
-
return loadNav(rowid, ty, ident, name, pos);
- }
case FGPositioned::FIX:
return new FGFix(rowid, ident, pos);
return NULL;
}
}
-
+
+bool NavDataCache::NavDataCachePrivate::isCachedFileModified(const SGPath& path, bool verbose)
+{
+ if (!path.exists()) {
+ throw sg_io_exception("isCachedFileModified: Missing file:" + path.str());
+ }
+
+ sqlite_bind_temp_stdstring(statCacheCheck, 1, path.str());
+ bool isModified = true;
+ sgDebugPriority logLevel = verbose ? SG_WARN : SG_DEBUG;
+ if (execSelect(statCacheCheck)) {
+ time_t modtime = sqlite3_column_int64(statCacheCheck, 0);
+ time_t delta = std::labs(modtime - path.modTime());
+ if (delta != 0)
+ {
+ SG_LOG(SG_NAVCACHE, logLevel, "NavCache: rebuild required for " << path <<
+ ". Timestamps: " << modtime << " != " << path.modTime());
+ }
+ else
+ {
+ SG_LOG(SG_NAVCACHE, SG_DEBUG, "NavCache: no rebuild required for " << path);
+ }
+
+ isModified = (delta != 0);
+ } else {
+ SG_LOG(SG_NAVCACHE, logLevel, "NavCache: initial build required for " << path);
+ }
+
+ reset(statCacheCheck);
+ return isModified;
+}
static NavDataCache* static_instance = NULL;
SG_LOG(SG_NAVCACHE, t == 0 ? SG_WARN : SG_ALERT, "NavCache: init failed:" << e.what()
<< " (attempt " << t << ")");
d.reset();
- homePath.remove();
+
+ // only wipe the existing if not readonly
+ if (!fgGetBool("/sim/fghome-readonly", false)) {
+ homePath.remove();
+ }
}
} // of retry loop
{
assert(static_instance == this);
static_instance = NULL;
- SG_LOG(SG_NAVCACHE, SG_INFO, "closing the navcache");
d.reset();
}
bool NavDataCache::isRebuildRequired()
{
- if (isCachedFileModified(d->aptDatPath) ||
- isCachedFileModified(d->metarDatPath) ||
- isCachedFileModified(d->navDatPath) ||
- isCachedFileModified(d->fixDatPath) ||
- isCachedFileModified(d->poiDatPath) ||
- isCachedFileModified(d->airwayDatPath))
+ if (d->readOnly) {
+ return false;
+ }
+
+ if (flightgear::Options::sharedInstance()->isOptionSet("restore-defaults")) {
+ SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: restore-defaults requested, will rebuild cache");
+ return true;
+ }
+
+ if (d->isCachedFileModified(d->aptDatPath, true) ||
+ d->isCachedFileModified(d->metarDatPath, true) ||
+ d->isCachedFileModified(d->navDatPath, true) ||
+ d->isCachedFileModified(d->fixDatPath, true) ||
+ d->isCachedFileModified(d->carrierDatPath, true) ||
+// since POI loading is disabled on Windows, don't check for it
+// this caused: https://code.google.com/p/flightgear-bugs/issues/detail?id=1227
+#ifndef SG_WINDOWS
+ d->isCachedFileModified(d->poiDatPath, true) ||
+#endif
+ d->isCachedFileModified(d->airwayDatPath, true))
{
SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: main cache rebuild required");
return true;
}
-
- string sceneryPaths = simgear::strutils::join(globals->get_fg_scenery(), ";");
+
+ string sceneryPaths = simgear::strutils::join(globals->get_fg_scenery(), ";");
if (readStringProperty("scenery_paths") != sceneryPaths) {
- SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: scenery paths changed, main cache rebuild required");
- return true;
+ SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: scenery paths changed,dropping ground net");
+ dropAllGroundnets();
+ writeStringProperty("scenery_paths", sceneryPaths);
}
-
+
SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: no main cache rebuild required");
return false;
}
try {
d->close(); // completely close the sqlite object
d->path.remove(); // remove the file on disk
- d->init(); // star again from scratch
+ d->init(); // start again from scratch
- Transaction txn(this);
- // initialise the root octree node
+ // initialise the root octree node
d->runSQL("INSERT INTO octree (rowid, children) VALUES (1, 0)");
-
+
SGTimeStamp st;
- st.stamp();
-
- airportDBLoad(d->aptDatPath);
- SG_LOG(SG_NAVCACHE, SG_INFO, "apt.dat load took:" << st.elapsedMSec());
-
- metarDataLoad(d->metarDatPath);
- stampCacheFile(d->aptDatPath);
- stampCacheFile(d->metarDatPath);
-
- st.stamp();
- loadFixes(d->fixDatPath);
- stampCacheFile(d->fixDatPath);
- SG_LOG(SG_NAVCACHE, SG_INFO, "fix.dat load took:" << st.elapsedMSec());
-
- st.stamp();
- navDBInit(d->navDatPath);
- stampCacheFile(d->navDatPath);
- SG_LOG(SG_NAVCACHE, SG_INFO, "nav.dat load took:" << st.elapsedMSec());
+ {
+ Transaction txn(this);
+
+ st.stamp();
+ airportDBLoad(d->aptDatPath);
+ SG_LOG(SG_NAVCACHE, SG_INFO, "apt.dat load took:" << st.elapsedMSec());
+
+ metarDataLoad(d->metarDatPath);
+ stampCacheFile(d->aptDatPath);
+ stampCacheFile(d->metarDatPath);
+
+ st.stamp();
+ loadFixes(d->fixDatPath);
+ stampCacheFile(d->fixDatPath);
+ SG_LOG(SG_NAVCACHE, SG_INFO, "fix.dat load took:" << st.elapsedMSec());
+
+ st.stamp();
+ navDBInit(d->navDatPath);
+ stampCacheFile(d->navDatPath);
+ SG_LOG(SG_NAVCACHE, SG_INFO, "nav.dat load took:" << st.elapsedMSec());
+
+ st.stamp();
+ txn.commit();
+ SG_LOG(SG_NAVCACHE, SG_INFO, "stage 1 commit took:" << st.elapsedMSec());
+ }
+
+#ifdef SG_WINDOWS
+ SG_LOG(SG_NAVCACHE, SG_ALERT, "SKIPPING POI load on Windows");
+#else
+ {
+ Transaction txn(this);
+
+ st.stamp();
+ poiDBInit(d->poiDatPath);
+ stampCacheFile(d->poiDatPath);
+ SG_LOG(SG_NAVCACHE, SG_INFO, "poi.dat load took:" << st.elapsedMSec());
+
+ st.stamp();
+ txn.commit();
+ SG_LOG(SG_NAVCACHE, SG_INFO, "POI commit took:" << st.elapsedMSec());
+ }
+#endif
+
+ {
+ Transaction txn(this);
+ loadCarrierNav(d->carrierDatPath);
+ stampCacheFile(d->carrierDatPath);
+
+ st.stamp();
+ Airway::load(d->airwayDatPath);
+ stampCacheFile(d->airwayDatPath);
+ SG_LOG(SG_NAVCACHE, SG_INFO, "awy.dat load took:" << st.elapsedMSec());
+
+ d->flushDeferredOctreeUpdates();
+
+ string sceneryPaths = simgear::strutils::join(globals->get_fg_scenery(), ";");
+ writeStringProperty("scenery_paths", sceneryPaths);
+
+ st.stamp();
+ txn.commit();
+ SG_LOG(SG_NAVCACHE, SG_INFO, "final commit took:" << st.elapsedMSec());
+
+ }
- st.stamp();
- poiDBInit(d->poiDatPath);
- stampCacheFile(d->poiDatPath);
- SG_LOG(SG_NAVCACHE, SG_INFO, "poi.dat load took:" << st.elapsedMSec());
-
- loadCarrierNav(d->carrierDatPath);
- stampCacheFile(d->carrierDatPath);
-
- st.stamp();
- Airway::load(d->airwayDatPath);
- stampCacheFile(d->airwayDatPath);
- SG_LOG(SG_NAVCACHE, SG_INFO, "awy.dat load took:" << st.elapsedMSec());
-
- d->flushDeferredOctreeUpdates();
-
- string sceneryPaths = simgear::strutils::join(globals->get_fg_scenery(), ";");
- writeStringProperty("scenery_paths", sceneryPaths);
-
- txn.commit();
} catch (sg_exception& e) {
SG_LOG(SG_NAVCACHE, SG_ALERT, "caught exception rebuilding navCache:" << e.what());
}
bool NavDataCache::isCachedFileModified(const SGPath& path) const
{
- if (!path.exists()) {
- throw sg_io_exception("isCachedFileModified: Missing file:" + path.str());
- }
-
- sqlite_bind_temp_stdstring(d->statCacheCheck, 1, path.str());
- bool isModified = true;
-
- if (d->execSelect(d->statCacheCheck)) {
- time_t modtime = sqlite3_column_int64(d->statCacheCheck, 0);
- time_t delta = std::labs(modtime - path.modTime());
- if (delta != 0)
- {
- SG_LOG(SG_NAVCACHE, SG_DEBUG, "NavCache: rebuild required for " << path << ". Timestamps: " << modtime << " != " << path.modTime());
- if (delta < 30)
- {
- // File system time stamp has slightly changed. It's unlikely that the user has managed to change a file, start fgfs,
- // and then changed file again within x seconds - so it's suspicious...
- SG_LOG(SG_NAVCACHE, SG_ALERT, "NavCache: suspicious file timestamp change. Please report this to FlightGear. "
- << "Delta: " << delta << ", Timestamps: " << modtime << ", " << path.modTime() << ", path: " << path);
- }
- }
- else
- {
- SG_LOG(SG_NAVCACHE, SG_DEBUG, "NavCache: no rebuild required for " << path);
- }
-
- isModified = (delta != 0);
- } else {
- SG_LOG(SG_NAVCACHE, SG_DEBUG, "NavCache: initial build required for " << path);
- }
-
- d->reset(d->statCacheCheck);
- return isModified;
+ return d->isCachedFileModified(path, false);
}
void NavDataCache::stampCacheFile(const SGPath& path)
return it->second; // cache it
}
- FGPositioned* pos = d->loadById(rowid);
+ PositionedID aptId;
+ FGPositioned* pos = d->loadById(rowid, aptId);
d->cache.insert(it, PositionedCache::value_type(rowid, pos));
- d->cacheMisses++;
+ d->cacheMisses++;
+
+ // when we loaded an ILS, we must apply per-airport changes
+ if ((pos->type() == FGPositioned::ILS) && (aptId > 0)) {
+ FGAirport* apt = FGPositioned::loadById<FGAirport>(aptId);
+ apt->validateILSData();
+ }
+
return pos;
}
}
}
-void NavDataCache::updateRunwayThreshold(PositionedID runwayID, const SGGeod &aThreshold,
- double aHeading, double aDisplacedThreshold,
- double aStopway)
-{
-// update the runway information
- sqlite3_bind_int64(d->updateRunwayThreshold, 1, runwayID);
- sqlite3_bind_double(d->updateRunwayThreshold, 2, aHeading);
- sqlite3_bind_double(d->updateRunwayThreshold, 3, aDisplacedThreshold);
- sqlite3_bind_double(d->updateRunwayThreshold, 4, aStopway);
- d->execUpdate(d->updateRunwayThreshold);
-
- // now update the positional data
- updatePosition(runwayID, aThreshold);
-}
-
PositionedID
NavDataCache::insertNavaid(FGPositioned::Type ty, const string& ident,
const string& name, const SGGeod& pos,
sqlite3_bind_int(d->insertNavaid, 3, range);
sqlite3_bind_double(d->insertNavaid, 4, multiuse);
sqlite3_bind_int64(d->insertNavaid, 5, runway);
+ sqlite3_bind_int64(d->insertNavaid, 6, 0);
return d->execInsert(d->insertNavaid);
}
-void NavDataCache::updateILS(PositionedID ils, const SGGeod& newPos, double aHdg)
+void NavDataCache::setNavaidColocated(PositionedID navaid, PositionedID colocatedDME)
{
- sqlite3_bind_int64(d->updateILS, 1, ils);
- sqlite3_bind_double(d->updateILS, 2, aHdg);
- d->execUpdate(d->updateILS);
- updatePosition(ils, newPos);
+ // Update DB entries...
+ sqlite3_bind_int64(d->setNavaidColocated, 1, navaid);
+ sqlite3_bind_int64(d->setNavaidColocated, 2, colocatedDME);
+ d->execUpdate(d->setNavaidColocated);
+
+ // ...and the in-memory copy of the navrecord
+ if (d->cache.find(navaid) != d->cache.end()) {
+ FGNavRecord* rec = (FGNavRecord*) d->cache[navaid].get();
+ rec->setColocatedDME(colocatedDME);
+ }
}
PositionedID NavDataCache::insertCommStation(FGPositioned::Type ty,
true /* spatial index */);
}
-void NavDataCache::removePOI(FGPositioned::Type ty, const std::string& aIdent)
+bool NavDataCache::removePOI(FGPositioned::Type ty, const std::string& aIdent)
{
d->removePositionedWithIdent(ty, aIdent);
// should remove from the live cache too?
+
+ return true;
}
void NavDataCache::setAirportMetar(const string& icao, bool hasMetar)
*/
char** NavDataCache::searchAirportNamesAndIdents(const std::string& aFilter)
{
- string s = "%" + aFilter + "%";
- sqlite_bind_stdstring(d->searchAirports, 1, s);
-
+ sqlite3_stmt_ptr stmt;
unsigned int numMatches = 0, numAllocated = 16;
- char** result = (char**) malloc(sizeof(char*) * numAllocated);
+ if (aFilter.empty()) {
+ stmt = d->getAllAirports;
+ numAllocated = 4096; // start much larger for all airports
+ } else {
+ stmt = d->searchAirports;
+ string s = "%" + aFilter + "%";
+ sqlite_bind_stdstring(stmt, 1, s);
+ }
- while (d->stepSelect(d->searchAirports)) {
+ char** result = (char**) malloc(sizeof(char*) * numAllocated);
+ while (d->stepSelect(stmt)) {
if ((numMatches + 1) >= numAllocated) {
numAllocated <<= 1; // double in size!
// reallocate results array
// which gives a grand total of 7 + name-length + icao-length.
// note the ident can be three letters (non-ICAO local strip), four
// (default ICAO) or more (extended format ICAO)
- int nameLength = sqlite3_column_bytes(d->searchAirports, 1);
- int icaoLength = sqlite3_column_bytes(d->searchAirports, 0);
+ int nameLength = sqlite3_column_bytes(stmt, 1);
+ int icaoLength = sqlite3_column_bytes(stmt, 0);
char* entry = (char*) malloc(7 + nameLength + icaoLength);
char* dst = entry;
*dst++ = ' ';
- memcpy(dst, sqlite3_column_text(d->searchAirports, 1), nameLength);
+ memcpy(dst, sqlite3_column_text(stmt, 1), nameLength);
dst += nameLength;
*dst++ = ' ';
*dst++ = ' ';
*dst++ = ' ';
*dst++ = '(';
- memcpy(dst, sqlite3_column_text(d->searchAirports, 0), icaoLength);
+ memcpy(dst, sqlite3_column_text(stmt, 0), icaoLength);
dst += icaoLength;
*dst++ = ')';
*dst++ = 0;
}
result[numMatches] = NULL; // end of list marker
- d->reset(d->searchAirports);
+ d->reset(stmt);
return result;
}
sqlite3_bind_int64(q, 1, aAirport);
d->execUpdate(q);
}
+
+void NavDataCache::dropAllGroundnets()
+{
+ SG_LOG(SG_NAVCACHE, SG_INFO, "dropping ground-net data");
+ beginTransaction();
+ d->runSQL("DELETE FROM groundnet_edge");
+ d->runSQL("DELETE FROM parking");
+ d->runSQL("DELETE FROM taxi_node");
+
+ sqlite3_stmt_ptr q = d->prepare("DELETE FROM positioned WHERE (type=?1 OR type=?2)");
+ sqlite3_bind_int(q, 1, FGPositioned::TAXI_NODE);
+ sqlite3_bind_int(q, 2, FGPositioned::PARKING);
+ d->execUpdate(q);
+ commitTransaction();
+}
+
+bool NavDataCache::isReadOnly() const
+{
+ return d->readOnly;
+}
/////////////////////////////////////////////////////////////////////////////////////////
// Transaction RAII object