susumu.yata
null+****@clear*****
Mon Mar 17 18:24:46 JST 2014
susumu.yata 2014-03-17 18:24:46 +0900 (Mon, 17 Mar 2014) New Revision: cd812c3675ffab05262af7ba9938b4a8ac6aab9e https://github.com/groonga/grnxx/commit/cd812c3675ffab05262af7ba9938b4a8ac6aab9e Message: Support primary key. Modified files: lib/grnxx/column.cpp lib/grnxx/column.hpp lib/grnxx/column_impl.cpp lib/grnxx/column_impl.hpp lib/grnxx/table.cpp lib/grnxx/table.hpp src/grnxx.cpp test/test_grnxx.cpp Modified: lib/grnxx/column.cpp (+34 -1) =================================================================== --- lib/grnxx/column.cpp 2014-03-13 13:39:04 +0900 (086d204) +++ lib/grnxx/column.cpp 2014-03-17 18:24:46 +0900 (bb062b6) @@ -12,11 +12,44 @@ Column::Column(Table *table, ColumnID id, const String &name, : table_(table), id_(id), name_(reinterpret_cast<const char *>(name.data()), name.size()), - data_type_(data_type) {} + data_type_(data_type), + is_unique_(false) {} // カラムを破棄する. Column::~Column() {} +// UNIQUE 制約を解除する. +bool Column::unset_unique() { + if (!is_unique_) { + return false; + } + is_unique_ = false; + return true; +} + +// FIXME: 指定された値を検索する. +RowID Column::generic_find(const Datum &datum) const { + switch (data_type()) { + case BOOLEAN: { + auto impl = static_cast<const ColumnImpl<Boolean> *>(this); + return impl->find(static_cast<Boolean>(datum)); + } + case INTEGER: { + auto impl = static_cast<const ColumnImpl<Int64> *>(this); + return impl->find(static_cast<Int64>(datum)); + } + case FLOAT: { + auto impl = static_cast<const ColumnImpl<Float> *>(this); + return impl->find(static_cast<Float>(datum)); + } + case STRING: { + auto impl = static_cast<const ColumnImpl<String> *>(this); + return impl->find(static_cast<std::string>(datum)); + } + } + return false; +} + // FIXME: 指定された ID の値を返す. Datum Column::generic_get(RowID row_id) const { switch (data_type()) { Modified: lib/grnxx/column.hpp (+12 -0) =================================================================== --- lib/grnxx/column.hpp 2014-03-13 13:39:04 +0900 (04111e7) +++ lib/grnxx/column.hpp 2014-03-17 18:24:46 +0900 (34f0b3d) @@ -28,6 +28,15 @@ class Column { DataType data_type() const { return data_type_; } + // UNIQUE 制約の有無を返す. + bool is_unique() const { + return is_unique_; + } + + // UNIQUE 制約を設定する. + virtual bool set_unique() = 0; + // UNIQUE 制約を解除する. + virtual bool unset_unique(); // 指定された索引との関連付けをおこなう. virtual bool register_index(Index *index) = 0; @@ -37,6 +46,8 @@ class Column { // 指定された行 ID が使えるようにサイズを変更する. virtual void resize(RowID max_row_id) = 0; + // FIXME: 指定された値を検索する. + virtual RowID generic_find(const Datum &datum) const; // FIXME: 指定された ID の値を返す. virtual Datum generic_get(RowID row_id) const; // FIXME: 指定された ID の値を設定する. @@ -50,6 +61,7 @@ class Column { ColumnID id_; std::string name_; DataType data_type_; + bool is_unique_; }; std::ostream &operator<<(std::ostream &stream, const Column &column); Modified: lib/grnxx/column_impl.cpp (+223 -2) =================================================================== --- lib/grnxx/column_impl.cpp 2014-03-13 13:39:04 +0900 (d346e21) +++ lib/grnxx/column_impl.cpp 2014-03-17 18:24:46 +0900 (909e625) @@ -3,7 +3,7 @@ #include "grnxx/index.hpp" #include "grnxx/table.hpp" -//#include <iostream> +#include <iostream> // For debugging. namespace grnxx { @@ -18,6 +18,22 @@ ColumnImpl<T>::ColumnImpl(Table *table, ColumnID id, const String &name) template <typename T> ColumnImpl<T>::~ColumnImpl() {} +// UNIQUE 制約を設定する. +template <typename T> +bool ColumnImpl<T>::set_unique() { + std::set<T> set; + for (RowID row_id = MIN_ROW_ID; row_id <= data_.size(); ++row_id) { + auto it = set.find(data_[row_id]); + if (it != set.end()) { + // 重複があれば失敗する. + return false; + } + set.insert(data_[row_id]); + } + is_unique_ = true; + return true; +} + // 指定された索引との関連付けをおこなう. template <typename T> bool ColumnImpl<T>::register_index(Index *index) { @@ -46,6 +62,27 @@ void ColumnImpl<T>::resize(RowID max_row_id) { data_.resize(max_row_id + 1, 0); } +// 指定された値を検索する. +template <typename T> +RowID ColumnImpl<T>::find(T value) const { + if (indexes_.empty()) { + // 索引がなければ全体を走査する. + for (RowID row_id = MIN_ROW_ID; row_id <= data_.size(); ++row_id) { + if (data_[row_id] == value) { + return row_id; + } + } + } else { + // 索引があれば使う. + auto cursor = indexes_[0]->find_equal(value); + RowID row_id; + if (cursor->get_next(&row_id, 1) != 0) { + return row_id; + } + } + return 0; +} + // 指定された ID の値を更新する. template <typename T> void ColumnImpl<T>::set(RowID row_id, T value) { @@ -75,6 +112,62 @@ ColumnImpl<Int64>::ColumnImpl(Table *table, ColumnID id, const String &name, // カラムを破棄する. ColumnImpl<Int64>::~ColumnImpl() {} +// UNIQUE 制約を設定する. +bool ColumnImpl<Int64>::set_unique() { + switch (internal_data_type_size_) { + case 8: { + std::set<Int8> set; + for (RowID row_id = MIN_ROW_ID; row_id <= data_8_.size(); ++row_id) { + auto it = set.find(data_8_[row_id]); + if (it != set.end()) { + // 重複があれば失敗する. + return false; + } + set.insert(get(row_id)); + } + break; + } + case 16: { + std::set<Int16> set; + for (RowID row_id = MIN_ROW_ID; row_id <= data_8_.size(); ++row_id) { + auto it = set.find(data_16_[row_id]); + if (it != set.end()) { + // 重複があれば失敗する. + return false; + } + set.insert(get(row_id)); + } + break; + } + case 32: { + std::set<Int32> set; + for (RowID row_id = MIN_ROW_ID; row_id <= data_8_.size(); ++row_id) { + auto it = set.find(data_32_[row_id]); + if (it != set.end()) { + // 重複があれば失敗する. + return false; + } + set.insert(get(row_id)); + } + break; + } + default: { + std::set<Int64> set; + for (RowID row_id = MIN_ROW_ID; row_id <= data_8_.size(); ++row_id) { + auto it = set.find(data_64_[row_id]); + if (it != set.end()) { + // 重複があれば失敗する. + return false; + } + set.insert(get(row_id)); + } + break; + } + } + is_unique_ = true; + return true; +} + // 指定された索引との関連付けをおこなう. bool ColumnImpl<Int64>::register_index(Index *index) { auto it = std::find(indexes_.begin(), indexes_.end(), index); @@ -113,6 +206,55 @@ void ColumnImpl<Int64>::resize(RowID max_row_id) { } } +// 指定された値を検索する. +RowID ColumnImpl<Int64>::find(Int64 value) const { + if (indexes_.empty()) { + // 索引がなければ全体を走査する. + switch (internal_data_type_size_) { + case 8: { + for (RowID row_id = MIN_ROW_ID; row_id <= data_8_.size(); ++row_id) { + if (data_8_[row_id] == value) { + return false; + } + } + break; + } + case 16: { + for (RowID row_id = MIN_ROW_ID; row_id <= data_16_.size(); ++row_id) { + if (data_16_[row_id] == value) { + return false; + } + } + break; + } + case 32: { + for (RowID row_id = MIN_ROW_ID; row_id <= data_32_.size(); ++row_id) { + if (data_32_[row_id] == value) { + return false; + } + } + break; + } + default: { + for (RowID row_id = MIN_ROW_ID; row_id <= data_64_.size(); ++row_id) { + if (data_64_[row_id] == value) { + return false; + } + } + break; + } + } + } else { + // 索引があれば使う. + auto cursor = indexes_[0]->find_equal(value); + RowID row_id; + if (cursor->get_next(&row_id, 1) != 0) { + return row_id; + } + } + return 0; +} + // 指定された ID の値を更新する. void ColumnImpl<Int64>::set(RowID row_id, Int64 value) { if (dest_table_) { @@ -220,14 +362,31 @@ void ColumnImpl<Int64>::expand_and_set(RowID row_id, Int64 value) { #else // GRNXX_ENABLE_VARIABLE_INTEGER_TYPE // カラムを初期化する. -ColumnImpl<Int64>::ColumnImpl(Table *table, ColumnID id, const String &name) +ColumnImpl<Int64>::ColumnImpl(Table *table, ColumnID id, const String &name, + Table *dest_table) : Column(table, id, name, INTEGER), + dest_table_(dest_table), data_(MIN_ROW_ID, 0), indexes_() {} // カラムを破棄する. ColumnImpl<Int64>::~ColumnImpl() {} +// UNIQUE 制約を設定する. +bool ColumnImpl<Int64>::set_unique() { + std::set<Int64> set; + for (RowID row_id = MIN_ROW_ID; row_id <= data_.size(); ++row_id) { + auto it = set.find(data_[row_id]); + if (it != set.end()) { + // 重複があれば失敗する. + return false; + } + set.insert(data_[row_id]); + } + is_unique_ = true; + return true; +} + // 指定された索引との関連付けをおこなう. bool ColumnImpl<Int64>::register_index(Index *index) { auto it = std::find(indexes_.begin(), indexes_.end(), index); @@ -253,8 +412,34 @@ void ColumnImpl<Int64>::resize(RowID max_row_id) { data_.resize(max_row_id + 1, 0); } +// 指定された値を検索する. +RowID ColumnImpl<Int64>::find(Int64 value) const { + if (indexes_.empty()) { + // 索引がなければ全体を走査する. + for (RowID row_id = MIN_ROW_ID; row_id <= data_.size(); ++row_id) { + if (data_[row_id] == value) { + return row_id; + } + } + } else { + // 索引があれば使う. + auto cursor = indexes_[0]->find_equal(value); + RowID row_id; + if (cursor->get_next(&row_id, 1) != 0) { + return row_id; + } + } + return 0; +} + // 指定された ID の値を更新する. void ColumnImpl<Int64>::set(RowID row_id, Int64 value) { + if (dest_table_) { + if ((value < dest_table_->min_row_id()) || + (value > dest_table_->max_row_id())) { + throw "invalid reference"; + } + } data_[row_id] = value; for (auto index : indexes_) { index->insert(row_id); @@ -273,6 +458,22 @@ ColumnImpl<String>::ColumnImpl(Table *table, ColumnID id, const String &name) // カラムを破棄する. ColumnImpl<String>::~ColumnImpl() {} +// UNIQUE 制約を設定する. +bool ColumnImpl<String>::set_unique() { + std::set<String> set; + for (RowID row_id = MIN_ROW_ID; row_id <= headers_.size(); ++row_id) { + auto value = get(row_id); + auto it = set.find(value); + if (it != set.end()) { + // 重複があれば失敗する. + return false; + } + set.insert(value); + } + is_unique_ = true; + return true; +} + // 指定された索引との関連付けをおこなう. bool ColumnImpl<String>::register_index(Index *index) { auto it = std::find(indexes_.begin(), indexes_.end(), index); @@ -298,6 +499,26 @@ void ColumnImpl<String>::resize(RowID max_row_id) { headers_.resize(max_row_id + 1, 0); } +// 指定された値を検索する. +RowID ColumnImpl<String>::find(const String &value) const { + if (indexes_.empty()) { + // 索引がなければ全体を走査する. + for (RowID row_id = MIN_ROW_ID; row_id <= headers_.size(); ++row_id) { + if (get(row_id) == value) { + return row_id; + } + } + } else { + // 索引があれば使う. + auto cursor = indexes_[0]->find_equal(value); + RowID row_id; + if (cursor->get_next(&row_id, 1) != 0) { + return row_id; + } + } + return 0; +} + // 指定された ID の値を更新する. void ColumnImpl<String>::set(RowID row_id, const String &value) { if (value.empty()) { Modified: lib/grnxx/column_impl.hpp (+33 -1) =================================================================== --- lib/grnxx/column_impl.hpp 2014-03-13 13:39:04 +0900 (9100225) +++ lib/grnxx/column_impl.hpp 2014-03-17 18:24:46 +0900 (2114a5f) @@ -20,6 +20,9 @@ class ColumnImpl : public Column { ColumnImpl(const ColumnImpl &) = delete; ColumnImpl &operator=(const ColumnImpl &) = delete; + // UNIQUE 制約を設定する. + bool set_unique(); + // 指定された索引との関連付けをおこなう. bool register_index(Index *index); // 指定された索引との関連を削除する. @@ -28,6 +31,9 @@ class ColumnImpl : public Column { // 指定された行 ID が使えるようにサイズを変更する. void resize(RowID max_row_id); + // 指定された値を検索する. + RowID find(T value) const; + // 指定された ID の値を返す. T get(RowID row_id) const { return data_[row_id]; @@ -56,6 +62,9 @@ class ColumnImpl<Int64> : public Column { ColumnImpl(const ColumnImpl &) = delete; ColumnImpl &operator=(const ColumnImpl &) = delete; + // UNIQUE 制約を設定する. + bool set_unique(); + // 指定された索引との関連付けをおこなう. bool register_index(Index *index); // 指定された索引との関連を削除する. @@ -70,6 +79,9 @@ class ColumnImpl<Int64> : public Column { return dest_table_; } + // 指定された値を検索する. + RowID find(Int64 value) const; + // 指定された ID の値を返す. Int64 get(RowID row_id) const { switch (internal_data_type_size_) { @@ -109,7 +121,8 @@ class ColumnImpl<Int64> : public Column { using Value = Int64; // カラムを初期化する. - ColumnImpl(Table *table, ColumnID id, const String &name); + ColumnImpl(Table *table, ColumnID id, const String &name, + Table *dest_table = nullptr); // カラムを破棄する. ~ColumnImpl(); @@ -117,6 +130,9 @@ class ColumnImpl<Int64> : public Column { ColumnImpl(const ColumnImpl &) = delete; ColumnImpl &operator=(const ColumnImpl &) = delete; + // UNIQUE 制約を設定する. + bool set_unique(); + // 指定された索引との関連付けをおこなう. bool register_index(Index *index); // 指定された索引との関連を削除する. @@ -125,6 +141,15 @@ class ColumnImpl<Int64> : public Column { // 指定された行 ID が使えるようにサイズを変更する. void resize(RowID max_row_id); + // 参照先のテーブルを返す. + // なければ nullptr を返す. + Table *dest_table() const { + return dest_table_; + } + + // 指定された値を検索する. + RowID find(Int64 value) const; + // 指定された ID の値を返す. Int64 get(RowID row_id) const { return data_[row_id]; @@ -133,6 +158,7 @@ class ColumnImpl<Int64> : public Column { void set(RowID row_id, Int64 value); private: + Table *dest_table_; std::vector<Int64> data_; std::vector<Index *> indexes_; }; @@ -152,6 +178,9 @@ class ColumnImpl<String> : public Column { ColumnImpl(const ColumnImpl &) = delete; ColumnImpl &operator=(const ColumnImpl &) = delete; + // UNIQUE 制約を設定する. + bool set_unique(); + // 指定された索引との関連付けをおこなう. bool register_index(Index *index); // 指定された索引との関連を削除する. @@ -160,6 +189,9 @@ class ColumnImpl<String> : public Column { // 指定された行 ID が使えるようにサイズを変更する. void resize(RowID max_row_id); + // 指定された値を検索する. + RowID find(const String &value) const; + // 指定された ID の値を返す. String get(RowID row_id) const { Int64 size = headers_[row_id] & 0xFFFF; Modified: lib/grnxx/table.cpp (+39 -0) =================================================================== --- lib/grnxx/table.cpp 2014-03-13 13:39:04 +0900 (8b321ac) +++ lib/grnxx/table.cpp 2014-03-17 18:24:46 +0900 (d230fb2) @@ -8,6 +8,8 @@ #include <ostream> +#include <iostream> // For debugging. + namespace grnxx { namespace { @@ -62,6 +64,7 @@ Table::Table(Database *database, TableID id, const String &name) id_(id), name_(reinterpret_cast<const char *>(name.data()), name.size()), max_row_id_(MIN_ROW_ID - 1), + primary_key_column_(nullptr), columns_(MIN_COLUMN_ID), columns_map_(), indexes_(MIN_INDEX_ID), @@ -144,6 +147,37 @@ bool Table::drop_column(const String &column_name) { return true; } +// 指定されたカラムに主キー属性を与える. +// 成功すれば true を返し,失敗すれば false を返す. +bool Table::set_primary_key(const String &column_name) { + if (primary_key_column_) { + return false; + } + auto it = columns_map_.find(column_name); + if (it == columns_map_.end()) { + return false; + } + auto column = columns_[it->second].get(); + if (!column->set_unique()) { + return false; + } + primary_key_column_ = column; + return true; +} + +// 主キー属性を解除する. +// 成功すれば true を返し,失敗すれば false を返す. +bool Table::unset_primary_key() { + if (!primary_key_column_) { + return false; + } + if (!primary_key_column_->unset_unique()) { + return false; + } + primary_key_column_ = nullptr; + return true; +} + // 指定された 名前 のカラムを返す. // なければ nullptr を返す. Column *Table::get_column_by_name(const String &column_name) const { @@ -290,6 +324,11 @@ Table::Cursor *Table::create_cursor(RowID range_min, RowID range_max) const { return new Cursor(range_min, range_max); } +// FIXME: 指定された主キーを持つ行を検索する. +RowID Table::find_row(const Datum &datum) { + return primary_key_column_->generic_find(datum); +} + // 演算器を作成する. Calc *Table::create_calc(const String &query) const { return CalcHelper::create(this, query); Modified: lib/grnxx/table.hpp (+15 -0) =================================================================== --- lib/grnxx/table.hpp 2014-03-13 13:39:04 +0900 (8e51a8c) +++ lib/grnxx/table.hpp 2014-03-17 18:24:46 +0900 (acb4a49) @@ -40,6 +40,13 @@ class Table { // 成功すれば true を返し,失敗すれば false を返す. bool drop_column(const String &column_name); + // 指定されたカラムに主キー属性を与える. + // 成功すれば true を返し,失敗すれば false を返す. + bool set_primary_key(const String &column_name); + // 主キー属性を解除する. + // 成功すれば true を返し,失敗すれば false を返す. + bool unset_primary_key(); + // カラム ID の最小値を返す. ColumnID min_column_id() const { return MIN_COLUMN_ID; @@ -106,6 +113,10 @@ class Table { RowID max_row_id() const { return max_row_id_; } + // 主キーカラムを返す. + Column *primary_key_column() const { + return primary_key_column_; + } // 行 ID を取得するカーソル. class Cursor : public RowIDCursor { @@ -128,6 +139,9 @@ class Table { Cursor *create_cursor(RowID range_min = MIN_ROW_ID, RowID range_max = INT64_MAX) const; + // FIXME: 指定された主キーを持つ行を検索する. + RowID find_row(const Datum &datum); + // 演算器を作成する. Calc *create_calc(const String &query) const; // 整列器を作成する. @@ -156,6 +170,7 @@ class Table { TableID id_; std::string name_; RowID max_row_id_; + Column *primary_key_column_; std::vector<std::unique_ptr<Column>> columns_; std::map<String, ColumnID> columns_map_; std::vector<std::unique_ptr<Index>> indexes_; Modified: src/grnxx.cpp (+57 -0) =================================================================== --- src/grnxx.cpp 2014-03-13 13:39:04 +0900 (7c37f7e) +++ src/grnxx.cpp 2014-03-17 18:24:46 +0900 (b6356f6) @@ -7,6 +7,7 @@ #include "grnxx/calc.hpp" #include "grnxx/column.hpp" +#include "grnxx/column_impl.hpp" #include "grnxx/database.hpp" #include "grnxx/index.hpp" #include "grnxx/library.hpp" @@ -368,6 +369,19 @@ bool run_load(grnxx::Database *database, if (!column) { continue; } + grnxx::Table *dest_table = nullptr; + if (params[begin] == '&') { + // 参照型. + if (column->data_type() != grnxx::INTEGER) { + return false; + } + auto impl = static_cast<grnxx::ColumnImpl<grnxx::Int64> *>(column); + dest_table = impl->dest_table(); + if (!dest_table || !dest_table->primary_key_column()) { + return false; + } + ++begin; + } if (params[begin] == '"') { // 文字列. end = params.find_first_of('"', ++begin); @@ -386,6 +400,16 @@ bool run_load(grnxx::Database *database, } datum = params.extract(begin, end - begin); } + if (dest_table) { + // 参照の解決. + datum = dest_table->find_row(datum); + } + if (column->is_unique()) { + // UNIQUE 制約の確認. + if (column->generic_find(datum) != 0) { + return false; + } + } column->generic_set(table->max_row_id(), datum); begin = params.find_first_not_of(" \t\n", end); if (begin == params.npos) { @@ -397,6 +421,37 @@ bool run_load(grnxx::Database *database, return true; } +// set_primary_key コマンド. +bool run_set_primary_key(grnxx::Database *database, + const grnxx::String ¶ms) { + auto end = params.find_first_of(" \t\n"); + if (end == params.npos) { + std::cerr << "Error: too few arguments" << std::endl; + return false; + } + grnxx::String table_name = params.prefix(end); + auto table = database->get_table_by_name(table_name); + if (!table) { + std::cerr << "Error: table not found: " + << "table_name = " << table_name << std::endl; + return false; + } + auto begin = params.find_first_not_of(" \t\n", end); + end = params.find_first_of(" \t\n", begin); + if (end == params.npos) { + end = params.size(); + } + grnxx::String column_name = params.extract(begin, end - begin); + if (!table->set_primary_key(column_name)) { + std::cerr << "Error: grnxx::Table::set_primary_key() failed: " + << "table_name = " << table_name + << ", column_name = " << column_name << std::endl; + return false; + } + std::cout << "OK\n"; + return true; +} + struct SelectQuery { grnxx::String table_name; grnxx::String output_column_names; @@ -913,6 +968,8 @@ void run_terminal() { run_index_list(&database, params); } else if (command == "load") { run_load(&database, params); + } else if (command == "set_primary_key") { + run_set_primary_key(&database, params); } else if (command == "select") { grnxx::Timer timer; run_select(&database, params, std::cout); Modified: test/test_grnxx.cpp (+73 -0) =================================================================== --- test/test_grnxx.cpp 2014-03-13 13:39:04 +0900 (6c0512e) +++ test/test_grnxx.cpp 2014-03-17 18:24:46 +0900 (134b660) @@ -835,6 +835,78 @@ void test_deep_reference() { } } +void test_primary_key() { + grnxx::Database database; + + grnxx::Table *src_table = database.create_table("Src"); + assert(src_table); + grnxx::Table *dest_table = database.create_table("Dest"); + assert(dest_table); + + auto reference_column = dynamic_cast<grnxx::ColumnImpl<grnxx::Int64> *>( + src_table->create_reference_column("Reference", "Dest")); + assert(reference_column); + + auto key_column = dynamic_cast<grnxx::ColumnImpl<grnxx::String> *>( + dest_table->create_column("Key", grnxx::STRING)); + assert(key_column); + assert(dest_table->set_primary_key("Key")); + + std::mt19937_64 random; + + std::vector<std::string> key_data; + for (grnxx::Int64 i = 0; i < 1000; ++i) { + std::string str(8, 'A'); + for (std::size_t i = 0; i < str.size(); ++i) { + str[i] += random() % 26; + } + key_data.push_back(str); + grnxx::RowID row_id = dest_table->insert_row(); + key_column->set(row_id, key_data[i]); + } + + std::vector<grnxx::Int64> reference_data; + for (grnxx::Int64 i = 0; i < 1000; ++i) { + reference_data.push_back(random() % 1000); + grnxx::RowID row_id = src_table->insert_row(); + reference_column->set(row_id, reference_data[i] + 1); + } + + std::vector<grnxx::RowID> all_row_ids(1000); + std::unique_ptr<grnxx::RowIDCursor> cursor(src_table->create_cursor()); + assert(cursor->get_next(&all_row_ids[0], 1000) == 1000); + + // Reference.Key で絞り込む. + { + std::unique_ptr<grnxx::Calc> calc( + src_table->create_calc("Reference.Key > \"N\"")); + assert(calc); + std::vector<grnxx::RowID> row_ids(all_row_ids); + grnxx::Int64 num_row_ids = calc->filter(&*row_ids.begin(), row_ids.size()); + assert(num_row_ids != 0); + grnxx::Int64 count = 0; + for (grnxx::Int64 i = 0; i < 1000; ++i) { + grnxx::RowID row_id = grnxx::MIN_ROW_ID + i; + if (key_data[reference_data[i]] > "N") { + assert(row_ids[count] == row_id); + assert(++count <= num_row_ids); + } + } + assert(count == num_row_ids); + } + + for (grnxx::Int64 i = 0; i < 1000; ++i) { + assert(dest_table->find_row(key_data[i]) == (i + 1)); + } + for (grnxx::Int64 i = 0; i < 1000; ++i) { + std::string str(8, 'a'); + for (std::size_t i = 0; i < str.size(); ++i) { + str[i] += random() % 26; + } + assert(dest_table->find_row(str) == 0); + } +} + void test_sorter() { constexpr grnxx::Int64 DATA_SIZE = 1000; @@ -1466,6 +1538,7 @@ int main() { test_calc(); test_reference(); test_deep_reference(); + test_primary_key(); test_sorter(); test_sorter_large(); test_index(); -------------- next part -------------- HTML����������������������������... Download