]> git.mxchange.org Git - flightgear.git/blobdiff - src/Navaids/NavDataCache.cxx
Fix distance-along-path computation
[flightgear.git] / src / Navaids / NavDataCache.cxx
index 2d44a88053dd4ce23e562d7e2d54c58d04f50dfb..f6756613bd6c19130d5c308b44c36282add9852f 100644 (file)
 # 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>
@@ -50,6 +58,8 @@
 #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>
@@ -64,6 +74,7 @@
 #include "poidb.hxx"
 #include <Airports/parking.hxx>
 #include <Airports/gnnode.hxx>
+#include "CacheSchema.h"
 
 using std::string;
 
@@ -73,7 +84,7 @@ using std::string;
 namespace {
 
 const int MAX_RETRIES = 10;
-const int SCHEMA_VERSION = 8;
+    
 const int CACHE_SIZE_KBYTES= 32 * 1024;
     
 // bind a std::string to a sqlite statement. The std::string must live the
@@ -199,6 +210,7 @@ public:
     outer(o),
     db(NULL),
     path(p),
+    readOnly(false),
     cacheHits(0),
     cacheMisses(0),
     transactionLevel(0),
@@ -215,12 +227,14 @@ public:
   {
     SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache at:" << path);
        
-       // see http://code.google.com/p/flightgear-bugs/issues/detail?id=1055
-       // for the logic here. Sigh.
+      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,
-                    SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
-    
+    sqlite3_open_v2(pathUtf8.c_str(), &db, openFlags, NULL);
     
     sqlite3_stmt_ptr checkTables =
       prepare("SELECT count(*) FROM sqlite_master WHERE name='properties'");
@@ -230,7 +244,7 @@ public:
     
     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;
@@ -286,6 +300,8 @@ public:
     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)
   {
@@ -414,116 +430,17 @@ public:
     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()
@@ -559,7 +476,6 @@ public:
     setRunwayReciprocal = prepare("UPDATE runway SET reciprocal=?2 WHERE rowid=?1");
     setRunwayILS = prepare("UPDATE runway SET ils=?2 WHERE rowid=?1");
     setNavaidColocated = prepare("UPDATE navaid SET colocated=?2 WHERE rowid=?1");
-    updateRunwayThreshold = prepare("UPDATE runway SET heading=?2, displaced_threshold=?3, stopway=?4 WHERE rowid=?1");
     
     insertPositionedQuery = prepare("INSERT INTO positioned "
                                     "(type, ident, name, airport, lon, lat, elev_m, octree_node, "
@@ -571,7 +487,6 @@ public:
     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 (?, ?, ?)");
@@ -621,6 +536,11 @@ public:
     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="
@@ -705,7 +625,7 @@ public:
   }
 
   
-  FGPositioned* loadById(sqlite_int64 rowId);
+  FGPositioned* loadById(sqlite_int64 rowId, sqlite3_int64& aptId);
   
   FGAirport* loadAirport(sqlite_int64 rowId,
                          FGPositioned::Type ty,
@@ -796,10 +716,15 @@ public:
     PositionedID colocated = sqlite3_column_int64(loadNavaid, 4);
     reset(loadNavaid);
 
-    FGNavRecord* n = new FGNavRecord(rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway);
-    if (colocated) {
-        n->setColocatedDME(colocated);
-    }
+    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;
   }
@@ -947,7 +872,8 @@ public:
   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
@@ -973,7 +899,7 @@ public:
   sqlite3_stmt_ptr insertPositionedQuery, insertAirport, insertTower, insertRunway,
   insertCommStation, insertNavaid;
   sqlite3_stmt_ptr setAirportMetar, setRunwayReciprocal, setRunwayILS, setNavaidColocated,
-    setAirportPos, updateRunwayThreshold, updateILS;
+    setAirportPos;
   sqlite3_stmt_ptr removePOIQuery;
   
   sqlite3_stmt_ptr findClosestWithIdent;
@@ -981,7 +907,7 @@ public:
   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;
@@ -1015,9 +941,10 @@ public:
   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);
@@ -1026,9 +953,10 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 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);
@@ -1043,7 +971,7 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid)
       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:
@@ -1061,18 +989,7 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid)
     case FGPositioned::DME:
     case FGPositioned::TACAN:
     case FGPositioned::MOBILE_TACAN:
-    {
-      if (aptId > 0) {
-        FGAirport* apt = FGPositioned::loadById<FGAirport>(aptId);
-        if (apt->validateILSData()) {
-          // 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);
@@ -1107,7 +1024,37 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid)
       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;
         
@@ -1137,7 +1084,11 @@ NavDataCache::NavDataCache()
       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
     
@@ -1186,26 +1137,49 @@ NavDataCache* NavDataCache::instance()
   
 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(), ";");  
-  if (readStringProperty("scenery_paths") != sceneryPaths) {
-    SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: scenery paths changed, main cache rebuild required");
-    return true;
-  }
-    
+  dropGroundnetsIfRequired();
+  
   SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: no main cache rebuild required");
   return false;
 }
+
+bool NavDataCache::dropGroundnetsIfRequired()
+{
+    string sceneryPaths = simgear::strutils::join(globals->get_fg_scenery(), ";");
+    if (readStringProperty("scenery_paths") != sceneryPaths) {
+        SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: scenery paths changed, dropping ground nets");
+        dropAllGroundnets();
+        writeStringProperty("scenery_paths", sceneryPaths);
+        return true;
+    }
+
+    return false;
+}
   
 bool NavDataCache::rebuild()
 {
@@ -1396,32 +1370,7 @@ void NavDataCache::writeStringListProperty(const string& key, const string_list&
   
 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());
-    }
-    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)
@@ -1512,9 +1461,17 @@ FGPositionedRef NavDataCache::loadById(PositionedID rowid)
     return it->second; // cache it
   }
   
-  FGPositioned* pos = d->loadById(rowid);
+  sqlite3_int64 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;
 }
 
@@ -1621,21 +1578,6 @@ void NavDataCache::setRunwayILS(PositionedID runway, PositionedID ils)
   }
 }
   
-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,
@@ -1671,14 +1613,6 @@ void NavDataCache::setNavaidColocated(PositionedID navaid, PositionedID colocate
     rec->setColocatedDME(colocatedDME);
   }
 }
-
-void NavDataCache::updateILS(PositionedID ils, const SGGeod& newPos, double aHdg)
-{
-  sqlite3_bind_int64(d->updateILS, 1, ils);
-  sqlite3_bind_double(d->updateILS, 2, aHdg);
-  d->execUpdate(d->updateILS);
-  updatePosition(ils, newPos);
-}
   
 PositionedID NavDataCache::insertCommStation(FGPositioned::Type ty,
                                              const string& name, const SGGeod& pos, int freq, int range,
@@ -1822,13 +1756,19 @@ NavDataCache::getOctreeLeafChildren(int64_t octreeNodeId)
  */
 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);
+  string searchTerm("%" + aFilter + "%");
+  if (aFilter.empty()) {
+    stmt = d->getAllAirports;
+    numAllocated = 4096; // start much larger for all airports
+  } else {
+    stmt = d->searchAirports;
+    sqlite_bind_stdstring(stmt, 1, searchTerm);
+  }
   
-  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
@@ -1846,18 +1786,18 @@ char** NavDataCache::searchAirportNamesAndIdents(const std::string& aFilter)
     // 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;
@@ -1866,7 +1806,7 @@ char** NavDataCache::searchAirportNamesAndIdents(const std::string& aFilter)
   }
   
   result[numMatches] = NULL; // end of list marker
-  d->reset(d->searchAirports);
+  d->reset(stmt);
   return result;
 }
   
@@ -1984,7 +1924,7 @@ NavDataCache::findAirportRunway(const std::string& aName)
 
   AirportRunwayPair result;
   sqlite_bind_stdstring(d->findAirportRunway, 1, parts[0]);
-  sqlite_bind_stdstring(d->findAirportRunway, 2, parts[1]);
+  sqlite_bind_stdstring(d->findAirportRunway, 2, cleanRunwayNo(parts[1]));
   
   if (d->execSelect(d->findAirportRunway)) {
     result = AirportRunwayPair(sqlite3_column_int64(d->findAirportRunway, 0),
@@ -1999,8 +1939,10 @@ NavDataCache::findAirportRunway(const std::string& aName)
 }
   
 PositionedID
-NavDataCache::findILS(PositionedID airport, const string& runway, const string& navIdent)
+NavDataCache::findILS(PositionedID airport, const string& aRunway, const string& navIdent)
 {
+  string runway(cleanRunwayNo(aRunway));
+    
   sqlite_bind_stdstring(d->findILS, 1, navIdent);
   sqlite3_bind_int64(d->findILS, 2, airport);
   sqlite_bind_stdstring(d->findILS, 3, runway);
@@ -2227,6 +2169,26 @@ void NavDataCache::dropGroundnetFor(PositionedID aAirport)
   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