Skip to content

Commit

Permalink
Tables with additional and no index should not use rowid
Browse files Browse the repository at this point in the history
  • Loading branch information
Ted Reed committed Dec 10, 2019
1 parent 5cf1514 commit fa33df3
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 9 deletions.
23 changes: 14 additions & 9 deletions osquery/core/tables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ CREATE_LAZY_REGISTRY(TablePlugin, "table");
size_t TablePlugin::kCacheInterval = 0;
size_t TablePlugin::kCacheStep = 0;

#define kDisableRowId "WITHOUT ROWID"

Status TablePlugin::addExternal(const std::string& name,
const PluginResponse& response) {
// Attach the table.
Expand Down Expand Up @@ -263,12 +265,12 @@ std::string columnDefinition(const TableColumns& columns, bool is_extension) {
statement +=
'`' + std::get<0>(column) + "` " + columnTypeName(std::get<1>(column));
auto& options = std::get<2>(column);
if (options & (ColumnOptions::INDEX | ColumnOptions::ADDITIONAL)) {
if (options & ColumnOptions::INDEX) {
indexed = true;
}
if (options & ColumnOptions::INDEX) {
pkeys.push_back(std::get<0>(column));
epilog["WITHOUT ROWID"] = true;
indexed = true;
}
if (options & (ColumnOptions::INDEX | ColumnOptions::ADDITIONAL)) {
epilog[kDisableRowId] = true;
}
if (options & ColumnOptions::HIDDEN) {
statement += " HIDDEN";
Expand All @@ -278,10 +280,13 @@ std::string columnDefinition(const TableColumns& columns, bool is_extension) {
}
}

// If there are only 'additional' columns (rare), do not attempt a pkey.
if (!indexed) {
epilog["WITHOUT ROWID"] = false;
// If there are only 'additional' columns (rare), pkey is the 'unique row'.
// Otherwise an additional constraint will create duplicate rowids.
if (!indexed && epilog[kDisableRowId]) {
pkeys.clear();
for (const auto& column : columns) {
pkeys.push_back(std::get<0>(column));
}
}

// Append the primary keys, if any were defined.
Expand All @@ -300,7 +305,7 @@ std::string columnDefinition(const TableColumns& columns, bool is_extension) {
// keep the rowid column, as we need it to reference rows when handling UPDATE
// and DELETE queries
if (is_extension) {
epilog["WITHOUT ROWID"] = false;
epilog[kDisableRowId] = false;
}

statement += ')';
Expand Down
27 changes: 27 additions & 0 deletions osquery/sql/tests/virtual_table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,33 @@ TEST_F(VirtualTableTests, test_tableplugin_moreoptions) {
EXPECT_EQ(expected_statement, columnDefinition(response, true, false));
}

class additionalOnlyTablePlugin : public TablePlugin {
private:
TableColumns columns() const override {
return {
std::make_tuple("id", INTEGER_TYPE, ColumnOptions::DEFAULT),
std::make_tuple("username", TEXT_TYPE, ColumnOptions::ADDITIONAL),
std::make_tuple("name", TEXT_TYPE, ColumnOptions::DEFAULT),
};
}

private:
FRIEND_TEST(VirtualTableTests, test_tableplugin_additionalonly);
};

TEST_F(VirtualTableTests, test_tableplugin_additionalonly) {
auto table = std::make_shared<additionalOnlyTablePlugin>();

PluginResponse response;
PluginRequest request = {{"action", "columns"}};
EXPECT_TRUE(table->call(request, response).ok());

std::string expected_statement =
"(`id` INTEGER, `username` TEXT, `name` TEXT, PRIMARY KEY (`id`, "
"`username`, `name`)) WITHOUT ROWID";
EXPECT_EQ(expected_statement, columnDefinition(response, true, false));
}

class aliasesTablePlugin : public TablePlugin {
private:
TableColumns columns() const override {
Expand Down

0 comments on commit fa33df3

Please sign in to comment.