[Groonga-commit] groonga/grnxx at 06bc56e [new_data_types] Enable DB and Table.

Back to archive index

susumu.yata null+****@clear*****
Wed Nov 5 17:35:04 JST 2014


susumu.yata	2014-11-05 17:35:04 +0900 (Wed, 05 Nov 2014)

  New Revision: 06bc56eec16fa86086055f1699ddfc15cbb626c5
  https://github.com/groonga/grnxx/commit/06bc56eec16fa86086055f1699ddfc15cbb626c5

  Message:
    Enable DB and Table.

  Added files:
    include/grnxx/array.hpp
    include/grnxx/data_types/data_type.hpp
    include/grnxx/data_types/datum.hpp
    include/grnxx/data_types/record.hpp
    lib/grnxx/impl/column/base.cpp
    lib/grnxx/impl/column/base.hpp
    lib/grnxx/impl/column/scalar.hpp
    lib/grnxx/impl/column/scalar/Makefile.am
    lib/grnxx/impl/column/vector.hpp
    lib/grnxx/impl/column/vector/Makefile.am
    lib/grnxx/impl/cursor.hpp
  Copied files:
    lib/grnxx/impl/column/scalar/bool.cpp
      (from include/grnxx/features/Makefile.am)
    lib/grnxx/impl/column/scalar/geo_point.cpp
      (from include/grnxx/features/Makefile.am)
    lib/grnxx/impl/column/vector/bool.cpp
      (from include/grnxx/features/Makefile.am)
  Removed files:
    include/grnxx/data_types/scalar/row_id.hpp
    include/grnxx/data_types/vector/row_id.hpp
    include/grnxx/memory.hpp
    lib/grnxx/array.cpp
    lib/grnxx/impl/column/column_base.cpp
    lib/grnxx/impl/column/column_base.hpp
  Modified files:
    configure.ac
    include/grnxx/Makefile.am
    include/grnxx/column.hpp
    include/grnxx/cursor.hpp
    include/grnxx/data_types.hpp
    include/grnxx/data_types/Makefile.am
    include/grnxx/data_types/na.hpp
    include/grnxx/data_types/scalar.hpp
    include/grnxx/data_types/scalar/Makefile.am
    include/grnxx/data_types/scalar/bool.hpp
    include/grnxx/data_types/scalar/float.hpp
    include/grnxx/data_types/scalar/geo_point.hpp
    include/grnxx/data_types/scalar/int.hpp
    include/grnxx/data_types/scalar/text.hpp
    include/grnxx/data_types/vector.hpp
    include/grnxx/data_types/vector/Makefile.am
    include/grnxx/data_types/vector/bool.hpp
    include/grnxx/data_types/vector/float.hpp
    include/grnxx/data_types/vector/geo_point.hpp
    include/grnxx/data_types/vector/int.hpp
    include/grnxx/data_types/vector/text.hpp
    include/grnxx/db.hpp
    include/grnxx/features/Makefile.am
    include/grnxx/string.hpp
    include/grnxx/table.hpp
    lib/grnxx/Makefile.am
    lib/grnxx/cursor.cpp
    lib/grnxx/db.cpp
    lib/grnxx/impl/Makefile.am
    lib/grnxx/impl/column.hpp
    lib/grnxx/impl/column/Makefile.am
    lib/grnxx/impl/column/column.hpp
    lib/grnxx/impl/db.cpp
    lib/grnxx/impl/db.hpp
    lib/grnxx/impl/table.cpp
    lib/grnxx/impl/table.hpp
    test/Makefile.am
    test/test_array.cpp
    test/test_db.cpp
    test/test_table.cpp
  Renamed files:
    lib/grnxx/impl/column/scalar/bool.hpp
      (from lib/grnxx/impl/column/column_bool.hpp)
    lib/grnxx/impl/column/scalar/float.cpp
      (from lib/grnxx/impl/column/column_float.cpp)
    lib/grnxx/impl/column/scalar/float.hpp
      (from lib/grnxx/impl/column/column_float.hpp)
    lib/grnxx/impl/column/scalar/geo_point.hpp
      (from lib/grnxx/impl/column/column_geo_point.hpp)
    lib/grnxx/impl/column/scalar/int.cpp
      (from lib/grnxx/impl/column/column_int.cpp)
    lib/grnxx/impl/column/scalar/int.hpp
      (from lib/grnxx/impl/column/column_int.hpp)
    lib/grnxx/impl/column/scalar/text.cpp
      (from lib/grnxx/impl/column/column_text.cpp)
    lib/grnxx/impl/column/scalar/text.hpp
      (from lib/grnxx/impl/column/column_text.hpp)
    lib/grnxx/impl/column/vector/bool.hpp
      (from lib/grnxx/impl/column/column_vector_bool.hpp)
    lib/grnxx/impl/column/vector/float.cpp
      (from lib/grnxx/impl/column/column_vector_float.cpp)
    lib/grnxx/impl/column/vector/float.hpp
      (from lib/grnxx/impl/column/column_vector_float.hpp)
    lib/grnxx/impl/column/vector/geo_point.cpp
      (from lib/grnxx/impl/column/column_vector_geo_point.cpp)
    lib/grnxx/impl/column/vector/geo_point.hpp
      (from lib/grnxx/impl/column/column_vector_geo_point.hpp)
    lib/grnxx/impl/column/vector/int.cpp
      (from lib/grnxx/impl/column/column_vector_int.cpp)
    lib/grnxx/impl/column/vector/int.hpp
      (from lib/grnxx/impl/column/column_vector_int.hpp)
    lib/grnxx/impl/column/vector/text.cpp
      (from lib/grnxx/impl/column/column_vector_text.cpp)
    lib/grnxx/impl/column/vector/text.hpp
      (from lib/grnxx/impl/column/column_vector_text.hpp)

  Modified: configure.ac (+4 -0)
===================================================================
--- configure.ac    2014-10-31 21:43:45 +0900 (1b98252)
+++ configure.ac    2014-11-05 17:35:04 +0900 (b6756ab)
@@ -58,6 +58,10 @@ AC_CONFIG_FILES([Makefile
                  include/grnxx/features/Makefile
                  lib/Makefile
                  lib/grnxx/Makefile
+                 lib/grnxx/impl/Makefile
+                 lib/grnxx/impl/column/Makefile
+                 lib/grnxx/impl/column/scalar/Makefile
+                 lib/grnxx/impl/column/vector/Makefile
                  src/Makefile
                  test/Makefile
                  benchmark/Makefile])

  Modified: include/grnxx/Makefile.am (+8 -8)
===================================================================
--- include/grnxx/Makefile.am    2014-10-31 21:43:45 +0900 (d491d1a)
+++ include/grnxx/Makefile.am    2014-11-05 17:35:04 +0900 (1d9b0e1)
@@ -3,19 +3,19 @@ SUBDIRS =		\
 	features
 
 pkginclude_HEADERS =	\
+	array.hpp	\
+	column.hpp	\
+	cursor.hpp	\
+	data_types.hpp	\
+	db.hpp		\
 	error.hpp	\
 	features.hpp	\
 	library.hpp	\
-	memory.hpp	\
-	string.hpp
+	string.hpp	\
+	table.hpp
 
-#	column.hpp	\
-#	cursor.hpp	\
-#	db.hpp		\
 #	expression.hpp	\
 #	index.hpp	\
 #	merger.hpp	\
 #	pipeline.hpp	\
-#	sorter.hpp	\
-#	table.hpp	\
-#	types.hpp
+#	sorter.hpp

  Added: include/grnxx/array.hpp (+349 -0) 100644
===================================================================
--- /dev/null
+++ include/grnxx/array.hpp    2014-11-05 17:35:04 +0900 (69d4cd1)
@@ -0,0 +1,349 @@
+#ifndef GRNXX_ARRAY_HPP
+#define GRNXX_ARRAY_HPP
+
+#include <cstdlib>
+#include <new>
+#include <utility>
+
+namespace grnxx {
+
+template <typename T>
+class ArrayCRef {
+ public:
+  using Value = T;
+
+  ArrayCRef() = default;
+  ~ArrayCRef() = default;
+
+  ArrayCRef(const ArrayCRef &) = default;
+  ArrayCRef &operator=(const ArrayCRef &) & = default;
+
+  // Create a reference to an array.
+  ArrayCRef(const Value *values, size_t size) : values_(values), size_(size) {}
+
+  // Create a reference to a part of "this".
+  ArrayCRef cref(size_t offset = 0) const {
+    return ArrayCRef(values_ + offset, size_ - offset);
+  }
+  // Create a reference to a part of "this".
+  ArrayCRef cref(size_t offset, size_t size) const {
+    return ArrayCRef(values_ + offset, size);
+  }
+
+  // Return a reference to the "i"-th value.
+  const Value &get(size_t i) const {
+    return values_[i];
+  }
+
+  // Return a reference to the "i"-th value.
+  const Value &operator[](size_t i) const {
+    return values_[i];
+  }
+
+  // Return the number of values.
+  size_t size() const {
+    return size_;
+  }
+
+ private:
+  const Value *values_;
+  size_t size_;
+};
+
+template <typename T>
+class ArrayRef {
+ public:
+  using Value = T;
+
+  ArrayRef() = default;
+  ~ArrayRef() = default;
+
+  ArrayRef(const ArrayRef &) = default;
+  ArrayRef &operator=(const ArrayRef &) & = default;
+
+  // Create a reference to an array.
+  ArrayRef(Value *values, size_t size) : values_(values), size_(size) {}
+
+  // Create a reference to "this".
+  operator ArrayCRef<Value>() const {
+    return cref();
+  }
+
+  // Create a reference to a part of "this".
+  ArrayCRef<Value> cref(size_t offset = 0) const {
+    return ArrayCRef<Value>(values_ + offset, size_ - offset);
+  }
+  // Create a reference to a part of "this".
+  ArrayCRef<Value> cref(size_t offset, size_t size) const {
+    return ArrayCRef<Value>(values_ + offset, size);
+  }
+
+  // Create a reference to a part of "this".
+  ArrayRef ref(size_t offset = 0) {
+    return ArrayRef(values_ + offset, size_ - offset);
+  }
+  // Create a reference to a part of "this".
+  ArrayRef ref(size_t offset, size_t size) {
+    return ArrayRef(values_ + offset, size);
+  }
+
+  // Return the "i"-th value.
+  const Value &get(size_t i) const {
+    return values_[i];
+  }
+  // Set the "i"-th value.
+  void set(size_t i, const Value &value) {
+    values_[i] = value;
+  }
+  // Set the "i"-th value.
+  void set(size_t i, Value &&value) {
+    values_[i] = std::move(value);
+  }
+
+  // Return a reference to the "i"-th value.
+  Value &operator[](size_t i) {
+    return values_[i];
+  }
+  // Return a reference to the "i"-th value.
+  const Value &operator[](size_t i) const {
+    return values_[i];
+  }
+
+  // Return the number of values.
+  size_t size() const {
+    return size_;
+  }
+
+ private:
+  Value *values_;
+  size_t size_;
+};
+
+template <typename T>
+class Array {
+ public:
+  using Value = T;
+
+  Array() : buffer_(nullptr), size_(0), capacity_(0) {}
+  ~Array() {
+    std::free(buffer_);
+  }
+
+  Array(const Array &) = delete;
+  Array &operator=(const Array &) & = delete;
+
+  // Move the ownership of an array.
+  Array(Array &&array)
+      : buffer_(array.buffer_),
+        size_(array.size_),
+        capacity_(array.capacity_) {
+    array.buffer_ = nullptr;
+    array.size_ = 0;
+    array.capacity_ = 0;
+  }
+  // Move the ownership of an array.
+  Array &operator=(Array &&array) & {
+    std::free(buffer_);
+    buffer_ = array.buffer_;
+    size_ = array.size_;
+    capacity_ = array.capacity_;
+    array.buffer_ = nullptr;
+    array.size_ = 0;
+    array.capacity_ = 0;
+    return *this;
+  }
+
+  // Create a reference to "this".
+  operator ArrayCRef<Value>() const {
+    return cref();
+  }
+
+  // Create a reference to a part of "this".
+  ArrayCRef<Value> cref(size_t offset = 0) const {
+    return ArrayCRef<Value>(data() + offset, size_ - offset);
+  }
+  // Create a reference to a part of "this".
+  ArrayCRef<Value> cref(size_t offset, size_t size) const {
+    return ArrayCRef<Value>(data() + offset, size);
+  }
+
+  // Create a reference to a part of "this".
+  ArrayRef<Value> ref(size_t offset = 0) {
+    return ArrayRef<Value>(buffer() + offset, size_ - offset);
+  }
+  // Create a reference to a part of "this".
+  ArrayRef<Value> ref(size_t offset, size_t size) {
+    return ArrayRef<Value>(buffer() + offset, size);
+  }
+
+  // Return a reference to the "i"-th value.
+  const Value &get(size_t i) const {
+    return data()[i];
+  }
+  // Set the "i"-th value.
+  void set(size_t i, const Value &value) {
+    buffer()[i] = value;
+  }
+  // Set the "i"-th value.
+  void set(size_t i, Value &&value) {
+    buffer()[i] = std::move(value);
+  }
+
+  // Return a reference to the "i"-th value.
+  Value &operator[](size_t i) {
+    return buffer()[i];
+  }
+  // Return a reference to the "i"-th value.
+  const Value &operator[](size_t i) const {
+    return data()[i];
+  }
+
+  // Return a reference to the first value.
+  Value &front() {
+    return *buffer();
+  }
+  // Return a reference to the first value.
+  const Value &front() const {
+    return *data();
+  }
+
+  // Return a reference to the last value.
+  Value &back() {
+    return buffer()[size_ - 1];
+  }
+  // Return a reference to the last value.
+  const Value &back() const {
+    return data()[size_ - 1];
+  }
+
+  // Return a pointer to the buffer.
+  Value *buffer() {
+    return static_cast<Value *>(buffer_);
+  }
+  // Return a pointer to the contents.
+  const Value *data() const {
+    return static_cast<const Value *>(buffer_);
+  }
+
+  // Return the number of values.
+  size_t size() const {
+    return size_;
+  }
+  // Return the number of values can be stored in the buffer.
+  size_t capacity() const {
+    return capacity_;
+  }
+
+  // Reserve memory for at least "new_size" values.
+  //
+  // On failure, throws an exception.
+  void reserve(size_t new_size) {
+    if (new_size > capacity_) {
+      resize_buffer(new_size);
+    }
+  }
+
+  // Resize "this".
+  //
+  // On failure, throws an exception.
+  void resize(size_t new_size) {
+    if (new_size > capacity_) {
+      resize_buffer(new_size);
+    }
+    for (size_t i = new_size; i < size_; ++i) {
+      buffer()[i].~Value();
+    }
+    for (size_t i = size_; i < new_size; ++i) {
+      new (&buffer()[i]) Value;
+    }
+    size_ = new_size;
+  }
+  // Resize "this" and fill the new values with "value".
+  //
+  // On failure, throws an exception.
+  void resize(size_t new_size, const Value &value) {
+    if (new_size > capacity_) {
+      resize_buffer(new_size);
+    }
+    for (size_t i = new_size; i < size_; ++i) {
+      buffer()[i].~Value();
+    }
+    for (size_t i = size_; i < new_size; ++i) {
+      new (&buffer()[i]) Value(value);
+    }
+    size_ = new_size;
+  }
+
+  // Clear the contents.
+  void clear() {
+    for (size_t i = 0; i < size_; ++i) {
+      buffer()[i].~Value();
+    }
+    size_ = 0;
+  }
+
+  // Remove the "i"-th value.
+  void erase(size_t i) {
+    for (size_t j = i + 1; j < size_; ++j) {
+      buffer()[j - 1] = std::move(buffer()[j]);
+    }
+    buffer()[size_ - 1].~Value();
+    --size_;
+  }
+
+  // Append "value" to the end.
+  //
+  // On failure, throws an exception.
+  void push_back(const Value &value) {
+    if (size_ == capacity_) {
+      resize_buffer(size_ + 1);
+    }
+    new (&buffer()[size_]) Value(value);
+    ++size_;
+  }
+  // Append "value" to the end.
+  //
+  // On failure, throws an exception.
+  void push_back(Value &&value) {
+    if (size_ == capacity_) {
+      resize_buffer(size_ + 1);
+    }
+    new (&buffer()[size_]) Value(std::move(value));
+    ++size_;
+  }
+  // Remove the last value.
+  void pop_back() {
+    buffer()[size_ - 1].~Value();
+    --size_;
+  }
+
+ private:
+  void *buffer_;
+  size_t size_;
+  size_t capacity_;
+
+  // Resize the buffer for at least "new_size" values.
+  //
+  // Assumes that "new_size" is greater than "capacity_".
+  void resize_buffer(size_t new_size) {
+    size_t new_capacity = capacity_ * 2;
+    if (new_size > new_capacity) {
+      new_capacity = new_size;
+    }
+    size_t new_buffer_size = sizeof(Value) * new_capacity;
+    Value *new_buffer = static_cast<Value *>(std::malloc(new_buffer_size));
+    if (!new_buffer) {
+      throw "Failed";  // TODO
+    }
+    for (size_t i = 0; i < size_; ++i) {
+      new (&new_buffer[i]) Value(std::move(buffer()[i]));
+    }
+    std::free(buffer_);
+    buffer_ = new_buffer;
+    capacity_ = new_capacity;
+  }
+};
+
+}  // namespace grnxx
+
+#endif  // GRNXX_ARRAY_HPP

  Modified: include/grnxx/column.hpp (+105 -92)
===================================================================
--- include/grnxx/column.hpp    2014-10-31 21:43:45 +0900 (38a8a6c)
+++ include/grnxx/column.hpp    2014-11-05 17:35:04 +0900 (2600868)
@@ -1,10 +1,24 @@
 #ifndef GRNXX_COLUMN_HPP
 #define GRNXX_COLUMN_HPP
 
-#include "grnxx/types.hpp"
+#include <memory>
+
+#include "grnxx/column.hpp"
+#include "grnxx/cursor.hpp"
+#include "grnxx/data_types.hpp"
+#include "grnxx/string.hpp"
 
 namespace grnxx {
 
+class Table;
+
+struct ColumnOptions {
+  // The referenced (parent) table.
+  String reference_table_name;
+
+  ColumnOptions();
+};
+
 class Column {
  public:
   Column() = default;
@@ -12,104 +26,103 @@ class Column {
   // Return the table.
   virtual Table *table() const = 0;
   // Return the name.
-  virtual StringCRef name() const = 0;
+  virtual String name() const = 0;
   // Return the data type.
   virtual DataType data_type() const = 0;
-  // Return the referenced (parent) table, or nullptr if the column is not a
-  // reference column.
-  virtual Table *ref_table() const = 0;
-  // Return whether the column has the key attribute or not.
-  virtual bool has_key_attribute() const = 0;
-  // Return the number of indexes.
-  virtual Int num_indexes() const = 0;
-
-  // Create an index with "name", "index_type", and "index_options".
-  //
-  // On success, returns a pointer to the index.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual Index *create_index(
-      Error *error,
-      const StringCRef &name,
-      IndexType type,
-      const IndexOptions &options = IndexOptions()) = 0;
-
-  // Remove an index named "name".
+  // Return the reference table.
+  // If "this" is not a reference column, returns nullptr.
+  virtual Table *reference_table() const = 0;
+//  // Return whether the column has the key attribute or not.
+//  virtual bool is_key() const = 0;
+//  // Return the number of indexes.
+//  virtual size_t num_indexes() const = 0;
+
+//  // Create an index with "name", "index_type", and "index_options".
+//  //
+//  // On success, returns a pointer to the index.
+//  // On failure, returns nullptr and stores error information into "*error" if
+//  // "error" != nullptr.
+//  virtual Index *create_index(
+//      Error *error,
+//      const String &name,
+//      IndexType type,
+//      const IndexOptions &options = IndexOptions()) = 0;
+
+//  // Remove an index named "name".
+//  //
+//  // On success, returns true.
+//  // On failure, returns false and stores error information into "*error" if
+//  // "error" != nullptr.
+//  //
+//  // Note: Pointers to the removed index must not be used after deletion.
+//  virtual bool remove_index(Error *error, const String &name) = 0;
+
+//  // Rename an index named "name" to "new_name".
+//  //
+//  // On success, returns true.
+//  // On failure, returns false and stores error information into "*error" if
+//  // "error" != nullptr.
+//  virtual bool rename_index(Error *error,
+//                            const String &name,
+//                            const String &new_name) = 0;
+
+//  // Change the order of indexes.
+//  //
+//  // If "prev_name" is  an empty string, moves an index named "name" to the
+//  // head.
+//  // If "name" == "prev_name", does nothing.
+//  // Otherwise, moves an index named "name" to next to an index named
+//  // "prev_name".
+//  //
+//  // On success, returns true.
+//  // On failure, returns false and stores error information into "*error" if
+//  // "error" != nullptr.
+//  virtual bool reorder_index(Error *error,
+//                             const String &name,
+//                             const String &prev_name) = 0;
+
+//  // Get an index identified by "index_id".
+//  //
+//  // If "index_id" is invalid, the result is undefined.
+//  //
+//  // On success, returns a pointer to the index.
+//  // On failure, returns nullptr and stores error information into "*error" if
+//  // "error" != nullptr.
+//  virtual Index *get_index(Int index_id) const = 0;
+
+//  // Find an index named "name".
+//  //
+//  // On success, returns a pointer to the index.
+//  // On failure, returns nullptr and stores error information into "*error" if
+//  // "error" != nullptr.
+//  virtual Index *find_index(Error *error, const String &name) const = 0;
+
+  // Get a value associated with "row_id".
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
+  // If "row_id" is invalid, stores N/A into "*datum".
   //
-  // Note: Pointers to the removed index must not be used after deletion.
-  virtual bool remove_index(Error *error, const StringCRef &name) = 0;
-
-  // Rename an index named "name" to "new_name".
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool rename_index(Error *error,
-                            const StringCRef &name,
-                            const StringCRef &new_name) = 0;
-
-  // Change the order of indexes.
-  //
-  // If "prev_name" is  an empty string, moves an index named "name" to the
-  // head.
-  // If "name" == "prev_name", does nothing.
-  // Otherwise, moves an index named "name" to next to an index named
-  // "prev_name".
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool reorder_index(Error *error,
-                             const StringCRef &name,
-                             const StringCRef &prev_name) = 0;
-
-  // Get an index identified by "index_id".
-  //
-  // If "index_id" is invalid, the result is undefined.
-  //
-  // On success, returns a pointer to the index.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual Index *get_index(Int index_id) const = 0;
-
-  // Find an index named "name".
-  //
-  // On success, returns a pointer to the index.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual Index *find_index(Error *error, const StringCRef &name) const = 0;
+  // On failure, throws an exception.
+  virtual void get(Int row_id, Datum *datum) const = 0;
 
   // Set a value.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool set(Error *error, Int row_id, const Datum &datum) = 0;
-
-  // Get a value.
-  //
-  // Stores a value identified by "row_id" into "*datum".
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool get(Error *error, Int row_id, Datum *datum) const = 0;
-
-  // Check if "datum" exists in the column or not.
-  //
-  // If exists, returns true.
-  // Otherwise, returns false.
-  virtual bool contains(const Datum &datum) const = 0;
-
-  // Find "datum" in the column.
-  //
-  // On success, returns the row ID of the matched value.
-  // On failure, returns NULL_ROW_ID.
-  virtual Int find_one(const Datum &datum) const = 0;
+  // On failure, throws an exception.
+  virtual void set(Int row_id, const Datum &datum) = 0;
+
+//  // Check if "datum" exists in the column or not.
+//  //
+//  // If exists, returns true.
+//  // Otherwise, returns false.
+//  virtual bool contains(const Datum &datum) const = 0;
+
+//  // Find "datum" in the column.
+//  //
+//  // On success, returns the row ID of the matched value.
+//  // On failure, returns NULL_ROW_ID.
+//  virtual Int find_one(const Datum &datum) const = 0;
+
+  std::unique_ptr<Cursor> create_cursor(
+      const CursorOptions &options = CursorOptions());
 
  protected:
   virtual ~Column() = default;

  Modified: include/grnxx/cursor.hpp (+33 -31)
===================================================================
--- include/grnxx/cursor.hpp    2014-10-31 21:43:45 +0900 (5fba651)
+++ include/grnxx/cursor.hpp    2014-11-05 17:35:04 +0900 (30dae7c)
@@ -1,59 +1,61 @@
 #ifndef GRNXX_CURSOR_HPP
 #define GRNXX_CURSOR_HPP
 
-#include "grnxx/types.hpp"
+#include <cstddef>
+
+#include "grnxx/array.hpp"
+#include "grnxx/data_types.hpp"
 
 namespace grnxx {
 
-struct CursorResult {
-  bool is_ok;
-  Int count;
+enum CursorOrderType {
+  // The natural order (the ascending order in most cases).
+  CURSOR_REGULAR_ORDER,
+  // The reverse order (the descending order in most cases).
+  CURSOR_REVERSE_ORDER
+};
+
+struct CursorOptions {
+  // The first "offset" records are skipped (default: 0).
+  size_t offset;
+
+  // At most "limit" records are read (default: numeric_limits<size_t>::max()).
+  size_t limit;
+
+  // The order of records (default: REGULAR_ORDER).
+  CursorOrderType order_type;
+
+  CursorOptions();
 };
 
 class Cursor {
  public:
-  virtual ~Cursor() {}
-
-  // Return the associated table.
-  const Table *table() const {
-    return table_;
-  }
+  Cursor() = default;
+  virtual ~Cursor() = default;
 
   // Read the next records.
   //
   // Reads at most "max_count" records into "*records".
   //
-  // On success, returns true and the number of records read.
-  // On failure, returns false and the number of records read and stores error
-  // information into "*error" if "error" != nullptr.
-  virtual CursorResult read(Error *error,
-                            Int max_count,
-                            Array<Record> *records);
+  // On success, returns the number of records read.
+  // On failure, throws an exception.
+  virtual size_t read(size_t max_count, Array<Record> *records);
 
   // Read the next records.
   //
   // Reads at most "records.size()" records into "records".
   //
-  // On success, returns true and the number of records read.
-  // On failure, returns false and the number of records read and stores error
-  // information into "*error" if "error" != nullptr.
-  virtual CursorResult read(Error *error,
-                            ArrayRef<Record> records) = 0;
+  // On success, returns the number of records read.
+  // On failure, throws an exception.
+  virtual size_t read(ArrayRef<Record> records) = 0;
 
   // Read all the remaining records.
   //
   // Reads records into "*records".
   //
-  // On success, returns true and the number of records read.
-  // On failure, returns false and the number of records read and stores error
-  // information into "*error" if "error" != nullptr.
-  virtual CursorResult read_all(Error *error,
-                                Array<Record> *records);
-
- protected:
-  const Table *table_;
-
-  explicit Cursor(const Table *table) : table_(table) {}
+  // On success, returns the number of records read.
+  // On failure, throws an exception.
+  virtual size_t read_all(Array<Record> *records);
 };
 
 }  // namespace grnxx

  Modified: include/grnxx/data_types.hpp (+4 -0)
===================================================================
--- include/grnxx/data_types.hpp    2014-10-31 21:43:45 +0900 (906d8fb)
+++ include/grnxx/data_types.hpp    2014-11-05 17:35:04 +0900 (3f5b701)
@@ -1,6 +1,10 @@
 #ifndef GRNXX_DATA_TYPES_HPP
 #define GRNXX_DATA_TYPES_HPP
 
+#include "grnxx/data_types/data_type.hpp"
+#include "grnxx/data_types/datum.hpp"
+#include "grnxx/data_types/na.hpp"
+#include "grnxx/data_types/record.hpp"
 #include "grnxx/data_types/scalar.hpp"
 #include "grnxx/data_types/vector.hpp"
 

  Modified: include/grnxx/data_types/Makefile.am (+3 -0)
===================================================================
--- include/grnxx/data_types/Makefile.am    2014-10-31 21:43:45 +0900 (c055bfa)
+++ include/grnxx/data_types/Makefile.am    2014-11-05 17:35:04 +0900 (392ca96)
@@ -4,6 +4,9 @@ SUBDIRS =		\
 
 pkgincludedir = ${includedir}/${PACKAGE}/data_types
 pkginclude_HEADERS =	\
+	data_type.hpp	\
+	datum.hpp	\
 	na.hpp		\
+	record.hpp	\
 	scalar.hpp	\
 	vector.hpp

  Added: include/grnxx/data_types/data_type.hpp (+33 -0) 100644
===================================================================
--- /dev/null
+++ include/grnxx/data_types/data_type.hpp    2014-11-05 17:35:04 +0900 (6858b8f)
@@ -0,0 +1,33 @@
+#ifndef GRNXX_DATA_TYPES_DATA_TYPE_HPP
+#define GRNXX_DATA_TYPES_DATA_TYPE_HPP
+
+namespace grnxx {
+
+enum DataType {
+  // N/A.
+  NA_DATA,
+  // True or false.
+  BOOL_DATA,
+  // 64-bit signed integer.
+  INT_DATA,
+  // Double precision (64-bit) floating point number.
+  FLOAT_DATA,
+  // Latitude-longitude in milliseconds.
+  GEO_POINT_DATA,
+  // Byte string.
+  TEXT_DATA,
+  // Vector of Bool.
+  BOOL_VECTOR_DATA,
+  // Vector of Int.
+  INT_VECTOR_DATA,
+  // Vector of Float.
+  FLOAT_VECTOR_DATA,
+  // Vector of GeoPoint.
+  GEO_POINT_VECTOR_DATA,
+  // Vector of Text.
+  TEXT_VECTOR_DATA
+};
+
+}  // namespace grnxx
+
+#endif  // GRNXX_DATA_TYPES_DATA_TYPE_HPP

  Added: include/grnxx/data_types/datum.hpp (+220 -0) 100644
===================================================================
--- /dev/null
+++ include/grnxx/data_types/datum.hpp    2014-11-05 17:35:04 +0900 (b97335a)
@@ -0,0 +1,220 @@
+#ifndef GRNXX_TYPES_DATUM_HPP
+#define GRNXX_TYPES_DATUM_HPP
+
+#include "grnxx/data_types/data_type.hpp"
+#include "grnxx/data_types/na.hpp"
+#include "grnxx/data_types/scalar.hpp"
+#include "grnxx/data_types/vector.hpp"
+
+namespace grnxx {
+
+class Datum {
+ public:
+  Datum() : type_(NA_DATA), na_() {}
+  // TODO: User-defined destructor will be required.
+  ~Datum() = default;
+
+  // Create a N/A object.
+  Datum(NA) : type_(NA_DATA), na_() {}
+  // Create a Bool object.
+  Datum(Bool value) : type_(BOOL_DATA), bool_(value) {}
+  // Create an Int object.
+  Datum(Int value) : type_(INT_DATA), int_(value) {}
+  // Create a Float object.
+  Datum(Float value) : type_(FLOAT_DATA), float_(value) {}
+  // Create a GeoPoint object.
+  Datum(GeoPoint value) : type_(GEO_POINT_DATA), geo_point_(value) {}
+  // Create a Text object.
+  Datum(const Text &value) : type_(TEXT_DATA), text_(value) {}
+  // Create a Vector<Bool> object.
+  Datum(const Vector<Bool> &value)
+      : type_(BOOL_VECTOR_DATA),
+        bool_vector_(value) {}
+  // Create a Vector<Int> object.
+  Datum(const Vector<Int> &value)
+      : type_(INT_VECTOR_DATA),
+        int_vector_(value) {}
+  // Create a Vector<Float> object.
+  Datum(const Vector<Float> &value)
+      : type_(FLOAT_VECTOR_DATA),
+        float_vector_(value) {}
+  // Create a Vector<GeoPoint> object.
+  Datum(const Vector<GeoPoint> &value)
+      : type_(GEO_POINT_VECTOR_DATA),
+        geo_point_vector_(value) {}
+  // Create a Vector<Text> object.
+  Datum(const Vector<Text> &value)
+      : type_(TEXT_VECTOR_DATA),
+        text_vector_(value) {}
+
+  // Return the data type.
+  DataType type() const {
+    return type_;
+  }
+
+  // Access the content as Bool.
+  const Bool &as_bool() const {
+    return bool_;
+  }
+  // Access the content as Int.
+  const Int &as_int() const {
+    return int_;
+  }
+  // Access the content as Float.
+  const Float &as_float() const {
+    return float_;
+  }
+  // Access the content as GeoPoint.
+  const GeoPoint &as_geo_point() const {
+    return geo_point_;
+  }
+  // Access the content as Text.
+  const Text &as_text() const {
+    return text_;
+  }
+  // Access the content as Vector<Bool>.
+  const Vector<Bool> &as_bool_vector() const {
+    return bool_vector_;
+  }
+  // Access the content as Vector<Int>.
+  const Vector<Int> &as_int_vector() const {
+    return int_vector_;
+  }
+  // Access the content as Vector<Float>.
+  const Vector<Float> &as_float_vector() const {
+    return float_vector_;
+  }
+  // Access the content as Vector<GeoPoint>.
+  const Vector<GeoPoint> &as_geo_point_vector() const {
+    return geo_point_vector_;
+  }
+  // Access the content as Vector<Text>.
+  const Vector<Text> &as_text_vector() const {
+    return text_vector_;
+  }
+
+  // Access the content as Bool.
+  Bool &as_bool() {
+    return bool_;
+  }
+  // Access the content as Int.
+  Int &as_int() {
+    return int_;
+  }
+  // Access the content as Float.
+  Float &as_float() {
+    return float_;
+  }
+  // Access the content as GeoPoint.
+  GeoPoint &as_geo_point() {
+    return geo_point_;
+  }
+  // Access the content as Text.
+  Text &as_text() {
+    return text_;
+  }
+  // Access the content as Vector<Bool>.
+  Vector<Bool> &as_bool_vector() {
+    return bool_vector_;
+  }
+  // Access the content as Vector<Int>.
+  Vector<Int> &as_int_vector() {
+    return int_vector_;
+  }
+  // Access the content as Vector<Float>.
+  Vector<Float> &as_float_vector() {
+    return float_vector_;
+  }
+  // Access the content as Vector<GeoPoint>.
+  Vector<GeoPoint> &as_geo_point_vector() {
+    return geo_point_vector_;
+  }
+  // Access the content as Vector<Text>.
+  Vector<Text> &as_text_vector() {
+    return text_vector_;
+  }
+
+  // Force the specified interpretation.
+  Bool force_bool() const {
+    return bool_;
+  }
+  Int force_int() const {
+    return int_;
+  }
+  Float force_float() const {
+    return float_;
+  }
+  GeoPoint force_geo_point() const {
+    return geo_point_;
+  }
+  Text force_text() const {
+    return text_;
+  }
+  Vector<Bool> force_bool_vector() const {
+    return bool_vector_;
+  }
+  Vector<Int> force_int_vector() const {
+    return int_vector_;
+  }
+  Vector<Float> force_float_vector() const {
+    return float_vector_;
+  }
+  Vector<GeoPoint> force_geo_point_vector() const {
+    return geo_point_vector_;
+  }
+  Vector<Text> force_text_vector() const {
+    return text_vector_;
+  }
+
+  // Force the specified interpretation.
+  void force(Bool *value) const {
+    *value = bool_;
+  }
+  void force(Int *value) const {
+    *value = int_;
+  }
+  void force(Float *value) const {
+    *value = float_;
+  }
+  void force(GeoPoint *value) const {
+    *value = geo_point_;
+  }
+  void force(Text *value) const {
+    *value = text_;
+  }
+  void force(Vector<Bool> *value) const {
+    *value = bool_vector_;
+  }
+  void force(Vector<Int> *value) const {
+    *value = int_vector_;
+  }
+  void force(Vector<Float> *value) const {
+    *value = float_vector_;
+  }
+  void force(Vector<GeoPoint> *value) const {
+    *value = geo_point_vector_;
+  }
+  void force(Vector<Text> *value) const {
+    *value = text_vector_;
+  }
+
+ private:
+  DataType type_;
+  union {
+    NA na_;
+    Bool bool_;
+    Int int_;
+    Float float_;
+    GeoPoint geo_point_;
+    Text text_;
+    Vector<Bool> bool_vector_;
+    Vector<Int> int_vector_;
+    Vector<Float> float_vector_;
+    Vector<GeoPoint> geo_point_vector_;
+    Vector<Text> text_vector_;
+  };
+};
+
+}  // namespace grnxx
+
+#endif  // GRNXX_TYPES_DATUM_HPP

  Modified: include/grnxx/data_types/na.hpp (+5 -1)
===================================================================
--- include/grnxx/data_types/na.hpp    2014-10-31 21:43:45 +0900 (b1fe63b)
+++ include/grnxx/data_types/na.hpp    2014-11-05 17:35:04 +0900 (50d7f3d)
@@ -1,10 +1,14 @@
 #ifndef GRNXX_DATA_TYPES_NA_HPP
 #define GRNXX_DATA_TYPES_NA_HPP
 
+#include "grnxx/data_types/data_type.hpp"
+
 namespace grnxx {
 
 struct NA {
-  // TODO
+  constexpr DataType type() const {
+    return NA_DATA;
+  }
 };
 
 }  // namespace grnxx

  Added: include/grnxx/data_types/record.hpp (+24 -0) 100644
===================================================================
--- /dev/null
+++ include/grnxx/data_types/record.hpp    2014-11-05 17:35:04 +0900 (882a253)
@@ -0,0 +1,24 @@
+#ifndef GRNXX_DATA_TYPES_RECORD_HPP
+#define GRNXX_DATA_TYPES_RECORD_HPP
+
+#include "grnxx/data_types/scalar/int.hpp"
+#include "grnxx/data_types/scalar/float.hpp"
+
+namespace grnxx {
+
+struct Record {
+  Int row_id;
+  Float score;
+
+  Record() = default;
+  ~Record() = default;
+
+  Record(const Record &) = default;
+  Record &operator=(const Record &) & = default;
+
+  Record(Int row_id, Float score) : row_id(row_id), score(score) {}
+};
+
+}  // namespace grnxx
+
+#endif  // GRNXX_DATA_TYPES_RECORD_HPP

  Modified: include/grnxx/data_types/scalar.hpp (+0 -1)
===================================================================
--- include/grnxx/data_types/scalar.hpp    2014-10-31 21:43:45 +0900 (5aaf3ca)
+++ include/grnxx/data_types/scalar.hpp    2014-11-05 17:35:04 +0900 (acebe7d)
@@ -6,7 +6,6 @@
 #include "grnxx/data_types/scalar/float.hpp"
 #include "grnxx/data_types/scalar/geo_point.hpp"
 #include "grnxx/data_types/scalar/int.hpp"
-#include "grnxx/data_types/scalar/row_id.hpp"
 #include "grnxx/data_types/scalar/text.hpp"
 
 #endif  // GRNXX_DATA_TYPES_SCALAR_HPP

  Modified: include/grnxx/data_types/scalar/Makefile.am (+0 -1)
===================================================================
--- include/grnxx/data_types/scalar/Makefile.am    2014-10-31 21:43:45 +0900 (7f77c2d)
+++ include/grnxx/data_types/scalar/Makefile.am    2014-11-05 17:35:04 +0900 (8b276e1)
@@ -4,5 +4,4 @@ pkginclude_HEADERS =	\
 	float.hpp	\
 	geo_point.hpp	\
 	int.hpp		\
-	row_id.hpp	\
 	text.hpp

  Modified: include/grnxx/data_types/scalar/bool.hpp (+4 -0)
===================================================================
--- include/grnxx/data_types/scalar/bool.hpp    2014-10-31 21:43:45 +0900 (233b2c6)
+++ include/grnxx/data_types/scalar/bool.hpp    2014-11-05 17:35:04 +0900 (383616c)
@@ -3,6 +3,7 @@
 
 #include <cstdint>
 
+#include "grnxx/data_types/data_type.hpp"
 #include "grnxx/data_types/na.hpp"
 
 namespace grnxx {
@@ -19,6 +20,9 @@ class Bool {
       : value_(value ? true_value() : false_value()) {}
   explicit constexpr Bool(NA) : value_(na_value()) {}
 
+  constexpr DataType type() const {
+    return BOOL_DATA;
+  }
   constexpr uint8_t value() const {
     return value_;
   }

  Modified: include/grnxx/data_types/scalar/float.hpp (+4 -0)
===================================================================
--- include/grnxx/data_types/scalar/float.hpp    2014-10-31 21:43:45 +0900 (be40c1f)
+++ include/grnxx/data_types/scalar/float.hpp    2014-11-05 17:35:04 +0900 (092aa36)
@@ -4,6 +4,7 @@
 #include <cmath>
 #include <limits>
 
+#include "grnxx/data_types/data_type.hpp"
 #include "grnxx/data_types/na.hpp"
 
 namespace grnxx {
@@ -22,6 +23,9 @@ class Float {
   explicit constexpr Float(double value) : value_(value) {}
   explicit constexpr Float(NA) : value_(na_value()) {}
 
+  constexpr DataType type() const {
+    return FLOAT_DATA;
+  }
   constexpr double value() const {
     return value_;
   }

  Modified: include/grnxx/data_types/scalar/geo_point.hpp (+4 -0)
===================================================================
--- include/grnxx/data_types/scalar/geo_point.hpp    2014-10-31 21:43:45 +0900 (ab55a61)
+++ include/grnxx/data_types/scalar/geo_point.hpp    2014-11-05 17:35:04 +0900 (414bff0)
@@ -4,6 +4,7 @@
 #include <cstdint>
 #include <limits>
 
+#include "grnxx/data_types/data_type.hpp"
 #include "grnxx/data_types/na.hpp"
 
 namespace grnxx {
@@ -30,6 +31,9 @@ class GeoPoint {
       : latitude_(na_latitude()),
         longitude_(na_longitude()) {}
 
+  constexpr DataType type() const {
+    return GEO_POINT_DATA;
+  }
   constexpr int32_t latitude() const {
     return latitude_;
   }

  Modified: include/grnxx/data_types/scalar/int.hpp (+4 -0)
===================================================================
--- include/grnxx/data_types/scalar/int.hpp    2014-10-31 21:43:45 +0900 (0c6de11)
+++ include/grnxx/data_types/scalar/int.hpp    2014-11-05 17:35:04 +0900 (2230004)
@@ -5,6 +5,7 @@
 #include <limits>
 
 #include "grnxx/features.hpp"
+#include "grnxx/data_types/data_type.hpp"
 #include "grnxx/data_types/na.hpp"
 
 namespace grnxx {
@@ -21,6 +22,9 @@ class Int {
   explicit constexpr Int(int64_t value) : value_(value) {}
   explicit constexpr Int(NA) : value_(na_value()) {}
 
+  constexpr DataType type() const {
+    return INT_DATA;
+  }
   constexpr int64_t value() const {
     return value_;
   }

  Deleted: include/grnxx/data_types/scalar/row_id.hpp (+0 -62) 100644
===================================================================
--- include/grnxx/data_types/scalar/row_id.hpp    2014-10-31 21:43:45 +0900 (c3f6f4d)
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef GRNXX_DATA_TYPES_SCALAR_ROW_ID_HPP
-#define GRNXX_DATA_TYPES_SCALAR_ROW_ID_HPP
-
-#include <cstdint>
-#include <limits>
-
-#include "grnxx/data_types/na.hpp"
-
-namespace grnxx {
-
-class RowID {
- public:
-  RowID() = default;
-  ~RowID() = default;
-
-  constexpr RowID(const RowID &) = default;
-  RowID &operator=(const RowID &) = default;
-
-  explicit constexpr RowID(uint64_t value) : value_(value) {}
-  explicit constexpr RowID(NA) : value_(na_value()) {}
-
-  constexpr uint64_t value() const {
-    return value_;
-  }
-
-  constexpr bool is_min() const {
-    return value_ == min_value();
-  }
-  constexpr bool is_max() const {
-    return value_ == max_value();
-  }
-  constexpr bool is_na() const {
-    return value_ == na_value();
-  }
-
-  static constexpr RowID min() {
-    return RowID(min_value());
-  }
-  static constexpr RowID max() {
-    return RowID(max_value());
-  }
-  static constexpr RowID na() {
-    return RowID(NA());
-  }
-
-  static constexpr uint64_t min_value() {
-    return 0;
-  }
-  static constexpr uint64_t max_value() {
-    return std::numeric_limits<uint64_t>::max() - 1;
-  }
-  static constexpr uint64_t na_value() {
-    return std::numeric_limits<uint64_t>::max();
-  }
-
- private:
-  uint64_t value_;
-};
-
-}  // namespace grnxx
-
-#endif  // GRNXX_DATA_TYPES_SCALAR_ROW_ID_HPP

  Modified: include/grnxx/data_types/scalar/text.hpp (+4 -0)
===================================================================
--- include/grnxx/data_types/scalar/text.hpp    2014-10-31 21:43:45 +0900 (2d18fde)
+++ include/grnxx/data_types/scalar/text.hpp    2014-11-05 17:35:04 +0900 (dbb6667)
@@ -4,6 +4,7 @@
 #include <cstdint>
 #include <cstring>
 
+#include "grnxx/data_types/data_type.hpp"
 #include "grnxx/data_types/na.hpp"
 
 namespace grnxx {
@@ -23,6 +24,9 @@ class Text {
   constexpr Text(const char *data, size_t size) : data_(data), size_(size) {}
   explicit constexpr Text(NA) : data_(na_data()), size_(na_size()) {}
 
+  constexpr DataType type() const {
+    return TEXT_DATA;
+  }
   const char &operator[](size_t i) const {
     return data_[i];
   }

  Modified: include/grnxx/data_types/vector.hpp (+0 -1)
===================================================================
--- include/grnxx/data_types/vector.hpp    2014-10-31 21:43:45 +0900 (9084a5f)
+++ include/grnxx/data_types/vector.hpp    2014-11-05 17:35:04 +0900 (04b35dd)
@@ -6,7 +6,6 @@
 #include "grnxx/data_types/vector/float.hpp"
 #include "grnxx/data_types/vector/geo_point.hpp"
 #include "grnxx/data_types/vector/int.hpp"
-#include "grnxx/data_types/vector/row_id.hpp"
 #include "grnxx/data_types/vector/text.hpp"
 
 #endif  // GRNXX_DATA_TYPES_VECTOR_HPP

  Modified: include/grnxx/data_types/vector/Makefile.am (+0 -1)
===================================================================
--- include/grnxx/data_types/vector/Makefile.am    2014-10-31 21:43:45 +0900 (73c2290)
+++ include/grnxx/data_types/vector/Makefile.am    2014-11-05 17:35:04 +0900 (8e7a423)
@@ -4,5 +4,4 @@ pkginclude_HEADERS =	\
 	float.hpp	\
 	geo_point.hpp	\
 	int.hpp		\
-	row_id.hpp	\
 	text.hpp

  Modified: include/grnxx/data_types/vector/bool.hpp (+1 -0)
===================================================================
--- include/grnxx/data_types/vector/bool.hpp    2014-10-31 21:43:45 +0900 (affd198)
+++ include/grnxx/data_types/vector/bool.hpp    2014-11-05 17:35:04 +0900 (d317c00)
@@ -1,6 +1,7 @@
 #ifndef GRNXX_DATA_TYPES_VECTOR_BOOL_HPP
 #define GRNXX_DATA_TYPES_VECTOR_BOOL_HPP
 
+#include "grnxx/data_types/data_type.hpp"
 #include "grnxx/data_types/na.hpp"
 #include "grnxx/data_types/scalar/bool.hpp"
 

  Modified: include/grnxx/data_types/vector/float.hpp (+1 -0)
===================================================================
--- include/grnxx/data_types/vector/float.hpp    2014-10-31 21:43:45 +0900 (687cd64)
+++ include/grnxx/data_types/vector/float.hpp    2014-11-05 17:35:04 +0900 (effc7d3)
@@ -1,6 +1,7 @@
 #ifndef GRNXX_DATA_TYPES_VECTOR_FLOAT_HPP
 #define GRNXX_DATA_TYPES_VECTOR_FLOAT_HPP
 
+#include "grnxx/data_types/data_type.hpp"
 #include "grnxx/data_types/na.hpp"
 #include "grnxx/data_types/scalar/float.hpp"
 

  Modified: include/grnxx/data_types/vector/geo_point.hpp (+1 -0)
===================================================================
--- include/grnxx/data_types/vector/geo_point.hpp    2014-10-31 21:43:45 +0900 (aea0cd0)
+++ include/grnxx/data_types/vector/geo_point.hpp    2014-11-05 17:35:04 +0900 (1c9d9e0)
@@ -1,6 +1,7 @@
 #ifndef GRNXX_DATA_TYPES_VECTOR_GEO_POINT_HPP
 #define GRNXX_DATA_TYPES_VECTOR_GEO_POINT_HPP
 
+#include "grnxx/data_types/data_type.hpp"
 #include "grnxx/data_types/na.hpp"
 #include "grnxx/data_types/scalar/geo_point.hpp"
 

  Modified: include/grnxx/data_types/vector/int.hpp (+1 -0)
===================================================================
--- include/grnxx/data_types/vector/int.hpp    2014-10-31 21:43:45 +0900 (9457fd0)
+++ include/grnxx/data_types/vector/int.hpp    2014-11-05 17:35:04 +0900 (892cc6c)
@@ -1,6 +1,7 @@
 #ifndef GRNXX_DATA_TYPES_VECTOR_INT_HPP
 #define GRNXX_DATA_TYPES_VECTOR_INT_HPP
 
+#include "grnxx/data_types/data_type.hpp"
 #include "grnxx/data_types/na.hpp"
 #include "grnxx/data_types/scalar/int.hpp"
 

  Deleted: include/grnxx/data_types/vector/row_id.hpp (+0 -20) 100644
===================================================================
--- include/grnxx/data_types/vector/row_id.hpp    2014-10-31 21:43:45 +0900 (8ccc280)
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef GRNXX_DATA_TYPES_VECTOR_ROW_ID_HPP
-#define GRNXX_DATA_TYPES_VECTOR_ROW_ID_HPP
-
-#include "grnxx/data_types/na.hpp"
-#include "grnxx/data_types/scalar/row_id.hpp"
-
-namespace grnxx {
-
-template <typename T> class Vector;
-
-template <>
-class Vector<RowID> {
-  // TODO
-};
-
-using RowIDVector = Vector<RowID>;
-
-}  // namespace grnxx
-
-#endif  // GRNXX_DATA_TYPES_VECTOR_ROW_ID_HPP

  Modified: include/grnxx/data_types/vector/text.hpp (+1 -1)
===================================================================
--- include/grnxx/data_types/vector/text.hpp    2014-10-31 21:43:45 +0900 (e965152)
+++ include/grnxx/data_types/vector/text.hpp    2014-11-05 17:35:04 +0900 (189ca22)
@@ -1,7 +1,7 @@
 #ifndef GRNXX_DATA_TYPES_VECTOR_TEXT_HPP
 #define GRNXX_DATA_TYPES_VECTOR_TEXT_HPP
 
-#include "grnxx/data_types/na.hpp"
+#include "grnxx/data_types/data_type.hpp"
 #include "grnxx/data_types/scalar/text.hpp"
 
 namespace grnxx {

  Modified: include/grnxx/db.hpp (+32 -54)
===================================================================
--- include/grnxx/db.hpp    2014-10-31 21:43:45 +0900 (53c94d6)
+++ include/grnxx/db.hpp    2014-11-05 17:35:04 +0900 (d1e3be2)
@@ -1,45 +1,41 @@
 #ifndef GRNXX_DB_HPP
 #define GRNXX_DB_HPP
 
-#include "grnxx/types.hpp"
+#include <memory>
+
+#include "grnxx/string.hpp"
+#include "grnxx/table.hpp"
 
 namespace grnxx {
 
+struct DBOptions {
+};
+
 class DB {
  public:
   DB() = default;
   virtual ~DB() = default;
 
   // Return the number of tables.
-  virtual Int num_tables() const = 0;
+  virtual size_t num_tables() const = 0;
 
-  // Create a table with "name" and "options".
+  // Create a table.
   //
   // On success, returns a pointer to the table.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
+  // On failure, throws an exception.
   virtual Table *create_table(
-      Error *error,
-      const StringCRef &name,
+      const String &name,
       const TableOptions &options = TableOptions()) = 0;
 
   // Remove a table named "name".
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  //
-  // Note: Pointers to the removed table must not be used after deletion.
-  virtual bool remove_table(Error *error, const StringCRef &name) = 0;
+  // On failure, throws an exception.
+  virtual void remove_table(const String &name) = 0;
 
   // Rename a table named "name" to "new_name".
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool rename_table(Error *error,
-                            const StringCRef &name,
-                            const StringCRef &new_name) = 0;
+  // On failure, throws an exception.
+  virtual void rename_table(const String &name, const String &new_name) = 0;
 
   // Change the order of tables.
   //
@@ -48,28 +44,19 @@ class DB {
   // Otherwise, moves a table named "name" to next to a table named
   // "prev_name".
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool reorder_table(Error *error,
-                             const StringCRef &name,
-                             const StringCRef &prev_name) = 0;
-
-  // Get a table identified by "table_id".
-  //
-  // If "table_id" is invalid, the result is undefined.
+  // On failure, throws an exception.
+  virtual void reorder_table(const String &name, const String &prev_name) = 0;
+
+  // Return the "i"-th table.
   //
-  // On success, returns a pointer to the table.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual Table *get_table(Int table_id) const = 0;
+  // If "i" >= "num_tables()", the behavior is undefined.
+  virtual Table *get_table(size_t table_id) const = 0;
 
   // Find a table named "name".
   //
-  // On success, returns a pointer to the table.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual Table *find_table(Error *error, const StringCRef &name) const = 0;
+  // If found, returns a pointer to the table.
+  // If not found, returns nullptr.
+  virtual Table *find_table(const String &name) const = 0;
 
   // TODO: Not supported yet.
   //
@@ -78,11 +65,8 @@ class DB {
   // If "path" is nullptr or an empty string, saves the database into its
   // associated file.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool save(Error *error,
-                    const StringCRef &path,
+  // On failure, throws an exception.
+  virtual void save(const String &path,
                     const DBOptions &options = DBOptions()) const = 0;
 };
 
@@ -93,22 +77,16 @@ class DB {
 // TODO: A named database is not supoprted yet.
 //
 // On success, returns a pointer to the database.
-// On failure, returns nullptr and stores error information into "*error" if
-// "error" != nullptr.
-unique_ptr<DB> open_db(Error *error,
-                       const StringCRef &path,
-                       const DBOptions &options = DBOptions());
+// On failure, throws an exception.
+std::unique_ptr<DB> open_db(const String &path,
+                            const DBOptions &options = DBOptions());
 
 // TODO: Not supported yet.
 //
-// Remove a database identified by "path".
+// Remove a database.
 //
-// On success, returns true.
-// On failure, returns false and stores error information into "*error" if
-// "error" != nullptr.
-bool remove_db(Error *error,
-               const StringCRef &path,
-               const DBOptions &options = DBOptions());
+// On failure, throws an exception.
+void remove_db(const String &path, const DBOptions &options = DBOptions());
 
 }  // namespace grnxx
 

  Modified: include/grnxx/features/Makefile.am (+6 -0)
===================================================================
--- include/grnxx/features/Makefile.am    2014-10-31 21:43:45 +0900 (e69de29)
+++ include/grnxx/features/Makefile.am    2014-11-05 17:35:04 +0900 (c8b0f70)
@@ -0,0 +1,6 @@
+pkgincludedir = ${includedir}/${PACKAGE}/features
+pkginclude_HEADERS =	\
+	compiler.hpp	\
+	cpu.hpp		\
+	functions.hpp	\
+	os.hpp

  Deleted: include/grnxx/memory.hpp (+0 -16) 100644
===================================================================
--- include/grnxx/memory.hpp    2014-10-31 21:43:45 +0900 (055f59d)
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef GRNXX_MEMORY_HPP
-#define GRNXX_MEMORY_HPP
-
-#include <memory>
-
-namespace grnxx {
-
-// Smart pointer.
-using std::unique_ptr;
-
-// An object to make memory allocation (new) return nullptr on failure.
-using std::nothrow;
-
-}  // namespace grnxx
-
-#endif  // GRNXX_MEMORY_HPP

  Modified: include/grnxx/string.hpp (+9 -5)
===================================================================
--- include/grnxx/string.hpp    2014-10-31 21:43:45 +0900 (a9299fe)
+++ include/grnxx/string.hpp    2014-11-05 17:35:04 +0900 (cb26266)
@@ -36,7 +36,7 @@ class String {
     return *this;
   }
 
-  // Create a reference to "string".
+  // Create a reference to a null-terminated string.
   //
   // If "string" == nullptr, the behavior is undefined.
   String(const char *string)
@@ -49,8 +49,12 @@ class String {
         size_(size),
         capacity_(0) {}
   // Create an instance.
+  //
+  // On failure, throws an exception.
   explicit String(size_t size);
   // Create an instance filled with "byte".
+  //
+  // On failure, throws an exception.
   String(size_t size, char byte);
 
   // Create a reference to a substring.
@@ -137,7 +141,7 @@ class String {
   size_t size() const {
     return size_;
   }
-  // Return the size of the internal buffer.
+  // Return the buffer size.
   size_t capacity() const {
     return capacity_;
   }
@@ -179,7 +183,7 @@ class String {
     }
     size_ = new_size;
   }
-  // Resize the string and fill the new space with "byte".
+  // Resize the string and fill the new bytes with "byte".
   //
   // On failure, throws an exception.
   void resize(size_t new_size, char byte) {
@@ -416,14 +420,14 @@ class String {
   size_t size_;
   size_t capacity_;
 
-  // Resize the internal buffer for at least "new_size".
+  // Resize the buffer for at least "new_size".
   //
   // Assumes that "new_size" is greater than "capacity_".
   //
   // On failure, throws an exception.
   void resize_buffer(size_t new_size);
 
-  // Resize the internal buffer and append a part of "this".
+  // Resize the buffer and append a part of "this".
   //
   // On failure, throws an exception.
   void append_overlap(const char *data, size_t size);

  Modified: include/grnxx/table.hpp (+70 -97)
===================================================================
--- include/grnxx/table.hpp    2014-10-31 21:43:45 +0900 (2dbf2f3)
+++ include/grnxx/table.hpp    2014-11-05 17:35:04 +0900 (6ff4c56)
@@ -1,11 +1,20 @@
 #ifndef GRNXX_TABLE_HPP
 #define GRNXX_TABLE_HPP
 
-#include "grnxx/name.hpp"
-#include "grnxx/types.hpp"
+#include <memory>
+
+#include "grnxx/column.hpp"
+#include "grnxx/cursor.hpp"
+#include "grnxx/data_types.hpp"
+#include "grnxx/string.hpp"
 
 namespace grnxx {
 
+class DB;
+
+struct TableOptions {
+};
+
 class Table {
  public:
   Table() = default;
@@ -13,44 +22,39 @@ class Table {
   // Return the owner DB.
   virtual DB *db() const = 0;
   // Return the name.
-  virtual StringCRef name() const = 0;
+  virtual String name() const = 0;
   // Return the number of columns.
-  virtual Int num_columns() const = 0;
+  virtual size_t num_columns() const = 0;
   // Return the key column, or nullptr if the table has no key column.
   virtual Column *key_column() const = 0;
   // Return the number of rows.
-  virtual Int num_rows() const = 0;
+  virtual size_t num_rows() const = 0;
   // Return the maximum row ID.
   virtual Int max_row_id() const = 0;
+  // Return whether "this" is empty or not.
+  virtual bool is_empty() const = 0;
+  // Return whether or not there are invalid records before the last record.
+  virtual bool is_full() const = 0;
 
   // Create a column with "name", "data_type", and "options".
   //
   // On success, returns a pointer to the column.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
+  // On failure, throws an exception.
   virtual Column *create_column(
-      Error *error,
-      const StringCRef &name,
+      const String &name,
       DataType data_type,
       const ColumnOptions &options = ColumnOptions()) = 0;
 
   // Remove a column named "name".
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  //
-  // Note: Pointers to the removed column must not be used after deletion.
-  virtual bool remove_column(Error *error, const StringCRef &name) = 0;
+  // On failure, throws an exception.
+  virtual void remove_column(const String &name) = 0;
 
   // Rename a column named "name" to "new_name".
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool rename_column(Error *error,
-                             const StringCRef &name,
-                             const StringCRef &new_name) = 0;
+  // On failure, throws an exception.
+  virtual void rename_column(const String &name,
+                             const String &new_name) = 0;
 
   // Change the order of columns.
   //
@@ -60,115 +64,84 @@ class Table {
   // Otherwise, moves a column named "name" to next to a column named
   // "prev_name".
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool reorder_column(Error *error,
-                              const StringCRef &name,
-                              const StringCRef &prev_name) = 0;
+  // On failure, throws an exception.
+  virtual void reorder_column(const String &name,
+                              const String &prev_name) = 0;
 
-  // Get a column identified by "column_id".
+  // Get the "i"-th column.
   //
-  // If "column_id" is invalid, the result is undefined.
+  // If "i" >= "num_columns", the behavior is undefined.
   //
   // On success, returns a pointer to the column.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual Column *get_column(Int column_id) const = 0;
+  virtual Column *get_column(size_t column_id) const = 0;
 
   // Find a column named "name".
   //
-  // On success, returns a pointer to the column.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual Column *find_column(Error *error, const StringCRef &name) const = 0;
+  // If found, returns a pointer to the column.
+  // If not found, returns nullptr.
+  virtual Column *find_column(const String &name) const = 0;
 
-  // Set the key attribute to the column named "name".
+  // Set a key column.
   //
   // Fails if the table already has a key column.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool set_key_column(Error *error, const StringCRef &name) = 0;
+  // On failure, throws an exception.
+  virtual void set_key_column(const String &name) = 0;
 
-  // Unset the key attribute of the key column.
+  // Unset a key column.
   //
   // Fails if the table does not have a key column.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool unset_key_column(Error *error) = 0;
+  // On failure, throws an exception.
+  virtual void unset_key_column() = 0;
 
   // Insert a row.
   //
-  // If "request_row_id" specifies an unused row ID, uses the row ID.
-  // If the table has a key column, "key" is used as the key of the new row.
-  // If "request_row_id" == NULL_ROW_ID, an unused row ID or max_row_id() + 1
-  // is allocated for the new row.
+  // Fails if "key" is invalid.
   //
-  // Fails if "request_row_id" specifies an existing row.
-  // Fails if the table has a key column and "key" is invalid.
+  // On success, returns the row ID.
+  // On failure, throws an exception.
+  virtual Int insert_row(const Datum &key = NA()) = 0;
+
+  // Find or insert a row.
   //
-  // On success, stores the inserted row ID into "*result_row_id".
-  // On failure, if "request_row_id" or "key" matches an existing row,
-  // stores the matched row ID into "*result_row_id".
+  // If "key" does not exist, insert a row with "key".
+  // If "inserted" != nullptr, stores whether inserted or not into "*inserted".
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool insert_row(Error *error,
-                          Int request_row_id,
-                          const Datum &key,
-                          Int *result_row_id) = 0;
+  // On success, returns the row ID.
+  // On failure, throws an exception.
+  virtual Int find_or_insert_row(const Datum &key,
+                                 bool *inserted = nullptr) = 0;
 
-  // Remove a row identified by "row_id".
+  // Insert a row.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool remove_row(Error *error, Int row_id) = 0;
-
-  // Check the validity of a row.
+  // Fails if "row_id" specifies an existing row.
   //
-  // Returns true if "row_id" specifies a row in use.
-  // Otherwise, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool test_row(Error *error, Int row_id) const = 0;
+  // On failure, throws an exception.
+  virtual void insert_row_at(Int row_id, const Datum &key = NA()) = 0;
 
-  // Find a row identified by "key".
+  // Remove a row.
   //
-  // Fails if the table does not have a key column.
+  // On failure, throws an exception.
+  virtual void remove_row(Int row_id) = 0;
+
+  // Return whether a row is valid or not.
+  virtual bool test_row(Int row_id) const = 0;
+
+  // Find a row with "key".
   //
-  // On success, returns the row ID.
-  // On failure, returns NULL_ROW_ID and stores error information into
-  // "*error" if "error" != nullptr.
-  virtual Int find_row(Error *error, const Datum &key) const = 0;
+  // If found, returns the row ID.
+  // If not found, returns N/A.
+  // On failure, throws an exception.
+  virtual Int find_row(const Datum &key) const = 0;
 
   // Create a cursor to get records.
   //
   // On success, returns a pointer to the cursor.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual unique_ptr<Cursor> create_cursor(
-      Error *error,
+  // On failure, throws an exception.
+  virtual std::unique_ptr<Cursor> create_cursor(
       const CursorOptions &options = CursorOptions()) const = 0;
 
-  // TODO: Grouping (drilldown).
-  //
-  // 分類器を作成する.
-  // 成功すれば有効なオブジェクトへのポインタを返す.
-  // 失敗したときは *error にその内容を格納し, nullptr を返す.
-  //
-  // 失敗する状況としては,以下のようなものが挙げられる.
-  // - オプションが不正である.
-  // - リソースが確保できない.
-//  virtual unique_ptr<Grouper> create_grouper(
-//      Error *error,
-//      unique_ptr<Expression> &&expression,
-//      const GrouperOptions &options = GrouperOptions()) const = 0;
-
  protected:
   virtual ~Table() = default;
 };

  Modified: lib/grnxx/Makefile.am (+7 -11)
===================================================================
--- lib/grnxx/Makefile.am    2014-10-31 21:43:45 +0900 (97d412a)
+++ lib/grnxx/Makefile.am    2014-11-05 17:35:04 +0900 (571f477)
@@ -1,29 +1,25 @@
-#SUBDIRS =				\
-#	impl
+SUBDIRS =				\
+	impl
 
 lib_LTLIBRARIES = libgrnxx.la
 
-#libgrnxx_la_LIBADD =			\
-#	impl/libgrnxx_impl.la
+libgrnxx_la_LIBADD =			\
+	impl/libgrnxx_impl.la
 
 libgrnxx_la_LDFLAGS = @AM_LTLDFLAGS@
 
 libgrnxx_la_SOURCES =			\
-	error.cpp			\
+	cursor.cpp			\
+	db.cpp				\
 	library.cpp			\
 	string.cpp
 
-#	array.cpp			\
-#	cursor.cpp			\
-#	db.cpp				\
-#	error.cpp			\
 #	expression.cpp			\
 #	index.cpp			\
 #	merger.cpp			\
 #	name.cpp			\
 #	pipeline.cpp			\
-#	sorter.cpp			\
-#	types.cpp
+#	sorter.cpp
 
 libgrnxx_includedir = ${includedir}/grnxx
 libgrnxx_include_HEADERS =		\

  Deleted: lib/grnxx/array.cpp (+0 -48) 100644
===================================================================
--- lib/grnxx/array.cpp    2014-10-31 21:43:45 +0900 (22b1a43)
+++ /dev/null
@@ -1,48 +0,0 @@
-#include "grnxx/types.hpp"
-
-namespace grnxx {
-
-void ArrayErrorReporter::report_memory_error(Error *error) {
-  GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-}
-
-bool Array<Bool>::resize_blocks(Error *error, Int new_size) {
-  Int new_capacity = capacity_ * 2;
-  if (new_size > new_capacity) {
-    new_capacity = (new_size + 63) & ~Int(63);
-  }
-  unique_ptr<Block[]> new_blocks(new (nothrow) Block[new_capacity / 64]);
-  if (!new_blocks) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  Int num_valid_blocks = (size_ + 63) / 64;
-  for (Int i = 0; i < num_valid_blocks; ++i) {
-    new_blocks[i] = blocks_[i];
-  }
-  blocks_ = std::move(new_blocks);
-  capacity_ = new_capacity;
-  return true;
-}
-
-bool Array<Record>::resize_buf(Error *error, Int new_size) {
-  Int new_capacity = capacity_ * 2;
-  if (new_size > new_capacity) {
-    new_capacity = new_size;
-  }
-  Int new_buf_size = sizeof(Value) * new_capacity;
-  unique_ptr<char[]> new_buf(new (nothrow) char[new_buf_size]);
-  if (!new_buf) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  Value *new_values = reinterpret_cast<Value *>(new_buf.get());
-  for (Int i = 0; i < size_; ++i) {
-    new (&new_values[i]) Value(std::move(data()[i]));
-  }
-  buf_ = std::move(new_buf);
-  capacity_ = new_capacity;
-  return true;
-}
-
-}  // namespace grnxx

  Modified: lib/grnxx/cursor.cpp (+41 -45)
===================================================================
--- lib/grnxx/cursor.cpp    2014-10-31 21:43:45 +0900 (d89d5cc)
+++ lib/grnxx/cursor.cpp    2014-11-05 17:35:04 +0900 (f52fd12)
@@ -1,79 +1,75 @@
 #include "grnxx/cursor.hpp"
 
+#include <limits>
+
 namespace grnxx {
 namespace {
 
-constexpr Int CURSOR_BLOCK_SIZE = 1024;
+constexpr size_t CURSOR_BLOCK_SIZE = 1024;
 
 }  // namespace
 
-CursorResult Cursor::read(Error *error,
-                          Int max_count,
-                          Array<Record> *records) {
-  if (max_count < 0) {
-    GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid argument");
-    return { false, 0 };
-  } else if (max_count == 0) {
-    return read(error, records->ref(0, 0));
+CursorOptions::CursorOptions()
+    : offset(0),
+      limit(std::numeric_limits<size_t>::max()),
+      order_type(CURSOR_REGULAR_ORDER) {}
+
+size_t Cursor::read(size_t max_count, Array<Record> *records) {
+  if (max_count == 0) {
+    return 0;
   }
 
-  Int offset = records->size();
-  if (offset > (numeric_limits<Int>::max() - max_count)) {
+  size_t offset = records->size();
+  if (offset > (std::numeric_limits<size_t>::max() - max_count)) {
     // Reduce "max_count" to avoid overflow.
-    max_count = numeric_limits<Int>::max() - offset;
+    max_count = std::numeric_limits<size_t>::max() - offset;
   }
 
-  Int next_size = offset + max_count;
+  size_t next_size = offset + max_count;
   if (next_size <= records->capacity()) {
-    // There are enough space for requested records.
-    records->resize(nullptr, next_size);
-    auto result = read(error, records->ref(offset, max_count));
-    records->resize(nullptr, offset + result.count);
-    return result;
+    // There is enough space to store requested records.
+    records->resize(next_size);
+    size_t count = read(records->ref(offset, max_count));
+    records->resize(offset + count);
+    return count;
   }
 
   // Read the first block.
-  Int block_size = max_count;
+  size_t block_size = max_count;
   if (block_size > CURSOR_BLOCK_SIZE) {
     block_size = CURSOR_BLOCK_SIZE;
   }
-  if (!records->resize(error, offset + block_size)) {
-    return { false, 0 };
-  }
-  auto result = read(error, records->ref(offset, block_size));
-  if (result.count != block_size) {
-    records->resize(nullptr, offset + result.count);
-  }
-  if (!result.is_ok || (result.count == 0)) {
-    return result;
+  records->resize(offset + block_size);
+  size_t count = read(records->ref(offset, block_size));
+  if (count != block_size) {
+    records->resize(offset + count);
+    if (count == 0) {
+      return 0;
+    }
   }
 
   // Read the remaining blocks.
-  while (result.count < max_count) {
-    block_size = max_count - result.count;
+  while (count < max_count) {
+    block_size = max_count - count;
     if (block_size > CURSOR_BLOCK_SIZE) {
       block_size = CURSOR_BLOCK_SIZE;
     }
-    Int this_offset = offset + result.count;
-    if (!records->resize(error, this_offset + block_size)) {
-      result.is_ok = false;
-      return result;
-    }
-    auto this_result = read(error, records->ref(this_offset, block_size));
-    if (this_result.count != block_size) {
-      records->resize(nullptr, this_offset + this_result.count);
+    size_t this_offset = offset + count;
+    records->resize(this_offset + block_size);
+    size_t this_count = read(records->ref(this_offset, block_size));
+    if (this_count != block_size) {
+      records->resize(this_offset + this_count);
     }
-    result.is_ok = this_result.is_ok;
-    result.count += this_result.count;
-    if (!this_result.is_ok || (this_result.count == 0)) {
-      return result;
+    count += this_count;
+    if (this_count == 0) {
+      return count;
     }
   }
-  return result;
+  return count;
 }
 
-CursorResult Cursor::read_all(Error *error, Array<Record> *records) {
-  return read(error, numeric_limits<Int>::max(), records);
+size_t Cursor::read_all(Array<Record> *records) {
+  return read(std::numeric_limits<size_t>::max(), records);
 }
 
 }  // namespace grnxx

  Modified: lib/grnxx/db.cpp (+9 -16)
===================================================================
--- lib/grnxx/db.cpp    2014-10-31 21:43:45 +0900 (6a8599c)
+++ lib/grnxx/db.cpp    2014-11-05 17:35:04 +0900 (97e70ba)
@@ -1,29 +1,22 @@
 #include "grnxx/db.hpp"
 
+#include <new>
+
 #include "grnxx/impl/db.hpp"
 
 namespace grnxx {
 
-unique_ptr<DB> open_db(Error *error,
-                       const StringCRef &path,
-                       const DBOptions &) {
+std::unique_ptr<DB> open_db(const String &path, const DBOptions &) try {
   if (path.size() != 0) {
-    // TODO: Named DB is not supported yet.
-    GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-    return nullptr;
-  }
-  unique_ptr<impl::DB> db(new (nothrow) impl::DB);
-  if (!db) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return nullptr;
+    throw "Not supported yet";  // TODO
   }
-  return unique_ptr<DB>(db.release());
+  return std::unique_ptr<impl::DB>(new impl::DB);
+} catch (const std::bad_alloc &) {
+  throw "Memory allocation failed";  // TODO
 }
 
-bool remove_db(Error *error, const StringCRef &, const DBOptions &) {
-  // TODO: Named DB is not supported yet.
-  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-  return false;
+void remove_db(const String &, const DBOptions &) {
+  throw "Not supported yet";  // TODO
 }
 
 }  // namespace grnxx

  Modified: lib/grnxx/impl/Makefile.am (+1 -0)
===================================================================
--- lib/grnxx/impl/Makefile.am    2014-10-31 21:43:45 +0900 (cc4ca15)
+++ lib/grnxx/impl/Makefile.am    2014-11-05 17:35:04 +0900 (cec31bb)
@@ -15,5 +15,6 @@ libgrnxx_impl_la_SOURCES =		\
 libgrnxx_impl_includedir = ${includedir}/grnxx/impl
 libgrnxx_impl_include_HEADERS =		\
 	column.hpp			\
+	cursor.hpp			\
 	db.hpp				\
 	table.hpp

  Modified: lib/grnxx/impl/column.hpp (+11 -10)
===================================================================
--- lib/grnxx/impl/column.hpp    2014-10-31 21:43:45 +0900 (8ea542d)
+++ lib/grnxx/impl/column.hpp    2014-11-05 17:35:04 +0900 (98e4360)
@@ -1,15 +1,16 @@
 #ifndef GRNXX_IMPL_COLUMN_HPP
 #define GRNXX_IMPL_COLUMN_HPP
 
-#include "grnxx/impl/column/column_bool.hpp"
-#include "grnxx/impl/column/column_int.hpp"
-#include "grnxx/impl/column/column_float.hpp"
-#include "grnxx/impl/column/column_geo_point.hpp"
-#include "grnxx/impl/column/column_text.hpp"
-#include "grnxx/impl/column/column_vector_bool.hpp"
-#include "grnxx/impl/column/column_vector_int.hpp"
-#include "grnxx/impl/column/column_vector_float.hpp"
-#include "grnxx/impl/column/column_vector_geo_point.hpp"
-#include "grnxx/impl/column/column_vector_text.hpp"
+#include "grnxx/impl/column/base.hpp"
+//#include "grnxx/impl/column/scalar/bool.hpp"
+//#include "grnxx/impl/column/scalar/int.hpp"
+//#include "grnxx/impl/column/scalar/float.hpp"
+//#include "grnxx/impl/column/scalar/geo_point.hpp"
+//#include "grnxx/impl/column/scalar/text.hpp"
+//#include "grnxx/impl/column/vector/bool.hpp"
+//#include "grnxx/impl/column/vector/int.hpp"
+//#include "grnxx/impl/column/vector/float.hpp"
+//#include "grnxx/impl/column/vector/geo_point.hpp"
+//#include "grnxx/impl/column/vector/text.hpp"
 
 #endif  // GRNXX_IMPL_COLUMN_HPP

  Modified: lib/grnxx/impl/column/Makefile.am (+10 -29)
===================================================================
--- lib/grnxx/impl/column/Makefile.am    2014-10-31 21:43:45 +0900 (fb38d8f)
+++ lib/grnxx/impl/column/Makefile.am    2014-11-05 17:35:04 +0900 (db32fcd)
@@ -1,39 +1,20 @@
-#SUBDIRS =					\
-#	sub
+SUBDIRS =					\
+	scalar					\
+	vector
 
 lib_LTLIBRARIES = libgrnxx_impl_column.la
 
-#libgrnxx_impl_column_la_LIBADD =		\
-#	sub/libgrnxx_impl_column_sub.la
+libgrnxx_impl_column_la_LIBADD =		\
+	scalar/libgrnxx_impl_column_scalar.la	\
+	vector/libgrnxx_impl_column_vector.la
 
 libgrnxx_impl_column_la_LDFLAGS = @AM_LTLDFLAGS@
 
 libgrnxx_impl_column_la_SOURCES =		\
-	column.cpp				\
-	column_base.cpp				\
-	column_float.cpp			\
-	column_int.cpp				\
-	column_text.cpp				\
-	column_vector_int.cpp			\
-	column_vector_float.cpp			\
-	column_vector_geo_point.cpp		\
-	column_vector_text.cpp
-
-#	column_bool.cpp				\
-#	column_float.cpp			\
-#	column_geo_point.cpp			\
-#	column_vector_bool.cpp
+	base.cpp
 
 libgrnxx_impl_column_includedir = ${includedir}/grnxx/impl/column
 libgrnxx_impl_column_include_HEADERS =		\
-	column.hpp				\
-	column_base.hpp				\
-	column_bool.hpp				\
-	column_float.hpp			\
-	column_geo_point.hpp			\
-	column_int.hpp				\
-	column_vector_bool.hpp			\
-	column_vector_float.hpp			\
-	column_vector_geo_point.hpp		\
-	column_vector_int.hpp			\
-	column_vector_text.hpp
+	base.hpp				\
+	scalar.hpp				\
+	vector.hpp

  Added: lib/grnxx/impl/column/base.cpp (+254 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/impl/column/base.cpp    2014-11-05 17:35:04 +0900 (42c8403)
@@ -0,0 +1,254 @@
+#include "grnxx/impl/column/base.hpp"
+
+//#include "grnxx/impl/column/scalar.hpp"
+//#include "grnxx/impl/column/vector.hpp"
+#include "grnxx/impl/db.hpp"
+#include "grnxx/impl/table.hpp"
+//#include "grnxx/index.hpp"
+
+namespace grnxx {
+namespace impl {
+
+ColumnBase::ColumnBase(Table *table,
+                       const String &name,
+                       DataType data_type,
+                       Table *reference_table)
+    : ColumnInterface(),
+      table_(table),
+      name_(name),
+      data_type_(data_type),
+      reference_table_(reference_table),
+      has_key_attribute_(false) {}
+
+ColumnBase::~ColumnBase() {}
+
+TableInterface *ColumnBase::table() const {
+  return table_;
+}
+
+TableInterface *ColumnBase::reference_table() const {
+  return reference_table_;
+}
+
+//Index *ColumnBase::create_index(Error *error,
+//                                const StringCRef &name,
+//                                IndexType type,
+//                                const IndexOptions &options) {
+//  if (find_index(nullptr, name)) {
+//    GRNXX_ERROR_SET(error, ALREADY_EXISTS,
+//                    "Index already exists: name = \"%.*s\"",
+//                    static_cast<int>(name.size()), name.data());
+//    return nullptr;
+//  }
+//  if (!indexes_.reserve(error, indexes_.size() + 1)) {
+//    return nullptr;
+//  }
+//  unique_ptr<Index> new_index =
+//      Index::create(error, this, name, type, options);
+//  if (!new_index) {
+//    return nullptr;
+//  }
+//  indexes_.push_back(error, std::move(new_index));
+//  return indexes_.back().get();
+//}
+
+//bool ColumnBase::remove_index(Error *error, const StringCRef &name) {
+//  Int index_id;
+//  if (!find_index_with_id(error, name, &index_id)) {
+//    return false;
+//  }
+//  if (!indexes_[index_id]->is_removable()) {
+//    GRNXX_ERROR_SET(error, NOT_REMOVABLE,
+//                    "Index is not removable: name = \"%.*s\"",
+//                    static_cast<int>(name.size()), name.data());
+//    return false;
+//  }
+//  indexes_.erase(index_id);
+//  return true;
+//}
+
+//bool ColumnBase::rename_index(Error *error,
+//                              const StringCRef &name,
+//                              const StringCRef &new_name) {
+//  Int index_id;
+//  if (!find_index_with_id(error, name, &index_id)) {
+//    return false;
+//  }
+//  if (name == new_name) {
+//    return true;
+//  }
+//  if (find_index(nullptr, new_name)) {
+//    GRNXX_ERROR_SET(error, ALREADY_EXISTS,
+//                    "Index already exists: new_name = \"%.*s\"",
+//                    static_cast<int>(new_name.size()), new_name.data());
+//    return false;
+//  }
+//  return indexes_[index_id]->rename(error, new_name);
+//}
+
+//bool ColumnBase::reorder_index(Error *error,
+//                               const StringCRef &name,
+//                               const StringCRef &prev_name) {
+//  Int index_id;
+//  if (!find_index_with_id(error, name, &index_id)) {
+//    return false;
+//  }
+//  Int new_index_id = 0;
+//  if (prev_name.size() != 0) {
+//    Int prev_index_id;
+//    if (!find_index_with_id(error, prev_name, &prev_index_id)) {
+//      return false;
+//    }
+//    if (index_id <= prev_index_id) {
+//      new_index_id = prev_index_id;
+//    } else {
+//      new_index_id = prev_index_id + 1;
+//    }
+//  }
+//  for ( ; index_id < new_index_id; ++index_id) {
+//    std::swap(indexes_[index_id], indexes_[index_id + 1]);
+//  }
+//  for ( ; index_id > new_index_id; --index_id) {
+//    std::swap(indexes_[index_id], indexes_[index_id - 1]);
+//  }
+//  return true;
+//}
+
+//Index *ColumnBase::find_index(Error *error, const StringCRef &name) const {
+//  for (Int index_id = 0; index_id < num_indexes(); ++index_id) {
+//    if (name == indexes_[index_id]->name()) {
+//      return indexes_[index_id].get();
+//    }
+//  }
+//  GRNXX_ERROR_SET(error, NOT_FOUND, "Index not found");
+//  return nullptr;
+//}
+
+//bool ColumnBase::set(Error *error, Int, const Datum &) {
+//  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet");
+//  return false;
+//}
+
+//bool ColumnBase::get(Error *error, Int, Datum *) const {
+//  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet");
+//  return false;
+//}
+
+//bool ColumnBase::contains(const Datum &datum) const {
+//  return find_one(datum) != NULL_ROW_ID;
+//}
+
+Int ColumnBase::find_one(const Datum &) const {
+  // TODO: This function should be pure virtual.
+  return Int::na();
+}
+
+std::unique_ptr<ColumnBase> ColumnBase::create(Table *table,
+                                               const String &name,
+                                               DataType data_type,
+                                               const ColumnOptions &options) {
+  throw "Not supported yet";  // TODO
+//  switch (data_type) {
+//    case BOOL_DATA: {
+//      return impl::Column<Bool>::create(error, table, name, options);
+//    }
+//    case INT_DATA: {
+//      return impl::Column<Int>::create(error, table, name, options);
+//    }
+//    case FLOAT_DATA: {
+//      return impl::Column<Float>::create(error, table, name, options);
+//    }
+//    case GEO_POINT_DATA: {
+//      return impl::Column<GeoPoint>::create(error, table, name, options);
+//    }
+//    case TEXT_DATA: {
+//      return impl::Column<Text>::create(error, table, name, options);
+//    }
+//    case BOOL_VECTOR_DATA: {
+//      return impl::Column<Vector<Bool>>::create(error, table, name, options);
+//    }
+//    case INT_VECTOR_DATA: {
+//      return impl::Column<Vector<Int>>::create(error, table, name, options);
+//    }
+//    case FLOAT_VECTOR_DATA: {
+//      return impl::Column<Vector<Float>>::create(error, table, name, options);
+//    }
+//    case GEO_POINT_VECTOR_DATA: {
+//      return impl::Column<Vector<GeoPoint>>::create(error, table, name, options);
+//    }
+//    case TEXT_VECTOR_DATA: {
+//      return impl::Column<Vector<Text>>::create(error, table, name, options);
+//    }
+//    default: {
+//      // TODO: Other data types are not supported yet.
+//      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet");
+//      return nullptr;
+//    }
+//  }
+}
+
+void ColumnBase::rename(const String &new_name) {
+  name_.assign(new_name);
+}
+
+bool ColumnBase::is_removable() const {
+  // TODO: Reference column is not supported yet.
+  return true;
+}
+
+void ColumnBase::set_key_attribute() {
+  throw "Not supported yet";  // TODO
+}
+
+void ColumnBase::unset_key_attribute() {
+  throw "Not supported yet";  // TODO
+}
+
+void ColumnBase::set_initial_key(Int, const Datum &) {
+  throw "Not supported yet";  // TODO
+}
+
+void ColumnBase::clear_references(Int) {
+  throw "Not supported yet";  // TODO
+}
+
+//bool ColumnBase::initialize_base(Error *error,
+//                                 Table *table,
+//                                 const StringCRef &name,
+//                                 DataType data_type,
+//                                 const ColumnOptions &options) {
+//  table_ = table;
+//  if (!name_.assign(error, name)) {
+//    return false;
+//  }
+//  data_type_ = data_type;
+//  if ((data_type == INT_DATA) || (data_type == INT_VECTOR_DATA)) {
+//    if (options.ref_table_name.size() != 0) {
+//      auto ref_table = table_->_db()->find_table(error, options.ref_table_name);
+//      if (!ref_table) {
+//        return false;
+//      }
+//      ref_table_ = ref_table;
+//    }
+//  }
+//  return true;
+//}
+
+//Index *ColumnBase::find_index_with_id(Error *error,
+//                                      const StringCRef &name,
+//                                      Int *index_id) const {
+//  for (Int i = 0; i < num_indexes(); ++i) {
+//    if (name == indexes_[i]->name()) {
+//      if (index_id != nullptr) {
+//        *index_id = i;
+//      }
+//      return indexes_[i].get();
+//    }
+//  }
+//  GRNXX_ERROR_SET(error, NOT_FOUND, "Index not found: name = \"%.*s\"",
+//                  static_cast<int>(name.size()), name.data());
+//  return nullptr;
+//}
+
+}  // namespace impl
+}  // namespace grnxx

  Added: lib/grnxx/impl/column/base.hpp (+150 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/impl/column/base.hpp    2014-11-05 17:35:04 +0900 (c437ff4)
@@ -0,0 +1,150 @@
+#ifndef GRNXX_IMPL_COLUMN_BASE_HPP
+#define GRNXX_IMPL_COLUMN_BASE_HPP
+
+#include <memory>
+
+#include "grnxx/column.hpp"
+
+namespace grnxx {
+namespace impl {
+
+using TableInterface = grnxx::Table;
+using ColumnInterface = grnxx::Column;
+
+class Table;
+
+class Index;  // TODO
+
+class ColumnBase : public ColumnInterface {
+ public:
+  // -- Public API (grnxx/column.hpp) --
+
+  ColumnBase(Table *table,
+             const String &name,
+             DataType data_type,
+             Table *reference_table = nullptr);
+  virtual ~ColumnBase();
+
+  TableInterface *table() const;
+  String name() const {
+    return name_;
+  }
+  DataType data_type() const {
+    return data_type_;
+  }
+  TableInterface *reference_table() const;
+  bool has_key_attribute() const {
+    return has_key_attribute_;
+  }
+  size_t num_indexes() const {
+    return indexes_.size();
+  }
+
+//  Index *create_index(
+//      Error *error,
+//      const String &name,
+//      IndexType type,
+//      const IndexOptions &options = IndexOptions());
+//  bool remove_index(Error *error, const String &name);
+//  bool rename_index(Error *error,
+//                    const String &name,
+//                    const String &new_name);
+//  bool reorder_index(Error *error,
+//                     const String &name,
+//                     const String &prev_name);
+
+//  Index *get_index(Int index_id) const {
+//    return indexes_[index_id].get();
+//  }
+//  Index *find_index(Error *error, const String &name) const;
+
+//  bool set(Error *error, Int row_id, const Datum &datum);
+//  bool get(Error *error, Int row_id, Datum *datum) const;
+
+//  bool contains(const Datum &datum) const;
+  Int find_one(const Datum &datum) const;
+
+  // -- Internal API --
+
+  // Create a new column.
+  //
+  // On success, returns the column.
+  // On failure, throws an exception.
+  static std::unique_ptr<ColumnBase> create(
+      Table *table,
+      const String &name,
+      DataType data_type,
+      const ColumnOptions &options = ColumnOptions());
+
+  // Return the owner table.
+  Table *_table() const {
+    return table_;
+  }
+  // Return the referenced (parent) table.
+  // If "this" is not a reference column, returns nullptr.
+  Table *_reference_table() const {
+    return reference_table_;
+  }
+
+  // Change the column name.
+  //
+  // On failure, throws an exception.
+  void rename(const String &new_name);
+
+  // Return whether the column is removable or not.
+  bool is_removable() const;
+
+  // Set the key attribute.
+  //
+  // On failure, throws an exception.
+  virtual void set_key_attribute();
+  // Unset the key attribute.
+  //
+  // On failure, throws an exception.
+  virtual void unset_key_attribute();
+
+  // Set the initial key.
+  //
+  // On failure, throws an exception.
+  virtual void set_initial_key(Int row_id, const Datum &key);
+
+  // Unset the value.
+  virtual void unset(Int row_id) = 0;
+
+  // Replace references to "row_id" with NULL.
+  virtual void clear_references(Int row_id);
+
+ protected:
+  Table *table_;
+  String name_;
+  DataType data_type_;
+  Table *reference_table_;
+  bool has_key_attribute_;
+  Array<std::unique_ptr<Index>> indexes_;
+
+//  // Initialize the base members.
+//  //
+//  // On success, returns true.
+//  // On failure, returns false and stores error information into "*error" if
+//  // "error" != nullptr.
+//  bool initialize_base(Error *error,
+//                       Table *table,
+//                       const String &name,
+//                       DataType data_type,
+//                       const ColumnOptions &options = ColumnOptions());
+
+// private:
+//  // Find an index with its ID.
+//  //
+//  // On success, returns a pointer to the index.
+//  // On failure, returns nullptr and stores error information into "*error" if
+//  // "error" != nullptr.
+//  Index *find_index_with_id(Error *error,
+//                            const String &name,
+//                            Int *column_id) const;
+};
+
+}  // namespace impl
+}  // namespace grnxx
+
+#endif  // GRNXX_IMPL_COLUMN_BASE_HPP

  Modified: lib/grnxx/impl/column/column.hpp (+1 -1)
===================================================================
--- lib/grnxx/impl/column/column.hpp    2014-10-31 21:43:45 +0900 (a440562)
+++ lib/grnxx/impl/column/column.hpp    2014-11-05 17:35:04 +0900 (4989837)
@@ -1,7 +1,7 @@
 #ifndef GRNXX_IMPL_COLUMN_COLUMN_HPP
 #define GRNXX_IMPL_COLUMN_COLUMN_HPP
 
-#include "grnxx/impl/column/column_base.hpp"
+#include "grnxx/impl/column/base.hpp"
 
 namespace grnxx {
 namespace impl {

  Deleted: lib/grnxx/impl/column/column_base.cpp (+0 -263) 100644
===================================================================
--- lib/grnxx/impl/column/column_base.cpp    2014-10-31 21:43:45 +0900 (6f2817e)
+++ /dev/null
@@ -1,263 +0,0 @@
-#include "grnxx/impl/column/column_base.hpp"
-
-#include "grnxx/impl/column/column.hpp"
-#include "grnxx/impl/column/column_bool.hpp"
-#include "grnxx/impl/column/column_int.hpp"
-#include "grnxx/impl/column/column_float.hpp"
-#include "grnxx/impl/column/column_geo_point.hpp"
-#include "grnxx/impl/column/column_text.hpp"
-#include "grnxx/impl/column/column_vector_bool.hpp"
-#include "grnxx/impl/column/column_vector_int.hpp"
-#include "grnxx/impl/column/column_vector_float.hpp"
-#include "grnxx/impl/column/column_vector_geo_point.hpp"
-#include "grnxx/impl/column/column_vector_text.hpp"
-#include "grnxx/impl/db.hpp"
-#include "grnxx/impl/table.hpp"
-#include "grnxx/index.hpp"
-
-namespace grnxx {
-namespace impl {
-
-ColumnBase::ColumnBase()
-    : ColumnInterface(),
-      table_(nullptr),
-      name_(),
-      data_type_(),
-      ref_table_(nullptr),
-      has_key_attribute_(false) {}
-
-ColumnBase::~ColumnBase() {}
-
-TableInterface *ColumnBase::table() const {
-  return table_;
-}
-
-TableInterface *ColumnBase::ref_table() const {
-  return ref_table_;
-}
-
-Index *ColumnBase::create_index(Error *error,
-                                const StringCRef &name,
-                                IndexType type,
-                                const IndexOptions &options) {
-  if (find_index(nullptr, name)) {
-    GRNXX_ERROR_SET(error, ALREADY_EXISTS,
-                    "Index already exists: name = \"%.*s\"",
-                    static_cast<int>(name.size()), name.data());
-    return nullptr;
-  }
-  if (!indexes_.reserve(error, indexes_.size() + 1)) {
-    return nullptr;
-  }
-  unique_ptr<Index> new_index =
-      Index::create(error, this, name, type, options);
-  if (!new_index) {
-    return nullptr;
-  }
-  indexes_.push_back(error, std::move(new_index));
-  return indexes_.back().get();
-}
-
-bool ColumnBase::remove_index(Error *error, const StringCRef &name) {
-  Int index_id;
-  if (!find_index_with_id(error, name, &index_id)) {
-    return false;
-  }
-  if (!indexes_[index_id]->is_removable()) {
-    GRNXX_ERROR_SET(error, NOT_REMOVABLE,
-                    "Index is not removable: name = \"%.*s\"",
-                    static_cast<int>(name.size()), name.data());
-    return false;
-  }
-  indexes_.erase(index_id);
-  return true;
-}
-
-bool ColumnBase::rename_index(Error *error,
-                              const StringCRef &name,
-                              const StringCRef &new_name) {
-  Int index_id;
-  if (!find_index_with_id(error, name, &index_id)) {
-    return false;
-  }
-  if (name == new_name) {
-    return true;
-  }
-  if (find_index(nullptr, new_name)) {
-    GRNXX_ERROR_SET(error, ALREADY_EXISTS,
-                    "Index already exists: new_name = \"%.*s\"",
-                    static_cast<int>(new_name.size()), new_name.data());
-    return false;
-  }
-  return indexes_[index_id]->rename(error, new_name);
-}
-
-bool ColumnBase::reorder_index(Error *error,
-                               const StringCRef &name,
-                               const StringCRef &prev_name) {
-  Int index_id;
-  if (!find_index_with_id(error, name, &index_id)) {
-    return false;
-  }
-  Int new_index_id = 0;
-  if (prev_name.size() != 0) {
-    Int prev_index_id;
-    if (!find_index_with_id(error, prev_name, &prev_index_id)) {
-      return false;
-    }
-    if (index_id <= prev_index_id) {
-      new_index_id = prev_index_id;
-    } else {
-      new_index_id = prev_index_id + 1;
-    }
-  }
-  for ( ; index_id < new_index_id; ++index_id) {
-    std::swap(indexes_[index_id], indexes_[index_id + 1]);
-  }
-  for ( ; index_id > new_index_id; --index_id) {
-    std::swap(indexes_[index_id], indexes_[index_id - 1]);
-  }
-  return true;
-}
-
-Index *ColumnBase::find_index(Error *error, const StringCRef &name) const {
-  for (Int index_id = 0; index_id < num_indexes(); ++index_id) {
-    if (name == indexes_[index_id]->name()) {
-      return indexes_[index_id].get();
-    }
-  }
-  GRNXX_ERROR_SET(error, NOT_FOUND, "Index not found");
-  return nullptr;
-}
-
-bool ColumnBase::set(Error *error, Int, const Datum &) {
-  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet");
-  return false;
-}
-
-bool ColumnBase::get(Error *error, Int, Datum *) const {
-  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet");
-  return false;
-}
-
-bool ColumnBase::contains(const Datum &datum) const {
-  return find_one(datum) != NULL_ROW_ID;
-}
-
-Int ColumnBase::find_one(const Datum &) const {
-  // TODO: This function should be pure virtual.
-  return NULL_ROW_ID;
-}
-
-unique_ptr<ColumnBase> ColumnBase::create(Error *error,
-                                          Table *table,
-                                          const StringCRef &name,
-                                          DataType data_type,
-                                          const ColumnOptions &options) {
-  switch (data_type) {
-    case BOOL_DATA: {
-      return impl::Column<Bool>::create(error, table, name, options);
-    }
-    case INT_DATA: {
-      return impl::Column<Int>::create(error, table, name, options);
-    }
-    case FLOAT_DATA: {
-      return impl::Column<Float>::create(error, table, name, options);
-    }
-    case GEO_POINT_DATA: {
-      return impl::Column<GeoPoint>::create(error, table, name, options);
-    }
-    case TEXT_DATA: {
-      return impl::Column<Text>::create(error, table, name, options);
-    }
-    case BOOL_VECTOR_DATA: {
-      return impl::Column<Vector<Bool>>::create(error, table, name, options);
-    }
-    case INT_VECTOR_DATA: {
-      return impl::Column<Vector<Int>>::create(error, table, name, options);
-    }
-    case FLOAT_VECTOR_DATA: {
-      return impl::Column<Vector<Float>>::create(error, table, name, options);
-    }
-    case GEO_POINT_VECTOR_DATA: {
-      return impl::Column<Vector<GeoPoint>>::create(error, table, name, options);
-    }
-    case TEXT_VECTOR_DATA: {
-      return impl::Column<Vector<Text>>::create(error, table, name, options);
-    }
-    default: {
-      // TODO: Other data types are not supported yet.
-      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet");
-      return nullptr;
-    }
-  }
-}
-
-bool ColumnBase::rename(Error *error, const StringCRef &new_name) {
-  return name_.assign(error, new_name);
-}
-
-bool ColumnBase::is_removable() {
-  // TODO: Reference column is not supported yet.
-  return true;
-}
-
-bool ColumnBase::set_key_attribute(Error *error) {
-  GRNXX_ERROR_SET(error, INVALID_OPERATION, "This type does not support Key");
-  return false;
-}
-
-bool ColumnBase::unset_key_attribute(Error *error) {
-  GRNXX_ERROR_SET(error, INVALID_OPERATION, "This type does not support Key");
-  return false;
-}
-
-bool ColumnBase::set_initial_key(Error *error, Int, const Datum &) {
-  // TODO: Key column is not supported yet.
-  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not suported yet");
-  return false;
-}
-
-void ColumnBase::clear_references(Int) {
-}
-
-bool ColumnBase::initialize_base(Error *error,
-                                 Table *table,
-                                 const StringCRef &name,
-                                 DataType data_type,
-                                 const ColumnOptions &options) {
-  table_ = table;
-  if (!name_.assign(error, name)) {
-    return false;
-  }
-  data_type_ = data_type;
-  if ((data_type == INT_DATA) || (data_type == INT_VECTOR_DATA)) {
-    if (options.ref_table_name.size() != 0) {
-      auto ref_table = table_->_db()->find_table(error, options.ref_table_name);
-      if (!ref_table) {
-        return false;
-      }
-      ref_table_ = ref_table;
-    }
-  }
-  return true;
-}
-
-Index *ColumnBase::find_index_with_id(Error *error,
-                                      const StringCRef &name,
-                                      Int *index_id) const {
-  for (Int i = 0; i < num_indexes(); ++i) {
-    if (name == indexes_[i]->name()) {
-      if (index_id != nullptr) {
-        *index_id = i;
-      }
-      return indexes_[i].get();
-    }
-  }
-  GRNXX_ERROR_SET(error, NOT_FOUND, "Index not found: name = \"%.*s\"",
-                  static_cast<int>(name.size()), name.data());
-  return nullptr;
-}
-
-}  // namespace impl
-}  // namespace grnxx

  Deleted: lib/grnxx/impl/column/column_base.hpp (+0 -162) 100644
===================================================================
--- lib/grnxx/impl/column/column_base.hpp    2014-10-31 21:43:45 +0900 (ad32fdb)
+++ /dev/null
@@ -1,162 +0,0 @@
-#ifndef GRNXX_IMPL_COLUMN_COLUMN_BASE_HPP
-#define GRNXX_IMPL_COLUMN_COLUMN_BASE_HPP
-
-#include "grnxx/column.hpp"
-#include "grnxx/name.hpp"
-#include "grnxx/types.hpp"
-
-namespace grnxx {
-namespace impl {
-
-using TableInterface = grnxx::Table;
-using ColumnInterface = grnxx::Column;
-
-class Table;
-
-class ColumnBase : public ColumnInterface {
- public:
-  // -- Public API (grnxx/column.hpp) --
-
-  ColumnBase();
-  virtual ~ColumnBase();
-
-  TableInterface *table() const;
-  StringCRef name() const {
-    return name_.ref();
-  }
-  DataType data_type() const {
-    return data_type_;
-  }
-  TableInterface *ref_table() const;
-  bool has_key_attribute() const {
-    return has_key_attribute_;
-  }
-  Int num_indexes() const {
-    return indexes_.size();
-  }
-
-  Index *create_index(
-      Error *error,
-      const StringCRef &name,
-      IndexType type,
-      const IndexOptions &options = IndexOptions());
-  bool remove_index(Error *error, const StringCRef &name);
-  bool rename_index(Error *error,
-                    const StringCRef &name,
-                    const StringCRef &new_name);
-  bool reorder_index(Error *error,
-                     const StringCRef &name,
-                     const StringCRef &prev_name);
-
-  Index *get_index(Int index_id) const {
-    return indexes_[index_id].get();
-  }
-  Index *find_index(Error *error, const StringCRef &name) const;
-
-  bool set(Error *error, Int row_id, const Datum &datum);
-  bool get(Error *error, Int row_id, Datum *datum) const;
-
-  bool contains(const Datum &datum) const;
-  Int find_one(const Datum &datum) const;
-
-  // -- Internal API --
-
-  // Create a new column.
-  //
-  // On success, returns a pointer to the column.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  static unique_ptr<ColumnBase> create(
-      Error *error,
-      Table *table,
-      const StringCRef &name,
-      DataType data_type,
-      const ColumnOptions &options = ColumnOptions());
-
-  // Return the owner table.
-  Table *_table() const {
-    return table_;
-  }
-  // Return the referenced (parent) table, or nullptr if the column is not a
-  // reference column.
-  Table *_ref_table() const {
-    return ref_table_;
-  }
-
-  // Change the column name.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool rename(Error *error, const StringCRef &new_name);
-
-  // Return whether the column is removable or not.
-  bool is_removable();
-
-  // Set the key attribute.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool set_key_attribute(Error *error);
-  // Unset the key attribute.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool unset_key_attribute(Error *error);
-
-  // Set the initial key.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool set_initial_key(Error *error, Int row_id, const Datum &key);
-
-  // Set the default value.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool set_default_value(Error *error, Int row_id) = 0;
-
-  // Unset the value.
-  virtual void unset(Int row_id) = 0;
-
-  // Replace references to "row_id" with NULL.
-  virtual void clear_references(Int row_id);
-
- protected:
-  Table *table_;
-  Name name_;
-  DataType data_type_;
-  Table *ref_table_;
-  bool has_key_attribute_;
-  Array<unique_ptr<Index>> indexes_;
-
-  // Initialize the base members.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool initialize_base(Error *error,
-                       Table *table,
-                       const StringCRef &name,
-                       DataType data_type,
-                       const ColumnOptions &options = ColumnOptions());
-
- private:
-  // Find an index with its ID.
-  //
-  // On success, returns a pointer to the index.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  Index *find_index_with_id(Error *error,
-                            const StringCRef &name,
-                            Int *column_id) const;
-};
-
-}  // namespace impl
-}  // namespace grnxx
-
-#endif  // GRNXX_IMPL_COLUMN_COLUMN_BASE_HPP

  Added: lib/grnxx/impl/column/scalar.hpp (+10 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/impl/column/scalar.hpp    2014-11-05 17:35:04 +0900 (f443aff)
@@ -0,0 +1,10 @@
+#ifndef GRNXX_IMPL_COLUMN_SCALAR_HPP
+#define GRNXX_IMPL_COLUMN_SCALAR_HPP
+
+#include "grnxx/impl/column/scalar/bool.hpp"
+#include "grnxx/impl/column/scalar/float.hpp"
+#include "grnxx/impl/column/scalar/geo_point.hpp"
+#include "grnxx/impl/column/scalar/int.hpp"
+#include "grnxx/impl/column/scalar/text.hpp"
+
+#endif  // GRNXX_IMPL_COLUMN_SCALAR_HPP

  Added: lib/grnxx/impl/column/scalar/Makefile.am (+25 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/impl/column/scalar/Makefile.am    2014-11-05 17:35:04 +0900 (f706517)
@@ -0,0 +1,25 @@
+#SUBDIRS =					\
+#	sub
+
+lib_LTLIBRARIES = libgrnxx_impl_column_scalar.la
+
+#libgrnxx_impl_column_scalar_la_LIBADD =	\
+#	sub/libgrnxx_impl_column_scalar_sub.la
+
+libgrnxx_impl_column_scalar_la_LDFLAGS = @AM_LTLDFLAGS@
+
+libgrnxx_impl_column_scalar_la_SOURCES =
+
+#	bool.cpp				\
+#	float.cpp				\
+#	geo_point.cpp				\
+#	int.cpp					\
+#	text.cpp
+
+libgrnxx_impl_column_scalar_includedir = ${includedir}/grnxx/impl/column/scalar
+libgrnxx_impl_column_scalar_include_HEADERS =	\
+	bool.hpp				\
+	float.hpp				\
+	geo_point.hpp				\
+	int.hpp					\
+	text.hpp

  Copied: lib/grnxx/impl/column/scalar/bool.cpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/scalar/bool.hpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/scalar/float.cpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/scalar/float.hpp (+0 -0) 100%
===================================================================

  Copied: lib/grnxx/impl/column/scalar/geo_point.cpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/scalar/geo_point.hpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/scalar/int.cpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/scalar/int.hpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/scalar/text.cpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/scalar/text.hpp (+0 -0) 100%
===================================================================

  Added: lib/grnxx/impl/column/vector.hpp (+10 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/impl/column/vector.hpp    2014-11-05 17:35:04 +0900 (aed3214)
@@ -0,0 +1,10 @@
+#ifndef GRNXX_IMPL_COLUMN_VECTOR_HPP
+#define GRNXX_IMPL_COLUMN_VECTOR_HPP
+
+#include "grnxx/impl/column/vector/bool.hpp"
+#include "grnxx/impl/column/vector/float.hpp"
+#include "grnxx/impl/column/vector/geo_point.hpp"
+#include "grnxx/impl/column/vector/int.hpp"
+#include "grnxx/impl/column/vector/text.hpp"
+
+#endif  // GRNXX_IMPL_COLUMN_VECTOR_HPP

  Added: lib/grnxx/impl/column/vector/Makefile.am (+25 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/impl/column/vector/Makefile.am    2014-11-05 17:35:04 +0900 (4c68d73)
@@ -0,0 +1,25 @@
+#SUBDIRS =					\
+#	sub
+
+lib_LTLIBRARIES = libgrnxx_impl_column_vector.la
+
+#libgrnxx_impl_column_vector_la_LIBADD =	\
+#	sub/libgrnxx_impl_column_vector_sub.la
+
+libgrnxx_impl_column_vector_la_LDFLAGS = @AM_LTLDFLAGS@
+
+libgrnxx_impl_column_vector_la_SOURCES =
+
+#	bool.cpp				\
+#	float.cpp				\
+#	geo_point.cpp				\
+#	int.cpp					\
+#	text.cpp
+
+libgrnxx_impl_column_vector_includedir = ${includedir}/grnxx/impl/column/vector
+libgrnxx_impl_column_vector_include_HEADERS =	\
+	bool.hpp				\
+	float.hpp				\
+	geo_point.hpp				\
+	int.hpp					\
+	text.hpp

  Copied: lib/grnxx/impl/column/vector/bool.cpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/vector/bool.hpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/vector/float.cpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/vector/float.hpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/vector/geo_point.cpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/vector/geo_point.hpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/vector/int.cpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/vector/int.hpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/vector/text.cpp (+0 -0) 100%
===================================================================

  Renamed: lib/grnxx/impl/column/vector/text.hpp (+0 -0) 100%
===================================================================

  Added: lib/grnxx/impl/cursor.hpp (+24 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/impl/cursor.hpp    2014-11-05 17:35:04 +0900 (432e1c4)
@@ -0,0 +1,24 @@
+#ifndef GRNXX_IMPL_CURSOR_HPP
+#define GRNXX_IMPL_CURSOR_HPP
+
+#include "grnxx/cursor.hpp"
+
+namespace grnxx {
+namespace impl {
+
+class EmptyCursor : public Cursor {
+ public:
+  // -- Public API --
+
+  EmptyCursor() = default;
+  ~EmptyCursor() = default;
+
+  size_t read(ArrayRef<Record>) {
+    return 0;
+  }
+};
+
+}  // namespace impl
+}  // namespace grnxx
+
+#endif  // GRNXX_IMPL_CURSOR_HPP

  Modified: lib/grnxx/impl/db.cpp (+36 -68)
===================================================================
--- lib/grnxx/impl/db.cpp    2014-10-31 21:43:45 +0900 (2ccb816)
+++ lib/grnxx/impl/db.cpp    2014-11-05 17:35:04 +0900 (c04e7e8)
@@ -7,72 +7,51 @@ DB::DB() : DBInterface(), tables_() {}
 
 DB::~DB() {}
 
-Table *DB::create_table(Error *error,
-                        const StringCRef &name,
-                        const TableOptions &options) {
-  if (find_table(nullptr, name)) {
-    GRNXX_ERROR_SET(error, ALREADY_EXISTS,
-                    "Table already exists: name = \"%.*s\"",
-                    static_cast<int>(name.size()), name.data());
-    return nullptr;
+Table *DB::create_table(const String &name, const TableOptions &options) {
+  if (find_table(name)) {
+    throw "Table already exists";  // TODO
   }
-  if (!tables_.reserve(error, num_tables() + 1)) {
-    return nullptr;
-  }
-  unique_ptr<Table> new_table = Table::create(error, this, name, options);
-  if (!new_table) {
-    return nullptr;
-  }
-  tables_.push_back(error, std::move(new_table));
+  tables_.reserve(num_tables() + 1);
+  std::unique_ptr<Table> new_table = Table::create(this, name, options);
+  tables_.push_back(std::move(new_table));
   return tables_.back().get();
 }
 
-bool DB::remove_table(Error *error, const StringCRef &name) {
-  Int table_id;
-  if (!find_table_with_id(error, name, &table_id)) {
-    return false;
+void DB::remove_table(const String &name) {
+  size_t table_id;
+  if (!find_table_with_id(name, &table_id)) {
+    throw "Table not found";  // TODO
   }
   if (!tables_[table_id]->is_removable()) {
-    GRNXX_ERROR_SET(error, NOT_REMOVABLE,
-                    "Table is not removable: name = \"%.*s\"",
-                    static_cast<int>(name.size()), name.data());
-    return false;
+    throw "Table not removable";  // TODO
   }
   tables_.erase(table_id);
-  return true;
 }
 
-bool DB::rename_table(Error *error,
-                      const StringCRef &name,
-                      const StringCRef &new_name) {
-  Int table_id;
-  if (!find_table_with_id(error, name, &table_id)) {
-    return false;
+void DB::rename_table(const String &name, const String &new_name) {
+  size_t table_id;
+  if (!find_table_with_id(name, &table_id)) {
+    throw "Table not found";  // TODO
   }
   if (name == new_name) {
-    return true;
+    return;
   }
-  if (find_table(nullptr, new_name)) {
-    GRNXX_ERROR_SET(error, ALREADY_EXISTS,
-                    "Table already exists: new_name = \"%.*s\"",
-                    static_cast<int>(new_name.size()), new_name.data());
-    return false;
+  if (find_table(new_name)) {
+    throw "Table already exists";  // TODO
   }
-  return tables_[table_id]->rename(error, new_name);
+  tables_[table_id]->rename(new_name);
 }
 
-bool DB::reorder_table(Error *error,
-                       const StringCRef &name,
-                       const StringCRef &prev_name) {
-  Int table_id;
-  if (!find_table_with_id(error, name, &table_id)) {
-    return false;
+void DB::reorder_table(const String &name, const String &prev_name) {
+  size_t table_id;
+  if (!find_table_with_id(name, &table_id)) {
+    throw "Table not found";  // TODO
   }
-  Int new_table_id = 0;
+  size_t new_table_id = 0;
   if (prev_name.size() != 0) {
-    Int prev_table_id;
-    if (!find_table_with_id(error, prev_name, &prev_table_id)) {
-      return false;
+    size_t prev_table_id;
+    if (!find_table_with_id(prev_name, &prev_table_id)) {
+      throw "Table not found";  // TODO
     }
     if (table_id <= prev_table_id) {
       new_table_id = prev_table_id;
@@ -86,41 +65,30 @@ bool DB::reorder_table(Error *error,
   for ( ; table_id > new_table_id; --table_id) {
     std::swap(tables_[table_id], tables_[table_id - 1]);
   }
-  return true;
 }
 
-Table *DB::find_table(Error *error, const StringCRef &name) const {
-  for (Int table_id = 0; table_id < num_tables(); ++table_id) {
-    if (name == tables_[table_id]->name()) {
-      return tables_[table_id].get();
+Table *DB::find_table(const String &name) const {
+  for (size_t i = 0; i < num_tables(); ++i) {
+    if (name == tables_[i]->name()) {
+      return tables_[i].get();
     }
   }
-  GRNXX_ERROR_SET(error, NOT_FOUND, "Table not found: name = \"%.*s\"",
-                  static_cast<int>(name.size()), name.data());
   return nullptr;
 }
 
-bool DB::save(Error *error,
-              const StringCRef &,
-              const DBOptions &) const {
-  // TODO: Named DB is not supported yet.
-  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-  return false;
+void DB::save(const String &, const DBOptions &) const {
+  throw "Not supported yet";  // TODO
 }
 
-Table *DB::find_table_with_id(Error *error,
-                              const StringCRef &name,
-                              Int *table_id) const {
-  for (Int i = 0; i < num_tables(); ++i) {
+Table *DB::find_table_with_id(const String &name, size_t *table_id) const {
+  for (size_t i = 0; i < num_tables(); ++i) {
     if (name == tables_[i]->name()) {
-      if (table_id != nullptr) {
+      if (table_id) {
         *table_id = i;
       }
       return tables_[i].get();
     }
   }
-  GRNXX_ERROR_SET(error, NOT_FOUND, "Table not found: name = \"%.*s\"",
-                  static_cast<int>(name.size()), name.data());
   return nullptr;
 }
 

  Modified: lib/grnxx/impl/db.hpp (+18 -25)
===================================================================
--- lib/grnxx/impl/db.hpp    2014-10-31 21:43:45 +0900 (a3537cb)
+++ lib/grnxx/impl/db.hpp    2014-11-05 17:35:04 +0900 (99edc78)
@@ -1,8 +1,12 @@
 #ifndef GRNXX_IMPL_DB_HPP
 #define GRNXX_IMPL_DB_HPP
 
+#include <memory>
+
+#include "grnxx/array.hpp"
 #include "grnxx/db.hpp"
 #include "grnxx/impl/table.hpp"
+#include "grnxx/string.hpp"
 
 namespace grnxx {
 namespace impl {
@@ -16,41 +20,30 @@ class DB : public DBInterface {
   DB();
   ~DB();
 
-  Int num_tables() const {
+  size_t num_tables() const {
     return tables_.size();
   }
 
-  Table *create_table(Error *error,
-                      const StringCRef &name,
-                      const TableOptions &options);
-  bool remove_table(Error *error, const StringCRef &name);
-  bool rename_table(Error *error,
-                    const StringCRef &name,
-                    const StringCRef &new_name);
-  bool reorder_table(Error *error,
-                     const StringCRef &name,
-                     const StringCRef &prev_name);
-
-  Table *get_table(Int table_id) const {
-    return tables_[table_id].get();
+  Table *create_table(const String &name, const TableOptions &options);
+  void remove_table(const String &name);
+  void rename_table(const String &name, const String &new_name);
+  void reorder_table(const String &name, const String &prev_name);
+
+  Table *get_table(size_t i) const {
+    return tables_[i].get();
   }
-  Table *find_table(Error *error, const StringCRef &name) const;
+  Table *find_table(const String &name) const;
 
-  bool save(Error *error,
-            const StringCRef &path,
-            const DBOptions &options = DBOptions()) const;
+  void save(const String &path, const DBOptions &options = DBOptions()) const;
 
  private:
-  Array<unique_ptr<Table>> tables_;
+  Array<std::unique_ptr<Table>> tables_;
 
   // Find a table with its ID.
   //
-  // On success, returns a pointer to the table.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  Table *find_table_with_id(Error *error,
-                            const StringCRef &name,
-                            Int *table_id) const;
+  // If found, returns the table and stores its ID into "*table_id".
+  // If not found, returns nullptr.
+  Table *find_table_with_id(const String &name, size_t *table_id) const;
 };
 
 }  // namespace impl

  Modified: lib/grnxx/impl/table.cpp (+313 -376)
===================================================================
--- lib/grnxx/impl/table.cpp    2014-10-31 21:43:45 +0900 (01d9859)
+++ lib/grnxx/impl/table.cpp    2014-11-05 17:35:04 +0900 (5678cdc)
@@ -1,117 +1,50 @@
 #include "grnxx/impl/table.hpp"
 
-#include "grnxx/cursor.hpp"
+#include "grnxx/impl/cursor.hpp"
 #include "grnxx/impl/db.hpp"
 
-#include <iostream>  // For debug.
-
 namespace grnxx {
 namespace impl {
 
-// -- TableCursor --
+// -- TableRegularCursor --
 
-class TableCursor : public Cursor {
+class TableRegularCursor : public Cursor {
  public:
   // -- Public API --
 
-  ~TableCursor() {}
+  ~TableRegularCursor() {}
 
-  CursorResult read(Error *error, ArrayRef<Record> records);
+  size_t read(ArrayRef<Record> records);
 
   // -- Internal API --
 
-  // Create a cursor.
-  //
-  // Returns a pointer to the cursor on success.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  static unique_ptr<TableCursor> create(Error *error,
-                                        const Table *table,
+  static std::unique_ptr<Cursor> create(const Table *table,
                                         const CursorOptions &options);
 
-  // Read records in regular order.
-  CursorResult regular_read(Error *error, ArrayRef<Record> records);
-
-  // Read records in reverse order.
-  CursorResult reverse_read(Error *error, ArrayRef<Record> records);
-
  private:
   const Table *table_;
-  Int offset_left_;
-  Int limit_left_;
-  OrderType order_type_;
-  Int next_row_id_;
+  int64_t max_row_id_;
+  bool is_full_;
+  size_t offset_left_;
+  size_t limit_left_;
+  int64_t next_row_id_;
 
-  explicit TableCursor(const Table *table);
+  TableRegularCursor(const Table *table, const CursorOptions &options);
 };
 
-CursorResult TableCursor::read(Error *error, ArrayRef<Record> records) {
+size_t TableRegularCursor::read(ArrayRef<Record> records) {
   if (records.size() <= 0) {
-    return { true, 0 };
-  }
-  switch (order_type_) {
-    case REGULAR_ORDER: {
-      return regular_read(error, records);
-    }
-    case REVERSE_ORDER: {
-      return reverse_read(error, records);
-    }
-    default: {
-      GRNXX_ERROR_SET(error, BROKEN, "Broken cursor");
-      return { false, 0 };
-    }
+    return 0;
   }
-}
-
-unique_ptr<TableCursor> TableCursor::create(Error *error,
-                                            const Table *table,
-                                            const CursorOptions &options) {
-  unique_ptr<TableCursor> cursor(new (nothrow) TableCursor(table));
-  if (!cursor) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return nullptr;
-  }
-  cursor->offset_left_ = options.offset;
-  cursor->limit_left_ = options.limit;
-  switch (options.order_type) {
-    case REGULAR_ORDER: {
-      cursor->order_type_ = REGULAR_ORDER;
-      cursor->next_row_id_ = MIN_ROW_ID;
-      break;
-    }
-    case REVERSE_ORDER: {
-      cursor->order_type_ = REVERSE_ORDER;
-      cursor->next_row_id_ = table->max_row_id();
-      break;
-    }
-    default: {
-      GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid order type");
-      return nullptr;
-    }
-  }
-  return cursor;
-}
-
-TableCursor::TableCursor(const Table *table)
-    : Cursor(table),
-      table_(table),
-      offset_left_(),
-      limit_left_(),
-      order_type_(),
-      next_row_id_() {}
-
-CursorResult TableCursor::regular_read(Error *, ArrayRef<Record> records) {
-  Int count = 0;
-  bool has_false_bit =
-      table_->num_rows() != (table_->max_row_id() - MIN_ROW_ID + 1);
-  if (!has_false_bit) {
+  size_t count = 0;
+  if (is_full_) {
     // There are no false bits in the bitmap and bit checks are not required.
-    Int num_remaining_records = table_->max_row_id() - next_row_id_ + 1;
+    size_t num_remaining_records = max_row_id_ - next_row_id_ + 1;
     if (offset_left_ > 0) {
       if (offset_left_ >= num_remaining_records) {
         next_row_id_ += num_remaining_records;
         offset_left_ -= num_remaining_records;
-        return { true, 0 };
+        return 0;
       }
       num_remaining_records -= offset_left_;
       next_row_id_ += offset_left_;
@@ -125,15 +58,15 @@ CursorResult TableCursor::regular_read(Error *, ArrayRef<Record> records) {
     if (count > limit_left_) {
       count = limit_left_;
     }
-    for (Int i = 0; i < count; ++i) {
-      records.set(i, Record(next_row_id_, 0.0));
+    for (size_t i = 0; i < count; ++i) {
+      records.set(i, Record(Int(next_row_id_), Float(0.0)));
       ++next_row_id_;
       --limit_left_;
     }
   } else {
     // There exist false bits in the bitmap and bit checks are required.
-    while (next_row_id_ <= table_->max_row_id()) {
-      if (!table_->get_bit(next_row_id_)) {
+    while (next_row_id_ <= max_row_id_) {
+      if (!table_->_test_row(next_row_id_)) {
         ++next_row_id_;
         continue;
       }
@@ -141,7 +74,7 @@ CursorResult TableCursor::regular_read(Error *, ArrayRef<Record> records) {
         --offset_left_;
         ++next_row_id_;
       } else {
-        records.set(count, Record(next_row_id_, 0.0));
+        records.set(count, Record(Int(next_row_id_), Float(0.0)));
         --limit_left_;
         ++count;
         ++next_row_id_;
@@ -151,21 +84,65 @@ CursorResult TableCursor::regular_read(Error *, ArrayRef<Record> records) {
       }
     }
   }
-  return { true, count };
+  return count;
 }
 
-CursorResult TableCursor::reverse_read(Error *, ArrayRef<Record> records) {
-  Int count = 0;
-  bool has_false_bit =
-      table_->num_rows() != (table_->max_row_id() - MIN_ROW_ID + 1);
-  if (!has_false_bit) {
+std::unique_ptr<Cursor> TableRegularCursor::create(
+    const Table *table,
+    const CursorOptions &options) {
+  if (table->is_empty()) {
+    return std::unique_ptr<Cursor>(new EmptyCursor);
+  }
+  return std::unique_ptr<Cursor>(new TableRegularCursor(table, options));
+}
+
+TableRegularCursor::TableRegularCursor(const Table *table,
+                                       const CursorOptions &options)
+    : table_(table),
+      max_row_id_(table->max_row_id().value()),
+      is_full_(table->is_full()),
+      offset_left_(options.offset),
+      limit_left_(options.limit),
+      next_row_id_(0) {}
+
+// -- TableReverseCursor --
+
+class TableReverseCursor : public Cursor {
+ public:
+  // -- Public API --
+
+  ~TableReverseCursor() {}
+
+  size_t read(ArrayRef<Record> records);
+
+  // -- Internal API --
+
+  static std::unique_ptr<Cursor> create(const Table *table,
+                                        const CursorOptions &options);
+
+ private:
+  const Table *table_;
+  bool is_full_;
+  size_t offset_left_;
+  size_t limit_left_;
+  int64_t next_row_id_;
+
+  TableReverseCursor(const Table *table, const CursorOptions &options);
+};
+
+size_t TableReverseCursor::read(ArrayRef<Record> records) {
+  if (records.size() <= 0) {
+    return 0;
+  }
+  size_t count = 0;
+  if (is_full_) {
     // There are no false bits in the bitmap and bit checks are not required.
-    Int num_remaining_records = next_row_id_ - MIN_ROW_ID + 1;
+    size_t num_remaining_records = next_row_id_ + 1;
     if (offset_left_ > 0) {
       if (offset_left_ >= num_remaining_records) {
         next_row_id_ -= num_remaining_records;
         offset_left_ -= num_remaining_records;
-        return { true, 0 };
+        return 0;
       }
       num_remaining_records -= offset_left_;
       next_row_id_ -= offset_left_;
@@ -179,15 +156,15 @@ CursorResult TableCursor::reverse_read(Error *, ArrayRef<Record> records) {
     if (count > limit_left_) {
       count = limit_left_;
     }
-    for (Int i = 0; i < count; ++i) {
-      records.set(i, Record(next_row_id_, 0.0));
+    for (size_t i = 0; i < count; ++i) {
+      records.set(i, Record(Int(next_row_id_), Float(0.0)));
       --next_row_id_;
       --limit_left_;
     }
   } else {
-    while (next_row_id_ >= MIN_ROW_ID) {
+    while (next_row_id_ >= 0) {
       // There exist false bits in the bitmap and bit checks are required.
-      if (!table_->get_bit(next_row_id_)) {
+      if (!table_->_test_row(next_row_id_)) {
         --next_row_id_;
         continue;
       }
@@ -195,7 +172,7 @@ CursorResult TableCursor::reverse_read(Error *, ArrayRef<Record> records) {
         --offset_left_;
         --next_row_id_;
       } else {
-        records.set(count, Record(next_row_id_, 0.0));
+        records.set(count, Record(Int(next_row_id_), Float(0.0)));
         --limit_left_;
         ++count;
         --next_row_id_;
@@ -205,20 +182,37 @@ CursorResult TableCursor::reverse_read(Error *, ArrayRef<Record> records) {
       }
     }
   }
-  return { true, count };
+  return count;
 }
 
+std::unique_ptr<Cursor> TableReverseCursor::create(
+    const Table *table,
+    const CursorOptions &options) {
+  if (table->is_empty()) {
+    return std::unique_ptr<Cursor>(new EmptyCursor);
+  }
+  return std::unique_ptr<Cursor>(new TableReverseCursor(table, options));
+}
+
+TableReverseCursor::TableReverseCursor(const Table *table,
+                                       const CursorOptions &options)
+    : table_(table),
+      is_full_(table->is_full()),
+      offset_left_(options.offset),
+      limit_left_(options.limit),
+      next_row_id_(table->max_row_id().value()) {}
+
 // -- Table --
 
-Table::Table()
+Table::Table(DB *db, const String &name)
     : TableInterface(),
-      db_(nullptr),
-      name_(),
+      db_(db),
+      name_(name),
       columns_(),
       referrer_columns_(),
       key_column_(nullptr),
       num_rows_(0),
-      max_row_id_(MIN_ROW_ID - 1),
+      max_row_id_(NA()),
       bitmap_(),
       bitmap_indexes_() {}
 
@@ -228,81 +222,61 @@ DBInterface *Table::db() const {
   return db_;
 }
 
-ColumnBase *Table::create_column(Error *error,
-                                 const StringCRef &name,
+ColumnBase *Table::create_column(const String &name,
                                  DataType data_type,
                                  const ColumnOptions &options) {
-  if (find_column(nullptr, name)) {
-    GRNXX_ERROR_SET(error, ALREADY_EXISTS,
-                    "Column already exists: name = \"%.*s\"",
-                    static_cast<int>(name.size()), name.data());
-    return nullptr;
-  }
-  if (!columns_.reserve(error, columns_.size() + 1)) {
-    return nullptr;
-  }
-  unique_ptr<ColumnBase> new_column =
-      ColumnBase::create(error, this, name, data_type, options);
-  if (!new_column) {
-    return nullptr;
+  if (find_column(name)) {
+    throw "Column already exists";  // TODO
   }
-  columns_.push_back(nullptr, std::move(new_column));
+  columns_.reserve(columns_.size() + 1);
+  std::unique_ptr<ColumnBase> new_column =
+      ColumnBase::create(this, name, data_type, options);
+  columns_.push_back(std::move(new_column));
   return columns_.back().get();
 }
 
-bool Table::remove_column(Error *error, const StringCRef &name) {
-  Int column_id;
-  if (!find_column_with_id(error, name, &column_id)) {
-    return false;
+void Table::remove_column(const String &name) {
+  size_t column_id;
+  if (!find_column_with_id(name, &column_id)) {
+    throw "Column not found";  // TODO
   }
   if (!columns_[column_id]->is_removable()) {
-    GRNXX_ERROR_SET(error, NOT_REMOVABLE,
-                    "Column is not removable: name = \"%.*s\"",
-                    static_cast<int>(name.size()), name.data());
-    return false;
+    throw "Column not removable";  // TODO
   }
   ColumnBase *column = columns_[column_id].get();
   if (column == key_column_) {
     key_column_ = nullptr;
   }
-  if (column->ref_table()) {
-    column->_ref_table()->remove_referrer_column(nullptr, column);
+  if (column->reference_table()) {
+    column->_reference_table()->remove_referrer_column(column);
   }
   columns_.erase(column_id);
-  return true;
 }
 
-bool Table::rename_column(Error *error,
-                          const StringCRef &name,
-                          const StringCRef &new_name) {
-  Int column_id;
-  if (!find_column_with_id(error, name, &column_id)) {
-    return false;
+void Table::rename_column(const String &name, const String &new_name) {
+  size_t column_id;
+  if (!find_column_with_id(name, &column_id)) {
+    throw "Column not found";  // TODO
   }
   if (name == new_name) {
-    return true;
+    return;
   }
-  if (find_column(nullptr, new_name)) {
-    GRNXX_ERROR_SET(error, ALREADY_EXISTS,
-                    "Column already exists: new_name = \"%.*s\"",
-                    static_cast<int>(new_name.size()), new_name.data());
-    return false;
+  if (find_column(new_name)) {
+    throw "Column already exists";  // TODO
   }
-  return columns_[column_id]->rename(error, new_name);
+  columns_[column_id]->rename(new_name);
 }
 
-bool Table::reorder_column(Error *error,
-                           const StringCRef &name,
-                           const StringCRef &prev_name) {
-  Int column_id;
-  if (!find_column_with_id(error, name, &column_id)) {
-    return false;
+void Table::reorder_column(const String &name, const String &prev_name) {
+  size_t column_id;
+  if (!find_column_with_id(name, &column_id)) {
+    throw "Column not found";  // TODO
   }
-  Int new_column_id = 0;
+  size_t new_column_id = 0;
   if (prev_name.size() != 0) {
-    Int prev_column_id;
-    if (!find_column_with_id(error, prev_name, &prev_column_id)) {
-      return false;
+    size_t prev_column_id;
+    if (!find_column_with_id(prev_name, &prev_column_id)) {
+      throw "Column not found";  // TODO
     }
     if (column_id <= prev_column_id) {
       new_column_id = prev_column_id;
@@ -316,209 +290,156 @@ bool Table::reorder_column(Error *error,
   for ( ; column_id > new_column_id; --column_id) {
     std::swap(columns_[column_id], columns_[column_id - 1]);
   }
-  return true;
 }
 
-ColumnBase *Table::find_column(Error *error, const StringCRef &name) const {
-  for (Int column_id = 0; column_id < num_columns(); ++column_id) {
-    if (name == columns_[column_id]->name()) {
-      return columns_[column_id].get();
+ColumnBase *Table::find_column(const String &name) const {
+  for (size_t i = 0; i < num_columns(); ++i) {
+    if (name == columns_[i]->name()) {
+      return columns_[i].get();
     }
   }
-  GRNXX_ERROR_SET(error, NOT_FOUND, "Column not found: name = \"%.*s\"",
-                  static_cast<int>(name.size()), name.data());
   return nullptr;
 }
 
-bool Table::set_key_column(Error *error, const StringCRef &name) {
+void Table::set_key_column(const String &name) {
   if (key_column_) {
-    GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key column already exists");
-    return false;
+    throw "Key column already exists";  // TODO
   }
-  ColumnBase *column = find_column(error, name);
+  ColumnBase *column = find_column(name);
   if (!column) {
-    return false;
-  }
-  if (!column->set_key_attribute(error)) {
-    return false;
+    throw "Column not found";  // TODO
   }
+  column->set_key_attribute();
   key_column_ = column;
-  return true;
 }
 
-bool Table::unset_key_column(Error *error) {
+void Table::unset_key_column() {
   if (!key_column_) {
-    GRNXX_ERROR_SET(error, NOT_FOUND, "Key column not found");
-    return false;
-  }
-  if (!key_column_->unset_key_attribute(error)) {
-    return false;
+    throw "Key column not found";  // TODO
   }
+  key_column_->unset_key_attribute();
   key_column_ = nullptr;
-  return true;
 }
 
-bool Table::insert_row(Error *error,
-                       Int request_row_id,
-                       const Datum &key,
-                       Int *result_row_id) {
-  *result_row_id = NULL_ROW_ID;
-  Int next_row_id;
-  if (request_row_id == NULL_ROW_ID) {
-    next_row_id = find_zero_bit();
-  } else if ((request_row_id < MIN_ROW_ID) || (request_row_id > MAX_ROW_ID)) {
-    GRNXX_ERROR_SET(error, INVALID_ARGUMENT,
-                    "Invalid argument: request_row_id = %" PRIi64,
-                    request_row_id);
-    return false;
-  } else if (request_row_id > max_row_id()) {
-    next_row_id = request_row_id;
-  } else {
-    // Fails if the request row ID is used.
-    if (get_bit(request_row_id)) {
-      *result_row_id = request_row_id;
-      GRNXX_ERROR_SET(error, ALREADY_EXISTS,
-                      "Row already exists: request_row_id = %" PRIi64,
-                      request_row_id);
-      return false;
+Int Table::insert_row(const Datum &key) {
+  if (key_column_) {
+    if (!find_row(key).is_na()) {
+      throw "Key already exists";  // TODO
     }
-    next_row_id = request_row_id;
+  } else if (key.type() != NA_DATA) {
+    throw "Wrong key";  // TODO
+  }
+  Int row_id = find_next_row_id();
+  reserve_row(row_id);
+  if (key_column_) {
+    key_column_->set_initial_key(row_id, key);
   }
+  validate_row(row_id);
+  return row_id;
+}
 
-  if (key_column()) {
-    // Fails if the key already exists.
-    *result_row_id = find_row(nullptr, key);
-    if (*result_row_id != NULL_ROW_ID) {
-      GRNXX_ERROR_SET(error, ALREADY_EXISTS, "Key already exists");
-      return false;
+Int Table::find_or_insert_row(const Datum &key, bool *inserted) {
+  if (key_column_) {
+    Int row_id = find_row(key);
+    if (!row_id.is_na()) {
+      if (inserted) {
+        *inserted = false;
+      }
+      return row_id;
     }
+  } else if (key.type() != NA_DATA) {
+    throw "Wrong key";  // TODO
   }
-
-  if (!reserve_bit(error, next_row_id)) {
-    return false;
+  Int row_id = find_next_row_id();
+  reserve_row(row_id);
+  if (key_column_) {
+    key_column_->set_initial_key(row_id, key);
   }
+  validate_row(row_id);
+  *inserted = true;
+  return row_id;
+}
 
-  if (key_column()) {
-    if (!key_column_->set_initial_key(error, next_row_id, key)) {
-      return false;
-    }
+void Table::insert_row_at(Int row_id, const Datum &key) {
+  if (test_row(row_id)) {
+    throw "Row ID already validated";  // TODO
   }
-
-  if (next_row_id > max_row_id()) {
-    // Fill non-key column values with the default values.
-    for (Int column_id = 0; column_id < num_columns(); ++column_id) {
-      if (columns_[column_id].get() != key_column()) {
-        if (!columns_[column_id]->set_default_value(error, next_row_id)) {
-          // Rollback the insertion.
-          if (key_column()) {
-            key_column_->unset(next_row_id);
-          }
-          for (Int i = 0; i < column_id; ++i) {
-            if (columns_[i].get() != key_column()) {
-              columns_[i]->unset(next_row_id);
-            }
-          }
-          return false;
-        }
-      }
+  if (row_id.value() < 0) {
+    throw "Negative row ID";  // TODO
+  }
+  if (key_column_) {
+    if (!find_row(key).is_na()) {
+      throw "Key already exists";  // TODO
     }
-    max_row_id_ = next_row_id;
   }
-
-  set_bit(next_row_id);
-  ++num_rows_;
-  *result_row_id = next_row_id;
-  return true;
+  reserve_row(row_id);
+  if (key_column_) {
+    key_column_->set_initial_key(row_id, key);
+  }
+  validate_row(row_id);
 }
 
-bool Table::remove_row(Error *error, Int row_id) {
-  if (!test_row(error, row_id)) {
-    return false;
+void Table::remove_row(Int row_id) {
+  if (!test_row(row_id)) {
+    throw "Invalid row ID";  // TODO
   }
   // TODO: Check removability.
-  for (Int i = 0; i < referrer_columns_.size(); ++i) {
+  for (size_t i = 0; i < referrer_columns_.size(); ++i) {
     if (referrer_columns_[i]->has_key_attribute()) {
-      GRNXX_ERROR_SET(error, INVALID_OPERATION,
-                      "This table is referred to from a key column");
-      return false;
+      throw "Reffered to from a key column";  // TODO
     }
   }
   // Unset column values.
-  for (Int column_id = 0; column_id < num_columns(); ++column_id) {
-    columns_[column_id]->unset(row_id);
-  }
-  unset_bit(row_id);
-  --num_rows_;
-  if (num_rows_ == 0) {
-    max_row_id_ = MIN_ROW_ID - 1;
-  } else if (row_id == max_row_id()) {
-    Int block_id = (max_row_id() - 1) / 64;
-    while (block_id >= 0) {
-      if (bitmap_[block_id] != 0) {
-        break;
-      }
-      --block_id;
-    }
-    max_row_id_ = (block_id * 64) + 63 - ::__builtin_clzll(bitmap_[block_id]);
+  for (size_t i = 0; i < num_columns(); ++i) {
+    columns_[i]->unset(row_id);
   }
+  invalidate_row(row_id);
   // Clear referrers.
-  for (Int i = 0; i < referrer_columns_.size(); ++i) {
+  for (size_t i = 0; i < referrer_columns_.size(); ++i) {
     referrer_columns_[i]->clear_references(row_id);
   }
-  return true;
 }
 
-bool Table::test_row(Error *error, Int row_id) const {
-  if ((row_id < MIN_ROW_ID) || (row_id > max_row_id())) {
-    GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid row ID");
-    return false;
-  }
-  if (!get_bit(row_id)) {
-    GRNXX_ERROR_SET(error, NOT_FOUND, "Removed row");
-    return false;
-  }
-  return true;
-}
-
-Int Table::find_row(Error *error, const Datum &key) const {
+Int Table::find_row(const Datum &key) const {
   if (!key_column_) {
-    GRNXX_ERROR_SET(error, NO_KEY_COLUMN, "No key column");
-    return NULL_ROW_ID;
+    throw "No key column";  // TODO
   }
   return key_column_->find_one(key);
 }
 
-unique_ptr<Cursor> Table::create_cursor(
-    Error *error,
+std::unique_ptr<Cursor> Table::create_cursor(
     const CursorOptions &options) const {
-  return TableCursor::create(error, this, options);
+  switch (options.order_type) {
+    case CURSOR_REGULAR_ORDER: {
+      return TableRegularCursor::create(this, options);
+    }
+    case CURSOR_REVERSE_ORDER: {
+      return TableReverseCursor::create(this, options);
+    }
+    default: {
+      throw "Invalid order type";  // TODO
+    }
+  }
 }
 
-unique_ptr<Table> Table::create(Error *error,
-                                DB *db,
-                                const StringCRef &name,
-                                const TableOptions &) {
-  unique_ptr<Table> table(new Table);
-  table->db_ = db;
-  if (!table->name_.assign(error, name)) {
-    return nullptr;
-  }
-  // Initialize the bitmap.
-  if (!table->reserve_bit(error, 0)) {
-    return nullptr;
-  }
-  table->set_bit(0);
-  // TODO: Apply options.
+std::unique_ptr<Table> Table::create(DB *db,
+                                     const String &name,
+                                     const TableOptions &) try {
+  std::unique_ptr<Table> table(new Table(db, name));
   return table;
+} catch (const std::bad_alloc &) {
+  throw "Memory allocation failed";  // TODO
 }
 
-bool Table::rename(Error *error, const StringCRef &new_name) {
-  return name_.assign(error, new_name);
+void Table::rename(const String &new_name) {
+  if (name_ != new_name) {
+    name_.assign(new_name);
+  }
 }
 
-bool Table::is_removable() {
-  // Referenced table (except self-reference) is not removable.
-  for (Int i = 0; i < referrer_columns_.size(); ++i) {
+bool Table::is_removable() const {
+  // A referenced table (except self-reference) is not removable.
+  for (size_t i = 0; i < referrer_columns_.size(); ++i) {
     if (referrer_columns_[i]->table() != this) {
       return false;
     }
@@ -526,107 +447,125 @@ bool Table::is_removable() {
   return true;
 }
 
-bool Table::append_referrer_column(Error *error, ColumnBase *column) {
-  if (column->ref_table() != this) {
-    GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong column");
-    return false;
+void Table::append_referrer_column(ColumnBase *column) {
+  if (column->reference_table() != this) {
+    throw "Wrong referrer column";  // TODO
   }
-  return referrer_columns_.push_back(error, column);
+  referrer_columns_.push_back(column);
 }
 
-bool Table::remove_referrer_column(Error *error, ColumnBase *column) {
-  for (Int i = 0; i < referrer_columns_.size(); ++i) {
+void Table::remove_referrer_column(ColumnBase *column) {
+  for (size_t i = 0; i < referrer_columns_.size(); ++i) {
     if (column == referrer_columns_[i]) {
       referrer_columns_.erase(i);
-      return true;
+      return;
     }
   }
-  GRNXX_ERROR_SET(error, NOT_FOUND, "Column not found");
-  return false;
+  throw "Referrer column not found";  // TODO
 }
 
-void Table::set_bit(Int i) {
-  bitmap_[i / 64] |= UInt(1) << (i % 64);
-  if (bitmap_[i / 64] == ~UInt(0)) {
-    for (Int index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) {
-      i /= 64;
-      bitmap_indexes_[index_id][i / 64] |= UInt(1) << (i % 64);
-      if (bitmap_indexes_[index_id][i / 64] != ~UInt(0)) {
-        break;
-      }
-    }
+Int Table::find_next_row_id() const {
+  if (is_empty()) {
+    return Int(0);
+  } else if (is_full()) {
+    return Int(max_row_id_.value() + 1);
   }
-}
-
-void Table::unset_bit(Int i) {
-  bool is_full = bitmap_[i / 64] == ~UInt(0);
-  bitmap_[i / 64] &= ~(UInt(1) << (i % 64));
-  if (is_full) {
-    for (Int index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) {
-      i /= 64;
-      is_full = bitmap_indexes_[index_id][i / 64] == ~UInt(0);
-      bitmap_indexes_[index_id][i / 64] &= ~(UInt(1) << (i % 64));
-      if (!is_full) {
-        break;
-      }
-    }
-  }
-}
-
-Int Table::find_zero_bit() const {
-  if (num_rows() == (max_row_id() - MIN_ROW_ID + 1)) {
-    return max_row_id() + 1;
-  }
-  Int pos = 0;
-  for (Int i = bitmap_indexes_.size(); i > 0; ) {
+  size_t pos = 0;
+  for (size_t i = bitmap_indexes_.size(); i > 0; ) {
+    // TODO: ::__builtin_ctzll() is not available on VC++.
     pos = (pos * 64) + ::__builtin_ctzll(~bitmap_indexes_[--i][pos]);
   }
-  return (pos * 64) + ::__builtin_ctzll(~bitmap_[pos]);
+  // TODO: ::__builtin_ctzll() is not available on VC++.
+  return Int((pos * 64) + ::__builtin_ctzll(~bitmap_[pos]));
 }
 
-bool Table::reserve_bit(Error *error, Int i) {
-  if (i > MAX_ROW_ID) {
-    GRNXX_ERROR_SET(error, INVALID_ARGUMENT,
-                    "Invalid argument: i = %" PRIi64, i);
-    return false;
-  }
+void Table::reserve_row(Int row_id) {
+  // TODO: Define the upper limit for row ID.
+//  if (row_id.value() > MAX_ROW_ID_VALUE) {
+//    throw "Too large row ID";  // TODO
+//  }
   // Resize the bitmap if required.
-  Int block_id = i / 64;
+  size_t block_id = static_cast<size_t>(row_id.value()) / 64;
   if (block_id >= bitmap_.size()) {
-    if (!bitmap_.resize(error, block_id + 1, 0)) {
-      return false;
-    }
+    bitmap_.resize(block_id + 1, 0);
   }
   // Resize the existing bitmap indexes if required.
-  for (Int index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) {
+  for (size_t index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) {
     block_id /= 64;
     if (block_id >= bitmap_indexes_[index_id].size()) {
-      if (!bitmap_indexes_[index_id].resize(error, block_id + 1, 0)) {
-        return false;
-      }
+      bitmap_indexes_[index_id].resize(block_id + 1, 0);
     }
   }
-  // Add bitmap indexes if requires.
-  Int depth = bitmap_indexes_.size();
+  // Add bitmap indexes if required.
+  size_t depth = bitmap_indexes_.size();
   while (block_id > 0) {
     block_id /= 64;
-    if (!bitmap_indexes_.resize(error, depth + 1) ||
-        !bitmap_indexes_[depth].resize(error, block_id + 1, 0)) {
-      return false;
-    }
+    bitmap_indexes_.resize(depth + 1);
+    bitmap_indexes_[depth].resize(block_id + 1, 0);
     if (depth == 0) {
       bitmap_indexes_[depth][0] = bitmap_[0] != 0;
     } else {
       bitmap_indexes_[depth][0] = bitmap_indexes_[depth - 1][0] != 0;
     }
   }
-  return true;
 }
 
-ColumnBase *Table::find_column_with_id(Error *error,
-                                       const StringCRef &name,
-                                       Int *column_id) const {
-  for (Int i = 0; i < num_columns(); ++i) {
+void Table::validate_row(Int row_id) {
+  // Update the bitmap and its indexes.
+  size_t bit_id = static_cast<size_t>(row_id.value());
+  bitmap_[bit_id / 64] |= uint64_t(1) << (bit_id % 64);
+  if (bitmap_[bit_id / 64] == ~uint64_t(0)) {
+    for (size_t index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) {
+      bit_id /= 64;
+      bitmap_indexes_[index_id][bit_id / 64] |= uint64_t(1) << (bit_id % 64);
+      if (bitmap_indexes_[index_id][bit_id / 64] != ~uint64_t(0)) {
+        break;
+      }
+    }
+  }
+  // This works well even if "max_row_id_" is N/A.
+  if (row_id.value() > max_row_id_.value()) {
+    max_row_id_ = row_id;
+  }
+  ++num_rows_;
+}
+
+void Table::invalidate_row(Int row_id) {
+  // Update the bitmap and its indexes.
+  size_t bit_id = static_cast<size_t>(row_id.value());
+  bool is_full = (bitmap_[bit_id / 64] == ~uint64_t(0));
+  bitmap_[bit_id / 64] &= ~(uint64_t(1) << (bit_id % 64));
+  if (is_full) {
+    for (size_t index_id = 0; index_id < bitmap_indexes_.size(); ++index_id) {
+      bit_id /= 64;
+      is_full = bitmap_indexes_[index_id][bit_id / 64] == ~uint64_t(0);
+      bitmap_indexes_[index_id][bit_id / 64] &=
+           ~(uint64_t(1) << (bit_id % 64));
+      if (!is_full) {
+        break;
+      }
+    }
+  }
+  --num_rows_;
+  if (is_empty()) {
+    max_row_id_ = Int::na();
+  } else if (row_id.value() == max_row_id_.value()) {
+    int64_t block_id = (row_id.value() - 1) / 64;
+    while (block_id >= 0) {
+      if (bitmap_[block_id] != 0) {
+        break;
+      }
+      --block_id;
+    }
+    // TODO: ::__builtin_clzll() is not available on VC++.
+    max_row_id_ = Int((block_id * 64) + 63 -
+                      ::__builtin_clzll(bitmap_[block_id]));
+  }
+}
+
+ColumnBase *Table::find_column_with_id(const String &name,
+                                       size_t *column_id) const {
+  for (size_t i = 0; i < num_columns(); ++i) {
     if (name == columns_[i]->name()) {
       if (column_id != nullptr) {
         *column_id = i;
@@ -634,8 +573,6 @@ ColumnBase *Table::find_column_with_id(Error *error,
       return columns_[i].get();
     }
   }
-  GRNXX_ERROR_SET(error, NOT_FOUND, "Column not found: name = \"%.*s\"",
-                  static_cast<int>(name.size()), name.data());
   return nullptr;
 }
 

  Modified: lib/grnxx/impl/table.hpp (+77 -78)
===================================================================
--- lib/grnxx/impl/table.hpp    2014-10-31 21:43:45 +0900 (59863ee)
+++ lib/grnxx/impl/table.hpp    2014-11-05 17:35:04 +0900 (9a62a99)
@@ -1,7 +1,9 @@
 #ifndef GRNXX_IMPL_TABLE_HPP
 #define GRNXX_IMPL_TABLE_HPP
 
-#include "grnxx/name.hpp"
+#include <cstdint>
+#include <memory>
+
 #include "grnxx/db.hpp"
 #include "grnxx/impl/column.hpp"
 #include "grnxx/table.hpp"
@@ -13,75 +15,81 @@ using DBInterface = grnxx::DB;
 using TableInterface = grnxx::Table;
 
 class DB;
+class TableRegularCursor;
+class TableReverseCursor;
 
 class Table : public TableInterface {
  public:
   // -- Public API (grnxx/table.hpp) --
 
-  Table();
+  Table(DB *db, const String &name);
   ~Table();
 
   DBInterface *db() const;
-  StringCRef name() const {
-    return name_.ref();
+  String name() const {
+    return name_;
   }
-  Int num_columns() const {
+  size_t num_columns() const {
     return columns_.size();
   }
   ColumnBase *key_column() const {
     return key_column_;
   }
-  Int num_rows() const {
+  size_t num_rows() const {
     return num_rows_;
   }
   Int max_row_id() const {
     return max_row_id_;
   }
+  bool is_empty() const {
+    return num_rows_ == 0;
+  }
+  bool is_full() const {
+    return is_empty() ||
+           (num_rows_ == static_cast<size_t>(max_row_id_.value() + 1));
+  }
 
-  ColumnBase *create_column(Error *error,
-                            const StringCRef &name,
+  ColumnBase *create_column(const String &name,
                             DataType data_type,
                             const ColumnOptions &options = ColumnOptions());
-  bool remove_column(Error *error, const StringCRef &name);
-  bool rename_column(Error *error,
-                     const StringCRef &name,
-                     const StringCRef &new_name);
-  bool reorder_column(Error *error,
-                      const StringCRef &name,
-                      const StringCRef &prev_name);
-
-  ColumnBase *get_column(Int column_id) const {
-    return columns_[column_id].get();
+  void remove_column(const String &name);
+  void rename_column(const String &name, const String &new_name);
+  void reorder_column(const String &name, const String &prev_name);
+
+  ColumnBase *get_column(size_t i) const {
+    return columns_[i].get();
   }
-  ColumnBase *find_column(Error *error, const StringCRef &name) const;
+  ColumnBase *find_column(const String &name) const;
+
+  void set_key_column(const String &name);
+  void unset_key_column();
 
-  bool set_key_column(Error *error, const StringCRef &name);
-  bool unset_key_column(Error *error);
+  Int insert_row(const Datum &key);
+  Int find_or_insert_row(const Datum &key, bool *inserted);
+  void insert_row_at(Int row_id, const Datum &key);
 
-  bool insert_row(Error *error,
-                  Int request_row_id,
-                  const Datum &key,
-                  Int *result_row_id);
-  bool remove_row(Error *error, Int row_id);
+  void remove_row(Int row_id);
 
-  bool test_row(Error *error, Int row_id) const;
-  Int find_row(Error *error, const Datum &key) const;
+  bool test_row(Int row_id) const {
+    size_t bit_id = static_cast<size_t>(row_id.value());
+    size_t block_id = bit_id / 64;
+    return (block_id < bitmap_.size()) &&
+           ((bitmap_[block_id] & (uint64_t(1) << (bit_id % 64))) != 0);
+  }
+  Int find_row(const Datum &key) const;
 
-  unique_ptr<Cursor> create_cursor(
-      Error *error,
+  std::unique_ptr<Cursor> create_cursor(
       const CursorOptions &options = CursorOptions()) const;
 
   // -- Internal API --
 
   // Create a new table.
   //
-  // On success, returns a pointer to the table.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  static unique_ptr<Table> create(
-      Error *error,
+  // On success, returns the table.
+  // On failure, throws an exception.
+  static std::unique_ptr<Table> create(
       DB *db,
-      const StringCRef &name,
+      const String &name,
       const TableOptions &options = TableOptions());
 
   // Return the owner DB.
@@ -89,68 +97,59 @@ class Table : public TableInterface {
     return db_;
   }
 
+  // Return whether a row is valid or not.
+  //
+  // If "row_id" is too large, the behavior is undefined.
+  bool _test_row(size_t row_id) const {
+    return (bitmap_[row_id / 64] & (uint64_t(1) << (row_id % 64))) != 0;
+  }
+
   // Change the table name.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool rename(Error *error, const StringCRef &new_name);
+  // On failure, throws an exception.
+  void rename(const String &new_name);
 
   // Return whether the table is removable or not.
-  bool is_removable();
+  bool is_removable() const;
 
   // Append a referrer column.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool append_referrer_column(Error *error, ColumnBase *column);
+  // On failure, throws an exception.
+  void append_referrer_column(ColumnBase *column);
 
-  // Append a referrer column.
+  // Remove a referrer column.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool remove_referrer_column(Error *error, ColumnBase *column);
+  // On failure, throws an exception.
+  void remove_referrer_column(ColumnBase *column);
 
  private:
   DB *db_;
-  Name name_;
-  Array<unique_ptr<ColumnBase>> columns_;
+  String name_;
+  Array<std::unique_ptr<ColumnBase>> columns_;
   Array<ColumnBase *> referrer_columns_;
   ColumnBase *key_column_;
-  Int num_rows_;
+  size_t num_rows_;
   Int max_row_id_;
-  Array<UInt> bitmap_;
-  Array<Array<UInt>> bitmap_indexes_;
+  Array<uint64_t> bitmap_;
+  Array<Array<uint64_t>> bitmap_indexes_;
 
-  // Get the "i"-th bit from the bitmap.
-  bool get_bit(Int i) const {
-    return (bitmap_[i / 64] & (Int(1) << (i % 64))) != 0;
-  }
-  // Set 1 to the "i"-th bit of the bitmap and update bitmap indexes.
-  void set_bit(Int i);
-  // Set 0 to the "i"-th bit of the bitmap and update bitmap indexes.
-  void unset_bit(Int i);
-  // Find a zero-bit and return its position.
-  Int find_zero_bit() const;
-  // Reserve the "i"-th bit for the next row.
+  // Find the next row ID candidate.
+  Int find_next_row_id() const;
+  // Reserve a row.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool reserve_bit(Error *error, Int i);
+  // On failure, throws an exception.
+  void reserve_row(Int row_id);
+  // Validate a row.
+  void validate_row(Int row_id);
+  // Invalidate a row.
+  void invalidate_row(Int row_id);
 
   // Find a column with its ID.
   //
-  // On success, returns a pointer to the column.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  ColumnBase *find_column_with_id(Error *error,
-                                  const StringCRef &name,
-                                  Int *column_id) const;
-
-  friend class TableCursor;
+  // If found, returns the column and stores its ID to "*column_id".
+  // If not found, returns nullptr.
+  ColumnBase *find_column_with_id(const String &name,
+                                  size_t *column_id) const;
 };
 
 }  // namespace impl

  Modified: test/Makefile.am (+12 -16)
===================================================================
--- test/Makefile.am    2014-10-31 21:43:45 +0900 (0f3e534)
+++ test/Makefile.am    2014-11-05 17:35:04 +0900 (0bb6481)
@@ -1,11 +1,10 @@
 TESTS =				\
+	test_array		\
 	test_data_types		\
-	test_string
+	test_string		\
+	test_db			\
+	test_table
 
-#	test_string		\
-#	test_array		\
-#	test_db			\
-#	test_table		\
 #	test_column		\
 #	test_index		\
 #	test_expression		\
@@ -16,23 +15,20 @@ TESTS =				\
 
 check_PROGRAMS = $(TESTS)
 
-test_data_types_SOURCES = test_data_types.cpp
-test_data_types_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la
-
 test_string_SOURCES = test_string.cpp
 test_string_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la
 
-#test_string_SOURCES = test_string.cpp
-#test_string_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la
+test_array_SOURCES = test_array.cpp
+test_array_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la
 
-#test_array_SOURCES = test_array.cpp
-#test_array_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la
+test_data_types_SOURCES = test_data_types.cpp
+test_data_types_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la
 
-#test_db_SOURCES = test_db.cpp
-#test_db_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la
+test_db_SOURCES = test_db.cpp
+test_db_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la
 
-#test_table_SOURCES = test_table.cpp
-#test_table_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la
+test_table_SOURCES = test_table.cpp
+test_table_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la
 
 #test_column_SOURCES = test_column.cpp
 #test_column_LDADD = $(top_srcdir)/lib/grnxx/libgrnxx.la

  Modified: test/test_array.cpp (+79 -65)
===================================================================
--- test/test_array.cpp    2014-10-31 21:43:45 +0900 (6f326a7)
+++ test/test_array.cpp    2014-11-05 17:35:04 +0900 (f6d9292)
@@ -20,128 +20,139 @@
 #include <random>
 #include <vector>
 
-#include "grnxx/types.hpp"
+#include "grnxx/array.hpp"
+#include "grnxx/data_types.hpp"
 
 std::mt19937_64 mersenne_twister;
 
 void test_bool() {
-  grnxx::Error error;
-
   grnxx::Array<grnxx::Bool> array;
   assert(array.size() == 0);
   assert(array.capacity() == 0);
 
-  assert(array.push_back(&error, true));
+  array.push_back(grnxx::Bool(true));
   assert(array.size() == 1);
-  assert(array.capacity() == 64);
+  assert(array.capacity() == 1);
   assert(array[0]);
 
-  assert(array.push_back(&error, false));
+  array.push_back(grnxx::Bool(false));
   assert(array.size() == 2);
-  assert(array.capacity() == 64);
+  assert(array.capacity() == 2);
   assert(array[0]);
   assert(!array[1]);
 
-  assert(array.resize(&error, 200, true));
+  array.push_back(grnxx::Bool(true));
+  assert(array.size() == 3);
+  assert(array.capacity() == 4);
+  assert(array[0]);
+  assert(!array[1]);
+  assert(array[2]);
+
+  array.resize(200, grnxx::Bool(true));
   assert(array.size() == 200);
-  assert(array.capacity() == 256);
+  assert(array.capacity() == 200);
   assert(array[0]);
   assert(!array[1]);
-  for (grnxx::Int i = 2; i < 200; ++i) {
-    assert(array.get(i));
+  assert(array[2]);
+  for (size_t i = 3; i < 200; ++i) {
+    assert(array[i]);
   }
 
-  constexpr grnxx::Int NUM_ROWS = 1 << 20;
+  constexpr size_t ARRAY_SIZE = 1 << 20;
 
-  assert(array.resize(&error, NUM_ROWS, false));
-  assert(array.size() == NUM_ROWS);
-  assert(array.capacity() == NUM_ROWS);
+  array.resize(ARRAY_SIZE, grnxx::Bool(false));
+  assert(array.size() == ARRAY_SIZE);
+  assert(array.capacity() == ARRAY_SIZE);
   assert(array[0]);
   assert(!array[1]);
-  for (grnxx::Int i = 2; i < 200; ++i) {
-    assert(array.get(i));
+  assert(array[2]);
+  for (size_t i = 3; i < 200; ++i) {
+    assert(array[i]);
   }
-  for (grnxx::Int i = 200; i < NUM_ROWS; ++i) {
-    assert(!array.get(i));
+  for (size_t i = 200; i < ARRAY_SIZE; ++i) {
+    assert(!array[i]);
   }
 
-  std::vector<grnxx::Bool> values(NUM_ROWS);
-  for (grnxx::Int i = 0; i < NUM_ROWS; ++i) {
-    values[i] = (mersenne_twister() & 1) != 0;
+  std::vector<grnxx::Bool> values(ARRAY_SIZE);
+  for (size_t i = 0; i < ARRAY_SIZE; ++i) {
+    values[i] = grnxx::Bool((mersenne_twister() & 1) != 0);
     array.set(i, values[i]);
-    assert(array[i] == values[i]);
+    assert(array.get(i) == values[i]);
   }
-
-  for (grnxx::Int i = 0; i < NUM_ROWS; ++i) {
-    assert(array[i] == values[i]);
+  for (size_t i = 0; i < ARRAY_SIZE; ++i) {
+    assert(array.get(i) == values[i]);
   }
 
   grnxx::Array<grnxx::Bool> array2;
   array2 = std::move(array);
   assert(array.size() == 0);
   assert(array.capacity() == 0);
-  assert(array2.size() == NUM_ROWS);
-  assert(array2.capacity() == NUM_ROWS);
+  assert(array2.size() == ARRAY_SIZE);
+  assert(array2.capacity() == ARRAY_SIZE);
+  for (size_t i = 0; i < ARRAY_SIZE; ++i) {
+    assert(array2.get(i) == values[i]);
+  }
 }
 
 void test_int() {
-  grnxx::Error error;
-
   grnxx::Array<grnxx::Int> array;
   assert(array.size() == 0);
   assert(array.capacity() == 0);
 
-  assert(array.push_back(&error, 123));
+  array.push_back(grnxx::Int(123));
   assert(array.size() == 1);
   assert(array.capacity() == 1);
-  assert(array[0] == 123);
+  assert(array[0] == grnxx::Int(123));
 
-  assert(array.push_back(&error, 456));
+  array.push_back(grnxx::Int(456));
   assert(array.size() == 2);
   assert(array.capacity() == 2);
-  assert(array[0] == 123);
-  assert(array[1] == 456);
+  assert(array[0] == grnxx::Int(123));
+  assert(array[1] == grnxx::Int(456));
 
-  assert(array.push_back(&error, 789));
+  array.push_back(grnxx::Int(789));
   assert(array.size() == 3);
   assert(array.capacity() == 4);
-  assert(array[0] == 123);
-  assert(array[1] == 456);
-  assert(array[2] == 789);
+  assert(array[0] == grnxx::Int(123));
+  assert(array[1] == grnxx::Int(456));
+  assert(array[2] == grnxx::Int(789));
 
-  assert(array.resize(&error, 200, 12345));
+  array.resize(200, grnxx::Int(12345));
   assert(array.size() == 200);
   assert(array.capacity() == 200);
-  assert(array[0] == 123);
-  assert(array[1] == 456);
-  assert(array[2] == 789);
-  for (grnxx::Int i = 3; i < 200; ++i) {
-    assert(array[i] == 12345);
+  assert(array[0] == grnxx::Int(123));
+  assert(array[1] == grnxx::Int(456));
+  assert(array[2] == grnxx::Int(789));
+  for (size_t i = 3; i < 200; ++i) {
+    assert(array[i] == grnxx::Int(12345));
   }
 
-  constexpr grnxx::Int NUM_ROWS = 1 << 20;
+  constexpr size_t ARRAY_SIZE = 1 << 20;
 
-  assert(array.resize(&error, NUM_ROWS, 0));
-  assert(array.size() == NUM_ROWS);
-  assert(array.capacity() == NUM_ROWS);
-  assert(array[0] == 123);
-  assert(array[1] == 456);
-  assert(array[2] == 789);
-  for (grnxx::Int i = 3; i < 200; ++i) {
-    assert(array[i] == 12345);
+  array.resize(ARRAY_SIZE, grnxx::Int(0));
+  assert(array.size() == ARRAY_SIZE);
+  assert(array.capacity() == ARRAY_SIZE);
+  assert(array[0] == grnxx::Int(123));
+  assert(array[1] == grnxx::Int(456));
+  assert(array[2] == grnxx::Int(789));
+  for (size_t i = 3; i < 200; ++i) {
+    assert(array[i] == grnxx::Int(12345));
   }
-  for (grnxx::Int i = 200; i < NUM_ROWS; ++i) {
-    assert(array[i] == 0);
+  for (size_t i = 200; i < ARRAY_SIZE; ++i) {
+    assert(array[i] == grnxx::Int(0));
   }
 
-  std::vector<grnxx::Int> values(NUM_ROWS);
-  for (grnxx::Int i = 0; i < NUM_ROWS; ++i) {
-    values[i] = mersenne_twister();
-    array[i] = values[i];
-    assert(array[i] == values[i]);
+  std::vector<grnxx::Int> values(ARRAY_SIZE);
+  for (size_t i = 0; i < ARRAY_SIZE; ++i) {
+    grnxx::Int value = grnxx::Int(mersenne_twister());
+    while (value.is_na()) {
+      value = grnxx::Int(mersenne_twister());
+    }
+    values[i] = grnxx::Int(value);
+    array.set(i, values[i]);
+    assert(array.get(i) == values[i]);
   }
-
-  for (grnxx::Int i = 0; i < NUM_ROWS; ++i) {
+  for (size_t i = 0; i < ARRAY_SIZE; ++i) {
     assert(array[i] == values[i]);
   }
 
@@ -149,8 +160,11 @@ void test_int() {
   array2 = std::move(array);
   assert(array.size() == 0);
   assert(array.capacity() == 0);
-  assert(array2.size() == NUM_ROWS);
-  assert(array2.capacity() == NUM_ROWS);
+  assert(array2.size() == ARRAY_SIZE);
+  assert(array2.capacity() == ARRAY_SIZE);
+  for (size_t i = 0; i < ARRAY_SIZE; ++i) {
+    assert(array2[i] == values[i]);
+  }
 }
 
 int main() {

  Modified: test/test_db.cpp (+20 -17)
===================================================================
--- test/test_db.cpp    2014-10-31 21:43:45 +0900 (2989bb1)
+++ test/test_db.cpp    2014-11-05 17:35:04 +0900 (b757eba)
@@ -22,54 +22,57 @@
 #include "grnxx/table.hpp"
 
 void test_db() {
-  grnxx::Error error;
-
   // Create a database with the default options.
-  auto db = grnxx::open_db(&error, "");
-  assert(db);
+  auto db = grnxx::open_db("");
   assert(db->num_tables() == 0);
 
   // Create a table named "Table_1".
-  auto table = db->create_table(&error, "Table_1");
-  assert(table);
+  auto table = db->create_table("Table_1");
   assert(table->name() == "Table_1");
   assert(db->num_tables() == 1);
-
   assert(db->get_table(0) == table);
-  assert(db->find_table(&error, "Table_1") == table);
+
+  assert(db->find_table("Table_1") == table);
+  assert(!db->find_table("Table_X"));
 
   // The following create_table() must fail because "Table_1" already exists.
-  assert(!db->create_table(&error, "Table_1"));
+  try {
+    db->create_table("Table_1");
+    assert(false);
+  } catch (...) {
+  }
 
   // Create tables named "Table_2" and "Table_3".
-  assert(db->create_table(&error, "Table_2"));
-  assert(db->create_table(&error, "Table_3"));
+  assert(db->create_table("Table_2"));
+  assert(db->create_table("Table_3"));
   assert(db->num_tables() == 3);
+  assert(db->get_table(0)->name() == "Table_1");
+  assert(db->get_table(1)->name() == "Table_2");
+  assert(db->get_table(2)->name() == "Table_3");
 
   // Remove "Table_2".
-  assert(db->remove_table(&error, "Table_2"));
+  db->remove_table("Table_2");
   assert(db->num_tables() == 2);
-
   assert(db->get_table(0)->name() == "Table_1");
   assert(db->get_table(1)->name() == "Table_3");
 
   // Recreate "Table_2".
-  assert(db->create_table(&error, "Table_2"));
+  assert(db->create_table("Table_2"));
 
   // Move "Table_3" to the next to "Table_2".
-  assert(db->reorder_table(&error, "Table_3", "Table_2"));
+  db->reorder_table("Table_3", "Table_2");
   assert(db->get_table(0)->name() == "Table_1");
   assert(db->get_table(1)->name() == "Table_2");
   assert(db->get_table(2)->name() == "Table_3");
 
   // Move "Table_3" to the head.
-  assert(db->reorder_table(&error, "Table_3", ""));
+  db->reorder_table("Table_3", "");
   assert(db->get_table(0)->name() == "Table_3");
   assert(db->get_table(1)->name() == "Table_1");
   assert(db->get_table(2)->name() == "Table_2");
 
   // Move "Table_2" to the next to "Table_3".
-  assert(db->reorder_table(&error, "Table_2", "Table_3"));
+  db->reorder_table("Table_2", "Table_3");
   assert(db->get_table(0)->name() == "Table_3");
   assert(db->get_table(1)->name() == "Table_2");
   assert(db->get_table(2)->name() == "Table_1");

  Modified: test/test_table.cpp (+460 -454)
===================================================================
--- test/test_table.cpp    2014-10-31 21:43:45 +0900 (ad33788)
+++ test/test_table.cpp    2014-11-05 17:35:04 +0900 (7d69b25)
@@ -24,487 +24,493 @@
 #include "grnxx/table.hpp"
 
 void test_table() {
-  grnxx::Error error;
-
   // Create a database with the default options.
-  auto db = grnxx::open_db(&error, "");
-  assert(db);
+  auto db = grnxx::open_db("");
 
   // Create a table named "Table".
-  auto table = db->create_table(&error, "Table");
-  assert(table);
+  auto table = db->create_table("Table");
   assert(table->db() == db.get());
   assert(table->name() == "Table");
   assert(table->num_columns() == 0);
   assert(!table->key_column());
   assert(table->num_rows() == 0);
-  assert(table->max_row_id() == 0);
-
-  // Create a column named "Column_1".
-  auto column = table->create_column(&error, "Column_1", grnxx::BOOL_DATA);
-  assert(column);
-  assert(column->name() == "Column_1");
-  assert(table->num_columns() == 1);
-
-  assert(table->get_column(0) == column);
-  assert(table->find_column(&error, "Column_1") == column);
-
-  // The following create_column() must fail because "Column_1" already exists.
-  assert(!table->create_column(&error, "Column_1", grnxx::BOOL_DATA));
-
-  // Create columns named "Column_2" and Column_3".
-  assert(table->create_column(&error, "Column_2", grnxx::BOOL_DATA));
-  assert(table->create_column(&error, "Column_3", grnxx::BOOL_DATA));
-  assert(table->num_columns() == 3);
-
-  // Remove "Column_2".
-  assert(table->remove_column(&error, "Column_2"));
-  assert(table->num_columns() == 2);
-
-  assert(table->get_column(0)->name() == "Column_1");
-  assert(table->get_column(1)->name() == "Column_3");
-
-  // Recreate "Column_2".
-  assert(table->create_column(&error, "Column_2", grnxx::BOOL_DATA));
-
-  // Move "Column_3" to the next to "Column_2".
-  assert(table->reorder_column(&error, "Column_3", "Column_2"));
-  assert(table->get_column(0)->name() == "Column_1");
-  assert(table->get_column(1)->name() == "Column_2");
-  assert(table->get_column(2)->name() == "Column_3");
-
-  // Move "Column_3" to the head.
-  assert(table->reorder_column(&error, "Column_3", ""));
-  assert(table->get_column(0)->name() == "Column_3");
-  assert(table->get_column(1)->name() == "Column_1");
-  assert(table->get_column(2)->name() == "Column_2");
-
-  // Move "Column_2" to the next to "Column3".
-  assert(table->reorder_column(&error, "Column_2", "Column_3"));
-  assert(table->get_column(0)->name() == "Column_3");
-  assert(table->get_column(1)->name() == "Column_2");
-  assert(table->get_column(2)->name() == "Column_1");
+  assert(table->max_row_id().is_na());
+  assert(table->is_empty());
+  assert(table->is_full());
+
+//  // Create a column named "Column_1".
+//  auto column = table->create_column(&error, "Column_1", grnxx::BOOL_DATA);
+//  assert(column);
+//  assert(column->name() == "Column_1");
+//  assert(table->num_columns() == 1);
+
+//  assert(table->get_column(0) == column);
+//  assert(table->find_column(&error, "Column_1") == column);
+
+//  // The following create_column() must fail because "Column_1" already exists.
+//  assert(!table->create_column(&error, "Column_1", grnxx::BOOL_DATA));
+
+//  // Create columns named "Column_2" and Column_3".
+//  assert(table->create_column(&error, "Column_2", grnxx::BOOL_DATA));
+//  assert(table->create_column(&error, "Column_3", grnxx::BOOL_DATA));
+//  assert(table->num_columns() == 3);
+
+//  // Remove "Column_2".
+//  assert(table->remove_column(&error, "Column_2"));
+//  assert(table->num_columns() == 2);
+
+//  assert(table->get_column(0)->name() == "Column_1");
+//  assert(table->get_column(1)->name() == "Column_3");
+
+//  // Recreate "Column_2".
+//  assert(table->create_column(&error, "Column_2", grnxx::BOOL_DATA));
+
+//  // Move "Column_3" to the next to "Column_2".
+//  assert(table->reorder_column(&error, "Column_3", "Column_2"));
+//  assert(table->get_column(0)->name() == "Column_1");
+//  assert(table->get_column(1)->name() == "Column_2");
+//  assert(table->get_column(2)->name() == "Column_3");
+
+//  // Move "Column_3" to the head.
+//  assert(table->reorder_column(&error, "Column_3", ""));
+//  assert(table->get_column(0)->name() == "Column_3");
+//  assert(table->get_column(1)->name() == "Column_1");
+//  assert(table->get_column(2)->name() == "Column_2");
+
+//  // Move "Column_2" to the next to "Column3".
+//  assert(table->reorder_column(&error, "Column_2", "Column_3"));
+//  assert(table->get_column(0)->name() == "Column_3");
+//  assert(table->get_column(1)->name() == "Column_2");
+//  assert(table->get_column(2)->name() == "Column_1");
 }
 
 void test_rows() {
-  grnxx::Error error;
-
   // Create a database with the default options.
-  auto db = grnxx::open_db(&error, "");
-  assert(db);
+  auto db = grnxx::open_db("");
 
   // Create a table named "Table".
-  auto table = db->create_table(&error, "Table");
-  assert(table);
+  auto table = db->create_table("Table");
 
   // Append the first row.
   grnxx::Int row_id;
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(row_id == 1);
+  row_id = table->insert_row();
+  assert(row_id == grnxx::Int(0));
   assert(table->num_rows() == 1);
-  assert(table->max_row_id() == 1);
-  assert(!table->test_row(&error, 0));
-  assert(table->test_row(&error, 1));
-  assert(!table->test_row(&error, 2));
+  assert(table->max_row_id() == row_id);
+  assert(!table->test_row(grnxx::Int(-1)));
+  assert(table->test_row(grnxx::Int(0)));
+  assert(!table->test_row(grnxx::Int(1)));
 
   // Append two more rows.
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(row_id == 3);
+  assert(table->insert_row() == grnxx::Int(1));
+  assert(table->insert_row() == grnxx::Int(2));
   assert(table->num_rows() == 3);
-  assert(table->max_row_id() == 3);
-  assert(!table->test_row(&error, 0));
-  assert(table->test_row(&error, 1));
-  assert(table->test_row(&error, 2));
-  assert(table->test_row(&error, 3));
-  assert(!table->test_row(&error, 4));
-
-  // Remove the 2nd row.
-  assert(table->remove_row(&error, 2));
+  assert(table->max_row_id() == grnxx::Int(2));
+  assert(table->test_row(grnxx::Int(0)));
+  assert(table->test_row(grnxx::Int(1)));
+  assert(table->test_row(grnxx::Int(2)));
+  assert(!table->test_row(grnxx::Int(3)));
+
+  // Remove the second row.
+  table->remove_row(grnxx::Int(1));
   assert(table->num_rows() == 2);
-  assert(table->max_row_id() == 3);
-  assert(!table->test_row(&error, 0));
-  assert(table->test_row(&error, 1));
-  assert(!table->test_row(&error, 2));
-  assert(table->test_row(&error, 3));
-  assert(!table->test_row(&error, 4));
-}
-
-void test_bitmap() {
-  constexpr int NUM_ROWS = 1 << 16;
-
-  grnxx::Error error;
-
-  // Create a database with the default options.
-  auto db = grnxx::open_db(&error, "");
-  assert(db);
-
-  // Create a table named "Table".
-  auto table = db->create_table(&error, "Table");
-  assert(table);
-
-  // Create rows.
-  for (int i = 0; i < NUM_ROWS; ++i) {
-    grnxx::Int row_id;
-    assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                             grnxx::Datum(), &row_id));
-    assert(row_id == (i + 1));
-  }
-  assert(table->num_rows() == NUM_ROWS);
-  assert(table->max_row_id() == NUM_ROWS);
-
-  // Remove all rows.
-  for (int i = 0; i < NUM_ROWS; ++i) {
-    grnxx::Int row_id = i + 1;
-    assert(table->remove_row(&error, row_id));
-  }
+  assert(table->max_row_id() == grnxx::Int(2));
+  assert(table->test_row(grnxx::Int(0)));
+  assert(!table->test_row(grnxx::Int(1)));
+  assert(table->test_row(grnxx::Int(2)));
+  assert(!table->test_row(grnxx::Int(3)));
+
+  // Remove the first row.
+  table->remove_row(grnxx::Int(0));
+  assert(table->num_rows() == 1);
+  assert(table->max_row_id() == grnxx::Int(2));
+  assert(!table->test_row(grnxx::Int(0)));
+  assert(!table->test_row(grnxx::Int(1)));
+  assert(table->test_row(grnxx::Int(2)));
+  assert(!table->test_row(grnxx::Int(3)));
+
+  // Remove the third row.
+  table->remove_row(grnxx::Int(2));
   assert(table->num_rows() == 0);
-  assert(table->max_row_id() == (grnxx::MIN_ROW_ID - 1));
-
-  // Recreate rows.
-  for (int i = 0; i < NUM_ROWS; ++i) {
-    grnxx::Int row_id;
-    assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                             grnxx::Datum(), &row_id));
-    assert(row_id == (i + 1));
-  }
-  assert(table->num_rows() == NUM_ROWS);
-  assert(table->max_row_id() == NUM_ROWS);
-
-  // Remove rows with odd IDs.
-  for (int i = 0; i < NUM_ROWS; i += 2) {
-    grnxx::Int row_id = i + 1;
-    assert(table->remove_row(&error, row_id));
-  }
-  assert(table->num_rows() == (NUM_ROWS / 2));
-  assert(table->max_row_id() == NUM_ROWS);
-
-  // Recreate rows.
-  for (int i = 0; i < NUM_ROWS; i += 2) {
-    grnxx::Int row_id;
-    assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                             grnxx::Datum(), &row_id));
-    assert(row_id == (i + 1));
-  }
-  assert(table->num_rows() == NUM_ROWS);
-  assert(table->max_row_id() == NUM_ROWS);
-
-  // Remove rows in reverse order.
-  for (int i = 0; i < NUM_ROWS; ++i) {
-    grnxx::Int row_id = NUM_ROWS - i;
-    assert(table->remove_row(&error, row_id));
-    assert(table->max_row_id() == (row_id - 1));
-  }
-
-  // Recreate rows.
-  for (int i = 0; i < NUM_ROWS; ++i) {
-    grnxx::Int row_id;
-    assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                             grnxx::Datum(), &row_id));
-    assert(row_id == (i + 1));
-  }
-  assert(table->num_rows() == NUM_ROWS);
-  assert(table->max_row_id() == NUM_ROWS);
+  assert(table->max_row_id().is_na());
+  assert(!table->test_row(grnxx::Int(0)));
+  assert(!table->test_row(grnxx::Int(1)));
+  assert(!table->test_row(grnxx::Int(2)));
+  assert(!table->test_row(grnxx::Int(3)));
 }
 
-void test_int_key() {
-  // TODO: find_row() is not supported yet.
-  grnxx::Error error;
-
-  // Create a database with the default options.
-  auto db = grnxx::open_db(&error, "");
-  assert(db);
-
-  // Create a table named "Table".
-  auto table = db->create_table(&error, "Table");
-  assert(table);
-
-  // Create a column named "Column".
-  auto column = table->create_column(&error, "Column", grnxx::INT_DATA);
-  assert(column);
-
-  // Append three rows.
-  grnxx::Int row_id;
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(column->set(&error, row_id, grnxx::Int(1)));
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(column->set(&error, row_id, grnxx::Int(10)));
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(column->set(&error, row_id, grnxx::Int(100)));
-
-  // Set key column.
-  assert(table->set_key_column(&error, "Column"));
-  assert(table->key_column() == column);
-
-  // Duplicate keys must be rejected.
-  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
-                            grnxx::Int(1), &row_id));
-  assert(row_id == 1);
-  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
-                            grnxx::Int(10), &row_id));
-  assert(row_id == 2);
-  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
-                            grnxx::Int(100), &row_id));
-  assert(row_id == 3);
-
-  // Append new keys.
-  grnxx::Datum datum;
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Int(2), &row_id));
-  assert(column->get(&error, row_id, &datum));
-  assert(datum.force_int() == 2);
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Int(20), &row_id));
-  assert(column->get(&error, row_id, &datum));
-  assert(datum.force_int() == 20);
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Int(200), &row_id));
-  assert(column->get(&error, row_id, &datum));
-  assert(datum.force_int() == 200);
-
-  // Find rows by key.
-  assert(table->find_row(&error, grnxx::Int(1)) == 1);
-  assert(table->find_row(&error, grnxx::Int(10)) == 2);
-  assert(table->find_row(&error, grnxx::Int(100)) == 3);
-  assert(table->find_row(&error, grnxx::Int(2)) == 4);
-  assert(table->find_row(&error, grnxx::Int(20)) == 5);
-  assert(table->find_row(&error, grnxx::Int(200)) == 6);
-
-  // Unset key column.
-  assert(table->unset_key_column(&error));
-  assert(!table->key_column());
-}
-
-void test_text_key() {
-  // TODO: find_row() is not supported yet.
-  grnxx::Error error;
-
-  // Create a database with the default options.
-  auto db = grnxx::open_db(&error, "");
-  assert(db);
-
-  // Create a table named "Table".
-  auto table = db->create_table(&error, "Table");
-  assert(table);
-
-  // Create a column named "Column".
-  auto column = table->create_column(&error, "Column", grnxx::TEXT_DATA);
-  assert(column);
-
-  // Append three rows.
-  grnxx::Int row_id;
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(column->set(&error, row_id, grnxx::Text("1")));
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(column->set(&error, row_id, grnxx::Text("12")));
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(column->set(&error, row_id, grnxx::Text("123")));
-
-  // Set key column.
-  assert(table->set_key_column(&error, "Column"));
-  assert(table->key_column() == column);
-
-  // Duplicate keys must be rejected.
-  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
-                            grnxx::Text("1"), &row_id));
-  assert(row_id == 1);
-  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
-                            grnxx::Text("12"), &row_id));
-  assert(row_id == 2);
-  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
-                            grnxx::Text("123"), &row_id));
-  assert(row_id == 3);
-
-  // Append new keys.
-  grnxx::Datum datum;
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Text("A"), &row_id));
-  assert(column->get(&error, row_id, &datum));
-  assert(datum.force_text() == "A");
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Text("AB"), &row_id));
-  assert(column->get(&error, row_id, &datum));
-  assert(datum.force_text() == "AB");
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Text("ABC"), &row_id));
-  assert(column->get(&error, row_id, &datum));
-  assert(datum.force_text() == "ABC");
-
-  // Find rows by key.
-  assert(table->find_row(&error, grnxx::Text("1")) == 1);
-  assert(table->find_row(&error, grnxx::Text("12")) == 2);
-  assert(table->find_row(&error, grnxx::Text("123")) == 3);
-  assert(table->find_row(&error, grnxx::Text("A")) == 4);
-  assert(table->find_row(&error, grnxx::Text("AB")) == 5);
-  assert(table->find_row(&error, grnxx::Text("ABC")) == 6);
-
-  // Unset key column.
-  assert(table->unset_key_column(&error));
-  assert(!table->key_column());
-}
-
-void test_cursor() {
-  grnxx::Error error;
-
-  // Create a database with the default options.
-  auto db = grnxx::open_db(&error, "");
-  assert(db);
-
-  // Create a table named "Table".
-  auto table = db->create_table(&error, "Table");
-  assert(table);
-
-  // Create a column named "Column".
-  assert(table->create_column(&error, "Column", grnxx::BOOL_DATA));
-
-  // Append three rows and remove the 2nd row.
-  grnxx::Int row_id;
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
-                           grnxx::Datum(), &row_id));
-  assert(table->remove_row(&error, 2));
-
-  // Create a cursor with the default options.
-  auto cursor = table->create_cursor(&error);
-  assert(cursor);
-
-  // Read records from the cursor.
-  grnxx::Array<grnxx::Record> records;
-  auto result = cursor->read(&error, 0, &records);
-  assert(result.is_ok);
-  assert(result.count == 0);
-
-  result = cursor->read(&error, 1, &records);
-  assert(result.is_ok);
-  assert(result.count == 1);
-  assert(records.size() == 1);
-  assert(records.get(0).row_id == 1);
-
-  result = cursor->read(&error, 2, &records);
-  assert(result.is_ok);
-  assert(result.count == 1);
-  assert(records.size() == 2);
-  assert(records.get(0).row_id == 1);
-  assert(records.get(1).row_id == 3);
-
-  records.clear();
-
-  // Create a cursor that scans a table in reverse order.
-  grnxx::CursorOptions cursor_options;
-  cursor_options.order_type = grnxx::REVERSE_ORDER;
-  cursor = table->create_cursor(&error, cursor_options);
-  assert(cursor);
-
-  result = cursor->read_all(&error, &records);
-  assert(result.is_ok);
-  assert(result.count == 2);
-  assert(records.size() == 2);
-  assert(records.get(0).row_id == 3);
-  assert(records.get(1).row_id == 1);
-
-  records.clear();
-
-  cursor = table->create_cursor(&error, cursor_options);
-  assert(cursor);
-
-  result = cursor->read(&error, 1, &records);
-  assert(result.is_ok);
-  assert(result.count == 1);
-  assert(records.size() == 1);
-  assert(records.get(0).row_id == 3);
-
-  result = cursor->read(&error, 2, &records);
-  assert(result.is_ok);
-  assert(result.count == 1);
-  assert(records.size() == 2);
-  assert(records.get(0).row_id == 3);
-  assert(records.get(1).row_id == 1);
-}
-
-void test_reference() {
-  grnxx::Error error;
-
-  // Create a database with the default options.
-  auto db = grnxx::open_db(&error, "");
-  assert(db);
-
-  // Create a table named "Table".
-  auto to_table = db->create_table(&error, "To");
-  assert(to_table);
-  auto from_table = db->create_table(&error, "From");
-  assert(from_table);
-
-  // Create a column named "Ref".
-  grnxx::ColumnOptions options;
-  options.ref_table_name = "To";
-  auto ref_column = from_table->create_column(&error, "Ref", grnxx::INT_DATA,
-                                              options);
-  assert(ref_column);
-
-  // Append rows.
-  grnxx::Int row_id;
-  assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID,
-                              grnxx::Datum(), &row_id));
-  assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID,
-                              grnxx::Datum(), &row_id));
-  assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID,
-                              grnxx::Datum(), &row_id));
-  assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID,
-                                grnxx::Datum(), &row_id));
-  assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID,
-                                grnxx::Datum(), &row_id));
-  assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID,
-                                grnxx::Datum(), &row_id));
-
-  assert(ref_column->set(&error, 1, grnxx::Int(1)));
-  assert(ref_column->set(&error, 2, grnxx::Int(2)));
-  assert(ref_column->set(&error, 3, grnxx::Int(2)));
-
-  assert(to_table->remove_row(&error, 1));
-
-  grnxx::Datum datum;
-  assert(ref_column->get(&error, 1, &datum));
-  assert(datum.type() == grnxx::INT_DATA);
-  assert(datum.force_int() == grnxx::NULL_ROW_ID);
-  assert(ref_column->get(&error, 2, &datum));
-  assert(datum.type() == grnxx::INT_DATA);
-  assert(datum.force_int() == 2);
-  assert(ref_column->get(&error, 3, &datum));
-  assert(datum.type() == grnxx::INT_DATA);
-  assert(datum.force_int() == 2);
-
-  assert(to_table->remove_row(&error, 2));
-
-  assert(ref_column->get(&error, 1, &datum));
-  assert(datum.type() == grnxx::INT_DATA);
-  assert(datum.force_int() == grnxx::NULL_ROW_ID);
-  assert(ref_column->get(&error, 2, &datum));
-  assert(datum.type() == grnxx::INT_DATA);
-  assert(datum.force_int() == grnxx::NULL_ROW_ID);
-  assert(ref_column->get(&error, 3, &datum));
-  assert(datum.type() == grnxx::INT_DATA);
-  assert(datum.force_int() == grnxx::NULL_ROW_ID);
-}
+//void test_bitmap() {
+//  constexpr int NUM_ROWS = 1 << 16;
+
+//  grnxx::Error error;
+
+//  // Create a database with the default options.
+//  auto db = grnxx::open_db(&error, "");
+//  assert(db);
+
+//  // Create a table named "Table".
+//  auto table = db->create_table(&error, "Table");
+//  assert(table);
+
+//  // Create rows.
+//  for (int i = 0; i < NUM_ROWS; ++i) {
+//    grnxx::Int row_id;
+//    assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                             grnxx::Datum(), &row_id));
+//    assert(row_id == (i + 1));
+//  }
+//  assert(table->num_rows() == NUM_ROWS);
+//  assert(table->max_row_id() == NUM_ROWS);
+
+//  // Remove all rows.
+//  for (int i = 0; i < NUM_ROWS; ++i) {
+//    grnxx::Int row_id = i + 1;
+//    assert(table->remove_row(&error, row_id));
+//  }
+//  assert(table->num_rows() == 0);
+//  assert(table->max_row_id() == (grnxx::MIN_ROW_ID - 1));
+
+//  // Recreate rows.
+//  for (int i = 0; i < NUM_ROWS; ++i) {
+//    grnxx::Int row_id;
+//    assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                             grnxx::Datum(), &row_id));
+//    assert(row_id == (i + 1));
+//  }
+//  assert(table->num_rows() == NUM_ROWS);
+//  assert(table->max_row_id() == NUM_ROWS);
+
+//  // Remove rows with odd IDs.
+//  for (int i = 0; i < NUM_ROWS; i += 2) {
+//    grnxx::Int row_id = i + 1;
+//    assert(table->remove_row(&error, row_id));
+//  }
+//  assert(table->num_rows() == (NUM_ROWS / 2));
+//  assert(table->max_row_id() == NUM_ROWS);
+
+//  // Recreate rows.
+//  for (int i = 0; i < NUM_ROWS; i += 2) {
+//    grnxx::Int row_id;
+//    assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                             grnxx::Datum(), &row_id));
+//    assert(row_id == (i + 1));
+//  }
+//  assert(table->num_rows() == NUM_ROWS);
+//  assert(table->max_row_id() == NUM_ROWS);
+
+//  // Remove rows in reverse order.
+//  for (int i = 0; i < NUM_ROWS; ++i) {
+//    grnxx::Int row_id = NUM_ROWS - i;
+//    assert(table->remove_row(&error, row_id));
+//    assert(table->max_row_id() == (row_id - 1));
+//  }
+
+//  // Recreate rows.
+//  for (int i = 0; i < NUM_ROWS; ++i) {
+//    grnxx::Int row_id;
+//    assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                             grnxx::Datum(), &row_id));
+//    assert(row_id == (i + 1));
+//  }
+//  assert(table->num_rows() == NUM_ROWS);
+//  assert(table->max_row_id() == NUM_ROWS);
+//}
+
+//void test_int_key() {
+//  // TODO: find_row() is not supported yet.
+//  grnxx::Error error;
+
+//  // Create a database with the default options.
+//  auto db = grnxx::open_db(&error, "");
+//  assert(db);
+
+//  // Create a table named "Table".
+//  auto table = db->create_table(&error, "Table");
+//  assert(table);
+
+//  // Create a column named "Column".
+//  auto column = table->create_column(&error, "Column", grnxx::INT_DATA);
+//  assert(column);
+
+//  // Append three rows.
+//  grnxx::Int row_id;
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Datum(), &row_id));
+//  assert(column->set(&error, row_id, grnxx::Int(1)));
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Datum(), &row_id));
+//  assert(column->set(&error, row_id, grnxx::Int(10)));
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Datum(), &row_id));
+//  assert(column->set(&error, row_id, grnxx::Int(100)));
+
+//  // Set key column.
+//  assert(table->set_key_column(&error, "Column"));
+//  assert(table->key_column() == column);
+
+//  // Duplicate keys must be rejected.
+//  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                            grnxx::Int(1), &row_id));
+//  assert(row_id == 1);
+//  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                            grnxx::Int(10), &row_id));
+//  assert(row_id == 2);
+//  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                            grnxx::Int(100), &row_id));
+//  assert(row_id == 3);
+
+//  // Append new keys.
+//  grnxx::Datum datum;
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Int(2), &row_id));
+//  assert(column->get(&error, row_id, &datum));
+//  assert(datum.force_int() == 2);
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Int(20), &row_id));
+//  assert(column->get(&error, row_id, &datum));
+//  assert(datum.force_int() == 20);
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Int(200), &row_id));
+//  assert(column->get(&error, row_id, &datum));
+//  assert(datum.force_int() == 200);
+
+//  // Find rows by key.
+//  assert(table->find_row(&error, grnxx::Int(1)) == 1);
+//  assert(table->find_row(&error, grnxx::Int(10)) == 2);
+//  assert(table->find_row(&error, grnxx::Int(100)) == 3);
+//  assert(table->find_row(&error, grnxx::Int(2)) == 4);
+//  assert(table->find_row(&error, grnxx::Int(20)) == 5);
+//  assert(table->find_row(&error, grnxx::Int(200)) == 6);
+
+//  // Unset key column.
+//  assert(table->unset_key_column(&error));
+//  assert(!table->key_column());
+//}
+
+//void test_text_key() {
+//  // TODO: find_row() is not supported yet.
+//  grnxx::Error error;
+
+//  // Create a database with the default options.
+//  auto db = grnxx::open_db(&error, "");
+//  assert(db);
+
+//  // Create a table named "Table".
+//  auto table = db->create_table(&error, "Table");
+//  assert(table);
+
+//  // Create a column named "Column".
+//  auto column = table->create_column(&error, "Column", grnxx::TEXT_DATA);
+//  assert(column);
+
+//  // Append three rows.
+//  grnxx::Int row_id;
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Datum(), &row_id));
+//  assert(column->set(&error, row_id, grnxx::Text("1")));
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Datum(), &row_id));
+//  assert(column->set(&error, row_id, grnxx::Text("12")));
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Datum(), &row_id));
+//  assert(column->set(&error, row_id, grnxx::Text("123")));
+
+//  // Set key column.
+//  assert(table->set_key_column(&error, "Column"));
+//  assert(table->key_column() == column);
+
+//  // Duplicate keys must be rejected.
+//  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                            grnxx::Text("1"), &row_id));
+//  assert(row_id == 1);
+//  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                            grnxx::Text("12"), &row_id));
+//  assert(row_id == 2);
+//  assert(!table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                            grnxx::Text("123"), &row_id));
+//  assert(row_id == 3);
+
+//  // Append new keys.
+//  grnxx::Datum datum;
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Text("A"), &row_id));
+//  assert(column->get(&error, row_id, &datum));
+//  assert(datum.force_text() == "A");
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Text("AB"), &row_id));
+//  assert(column->get(&error, row_id, &datum));
+//  assert(datum.force_text() == "AB");
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Text("ABC"), &row_id));
+//  assert(column->get(&error, row_id, &datum));
+//  assert(datum.force_text() == "ABC");
+
+//  // Find rows by key.
+//  assert(table->find_row(&error, grnxx::Text("1")) == 1);
+//  assert(table->find_row(&error, grnxx::Text("12")) == 2);
+//  assert(table->find_row(&error, grnxx::Text("123")) == 3);
+//  assert(table->find_row(&error, grnxx::Text("A")) == 4);
+//  assert(table->find_row(&error, grnxx::Text("AB")) == 5);
+//  assert(table->find_row(&error, grnxx::Text("ABC")) == 6);
+
+//  // Unset key column.
+//  assert(table->unset_key_column(&error));
+//  assert(!table->key_column());
+//}
+
+//void test_cursor() {
+//  grnxx::Error error;
+
+//  // Create a database with the default options.
+//  auto db = grnxx::open_db(&error, "");
+//  assert(db);
+
+//  // Create a table named "Table".
+//  auto table = db->create_table(&error, "Table");
+//  assert(table);
+
+//  // Create a column named "Column".
+//  assert(table->create_column(&error, "Column", grnxx::BOOL_DATA));
+
+//  // Append three rows and remove the 2nd row.
+//  grnxx::Int row_id;
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Datum(), &row_id));
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Datum(), &row_id));
+//  assert(table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                           grnxx::Datum(), &row_id));
+//  assert(table->remove_row(&error, 2));
+
+//  // Create a cursor with the default options.
+//  auto cursor = table->create_cursor(&error);
+//  assert(cursor);
+
+//  // Read records from the cursor.
+//  grnxx::Array<grnxx::Record> records;
+//  auto result = cursor->read(&error, 0, &records);
+//  assert(result.is_ok);
+//  assert(result.count == 0);
+
+//  result = cursor->read(&error, 1, &records);
+//  assert(result.is_ok);
+//  assert(result.count == 1);
+//  assert(records.size() == 1);
+//  assert(records.get(0).row_id == 1);
+
+//  result = cursor->read(&error, 2, &records);
+//  assert(result.is_ok);
+//  assert(result.count == 1);
+//  assert(records.size() == 2);
+//  assert(records.get(0).row_id == 1);
+//  assert(records.get(1).row_id == 3);
+
+//  records.clear();
+
+//  // Create a cursor that scans a table in reverse order.
+//  grnxx::CursorOptions cursor_options;
+//  cursor_options.order_type = grnxx::REVERSE_ORDER;
+//  cursor = table->create_cursor(&error, cursor_options);
+//  assert(cursor);
+
+//  result = cursor->read_all(&error, &records);
+//  assert(result.is_ok);
+//  assert(result.count == 2);
+//  assert(records.size() == 2);
+//  assert(records.get(0).row_id == 3);
+//  assert(records.get(1).row_id == 1);
+
+//  records.clear();
+
+//  cursor = table->create_cursor(&error, cursor_options);
+//  assert(cursor);
+
+//  result = cursor->read(&error, 1, &records);
+//  assert(result.is_ok);
+//  assert(result.count == 1);
+//  assert(records.size() == 1);
+//  assert(records.get(0).row_id == 3);
+
+//  result = cursor->read(&error, 2, &records);
+//  assert(result.is_ok);
+//  assert(result.count == 1);
+//  assert(records.size() == 2);
+//  assert(records.get(0).row_id == 3);
+//  assert(records.get(1).row_id == 1);
+//}
+
+//void test_reference() {
+//  grnxx::Error error;
+
+//  // Create a database with the default options.
+//  auto db = grnxx::open_db(&error, "");
+//  assert(db);
+
+//  // Create a table named "Table".
+//  auto to_table = db->create_table(&error, "To");
+//  assert(to_table);
+//  auto from_table = db->create_table(&error, "From");
+//  assert(from_table);
+
+//  // Create a column named "Ref".
+//  grnxx::ColumnOptions options;
+//  options.ref_table_name = "To";
+//  auto ref_column = from_table->create_column(&error, "Ref", grnxx::INT_DATA,
+//                                              options);
+//  assert(ref_column);
+
+//  // Append rows.
+//  grnxx::Int row_id;
+//  assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                              grnxx::Datum(), &row_id));
+//  assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                              grnxx::Datum(), &row_id));
+//  assert(to_table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                              grnxx::Datum(), &row_id));
+//  assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                                grnxx::Datum(), &row_id));
+//  assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                                grnxx::Datum(), &row_id));
+//  assert(from_table->insert_row(&error, grnxx::NULL_ROW_ID,
+//                                grnxx::Datum(), &row_id));
+
+//  assert(ref_column->set(&error, 1, grnxx::Int(1)));
+//  assert(ref_column->set(&error, 2, grnxx::Int(2)));
+//  assert(ref_column->set(&error, 3, grnxx::Int(2)));
+
+//  assert(to_table->remove_row(&error, 1));
+
+//  grnxx::Datum datum;
+//  assert(ref_column->get(&error, 1, &datum));
+//  assert(datum.type() == grnxx::INT_DATA);
+//  assert(datum.force_int() == grnxx::NULL_ROW_ID);
+//  assert(ref_column->get(&error, 2, &datum));
+//  assert(datum.type() == grnxx::INT_DATA);
+//  assert(datum.force_int() == 2);
+//  assert(ref_column->get(&error, 3, &datum));
+//  assert(datum.type() == grnxx::INT_DATA);
+//  assert(datum.force_int() == 2);
+
+//  assert(to_table->remove_row(&error, 2));
+
+//  assert(ref_column->get(&error, 1, &datum));
+//  assert(datum.type() == grnxx::INT_DATA);
+//  assert(datum.force_int() == grnxx::NULL_ROW_ID);
+//  assert(ref_column->get(&error, 2, &datum));
+//  assert(datum.type() == grnxx::INT_DATA);
+//  assert(datum.force_int() == grnxx::NULL_ROW_ID);
+//  assert(ref_column->get(&error, 3, &datum));
+//  assert(datum.type() == grnxx::INT_DATA);
+//  assert(datum.force_int() == grnxx::NULL_ROW_ID);
+//}
 
 int main() {
   test_table();
-  test_rows();
-  test_bitmap();
-  test_int_key();
-  test_text_key();
-  test_cursor();
-  test_reference();
+//  test_rows();
+//  test_bitmap();
+//  test_int_key();
+//  test_text_key();
+//  test_cursor();
+//  test_reference();
   return 0;
 }




More information about the Groonga-commit mailing list
Back to archive index