mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[324] various fixes for SQLite3 schema
- STRING => TEXT - make sure the right side of LIKE is a placeholder for a string, not an expression (otherwise it doesn't use indices) - introduce the "records_bytype_and_rname" index. it's necessary to optimize the FIND_PREVIOUS query.
This commit is contained in:
@@ -47,9 +47,9 @@ except sqlite3.OperationalError as ex:
|
|||||||
'zone_id INTEGER NOT NULL, ' +
|
'zone_id INTEGER NOT NULL, ' +
|
||||||
'version INTEGER NOT NULL, ' +
|
'version INTEGER NOT NULL, ' +
|
||||||
'operation INTEGER NOT NULL, ' +
|
'operation INTEGER NOT NULL, ' +
|
||||||
'name STRING NOT NULL COLLATE NOCASE, ' +
|
'name TEXT NOT NULL COLLATE NOCASE, ' +
|
||||||
'rrtype STRING NOT NULL COLLATE NOCASE, ' +
|
'rrtype TEXT NOT NULL COLLATE NOCASE, ' +
|
||||||
'ttl INTEGER NOT NULL, rdata STRING NOT NULL)')
|
'ttl INTEGER NOT NULL, rdata TEXT NOT NULL)')
|
||||||
else:
|
else:
|
||||||
sys.stdout.write('Found an older version of SQLite3 DB file: ' +
|
sys.stdout.write('Found an older version of SQLite3 DB file: ' +
|
||||||
db_file + '\n' + "Perform '" + os.getcwd() +
|
db_file + '\n' + "Perform '" + os.getcwd() +
|
||||||
|
@@ -245,31 +245,38 @@ const char* const SCHEMA_LIST[] = {
|
|||||||
"CREATE TABLE schema_version (version INTEGER NOT NULL)",
|
"CREATE TABLE schema_version (version INTEGER NOT NULL)",
|
||||||
"INSERT INTO schema_version VALUES (1)",
|
"INSERT INTO schema_version VALUES (1)",
|
||||||
"CREATE TABLE zones (id INTEGER PRIMARY KEY, "
|
"CREATE TABLE zones (id INTEGER PRIMARY KEY, "
|
||||||
"name STRING NOT NULL COLLATE NOCASE, "
|
"name TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"rdclass STRING NOT NULL COLLATE NOCASE DEFAULT 'IN', "
|
"rdclass TEXT NOT NULL COLLATE NOCASE DEFAULT 'IN', "
|
||||||
"dnssec BOOLEAN NOT NULL DEFAULT 0)",
|
"dnssec BOOLEAN NOT NULL DEFAULT 0)",
|
||||||
"CREATE INDEX zones_byname ON zones (name)",
|
"CREATE INDEX zones_byname ON zones (name)",
|
||||||
"CREATE TABLE records (id INTEGER PRIMARY KEY, "
|
"CREATE TABLE records (id INTEGER PRIMARY KEY, "
|
||||||
"zone_id INTEGER NOT NULL, name STRING NOT NULL COLLATE NOCASE, "
|
"zone_id INTEGER NOT NULL, name TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"rname STRING NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
|
"rname TEXT NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
|
||||||
"rdtype STRING NOT NULL COLLATE NOCASE, sigtype STRING COLLATE NOCASE, "
|
"rdtype TEXT NOT NULL COLLATE NOCASE, sigtype TEXT COLLATE NOCASE, "
|
||||||
"rdata STRING NOT NULL)",
|
"rdata TEXT NOT NULL)",
|
||||||
"CREATE INDEX records_byname ON records (name)",
|
"CREATE INDEX records_byname ON records (name)",
|
||||||
"CREATE INDEX records_byrname ON records (rname)",
|
"CREATE INDEX records_byrname ON records (rname)",
|
||||||
|
// The next index is a tricky one. It's necessary for
|
||||||
|
// FIND_PREVIOUS to use the index efficiently; since there's an
|
||||||
|
// "inequality", the rname column must be placed later. records_byrname
|
||||||
|
// may not be sufficient especially when the zone is not signed (and
|
||||||
|
// defining a separate index for rdtype only doesn't work either; SQLite3
|
||||||
|
// would then create a temporary B-tree for "ORDER BY").
|
||||||
|
"CREATE INDEX records_bytype_and_rname ON records (rdtype, rname)",
|
||||||
"CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
|
"CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
|
||||||
"hash STRING NOT NULL COLLATE NOCASE, "
|
"hash TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"owner STRING NOT NULL COLLATE NOCASE, "
|
"owner TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
|
"ttl INTEGER NOT NULL, rdtype TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"rdata STRING NOT NULL)",
|
"rdata TEXT NOT NULL)",
|
||||||
"CREATE INDEX nsec3_byhash ON nsec3 (hash)",
|
"CREATE INDEX nsec3_byhash ON nsec3 (hash)",
|
||||||
"CREATE TABLE diffs (id INTEGER PRIMARY KEY, "
|
"CREATE TABLE diffs (id INTEGER PRIMARY KEY, "
|
||||||
"zone_id INTEGER NOT NULL, "
|
"zone_id INTEGER NOT NULL, "
|
||||||
"version INTEGER NOT NULL, "
|
"version INTEGER NOT NULL, "
|
||||||
"operation INTEGER NOT NULL, "
|
"operation INTEGER NOT NULL, "
|
||||||
"name STRING NOT NULL COLLATE NOCASE, "
|
"name TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"rrtype STRING NOT NULL COLLATE NOCASE, "
|
"rrtype TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"ttl INTEGER NOT NULL, "
|
"ttl INTEGER NOT NULL, "
|
||||||
"rdata STRING NOT NULL)",
|
"rdata TEXT NOT NULL)",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -26,7 +26,7 @@
|
|||||||
#include <dns/rrset.h>
|
#include <dns/rrset.h>
|
||||||
#include <dns/rrsetlist.h>
|
#include <dns/rrsetlist.h>
|
||||||
|
|
||||||
#define SQLITE_SCHEMA_VERSION 1
|
#define SQLITE_SCHEMA_VERSION 2
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace isc::dns;
|
using namespace isc::dns;
|
||||||
@@ -57,33 +57,34 @@ struct Sqlite3Parameters {
|
|||||||
namespace {
|
namespace {
|
||||||
const char* const SCHEMA_LIST[] = {
|
const char* const SCHEMA_LIST[] = {
|
||||||
"CREATE TABLE schema_version (version INTEGER NOT NULL)",
|
"CREATE TABLE schema_version (version INTEGER NOT NULL)",
|
||||||
"INSERT INTO schema_version VALUES (1)",
|
"INSERT INTO schema_version VALUES (2)",
|
||||||
"CREATE TABLE zones (id INTEGER PRIMARY KEY, "
|
"CREATE TABLE zones (id INTEGER PRIMARY KEY, "
|
||||||
"name STRING NOT NULL COLLATE NOCASE, "
|
"name TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"rdclass STRING NOT NULL COLLATE NOCASE DEFAULT 'IN', "
|
"rdclass TEXT NOT NULL COLLATE NOCASE DEFAULT 'IN', "
|
||||||
"dnssec BOOLEAN NOT NULL DEFAULT 0)",
|
"dnssec BOOLEAN NOT NULL DEFAULT 0)",
|
||||||
"CREATE INDEX zones_byname ON zones (name)",
|
"CREATE INDEX zones_byname ON zones (name)",
|
||||||
"CREATE TABLE records (id INTEGER PRIMARY KEY, "
|
"CREATE TABLE records (id INTEGER PRIMARY KEY, "
|
||||||
"zone_id INTEGER NOT NULL, name STRING NOT NULL COLLATE NOCASE, "
|
"zone_id INTEGER NOT NULL, name TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"rname STRING NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
|
"rname TEXT NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
|
||||||
"rdtype STRING NOT NULL COLLATE NOCASE, sigtype STRING COLLATE NOCASE, "
|
"rdtype TEXT NOT NULL COLLATE NOCASE, sigtype TEXT COLLATE NOCASE, "
|
||||||
"rdata STRING NOT NULL)",
|
"rdata TEXT NOT NULL)",
|
||||||
"CREATE INDEX records_byname ON records (name)",
|
"CREATE INDEX records_byname ON records (name)",
|
||||||
"CREATE INDEX records_byrname ON records (rname)",
|
"CREATE INDEX records_byrname ON records (rname)",
|
||||||
|
"CREATE INDEX records_bytype_and_rname ON records (rdtype, rname)",
|
||||||
"CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
|
"CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
|
||||||
"hash STRING NOT NULL COLLATE NOCASE, "
|
"hash TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"owner STRING NOT NULL COLLATE NOCASE, "
|
"owner TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
|
"ttl INTEGER NOT NULL, rdtype TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"rdata STRING NOT NULL)",
|
"rdata TEXT NOT NULL)",
|
||||||
"CREATE INDEX nsec3_byhash ON nsec3 (hash)",
|
"CREATE INDEX nsec3_byhash ON nsec3 (hash)",
|
||||||
"CREATE TABLE diffs (id INTEGER PRIMARY KEY, "
|
"CREATE TABLE diffs (id INTEGER PRIMARY KEY, "
|
||||||
"zone_id INTEGER NOT NULL, "
|
"zone_id INTEGER NOT NULL, "
|
||||||
"version INTEGER NOT NULL, "
|
"version INTEGER NOT NULL, "
|
||||||
"operation INTEGER NOT NULL, "
|
"operation INTEGER NOT NULL, "
|
||||||
"name STRING NOT NULL COLLATE NOCASE, "
|
"name TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"rrtype STRING NOT NULL COLLATE NOCASE, "
|
"rrtype TEXT NOT NULL COLLATE NOCASE, "
|
||||||
"ttl INTEGER NOT NULL, "
|
"ttl INTEGER NOT NULL, "
|
||||||
"rdata STRING NOT NULL)",
|
"rdata TEXT NOT NULL)",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -109,12 +110,16 @@ const char* const q_referral_str = "SELECT rdtype, ttl, sigtype, rdata FROM "
|
|||||||
const char* const q_any_str = "SELECT rdtype, ttl, sigtype, rdata "
|
const char* const q_any_str = "SELECT rdtype, ttl, sigtype, rdata "
|
||||||
"FROM records WHERE zone_id=?1 AND name=?2";
|
"FROM records WHERE zone_id=?1 AND name=?2";
|
||||||
|
|
||||||
|
// Note: the wildcard symbol '%' is expected to be added to the text
|
||||||
|
// for the placeholder for LIKE given via sqlite3_bind_text(). We don't
|
||||||
|
// use the expression such as (?2 || '%') because it would disable the use
|
||||||
|
// of indices and could result in terrible performance.
|
||||||
const char* const q_count_str = "SELECT COUNT(*) FROM records "
|
const char* const q_count_str = "SELECT COUNT(*) FROM records "
|
||||||
"WHERE zone_id=?1 AND rname LIKE (?2 || '%');";
|
"WHERE zone_id=?1 AND rname LIKE ?2;";
|
||||||
|
|
||||||
const char* const q_previous_str = "SELECT name FROM records "
|
const char* const q_previous_str = "SELECT name FROM records "
|
||||||
"WHERE zone_id=?1 AND rdtype = 'NSEC' AND "
|
"WHERE rname < ?2 AND zone_id=?1 AND rdtype = 'NSEC' "
|
||||||
"rname < $2 ORDER BY rname DESC LIMIT 1";
|
"ORDER BY rname DESC LIMIT 1";
|
||||||
|
|
||||||
const char* const q_nsec3_str = "SELECT rdtype, ttl, rdata FROM nsec3 "
|
const char* const q_nsec3_str = "SELECT rdtype, ttl, rdata FROM nsec3 "
|
||||||
"WHERE zone_id = ?1 AND hash = $2";
|
"WHERE zone_id = ?1 AND hash = $2";
|
||||||
@@ -314,8 +319,9 @@ Sqlite3DataSrc::findRecords(const Name& name, const RRType& rdtype,
|
|||||||
" to SQL statement (qcount)");
|
" to SQL statement (qcount)");
|
||||||
}
|
}
|
||||||
|
|
||||||
const string revname_text = name.reverse().toText();
|
const string revname_text = name.reverse().toText() + "%";
|
||||||
rc = sqlite3_bind_text(dbparameters->q_count_, 2, revname_text.c_str(),
|
rc = sqlite3_bind_text(dbparameters->q_count_, 2,
|
||||||
|
revname_text.c_str(),
|
||||||
-1, SQLITE_STATIC);
|
-1, SQLITE_STATIC);
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
isc_throw(Sqlite3Error, "Could not bind name " << name.reverse() <<
|
isc_throw(Sqlite3Error, "Could not bind name " << name.reverse() <<
|
||||||
|
@@ -23,6 +23,9 @@ RR_NAME_INDEX = 2
|
|||||||
RR_TTL_INDEX = 4
|
RR_TTL_INDEX = 4
|
||||||
RR_RDATA_INDEX = 7
|
RR_RDATA_INDEX = 7
|
||||||
|
|
||||||
|
# Current version of schema (maybe we need a minor version, too)
|
||||||
|
SCHEMA_VERSION = 2
|
||||||
|
|
||||||
class Sqlite3DSError(Exception):
|
class Sqlite3DSError(Exception):
|
||||||
""" Define exceptions."""
|
""" Define exceptions."""
|
||||||
pass
|
pass
|
||||||
@@ -48,39 +51,43 @@ def create(cur):
|
|||||||
row = cur.fetchone()
|
row = cur.fetchone()
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
cur.execute("CREATE TABLE schema_version (version INTEGER NOT NULL)")
|
cur.execute("CREATE TABLE schema_version (version INTEGER NOT NULL)")
|
||||||
cur.execute("INSERT INTO schema_version VALUES (1)")
|
cur.execute("INSERT INTO schema_version VALUES (" +
|
||||||
|
str(SCHEMA_VERSION) + ")")
|
||||||
cur.execute("""CREATE TABLE zones (id INTEGER PRIMARY KEY,
|
cur.execute("""CREATE TABLE zones (id INTEGER PRIMARY KEY,
|
||||||
name STRING NOT NULL COLLATE NOCASE,
|
name TEXT NOT NULL COLLATE NOCASE,
|
||||||
rdclass STRING NOT NULL COLLATE NOCASE DEFAULT 'IN',
|
rdclass TEXT NOT NULL COLLATE NOCASE DEFAULT 'IN',
|
||||||
dnssec BOOLEAN NOT NULL DEFAULT 0)""")
|
dnssec BOOLEAN NOT NULL DEFAULT 0)""")
|
||||||
cur.execute("CREATE INDEX zones_byname ON zones (name)")
|
cur.execute("CREATE INDEX zones_byname ON zones (name)")
|
||||||
cur.execute("""CREATE TABLE records (id INTEGER PRIMARY KEY,
|
cur.execute("""CREATE TABLE records (id INTEGER PRIMARY KEY,
|
||||||
zone_id INTEGER NOT NULL,
|
zone_id INTEGER NOT NULL,
|
||||||
name STRING NOT NULL COLLATE NOCASE,
|
name TEXT NOT NULL COLLATE NOCASE,
|
||||||
rname STRING NOT NULL COLLATE NOCASE,
|
rname TEXT NOT NULL COLLATE NOCASE,
|
||||||
ttl INTEGER NOT NULL,
|
ttl INTEGER NOT NULL,
|
||||||
rdtype STRING NOT NULL COLLATE NOCASE,
|
rdtype TEXT NOT NULL COLLATE NOCASE,
|
||||||
sigtype STRING COLLATE NOCASE,
|
sigtype TEXT COLLATE NOCASE,
|
||||||
rdata STRING NOT NULL)""")
|
rdata TEXT NOT NULL)""")
|
||||||
cur.execute("CREATE INDEX records_byname ON records (name)")
|
cur.execute("CREATE INDEX records_byname ON records (name)")
|
||||||
cur.execute("CREATE INDEX records_byrname ON records (rname)")
|
cur.execute("CREATE INDEX records_byrname ON records (rname)")
|
||||||
|
cur.execute("""CREATE INDEX records_bytype_and_rname ON records
|
||||||
|
(rdtype, rname)""")
|
||||||
cur.execute("""CREATE TABLE nsec3 (id INTEGER PRIMARY KEY,
|
cur.execute("""CREATE TABLE nsec3 (id INTEGER PRIMARY KEY,
|
||||||
zone_id INTEGER NOT NULL,
|
zone_id INTEGER NOT NULL,
|
||||||
hash STRING NOT NULL COLLATE NOCASE,
|
hash TEXT NOT NULL COLLATE NOCASE,
|
||||||
owner STRING NOT NULL COLLATE NOCASE,
|
owner TEXT NOT NULL COLLATE NOCASE,
|
||||||
ttl INTEGER NOT NULL,
|
ttl INTEGER NOT NULL,
|
||||||
rdtype STRING NOT NULL COLLATE NOCASE,
|
rdtype TEXT NOT NULL COLLATE NOCASE,
|
||||||
rdata STRING NOT NULL)""")
|
rdata TEXT NOT NULL)""")
|
||||||
cur.execute("CREATE INDEX nsec3_byhash ON nsec3 (hash)")
|
cur.execute("CREATE INDEX nsec3_byhash ON nsec3 (hash)")
|
||||||
cur.execute("""CREATE TABLE diffs (id INTEGER PRIMARY KEY,
|
cur.execute("""CREATE TABLE diffs (id INTEGER PRIMARY KEY,
|
||||||
zone_id INTEGER NOT NULL,
|
zone_id INTEGER NOT NULL,
|
||||||
version INTEGER NOT NULL,
|
version INTEGER NOT NULL,
|
||||||
operation INTEGER NOT NULL,
|
operation INTEGER NOT NULL,
|
||||||
name STRING NOT NULL COLLATE NOCASE,
|
name TEXT NOT NULL COLLATE NOCASE,
|
||||||
rrtype STRING NOT NULL COLLATE NOCASE,
|
rrtype TEXT NOT NULL COLLATE NOCASE,
|
||||||
ttl INTEGER NOT NULL,
|
ttl INTEGER NOT NULL,
|
||||||
rdata STRING NOT NULL)""")
|
rdata TEXT NOT NULL)""")
|
||||||
row = [1]
|
cur.execute("SELECT version FROM schema_version")
|
||||||
|
row = cur.fetchone()
|
||||||
cur.execute("COMMIT TRANSACTION")
|
cur.execute("COMMIT TRANSACTION")
|
||||||
return row
|
return row
|
||||||
|
|
||||||
@@ -115,8 +122,9 @@ def open(dbfile, connect_timeout=5.0):
|
|||||||
row = create(cur)
|
row = create(cur)
|
||||||
conn.isolation_level = iso_lvl
|
conn.isolation_level = iso_lvl
|
||||||
|
|
||||||
if row == None or row[0] != 1:
|
if row == None or row[0] != SCHEMA_VERSION:
|
||||||
raise Sqlite3DSError("Bad database schema version")
|
bad_version = "(unknown)" if row is None else str(row[0])
|
||||||
|
raise Sqlite3DSError("Bad database schema version: " + bad_version)
|
||||||
|
|
||||||
return conn, cur
|
return conn, cur
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user