Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sebastian Schrader
Kea
Commits
c35f6b15
Commit
c35f6b15
authored
Sep 09, 2011
by
Michal 'vorner' Vaner
Browse files
[1177] Implement previous name for SQLite3
parent
3f2864bf
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/lib/datasrc/sqlite3_accessor.cc
View file @
c35f6b15
...
...
@@ -47,7 +47,9 @@ enum StatementID {
ADD_RECORD
=
7
,
DEL_RECORD
=
8
,
ITERATE
=
9
,
NUM_STATEMENTS
=
10
FIND_PREVIOUS
=
10
,
FIND_PREVIOUS_WRAP
=
11
,
NUM_STATEMENTS
=
12
};
const
char
*
const
text_statements
[
NUM_STATEMENTS
]
=
{
...
...
@@ -68,7 +70,13 @@ const char* const text_statements[NUM_STATEMENTS] = {
"DELETE FROM records WHERE zone_id=?1 AND name=?2 "
// DEL_RECORD
"AND rdtype=?3 AND rdata=?4"
,
"SELECT rdtype, ttl, sigtype, rdata, name FROM records "
// ITERATE
"WHERE zone_id = ?1 ORDER BY name, rdtype"
"WHERE zone_id = ?1 ORDER BY name, rdtype"
,
"SELECT name FROM records "
// FIND_PREVIOUS
"WHERE zone_id=?1 AND rdtype = 'NSEC' AND "
"rname < $2 ORDER BY rname DESC LIMIT 1"
,
// FIND_PREVIOUS_WRAP
"SELECT name FROM records "
"WHERE zone_id = ?1 AND rdtype = 'NSEC' "
"ORDER BY rname DESC LIMIT 1"
};
struct
SQLite3Parameters
{
...
...
@@ -391,6 +399,28 @@ SQLite3Accessor::getZone(const std::string& name) const {
return
(
std
::
pair
<
bool
,
int
>
(
false
,
0
));
}
namespace
{
// Conversion to plain char
const
char
*
convertToPlainCharInternal
(
const
unsigned
char
*
ucp
,
sqlite3
*
db
)
{
if
(
ucp
==
NULL
)
{
// The field can really be NULL, in which case we return an
// empty string, or sqlite may have run out of memory, in
// which case we raise an error
if
(
sqlite3_errcode
(
db
)
==
SQLITE_NOMEM
)
{
isc_throw
(
DataSourceError
,
"Sqlite3 backend encountered a memory allocation "
"error in sqlite3_column_text()"
);
}
else
{
return
(
""
);
}
}
const
void
*
p
=
ucp
;
return
(
static_cast
<
const
char
*>
(
p
));
}
}
class
SQLite3Accessor
::
Context
:
public
DatabaseAccessor
::
IteratorContext
{
public:
// Construct an iterator for all records. When constructed this
...
...
@@ -501,21 +531,8 @@ private:
// In case sqlite3_column_text() returns NULL, we just make it an
// empty string, unless it was caused by a memory error
const
char
*
convertToPlainChar
(
const
unsigned
char
*
ucp
)
{
if
(
ucp
==
NULL
)
{
// The field can really be NULL, in which case we return an
// empty string, or sqlite may have run out of memory, in
// which case we raise an error
if
(
sqlite3_errcode
(
accessor_
->
dbparameters_
->
db_
)
==
SQLITE_NOMEM
)
{
isc_throw
(
DataSourceError
,
"Sqlite3 backend encountered a memory allocation "
"error in sqlite3_column_text()"
);
}
else
{
return
(
""
);
}
}
const
void
*
p
=
ucp
;
return
(
static_cast
<
const
char
*>
(
p
));
return
(
convertToPlainCharInternal
(
ucp
,
accessor_
->
dbparameters_
->
db_
));
}
const
IteratorType
iterator_type_
;
...
...
@@ -659,8 +676,68 @@ SQLite3Accessor::deleteRecordInZone(const string (¶ms)[DEL_PARAM_COUNT]) {
}
std
::
string
SQLite3Accessor
::
findPreviousName
(
int
,
const
std
::
string
&
)
const
{
return
(
"."
);
// TODO Test and implement
SQLite3Accessor
::
findPreviousName
(
int
zone_id
,
const
std
::
string
&
rname
)
const
{
sqlite3_reset
(
dbparameters_
->
statements_
[
FIND_PREVIOUS
]);
sqlite3_clear_bindings
(
dbparameters_
->
statements_
[
FIND_PREVIOUS
]);
int
rc
=
sqlite3_bind_int
(
dbparameters_
->
statements_
[
FIND_PREVIOUS
],
1
,
zone_id
);
if
(
rc
!=
SQLITE_OK
)
{
isc_throw
(
SQLite3Error
,
"Could not bind zone ID "
<<
zone_id
<<
" to SQL statement (find previous)"
);
}
rc
=
sqlite3_bind_text
(
dbparameters_
->
statements_
[
FIND_PREVIOUS
],
2
,
rname
.
c_str
(),
-
1
,
SQLITE_STATIC
);
if
(
rc
!=
SQLITE_OK
)
{
isc_throw
(
SQLite3Error
,
"Could not bind name "
<<
rname
<<
" to SQL statement (find previous)"
);
}
std
::
string
result
;
rc
=
sqlite3_step
(
dbparameters_
->
statements_
[
FIND_PREVIOUS
]);
if
(
rc
==
SQLITE_ROW
)
{
// We found it
result
=
convertToPlainCharInternal
(
sqlite3_column_text
(
dbparameters_
->
statements_
[
FIND_PREVIOUS
],
0
),
dbparameters_
->
db_
);
}
sqlite3_reset
(
dbparameters_
->
statements_
[
FIND_PREVIOUS
]);
if
(
rc
==
SQLITE_DONE
)
{
// Nothing previous, wrap around (is it needed for anything?
// Well, just for completeness)
sqlite3_reset
(
dbparameters_
->
statements_
[
FIND_PREVIOUS_WRAP
]);
sqlite3_clear_bindings
(
dbparameters_
->
statements_
[
FIND_PREVIOUS_WRAP
]);
int
rc
=
sqlite3_bind_int
(
dbparameters_
->
statements_
[
FIND_PREVIOUS_WRAP
],
1
,
zone_id
);
if
(
rc
!=
SQLITE_OK
)
{
isc_throw
(
SQLite3Error
,
"Could not bind zone ID "
<<
zone_id
<<
" to SQL statement (find previous wrap)"
);
}
rc
=
sqlite3_step
(
dbparameters_
->
statements_
[
FIND_PREVIOUS_WRAP
]);
if
(
rc
==
SQLITE_ROW
)
{
// We found it
result
=
convertToPlainCharInternal
(
sqlite3_column_text
(
dbparameters_
->
statements_
[
FIND_PREVIOUS_WRAP
],
0
),
dbparameters_
->
db_
);
}
sqlite3_reset
(
dbparameters_
->
statements_
[
FIND_PREVIOUS_WRAP
]);
if
(
rc
==
SQLITE_DONE
)
{
// No NSEC records, this DB doesn't support DNSSEC
isc_throw
(
isc
::
NotImplemented
,
"The zone doesn't support DNSSEC"
);
}
}
if
(
rc
!=
SQLITE_ROW
&&
rc
!=
SQLITE_DONE
)
{
// Some kind of error
isc_throw
(
SQLite3Error
,
"Could get data for previous name"
);
}
return
(
result
);
}
}
...
...
src/lib/datasrc/tests/database_unittest.cc
View file @
c35f6b15
...
...
@@ -549,7 +549,8 @@ public:
}
else
if
(
id
==
42
)
{
if
(
rname
==
"org.example."
)
{
return
(
"zzz.example.org."
);
}
else
if
(
rname
==
"org.example.www2."
)
{
}
else
if
(
rname
==
"org.example.www2."
||
rname
==
"org.example.www1."
)
{
return
(
"www.example.org."
);
}
else
{
isc_throw
(
isc
::
Unexpected
,
"Unexpected name"
);
...
...
@@ -2228,13 +2229,19 @@ TYPED_TEST(DatabaseClientTest, previous) {
// Check wrap around
EXPECT_EQ
(
Name
(
"zzz.example.org."
),
finder
->
findPreviousName
(
Name
(
"example.org."
)));
// Check it doesn't crash or anything if the underlying DB throws
DataSourceClient
::
FindResult
zone
(
this
->
client_
->
findZone
(
Name
(
"bad.example.org"
)));
finder
=
dynamic_pointer_cast
<
DatabaseClient
::
Finder
>
(
zone
.
zone_finder
);
EXPECT_THROW
(
finder
->
findPreviousName
(
Name
(
"bad.example.org"
)),
isc
::
NotImplemented
);
// Check a name that doesn't exist there
EXPECT_EQ
(
Name
(
"www.example.org."
),
finder
->
findPreviousName
(
Name
(
"www1.example.org."
)));
if
(
this
->
is_mock_
)
{
// We can't really force the DB to throw
// Check it doesn't crash or anything if the underlying DB throws
DataSourceClient
::
FindResult
zone
(
this
->
client_
->
findZone
(
Name
(
"bad.example.org"
)));
finder
=
dynamic_pointer_cast
<
DatabaseClient
::
Finder
>
(
zone
.
zone_finder
);
EXPECT_THROW
(
finder
->
findPreviousName
(
Name
(
"bad.example.org"
)),
isc
::
NotImplemented
);
}
}
}
src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
View file @
c35f6b15
...
...
@@ -354,6 +354,9 @@ TEST_F(SQLite3AccessorTest, getRecords) {
TEST_F
(
SQLite3AccessorTest
,
findPrevious
)
{
EXPECT_EQ
(
"dns01.example.com."
,
accessor
->
findPreviousName
(
1
,
"com.example.dns02."
));
// A name that doesn't exist
EXPECT_EQ
(
"dns01.example.com."
,
accessor
->
findPreviousName
(
1
,
"com.example.dns01x."
));
// Wrap around
EXPECT_EQ
(
"www.example.com."
,
accessor
->
findPreviousName
(
1
,
"com.example."
));
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment