[Groonga-commit] groonga/grngo at ba4fc4f [master] Copy files from groonga/grnxx/go3/gnx.

Back to archive index

susumu.yata null+****@clear*****
Fri Jun 19 14:34:28 JST 2015


susumu.yata	2015-06-19 14:34:28 +0900 (Fri, 19 Jun 2015)

  New Revision: ba4fc4ff7efc4beb4018e9d9489a5dcee67c96f7
  https://github.com/groonga/grngo/commit/ba4fc4ff7efc4beb4018e9d9489a5dcee67c96f7

  Message:
    Copy files from groonga/grnxx/go3/gnx.
    
    * TODO
     * The package name must be changed to grngo.
     * gnx.go is not requried.
     * GetValues() should be removed.
     * The prefix "Grn" should be removed.

  Added files:
    gnx.go
    grn.go
    grn_cgo.c
    grn_cgo.h
    grn_test.go
    options.go

  Added: gnx.go (+87 -0) 100644
===================================================================
--- /dev/null
+++ gnx.go    2015-06-19 14:34:28 +0900 (bc7b068)
@@ -0,0 +1,87 @@
+package gnx
+
+/*
+#cgo pkg-config: groonga
+*/
+import "C"
+
+import (
+	"fmt"
+	"math"
+)
+
+// -- Data types --
+
+type Bool uint8
+type Int int64
+type Float float64
+type GeoPoint struct{ Latitude, Longitude int32 }
+type Text []byte
+
+//type BoolVector []Bool
+//type IntVector []Int
+//type FloatVector []Float
+//type GeoPointVector []GeoPoint
+//type TextVector []Text
+
+const (
+	True  = Bool(3)
+	False = Bool(0)
+)
+
+func NullBool() Bool         { return Bool(1) }
+func NullInt() Int           { return Int(math.MinInt64) }
+func NullFloat() Float       { return Float(math.NaN()) }
+func NullGeoPoint() GeoPoint { return GeoPoint{math.MinInt32, math.MinInt32} }
+func NullText() Text         { return nil }
+
+//func NullBoolVector() BoolVector         { return nil }
+//func NullIntVector() IntVector           { return nil }
+//func NullFloatVector() FloatVector       { return nil }
+//func NullGeoPointVector() GeoPointVector { return nil }
+//func NullTextVector() TextVector         { return nil }
+
+type TypeID int
+
+const (
+	VoidID = TypeID(iota)
+	BoolID
+	IntID
+	FloatID
+	GeoPointID
+	TextID
+//	BoolVectorID
+//	IntVectorID
+//	FloatVectorID
+//	GeoPointVectorID
+//	TextVectorID
+)
+
+func (id TypeID) String() string {
+	switch id {
+	case VoidID:
+		return "Void"
+	case BoolID:
+		return "Bool"
+	case IntID:
+		return "Int"
+	case FloatID:
+		return "Float"
+	case GeoPointID:
+		return "GeoPoint"
+	case TextID:
+		return "Text"
+//	case BoolVectorID:
+//		return "BoolVector"
+//	case IntVectorID:
+//		return "IntVector"
+//	case FloatVectorID:
+//		return "FloatVector"
+//	case GeoPointVectorID:
+//		return "GeoPointVector"
+//	case TextVectorID:
+//		return "TextVector"
+	default:
+		return fmt.Sprintf("TypeID(%d)", id)
+	}
+}

  Added: grn.go (+1219 -0) 100644
===================================================================
--- /dev/null
+++ grn.go    2015-06-19 14:34:28 +0900 (06024c7)
@@ -0,0 +1,1219 @@
+package gnx
+
+/*
+#cgo pkg-config: groonga
+#include "grn_cgo.h"
+*/
+import "C"
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+	"unsafe"
+)
+
+// -- Groonga --
+
+// grnInitCount is a counter for automatically initializing and finalizing
+// Groonga.
+var grnInitCount = 0
+
+// DisableGrnInitCount() disables grnInitCount.
+// This is useful if you want to manyally initialize and finalize Groonga.
+func DisableGrnInitCount() {
+	grnInitCount = -1
+}
+
+// GrnInit() initializes Groonga if needed.
+// grnInitCount is incremented and when it changes from 0 to 1, Groonga is
+// initialized.
+func GrnInit() error {
+	switch grnInitCount {
+	case -1: // Disabled.
+		return nil
+	case 0:
+		if rc := C.grn_init(); rc != C.GRN_SUCCESS {
+			return fmt.Errorf("grn_init() failed: rc = %d", rc)
+		}
+	}
+	grnInitCount++
+	return nil
+}
+
+// GrnFin() finalizes Groonga if needed.
+// grnInitCount is decremented and when it changes from 1 to 0, Groonga is
+// finalized.
+func GrnFin() error {
+	switch grnInitCount {
+	case -1: // Disabled.
+		return nil
+	case 0:
+		return fmt.Errorf("Groonga is not initialized yet")
+	case 1:
+		if rc := C.grn_fin(); rc != C.GRN_SUCCESS {
+			return fmt.Errorf("grn_fin() failed: rc = %d", rc)
+		}
+	}
+	grnInitCount--
+	return nil
+}
+
+// openGrnCtx() allocates memory for grn_ctx and initializes it.
+func openGrnCtx() (*C.grn_ctx, error) {
+	if err := GrnInit(); err != nil {
+		return nil, err
+	}
+	ctx := C.grn_ctx_open(0)
+	if ctx == nil {
+		GrnFin()
+		return nil, fmt.Errorf("grn_ctx_open() failed")
+	}
+	return ctx, nil
+}
+
+// closeGrnCtx() finalizes grn_ctx and frees allocated memory.
+func closeGrnCtx(ctx *C.grn_ctx) error {
+	rc := C.grn_ctx_close(ctx)
+	GrnFin()
+	if rc != C.GRN_SUCCESS {
+		return fmt.Errorf("grn_ctx_close() failed: rc = %d", rc)
+	}
+	return nil
+}
+
+// -- GrnDB --
+
+type GrnDB struct {
+	ctx    *C.grn_ctx
+	obj    *C.grn_obj
+	tables map[string]*GrnTable
+}
+
+// newGrnDB() creates a new GrnDB object.
+func newGrnDB(ctx *C.grn_ctx, obj *C.grn_obj) *GrnDB {
+	return &GrnDB{ctx, obj, make(map[string]*GrnTable)}
+}
+
+// CreateGrnDB() creates a Groonga database and returns a handle to it.
+// A temporary database is created if path is empty.
+func CreateGrnDB(path string) (*GrnDB, error) {
+	ctx, err := openGrnCtx()
+	if err != nil {
+		return nil, err
+	}
+	var cPath *C.char
+	if path != "" {
+		cPath = C.CString(path)
+		defer C.free(unsafe.Pointer(cPath))
+	}
+	obj := C.grn_db_create(ctx, cPath, nil)
+	if obj == nil {
+		closeGrnCtx(ctx)
+		errMsg := C.GoString(&ctx.errbuf[0])
+		return nil, fmt.Errorf("grn_db_create() failed: err = %s", errMsg)
+	}
+	return newGrnDB(ctx, obj), nil
+}
+
+// OpenGrnDB() opens an existing Groonga database and returns a handle.
+func OpenGrnDB(path string) (*GrnDB, error) {
+	ctx, err := openGrnCtx()
+	if err != nil {
+		return nil, err
+	}
+	cPath := C.CString(path)
+	defer C.free(unsafe.Pointer(cPath))
+	obj := C.grn_db_open(ctx, cPath)
+	if obj == nil {
+		closeGrnCtx(ctx)
+		errMsg := C.GoString(&ctx.errbuf[0])
+		return nil, fmt.Errorf("grn_db_open() failed: err = %s", errMsg)
+	}
+	return newGrnDB(ctx, obj), nil
+}
+
+// Close() closes a handle.
+func (db *GrnDB) Close() error {
+  rc := C.grn_obj_close(db.ctx, db.obj)
+  if rc != C.GRN_SUCCESS {
+    closeGrnCtx(db.ctx)
+    return fmt.Errorf("grn_obj_close() failed: rc = %d", rc)
+  }
+	return closeGrnCtx(db.ctx)
+}
+
+// Send() sends a raw command.
+// The given command must be well-formed.
+func (db *GrnDB) Send(command string) error {
+	commandBytes := []byte(command)
+	var cCommand *C.char
+	if len(commandBytes) != 0 {
+		cCommand = (*C.char)(unsafe.Pointer(&commandBytes[0]))
+	}
+	rc := C.grn_ctx_send(db.ctx, cCommand, C.uint(len(commandBytes)), 0)
+	switch {
+	case rc != C.GRN_SUCCESS:
+		errMsg := C.GoString(&db.ctx.errbuf[0])
+		return fmt.Errorf("grn_ctx_send() failed: rc = %d, err = %s", rc, errMsg)
+	case db.ctx.rc != C.GRN_SUCCESS:
+		errMsg := C.GoString(&db.ctx.errbuf[0])
+		return fmt.Errorf("grn_ctx_send() failed: ctx.rc = %d, err = %s",
+			db.ctx.rc, errMsg)
+	}
+	return nil
+}
+
+// SendEx() sends a command with separated options.
+func (db *GrnDB) SendEx(name string, options map[string]string) error {
+	if name == "" {
+		return fmt.Errorf("invalid command: name = <%s>", name)
+	}
+	for _, r := range name {
+		if (r != '_') && (r < 'a') && (r > 'z') {
+			return fmt.Errorf("invalid command: name = <%s>", name)
+		}
+	}
+	commandParts := []string{name}
+	for key, value := range options {
+		if key == "" {
+			return fmt.Errorf("invalid option: key = <%s>", key)
+		}
+		for _, r := range key {
+			if (r != '_') && (r < 'a') && (r > 'z') {
+				return fmt.Errorf("invalid option: key = <%s>", key)
+			}
+		}
+		value = strings.Replace(value, "\\", "\\\\", -1)
+		value = strings.Replace(value, "'", "\\'", -1)
+		commandParts = append(commandParts, fmt.Sprintf("--%s '%s'", key, value))
+	}
+	return db.Send(strings.Join(commandParts, " "))
+}
+
+// Recv() receives the result of commands sent by Send().
+func (db *GrnDB) Recv() ([]byte, error) {
+	var resultBuffer *C.char
+	var resultLength C.uint
+	var flags C.int
+	rc := C.grn_ctx_recv(db.ctx, &resultBuffer, &resultLength, &flags)
+	switch {
+	case rc != C.GRN_SUCCESS:
+		errMsg := C.GoString(&db.ctx.errbuf[0])
+		return nil, fmt.Errorf(
+			"grn_ctx_recv() failed: rc = %d, err = %s", rc, errMsg)
+	case db.ctx.rc != C.GRN_SUCCESS:
+		errMsg := C.GoString(&db.ctx.errbuf[0])
+		return nil, fmt.Errorf(
+			"grn_ctx_recv() failed: ctx.rc = %d, err = %s", db.ctx.rc, errMsg)
+	}
+	result := C.GoBytes(unsafe.Pointer(resultBuffer), C.int(resultLength))
+	return result, nil
+}
+
+// Query() sends a raw command and receive the result.
+func (db *GrnDB) Query(command string) ([]byte, error) {
+	if err := db.Send(command); err != nil {
+		result, _ := db.Recv()
+		return result, err
+	}
+	return db.Recv()
+}
+
+// QueryEx() sends a command with separated options and receives the result.
+func (db *GrnDB) QueryEx(name string, options map[string]string) (
+	[]byte, error) {
+	if err := db.SendEx(name, options); err != nil {
+		result, _ := db.Recv()
+		return result, err
+	}
+	return db.Recv()
+}
+
+// CreateTable() creates a table.
+func (db *GrnDB) CreateTable(name string, options *TableOptions) (*GrnTable, error) {
+	if options == nil {
+		options = NewTableOptions()
+	}
+	optionsMap := make(map[string]string)
+	optionsMap["name"] = name
+	switch options.TableType {
+	case ArrayTable:
+		optionsMap["flags"] = "TABLE_NO_KEY"
+	case HashTable:
+		optionsMap["flags"] = "TABLE_HASH_KEY"
+	case PatTable:
+		optionsMap["flags"] = "TABLE_PAT_KEY"
+	case DatTable:
+		optionsMap["flags"] = "TABLE_DAT_KEY"
+	default:
+		return nil, fmt.Errorf("undefined table type: options = %+v", options)
+	}
+	if options.WithSIS {
+		optionsMap["flags"] += "|KEY_WITH_SIS"
+	}
+	if options.KeyType != "" {
+		switch options.KeyType {
+		case "Bool":
+			optionsMap["key_type"] = "Bool"
+		case "Int":
+			optionsMap["key_type"] = "Int64"
+		case "Float":
+			optionsMap["key_type"] = "Float"
+		case "GeoPoint":
+			optionsMap["key_type"] = "WGS84GeoPoint"
+		case "Text":
+			optionsMap["key_type"] = "ShortText"
+		default:
+			if _, err := db.FindTable(options.KeyType); err != nil {
+				return nil, fmt.Errorf("unsupported key type: options = %+v", options)
+			}
+			optionsMap["key_type"] = options.KeyType
+		}
+	}
+	if options.ValueType != "" {
+		switch options.ValueType {
+		case "Bool":
+			optionsMap["value_type"] = "Bool"
+		case "Int":
+			optionsMap["value_type"] = "Int64"
+		case "Float":
+			optionsMap["value_type"] = "Float"
+		case "GeoPoint":
+			optionsMap["value_type"] = "WGS84GeoPoint"
+		default:
+			if _, err := db.FindTable(options.ValueType); err != nil {
+				return nil, fmt.Errorf("unsupported value type: options = %+v",
+					options)
+			}
+			optionsMap["value_type"] = options.ValueType
+		}
+	}
+	if options.DefaultTokenizer != "" {
+		optionsMap["default_tokenizer"] = options.DefaultTokenizer
+	}
+	if options.Normalizer != "" {
+		optionsMap["normalizer"] = options.Normalizer
+	}
+	if len(options.TokenFilters) != 0 {
+		optionsMap["token_filters"] = strings.Join(options.TokenFilters, ",")
+	}
+	bytes, err := db.QueryEx("table_create", optionsMap)
+	if err != nil {
+		return nil, err
+	}
+	if string(bytes) != "true" {
+		return nil, fmt.Errorf("table_create failed: name = <%s>", name)
+	}
+	return db.FindTable(name)
+}
+
+// FindTable() finds a table.
+func (db *GrnDB) FindTable(name string) (*GrnTable, error) {
+	if table, ok := db.tables[name]; ok {
+		return table, nil
+	}
+	nameBytes := []byte(name)
+	var cName *C.char
+	if len(nameBytes) != 0 {
+		cName = (*C.char)(unsafe.Pointer(&nameBytes[0]))
+	}
+	obj := C.grn_cgo_find_table(db.ctx, cName, C.int(len(nameBytes)))
+	if obj == nil {
+		return nil, fmt.Errorf("table not found: name = <%s>", name)
+	}
+	var keyInfo C.grn_cgo_type_info
+	if ok := C.grn_cgo_table_get_key_info(db.ctx, obj, &keyInfo); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_table_get_key_info() failed: name = <%s>",
+			name)
+	}
+	// Check the key type.
+	var keyType TypeID
+	switch keyInfo.data_type {
+	case C.GRN_DB_VOID:
+		keyType = VoidID
+	case C.GRN_DB_BOOL:
+		keyType = BoolID
+	case C.GRN_DB_INT64:
+		keyType = IntID
+	case C.GRN_DB_FLOAT:
+		keyType = FloatID
+	case C.GRN_DB_WGS84_GEO_POINT:
+		keyType = GeoPointID
+	case C.GRN_DB_SHORT_TEXT:
+		keyType = TextID
+	default:
+		return nil, fmt.Errorf("unsupported key type: data_type = %d",
+			keyInfo.data_type)
+	}
+	// Find the destination table if the key is table reference.
+	var keyTable *GrnTable
+	if keyInfo.ref_table != nil {
+		if keyType == VoidID {
+			return nil, fmt.Errorf("reference to void: name = <%s>", name)
+		}
+		cKeyTableName := C.grn_cgo_table_get_name(db.ctx, keyInfo.ref_table)
+		if cKeyTableName == nil {
+			return nil, fmt.Errorf("grn_cgo_table_get_name() failed")
+		}
+		defer C.free(unsafe.Pointer(cKeyTableName))
+		var err error
+		keyTable, err = db.FindTable(C.GoString(cKeyTableName))
+		if err != nil {
+			return nil, err
+		}
+	}
+	var valueInfo C.grn_cgo_type_info
+	if ok := C.grn_cgo_table_get_value_info(db.ctx, obj, &valueInfo); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_table_get_value_info() failed: name = <%s>",
+			name)
+	}
+	// Check the value type.
+	var valueType TypeID
+	switch valueInfo.data_type {
+	case C.GRN_DB_VOID:
+		valueType = VoidID
+	case C.GRN_DB_BOOL:
+		valueType = BoolID
+	case C.GRN_DB_INT64:
+		valueType = IntID
+	case C.GRN_DB_FLOAT:
+		valueType = FloatID
+	case C.GRN_DB_WGS84_GEO_POINT:
+		valueType = GeoPointID
+	case C.GRN_DB_SHORT_TEXT:
+		valueType = TextID
+	default:
+		return nil, fmt.Errorf("unsupported value type: data_type = %d",
+			valueInfo.data_type)
+	}
+	// Find the destination table if the value is table reference.
+	var valueTable *GrnTable
+	if valueInfo.ref_table != nil {
+		if valueType == VoidID {
+			return nil, fmt.Errorf("reference to void: name = <%s>", name)
+		}
+		cValueTableName := C.grn_cgo_table_get_name(db.ctx, valueInfo.ref_table)
+		if cValueTableName == nil {
+			return nil, fmt.Errorf("grn_cgo_table_get_name() failed")
+		}
+		defer C.free(unsafe.Pointer(cValueTableName))
+		var err error
+		valueTable, err = db.FindTable(C.GoString(cValueTableName))
+		if err != nil {
+			return nil, err
+		}
+	}
+	table := newGrnTable(db, obj, name, keyType, keyTable, valueType, valueTable)
+	db.tables[name] = table
+	return table, nil
+}
+
+// InsertRow() inserts a row.
+func (db *GrnDB) InsertRow(tableName string, key interface{}) (bool, Int, error) {
+	table, err := db.FindTable(tableName)
+	if err != nil {
+		return false, NullInt(), err
+	}
+	return table.InsertRow(key)
+}
+
+// CreateColumn() creates a column.
+func (db *GrnDB) CreateColumn(tableName, columnName string, valueType string,
+	options *ColumnOptions) (*GrnColumn, error) {
+	table, err := db.FindTable(tableName)
+	if err != nil {
+		return nil, err
+	}
+	return table.CreateColumn(columnName, valueType, options)
+}
+
+// FindColumn() finds a column.
+func (db *GrnDB) FindColumn(tableName, columnName string) (*GrnColumn, error) {
+	table, err := db.FindTable(tableName)
+	if err != nil {
+		return nil, err
+	}
+	return table.FindColumn(columnName)
+}
+
+// -- GrnTable --
+
+type GrnTable struct {
+	db         *GrnDB
+	obj        *C.grn_obj
+	name       string
+	keyType    TypeID
+	keyTable   *GrnTable
+	valueType  TypeID
+	valueTable *GrnTable
+	columns    map[string]*GrnColumn
+}
+
+// newGrnTable() creates a new GrnTable object.
+func newGrnTable(db *GrnDB, obj *C.grn_obj, name string, keyType TypeID,
+	keyTable *GrnTable, valueType TypeID, valueTable *GrnTable) *GrnTable {
+	var table GrnTable
+	table.db = db
+	table.obj = obj
+	table.name = name
+	table.keyType = keyType
+	table.keyTable = keyTable
+	table.valueType = valueType
+	table.valueTable = valueTable
+	table.columns = make(map[string]*GrnColumn)
+	return &table
+}
+
+// insertVoid() inserts an empty row.
+func (table *GrnTable) insertVoid() (bool, Int, error) {
+	if table.keyType != VoidID {
+		return false, NullInt(), fmt.Errorf("key type conflict")
+	}
+	rowInfo := C.grn_cgo_table_insert_void(table.db.ctx, table.obj)
+	if rowInfo.id == C.GRN_ID_NIL {
+		return false, NullInt(), fmt.Errorf("grn_cgo_table_insert_void() failed")
+	}
+	return rowInfo.inserted == C.GRN_TRUE, Int(rowInfo.id), nil
+}
+
+// insertBool() inserts a row with Bool key.
+func (table *GrnTable) insertBool(key Bool) (bool, Int, error) {
+	if table.keyType != BoolID {
+		return false, NullInt(), fmt.Errorf("key type conflict")
+	}
+	grnKey := C.grn_bool(C.GRN_FALSE)
+	if key == True {
+		grnKey = C.grn_bool(C.GRN_TRUE)
+	}
+	rowInfo := C.grn_cgo_table_insert_bool(table.db.ctx, table.obj, grnKey)
+	if rowInfo.id == C.GRN_ID_NIL {
+		return false, NullInt(), fmt.Errorf("grn_cgo_table_insert_bool() failed")
+	}
+	return rowInfo.inserted == C.GRN_TRUE, Int(rowInfo.id), nil
+}
+
+// insertInt() inserts a row with Int key.
+func (table *GrnTable) insertInt(key Int) (bool, Int, error) {
+	if table.keyType != IntID {
+		return false, NullInt(), fmt.Errorf("key type conflict")
+	}
+	grnKey := C.int64_t(key)
+	rowInfo := C.grn_cgo_table_insert_int(table.db.ctx, table.obj, grnKey)
+	if rowInfo.id == C.GRN_ID_NIL {
+		return false, NullInt(), fmt.Errorf("grn_cgo_table_insert_int() failed")
+	}
+	return rowInfo.inserted == C.GRN_TRUE, Int(rowInfo.id), nil
+}
+
+// insertFloat() inserts a row with Float key.
+func (table *GrnTable) insertFloat(key Float) (bool, Int, error) {
+	if table.keyType != FloatID {
+		return false, NullInt(), fmt.Errorf("key type conflict")
+	}
+	grnKey := C.double(key)
+	rowInfo := C.grn_cgo_table_insert_float(table.db.ctx, table.obj, grnKey)
+	if rowInfo.id == C.GRN_ID_NIL {
+		return false, NullInt(), fmt.Errorf("grn_cgo_table_insert_float() failed")
+	}
+	return rowInfo.inserted == C.GRN_TRUE, Int(rowInfo.id), nil
+}
+
+// insertGeoPoint() inserts a row with GeoPoint key.
+func (table *GrnTable) insertGeoPoint(key GeoPoint) (bool, Int, error) {
+	if table.keyType != GeoPointID {
+		return false, NullInt(), fmt.Errorf("key type conflict")
+	}
+	grnKey := C.grn_geo_point{C.int(key.Latitude), C.int(key.Longitude)}
+	rowInfo := C.grn_cgo_table_insert_geo_point(table.db.ctx, table.obj, grnKey)
+	if rowInfo.id == C.GRN_ID_NIL {
+		return false, NullInt(), fmt.Errorf("grn_cgo_table_insert_geo_point() failed")
+	}
+	return rowInfo.inserted == C.GRN_TRUE, Int(rowInfo.id), nil
+}
+
+// insertText() inserts a row with Text key.
+func (table *GrnTable) insertText(key Text) (bool, Int, error) {
+	if table.keyType != TextID {
+		return false, NullInt(), fmt.Errorf("key type conflict")
+	}
+	var grnKey C.grn_cgo_text
+	if len(key) != 0 {
+		grnKey.ptr = (*C.char)(unsafe.Pointer(&key[0]))
+		grnKey.size = C.size_t(len(key))
+	}
+	rowInfo := C.grn_cgo_table_insert_text(table.db.ctx, table.obj, &grnKey)
+	if rowInfo.id == C.GRN_ID_NIL {
+		return false, NullInt(), fmt.Errorf("grn_cgo_table_insert_text() failed")
+	}
+	return rowInfo.inserted == C.GRN_TRUE, Int(rowInfo.id), nil
+}
+
+// InsertRow() inserts a row.
+// The first return value specifies whether a row is inserted or not.
+// The second return value is the ID of the inserted or found row.
+func (table *GrnTable) InsertRow(key interface{}) (bool, Int, error) {
+	switch value := key.(type) {
+	case nil:
+		return table.insertVoid()
+	case Bool:
+		return table.insertBool(value)
+	case Int:
+		return table.insertInt(value)
+	case Float:
+		return table.insertFloat(value)
+	case GeoPoint:
+		return table.insertGeoPoint(value)
+	case Text:
+		return table.insertText(value)
+	default:
+		return false, NullInt(), fmt.Errorf(
+			"unsupported key type: typeName = <%s>", reflect.TypeOf(key).Name())
+	}
+}
+
+// CreateColumn() creates a column.
+func (table *GrnTable) CreateColumn(name string, valueType string,
+	options *ColumnOptions) (*GrnColumn, error) {
+	if options == nil {
+		options = NewColumnOptions()
+	}
+	optionsMap := make(map[string]string)
+	optionsMap["table"] = table.name
+	optionsMap["name"] = name
+	switch valueType {
+	case "Bool":
+		optionsMap["type"] = "Bool"
+	case "Int":
+		optionsMap["type"] = "Int64"
+	case "Float":
+		optionsMap["type"] = "Float"
+	case "GeoPoint":
+		optionsMap["type"] = "WGS84GeoPoint"
+	case "Text":
+		optionsMap["type"] = "LongText"
+	default:
+		if _, err := table.db.FindTable(valueType); err != nil {
+			return nil, fmt.Errorf("unsupported value type: valueType = %s", valueType)
+		}
+		optionsMap["type"] = valueType
+	}
+	switch options.ColumnType {
+	case ScalarColumn:
+		optionsMap["flags"] = "COLUMN_SCALAR"
+	case VectorColumn:
+		optionsMap["flags"] = "COLUMN_VECTOR"
+	case IndexColumn:
+		optionsMap["flags"] = "COLUMN_INDEX"
+	default:
+		return nil, fmt.Errorf("undefined column type: options = %+v", options)
+	}
+	switch options.CompressionType {
+	case NoCompression:
+	case ZlibCompression:
+		optionsMap["flags"] = "|COMPRESS_ZLIB"
+	case LzoCompression:
+		optionsMap["flags"] = "|COMRESS_LZO"
+	default:
+		return nil, fmt.Errorf("undefined compression type: options = %+v", options)
+	}
+	if options.WithSection {
+		optionsMap["flags"] += "|WITH_SECTION"
+	}
+	if options.WithWeight {
+		optionsMap["flags"] += "|WITH_WEIGHT"
+	}
+	if options.WithPosition {
+		optionsMap["flags"] += "|WITH_POSITION"
+	}
+	if options.Source != "" {
+		optionsMap["source"] = options.Source
+	}
+	bytes, err := table.db.QueryEx("column_create", optionsMap)
+	if err != nil {
+		return nil, err
+	}
+	if string(bytes) != "true" {
+		return nil, fmt.Errorf("column_create failed: name = <%s>", name)
+	}
+	return table.FindColumn(name)
+}
+
+// findColumn() finds a column.
+func (table *GrnTable) findColumn(name string) (*GrnColumn, error) {
+	if column, ok := table.columns[name]; ok {
+		return column, nil
+	}
+	nameBytes := []byte(name)
+	var cName *C.char
+	if len(nameBytes) != 0 {
+		cName = (*C.char)(unsafe.Pointer(&nameBytes[0]))
+	}
+	obj := C.grn_obj_column(table.db.ctx, table.obj, cName, C.uint(len(name)))
+	if obj == nil {
+		return nil, fmt.Errorf("grn_obj_column() failed: table = %+v, name = <%s>", table, name)
+	}
+	var valueType TypeID
+	var valueTable *GrnTable
+	var isVector bool
+	switch name {
+	case "_id":
+		valueType = IntID
+	case "_key":
+		valueType = table.keyType
+		valueTable = table.keyTable
+	case "_value":
+		valueType = table.valueType
+		valueTable = table.valueTable
+	default:
+		var valueInfo C.grn_cgo_type_info
+		if ok := C.grn_cgo_column_get_value_info(table.db.ctx, obj, &valueInfo); ok != C.GRN_TRUE {
+			return nil, fmt.Errorf("grn_cgo_column_get_value_info() failed: name = <%s>",
+				name)
+		}
+		// Check the value type.
+		switch valueInfo.data_type {
+		case C.GRN_DB_BOOL:
+			valueType = BoolID
+		case C.GRN_DB_INT64:
+			valueType = IntID
+		case C.GRN_DB_FLOAT:
+			valueType = FloatID
+		case C.GRN_DB_WGS84_GEO_POINT:
+			valueType = GeoPointID
+		case C.GRN_DB_SHORT_TEXT, C.GRN_DB_LONG_TEXT:
+			valueType = TextID
+		default:
+			return nil, fmt.Errorf("unsupported value type: data_type = %d",
+				valueInfo.data_type)
+		}
+		isVector = valueInfo.dimension > 0
+		// Find the destination table if the value is table reference.
+		if valueInfo.ref_table != nil {
+			if valueType == VoidID {
+				return nil, fmt.Errorf("reference to void: name = <%s>", name)
+			}
+			cValueTableName := C.grn_cgo_table_get_name(table.db.ctx, valueInfo.ref_table)
+			if cValueTableName == nil {
+				return nil, fmt.Errorf("grn_cgo_table_get_name() failed")
+			}
+			defer C.free(unsafe.Pointer(cValueTableName))
+			var err error
+			valueTable, err = table.db.FindTable(C.GoString(cValueTableName))
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+	column := newGrnColumn(table, obj, name, valueType, isVector, valueTable)
+	table.columns[name] = column
+	return column, nil
+}
+
+// FindColumn() finds a column.
+func (table *GrnTable) FindColumn(name string) (*GrnColumn, error) {
+	if column, ok := table.columns[name]; ok {
+		return column, nil
+	}
+	delimPos := strings.IndexByte(name, '.')
+	if delimPos == -1 {
+		return table.findColumn(name)
+	}
+	columnNames := strings.Split(name, ".")
+	column, err := table.findColumn(columnNames[0])
+	if err != nil {
+		return nil, err
+	}
+	isVector := column.isVector
+	valueTable := column.valueTable
+	for _, columnName := range columnNames[1:] {
+		if column.valueTable == nil {
+			return nil, fmt.Errorf("not table reference: column.name = <%s>", column.name)
+		}
+		column, err = column.valueTable.findColumn(columnName)
+		if err != nil {
+			return nil, err
+		}
+		if column.isVector {
+			if isVector {
+				return nil, fmt.Errorf("vector of vector is not supported")
+			}
+			isVector = true
+		}
+	}
+	nameBytes := []byte(name)
+	var cName *C.char
+	if len(nameBytes) != 0 {
+		cName = (*C.char)(unsafe.Pointer(&nameBytes[0]))
+	}
+	obj := C.grn_obj_column(table.db.ctx, table.obj, cName, C.uint(len(name)))
+	if obj == nil {
+		return nil, fmt.Errorf("grn_obj_column() failed: name = <%s>", name)
+	}
+	column = newGrnColumn(table, obj, name, column.valueType, isVector, valueTable)
+	table.columns[name] = column
+	return column, nil
+}
+
+// -- GrnColumn --
+
+type GrnColumn struct {
+	table      *GrnTable
+	obj        *C.grn_obj
+	name       string
+	valueType  TypeID
+	isVector   bool
+	valueTable *GrnTable
+}
+
+// newGrnColumn() creates a new GrnColumn object.
+func newGrnColumn(table *GrnTable, obj *C.grn_obj, name string,
+	valueType TypeID, isVector bool, valueTable *GrnTable) *GrnColumn {
+	var column GrnColumn
+	column.table = table
+	column.obj = obj
+	column.name = name
+	column.valueType = valueType
+	column.isVector = isVector
+	column.valueTable = valueTable
+	return &column
+}
+
+// setBool() assigns a Bool value.
+func (column *GrnColumn) setBool(id Int, value Bool) error {
+	if (column.valueType != BoolID) || column.isVector {
+		return fmt.Errorf("value type conflict")
+	}
+	var grnValue C.grn_bool = C.GRN_FALSE
+	if value == True {
+		grnValue = C.GRN_TRUE
+	}
+	if ok := C.grn_cgo_column_set_bool(column.table.db.ctx, column.obj,
+		C.grn_id(id), grnValue); ok != C.GRN_TRUE {
+		return fmt.Errorf("grn_cgo_column_set_bool() failed")
+	}
+	return nil
+}
+
+// setInt() assigns an Int value.
+func (column *GrnColumn) setInt(id Int, value Int) error {
+	if (column.valueType != IntID) || column.isVector {
+		return fmt.Errorf("value type conflict")
+	}
+	grnValue := C.int64_t(value)
+	if ok := C.grn_cgo_column_set_int(column.table.db.ctx, column.obj,
+		C.grn_id(id), grnValue); ok != C.GRN_TRUE {
+		return fmt.Errorf("grn_cgo_column_set_int() failed")
+	}
+	return nil
+}
+
+// setFloat() assigns a Float value.
+func (column *GrnColumn) setFloat(id Int, value Float) error {
+	if (column.valueType != FloatID) || column.isVector {
+		return fmt.Errorf("value type conflict")
+	}
+	grnValue := C.double(value)
+	if ok := C.grn_cgo_column_set_float(column.table.db.ctx, column.obj,
+		C.grn_id(id), grnValue); ok != C.GRN_TRUE {
+		return fmt.Errorf("grn_cgo_column_set_float() failed")
+	}
+	return nil
+}
+
+// setGeoPoint() assigns a GeoPoint value.
+func (column *GrnColumn) setGeoPoint(id Int, value GeoPoint) error {
+	if (column.valueType != GeoPointID) || column.isVector {
+		return fmt.Errorf("value type conflict")
+	}
+	grnValue := C.grn_geo_point{C.int(value.Latitude), C.int(value.Longitude)}
+	if ok := C.grn_cgo_column_set_geo_point(column.table.db.ctx, column.obj,
+		C.grn_id(id), grnValue); ok != C.GRN_TRUE {
+		return fmt.Errorf("grn_cgo_column_set_geo_point() failed")
+	}
+	return nil
+}
+
+// setText() assigns a Text value.
+func (column *GrnColumn) setText(id Int, value Text) error {
+	if (column.valueType != TextID) || column.isVector {
+		return fmt.Errorf("value type conflict")
+	}
+	var grnValue C.grn_cgo_text
+	if len(value) != 0 {
+		grnValue.ptr = (*C.char)(unsafe.Pointer(&value[0]))
+		grnValue.size = C.size_t(len(value))
+	}
+	if ok := C.grn_cgo_column_set_text(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return fmt.Errorf("grn_cgo_column_set_text() failed")
+	}
+	return nil
+}
+
+// setBoolVector() assigns a Bool vector.
+func (column *GrnColumn) setBoolVector(id Int, value []Bool) error {
+	grnValue := make([]C.grn_bool, len(value))
+	for i, v := range value {
+		if v == True {
+			grnValue[i] = C.GRN_TRUE
+		}
+	}
+	var grnVector C.grn_cgo_vector
+	if len(grnValue) != 0 {
+		grnVector.ptr = unsafe.Pointer(&grnValue[0])
+		grnVector.size = C.size_t(len(grnValue))
+	}
+	if ok := C.grn_cgo_column_set_bool_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
+		return fmt.Errorf("grn_cgo_column_set_bool_vector() failed")
+	}
+	return nil
+}
+
+// setIntVector() assigns an Int vector.
+func (column *GrnColumn) setIntVector(id Int, value []Int) error {
+	var grnVector C.grn_cgo_vector
+	if len(value) != 0 {
+		grnVector.ptr = unsafe.Pointer(&value[0])
+		grnVector.size = C.size_t(len(value))
+	}
+	if ok := C.grn_cgo_column_set_int_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
+		return fmt.Errorf("grn_cgo_column_set_int_vector() failed")
+	}
+	return nil
+}
+
+// setFloatVector() assigns a Float vector.
+func (column *GrnColumn) setFloatVector(id Int, value []Float) error {
+	var grnVector C.grn_cgo_vector
+	if len(value) != 0 {
+		grnVector.ptr = unsafe.Pointer(&value[0])
+		grnVector.size = C.size_t(len(value))
+	}
+	if ok := C.grn_cgo_column_set_float_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
+		return fmt.Errorf("grn_cgo_column_set_float_vector() failed")
+	}
+	return nil
+}
+
+// setGeoPointVector() assigns a GeoPoint vector.
+func (column *GrnColumn) setGeoPointVector(id Int, value []GeoPoint) error {
+	var grnVector C.grn_cgo_vector
+	if len(value) != 0 {
+		grnVector.ptr = unsafe.Pointer(&value[0])
+		grnVector.size = C.size_t(len(value))
+	}
+	if ok := C.grn_cgo_column_set_geo_point_vector(column.table.db.ctx,
+		column.obj, C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
+		return fmt.Errorf("grn_cgo_column_set_geo_point_vector() failed")
+	}
+	return nil
+}
+
+// setTextVector() assigns a Text vector.
+func (column *GrnColumn) setTextVector(id Int, value []Text) error {
+	grnValue := make([]C.grn_cgo_text, len(value))
+	for i, v := range value {
+		if len(v) != 0 {
+			grnValue[i].ptr = (*C.char)(unsafe.Pointer(&v[0]))
+			grnValue[i].size = C.size_t(len(v))
+		}
+	}
+	var grnVector C.grn_cgo_vector
+	if len(grnValue) != 0 {
+		grnVector.ptr = unsafe.Pointer(&grnValue[0])
+		grnVector.size = C.size_t(len(grnValue))
+	}
+	if ok := C.grn_cgo_column_set_text_vector(column.table.db.ctx,
+		column.obj, C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
+		return fmt.Errorf("grn_cgo_column_set_text_vector() failed")
+	}
+	return nil
+}
+
+// SetValue() assigns a value.
+func (column *GrnColumn) SetValue(id Int, value interface{}) error {
+	switch v := value.(type) {
+	case Bool:
+		return column.setBool(id, v)
+	case Int:
+		return column.setInt(id, v)
+	case Float:
+		return column.setFloat(id, v)
+	case GeoPoint:
+		return column.setGeoPoint(id, v)
+	case Text:
+		return column.setText(id, v)
+	case []Bool:
+		return column.setBoolVector(id, v)
+	case []Int:
+		return column.setIntVector(id, v)
+	case []Float:
+		return column.setFloatVector(id, v)
+	case []GeoPoint:
+		return column.setGeoPointVector(id, v)
+	case []Text:
+		return column.setTextVector(id, v)
+	default:
+		return fmt.Errorf("unsupported value type: name = <%s>",
+			reflect.TypeOf(value).Name())
+	}
+}
+
+// getBool() gets a Bool value.
+func (column *GrnColumn) getBool(id Int) (interface{}, error) {
+	var grnValue C.grn_bool
+	if ok := C.grn_cgo_column_get_bool(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_bool() failed")
+	}
+	if grnValue == C.GRN_TRUE {
+		return True, nil
+	} else {
+		return False, nil
+	}
+}
+
+// getInt() gets an Int value.
+func (column *GrnColumn) getInt(id Int) (interface{}, error) {
+	var grnValue C.int64_t
+	if ok := C.grn_cgo_column_get_int(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_int() failed")
+	}
+	return Int(grnValue), nil
+}
+
+// getFloat() gets a Float value.
+func (column *GrnColumn) getFloat(id Int) (interface{}, error) {
+	var grnValue C.double
+	if ok := C.grn_cgo_column_get_float(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_float() failed")
+	}
+	return Float(grnValue), nil
+}
+
+// getGeoPoint() gets a GeoPoint value.
+func (column *GrnColumn) getGeoPoint(id Int) (interface{}, error) {
+	var grnValue C.grn_geo_point
+	if ok := C.grn_cgo_column_get_geo_point(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_geo_point() failed")
+	}
+	return GeoPoint{int32(grnValue.latitude), int32(grnValue.longitude)}, nil
+}
+
+// getText() gets a Text value.
+func (column *GrnColumn) getText(id Int) (interface{}, error) {
+	var grnValue C.grn_cgo_text
+	if ok := C.grn_cgo_column_get_text(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_text() failed")
+	}
+	if grnValue.size == 0 {
+		return make(Text, 0), nil
+	}
+	value := make(Text, int(grnValue.size))
+	grnValue.ptr = (*C.char)(unsafe.Pointer(&value[0]))
+	if ok := C.grn_cgo_column_get_text(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_text() failed")
+	}
+	return value, nil
+}
+
+// getBoolVector() gets a BoolVector.
+func (column *GrnColumn) getBoolVector(id Int) (interface{}, error) {
+	var grnVector C.grn_cgo_vector
+	if ok := C.grn_cgo_column_get_bool_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_bool_vector() failed")
+	}
+	if grnVector.size == 0 {
+		return make([]Bool, 0), nil
+	}
+	grnValue := make([]C.grn_bool, int(grnVector.size))
+	grnVector.ptr = unsafe.Pointer(&grnValue[0])
+	if ok := C.grn_cgo_column_get_bool_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_bool_vector() failed")
+	}
+	value := make([]Bool, int(grnVector.size))
+	for i, v := range grnValue {
+		if v == C.GRN_TRUE {
+			value[i] = True
+		}
+	}
+	return value, nil
+}
+
+// getIntVector() gets a IntVector.
+func (column *GrnColumn) getIntVector(id Int) (interface{}, error) {
+	var grnValue C.grn_cgo_vector
+	if ok := C.grn_cgo_column_get_int_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_int_vector() failed")
+	}
+	if grnValue.size == 0 {
+		return make([]Int, 0), nil
+	}
+	value := make([]Int, int(grnValue.size))
+	grnValue.ptr = unsafe.Pointer(&value[0])
+	if ok := C.grn_cgo_column_get_int_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_int_vector() failed")
+	}
+	return value, nil
+}
+
+// getFloatVector() gets a FloatVector.
+func (column *GrnColumn) getFloatVector(id Int) (interface{}, error) {
+	var grnValue C.grn_cgo_vector
+	if ok := C.grn_cgo_column_get_float_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_float_vector() failed")
+	}
+	if grnValue.size == 0 {
+		return make([]Float, 0), nil
+	}
+	value := make([]Float, int(grnValue.size))
+	grnValue.ptr = unsafe.Pointer(&value[0])
+	if ok := C.grn_cgo_column_get_float_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_float_vector() failed")
+	}
+	return value, nil
+}
+
+// getGeoPointVector() gets a GeoPointVector.
+func (column *GrnColumn) getGeoPointVector(id Int) (interface{}, error) {
+	var grnValue C.grn_cgo_vector
+	if ok := C.grn_cgo_column_get_geo_point_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_geo_point_vector() failed")
+	}
+	if grnValue.size == 0 {
+		return make([]GeoPoint, 0), nil
+	}
+	value := make([]GeoPoint, int(grnValue.size))
+	grnValue.ptr = unsafe.Pointer(&value[0])
+	if ok := C.grn_cgo_column_get_geo_point_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_geo_point_vector() failed")
+	}
+	return value, nil
+}
+
+// getTextVector() gets a TextVector.
+func (column *GrnColumn) getTextVector(id Int) (interface{}, error) {
+	var grnVector C.grn_cgo_vector
+	if ok := C.grn_cgo_column_get_text_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_text_vector() failed")
+	}
+	if grnVector.size == 0 {
+		return make([]Text, 0), nil
+	}
+	grnValues := make([]C.grn_cgo_text, int(grnVector.size))
+	grnVector.ptr = unsafe.Pointer(&grnValues[0])
+	if ok := C.grn_cgo_column_get_text_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_text_vector() failed")
+	}
+	value := make([]Text, int(grnVector.size))
+	for i, grnValue := range grnValues {
+		if grnValue.size != 0 {
+			value[i] = make(Text, int(grnValue.size))
+			grnValues[i].ptr = (*C.char)(unsafe.Pointer(&value[i][0]))
+		}
+	}
+	if ok := C.grn_cgo_column_get_text_vector(column.table.db.ctx, column.obj,
+		C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_text_vector() failed")
+	}
+	return value, nil
+}
+
+// GetValue() gets a value.
+// TODO: GetValue() should use allocated spaces for better performance.
+func (column *GrnColumn) GetValue(id Int) (interface{}, error) {
+	if !column.isVector {
+		switch column.valueType {
+		case BoolID:
+			return column.getBool(id)
+		case IntID:
+			return column.getInt(id)
+		case FloatID:
+			return column.getFloat(id)
+		case GeoPointID:
+			return column.getGeoPoint(id)
+		case TextID:
+			return column.getText(id)
+		}
+	} else {
+		switch column.valueType {
+		case BoolID:
+			return column.getBoolVector(id)
+		case IntID:
+			return column.getIntVector(id)
+		case FloatID:
+			return column.getFloatVector(id)
+		case GeoPointID:
+			return column.getGeoPointVector(id)
+		case TextID:
+			return column.getTextVector(id)
+		}
+	}
+	return nil, fmt.Errorf("undefined value type: valueType = %d", column.valueType)
+}
+
+func (column *GrnColumn) getBools(ids []Int) (interface{}, error) {
+	grnValues := make([]C.grn_bool, len(ids))
+	if ok := C.grn_cgo_column_get_bools(column.table.db.ctx, column.obj,
+		C.size_t(len(ids)), (*C.int64_t)(unsafe.Pointer(&ids[0])),
+		&grnValues[0]); ok != C.GRN_TRUE {
+		return nil, fmt.Errorf("grn_cgo_column_get_bools() failed")
+	}
+	values := make([]Bool, len(ids))
+	for i, _ := range values {
+		if grnValues[i] == C.GRN_TRUE {
+			values[i] = True
+		}
+	}
+	return values, nil
+}
+
+func (column *GrnColumn) GetValues(ids []Int) (interface{}, error) {
+	if !column.isVector {
+		switch column.valueType {
+		case BoolID:
+			return column.getBools(ids)
+//		case IntID:
+//			return column.getInts(ids)
+//		case FloatID:
+//			return column.getFloats(ids)
+//		case GeoPointID:
+//			return column.getGeoPoints(ids)
+//		case TextID:
+//			return column.getTexts(ids)
+		}
+	} else {
+//		switch column.valueType {
+//		case BoolID:
+//			return column.getBoolVectors(ids)
+//		case IntID:
+//			return column.getIntVectors(ids)
+//		case FloatID:
+//			return column.getFloatVectors(ids)
+//		case GeoPointID:
+//			return column.getGeoPointVectors(ids)
+//		case TextID:
+//			return column.getTextVectors(ids)
+//		}
+	}
+	return nil, fmt.Errorf("undefined value type: valueType = %d", column.valueType)
+}

  Added: grn_cgo.c (+483 -0) 100644
===================================================================
--- /dev/null
+++ grn_cgo.c    2015-06-19 14:34:28 +0900 (89de52b)
@@ -0,0 +1,483 @@
+#include "grn_cgo.h"
+
+#include <string.h>
+
+#define GRN_CGO_MAX_DATA_TYPE_ID GRN_DB_WGS84_GEO_POINT
+
+grn_obj *grn_cgo_find_table(grn_ctx *ctx, const char *name, int name_len) {
+  grn_obj *obj = grn_ctx_get(ctx, name, name_len);
+  if (!obj) {
+    return NULL;
+  }
+  switch (obj->header.type) {
+    case GRN_TABLE_HASH_KEY:
+    case GRN_TABLE_PAT_KEY:
+    case GRN_TABLE_DAT_KEY:
+    case GRN_TABLE_NO_KEY: {
+      return obj;
+    }
+    default: {
+      // The object is not a table.
+      return NULL;
+    }
+  }
+}
+
+// grn_cgo_init_type_info() initializes the members of type_info.
+// The initialized type info specifies a valid Void type.
+static void grn_cgo_init_type_info(grn_cgo_type_info *type_info) {
+  type_info->data_type = GRN_DB_VOID;
+  type_info->dimension = 0;
+  type_info->ref_table = NULL;
+}
+
+grn_bool grn_cgo_table_get_key_info(grn_ctx *ctx, grn_obj *table,
+                                    grn_cgo_type_info *key_info) {
+  grn_cgo_init_type_info(key_info);
+  while (table) {
+    switch (table->header.type) {
+      case GRN_TABLE_HASH_KEY:
+      case GRN_TABLE_PAT_KEY:
+      case GRN_TABLE_DAT_KEY: {
+        if (table->header.domain <= GRN_CGO_MAX_DATA_TYPE_ID) {
+          key_info->data_type = table->header.domain;
+          return GRN_TRUE;
+        }
+        table = grn_ctx_at(ctx, table->header.domain);
+        if (!table) {
+          return GRN_FALSE;
+        }
+        if (!key_info->ref_table) {
+          key_info->ref_table = table;
+        }
+        break;
+      }
+      case GRN_TABLE_NO_KEY: {
+        // GRN_DB_VOID, if the table has no key.
+        return GRN_TRUE;
+      }
+      default: {
+        // The object is not a table.
+        return GRN_FALSE;
+      }
+    }
+  }
+  return GRN_FALSE;
+}
+
+grn_bool grn_cgo_table_get_value_info(grn_ctx *ctx, grn_obj *table,
+                                      grn_cgo_type_info *value_info) {
+  grn_cgo_init_type_info(value_info);
+  if (!table) {
+    return GRN_FALSE;
+  }
+  switch (table->header.type) {
+    case GRN_TABLE_HASH_KEY:
+    case GRN_TABLE_PAT_KEY:
+    case GRN_TABLE_DAT_KEY:
+    case GRN_TABLE_NO_KEY: {
+      grn_id range = grn_obj_get_range(ctx, table);
+      if (range <= GRN_CGO_MAX_DATA_TYPE_ID) {
+        value_info->data_type = range;
+        return GRN_TRUE;
+      }
+      value_info->ref_table = grn_ctx_at(ctx, range);
+      grn_cgo_type_info key_info;
+      if (!grn_cgo_table_get_key_info(ctx, value_info->ref_table, &key_info)) {
+        return GRN_FALSE;
+      }
+      value_info->data_type = key_info.data_type;
+      return GRN_TRUE;
+    }
+    default: {
+      // The object is not a table.
+      return GRN_FALSE;
+    }
+  }
+}
+
+grn_bool grn_cgo_column_get_value_info(grn_ctx *ctx, grn_obj *column,
+                                       grn_cgo_type_info *value_info) {
+  grn_cgo_init_type_info(value_info);
+  if (!column) {
+    return GRN_FALSE;
+  }
+  switch (column->header.type) {
+    case GRN_COLUMN_FIX_SIZE: {
+      break;
+    }
+    case GRN_COLUMN_VAR_SIZE: {
+      grn_obj_flags type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
+      if (type == GRN_OBJ_COLUMN_VECTOR) {
+        ++value_info->dimension;
+      }
+      break;
+    }
+    default: {
+      // The object is not a data column.
+      return GRN_FALSE;
+    }
+  }
+  grn_id range = grn_obj_get_range(ctx, column);
+  if (range <= GRN_CGO_MAX_DATA_TYPE_ID) {
+    value_info->data_type = range;
+    return GRN_TRUE;
+  }
+  value_info->ref_table = grn_ctx_at(ctx, range);
+  grn_cgo_type_info key_info;
+  if (!grn_cgo_table_get_key_info(ctx, value_info->ref_table, &key_info)) {
+    return GRN_FALSE;
+  }
+  value_info->data_type = key_info.data_type;
+  return GRN_TRUE;
+}
+
+char *grn_cgo_table_get_name(grn_ctx *ctx, grn_obj *table) {
+  if (!table) {
+    return NULL;
+  }
+  switch (table->header.type) {
+    case GRN_TABLE_HASH_KEY:
+    case GRN_TABLE_PAT_KEY:
+    case GRN_TABLE_DAT_KEY:
+    case GRN_TABLE_NO_KEY: {
+      break;
+    }
+    default: {
+      // The object is not a table.
+      return NULL;
+    }
+  }
+  char buf[GRN_TABLE_MAX_KEY_SIZE];
+  int len = grn_obj_name(ctx, table, buf, GRN_TABLE_MAX_KEY_SIZE);
+  if (len <= 0) {
+    return NULL;
+  }
+  char *table_name = (char *)malloc(len + 1);
+  if (!table_name) {
+    return NULL;
+  }
+  memcpy(table_name, buf, len);
+  table_name[len] = '\0';
+  return table_name;
+}
+
+// grn_cgo_table_insert_row() calls grn_table_add() and converts the result.
+static grn_cgo_row_info grn_cgo_table_insert_row(
+    grn_ctx *ctx, grn_obj *table, const void *key_ptr, size_t key_size) {
+  grn_cgo_row_info row_info;
+  int inserted;
+  row_info.id = grn_table_add(ctx, table, key_ptr, key_size, &inserted);
+  row_info.inserted = inserted ? GRN_TRUE : GRN_FALSE;
+  return row_info;
+}
+
+grn_cgo_row_info grn_cgo_table_insert_void(grn_ctx *ctx, grn_obj *table) {
+  return grn_cgo_table_insert_row(ctx, table, NULL, 0);
+}
+
+grn_cgo_row_info grn_cgo_table_insert_bool(grn_ctx *ctx, grn_obj *table,
+                                           grn_bool key) {
+  return grn_cgo_table_insert_row(ctx, table, &key, sizeof(key));
+}
+
+grn_cgo_row_info grn_cgo_table_insert_int(grn_ctx *ctx, grn_obj *table,
+                                          int64_t key) {
+  return grn_cgo_table_insert_row(ctx, table, &key, sizeof(key));
+}
+
+grn_cgo_row_info grn_cgo_table_insert_float(grn_ctx *ctx, grn_obj *table,
+                                            double key) {
+  return grn_cgo_table_insert_row(ctx, table, &key, sizeof(key));
+}
+
+grn_cgo_row_info grn_cgo_table_insert_geo_point(grn_ctx *ctx, grn_obj *table,
+                                                grn_geo_point key) {
+  return grn_cgo_table_insert_row(ctx, table, &key, sizeof(key));
+}
+
+grn_cgo_row_info grn_cgo_table_insert_text(grn_ctx *ctx, grn_obj *table,
+                                           const grn_cgo_text *key) {
+  return grn_cgo_table_insert_row(ctx, table, key->ptr, key->size);
+}
+
+grn_bool grn_cgo_column_set_bool(grn_ctx *ctx, grn_obj *column,
+                                 grn_id id, grn_bool value) {
+  grn_obj obj;
+  GRN_BOOL_INIT(&obj, 0);
+  GRN_BOOL_SET(ctx, &obj, value);
+  grn_rc rc = grn_obj_set_value(ctx, column, id, &obj, GRN_OBJ_SET);
+  GRN_OBJ_FIN(ctx, &obj);
+  return rc == GRN_SUCCESS;
+}
+
+grn_bool grn_cgo_column_set_int(grn_ctx *ctx, grn_obj *column,
+                                grn_id id, int64_t value) {
+  grn_obj obj;
+  GRN_INT64_INIT(&obj, 0);
+  GRN_INT64_SET(ctx, &obj, value);
+  grn_rc rc = grn_obj_set_value(ctx, column, id, &obj, GRN_OBJ_SET);
+  GRN_OBJ_FIN(ctx, &obj);
+  return rc == GRN_SUCCESS;
+}
+
+grn_bool grn_cgo_column_set_float(grn_ctx *ctx, grn_obj *column,
+                                  grn_id id, double value) {
+  grn_obj obj;
+  GRN_FLOAT_INIT(&obj, 0);
+  GRN_FLOAT_SET(ctx, &obj, value);
+  grn_rc rc = grn_obj_set_value(ctx, column, id, &obj, GRN_OBJ_SET);
+  GRN_OBJ_FIN(ctx, &obj);
+  return rc == GRN_SUCCESS;
+}
+
+grn_bool grn_cgo_column_set_geo_point(grn_ctx *ctx, grn_obj *column,
+                                      grn_id id, grn_geo_point value) {
+  grn_obj obj;
+  GRN_WGS84_GEO_POINT_INIT(&obj, 0);
+  GRN_GEO_POINT_SET(ctx, &obj, value.latitude, value.longitude);
+  grn_rc rc = grn_obj_set_value(ctx, column, id, &obj, GRN_OBJ_SET);
+  GRN_OBJ_FIN(ctx, &obj);
+  return rc == GRN_SUCCESS;
+}
+
+grn_bool grn_cgo_column_set_text(grn_ctx *ctx, grn_obj *column,
+                                 grn_id id, const grn_cgo_text *value) {
+  grn_obj obj;
+  GRN_TEXT_INIT(&obj, 0);
+  if (value) {
+    GRN_TEXT_SET(ctx, &obj, value->ptr, value->size);
+  } else {
+    GRN_TEXT_SET(ctx, &obj, NULL, 0);
+  }
+  grn_rc rc = grn_obj_set_value(ctx, column, id, &obj, GRN_OBJ_SET);
+  GRN_OBJ_FIN(ctx, &obj);
+  return rc == GRN_SUCCESS;
+}
+
+grn_bool grn_cgo_column_set_bool_vector(grn_ctx *ctx, grn_obj *column,
+                                        grn_id id,
+                                        const grn_cgo_vector *value) {
+  grn_obj obj;
+  GRN_BOOL_INIT(&obj, GRN_OBJ_VECTOR);
+  size_t i;
+  for (i = 0; i < value->size; i++) {
+    GRN_BOOL_SET_AT(ctx, &obj, i, ((const grn_bool *)value->ptr)[i]);
+  }
+  grn_rc rc = grn_obj_set_value(ctx, column, id, &obj, GRN_OBJ_SET);
+  GRN_OBJ_FIN(ctx, &obj);
+  return rc == GRN_SUCCESS;
+}
+
+grn_bool grn_cgo_column_set_int_vector(grn_ctx *ctx, grn_obj *column,
+                                       grn_id id,
+                                       const grn_cgo_vector *value) {
+  grn_obj obj;
+  GRN_INT64_INIT(&obj, GRN_OBJ_VECTOR);
+  size_t i;
+  for (i = 0; i < value->size; i++) {
+    GRN_INT64_SET_AT(ctx, &obj, i, ((const int64_t *)value->ptr)[i]);
+  }
+  grn_rc rc = grn_obj_set_value(ctx, column, id, &obj, GRN_OBJ_SET);
+  GRN_OBJ_FIN(ctx, &obj);
+  return rc == GRN_SUCCESS;
+}
+
+grn_bool grn_cgo_column_set_float_vector(grn_ctx *ctx, grn_obj *column,
+                                         grn_id id,
+                                         const grn_cgo_vector *value) {
+  grn_obj obj;
+  GRN_FLOAT_INIT(&obj, GRN_OBJ_VECTOR);
+  size_t i;
+  for (i = 0; i < value->size; i++) {
+    GRN_FLOAT_SET_AT(ctx, &obj, i, ((const double *)value->ptr)[i]);
+  }
+  grn_rc rc = grn_obj_set_value(ctx, column, id, &obj, GRN_OBJ_SET);
+  GRN_OBJ_FIN(ctx, &obj);
+  return rc == GRN_SUCCESS;
+}
+
+grn_bool grn_cgo_column_set_geo_point_vector(grn_ctx *ctx, grn_obj *column,
+                                             grn_id id,
+                                             const grn_cgo_vector *value) {
+  grn_obj obj;
+  GRN_WGS84_GEO_POINT_INIT(&obj, GRN_OBJ_VECTOR);
+  size_t i;
+  const grn_geo_point *values = (const grn_geo_point *)value->ptr;
+  for (i = 0; i < value->size; i++) {
+    grn_bulk_write(ctx, &obj, (const char *)&values[i], sizeof(values[i]));
+  }
+  grn_rc rc = grn_obj_set_value(ctx, column, id, &obj, GRN_OBJ_SET);
+  GRN_OBJ_FIN(ctx, &obj);
+  return rc == GRN_SUCCESS;
+}
+
+grn_bool grn_cgo_column_set_text_vector(grn_ctx *ctx, grn_obj *column,
+                                        grn_id id,
+                                        const grn_cgo_vector *value) {
+  grn_obj obj;
+  GRN_TEXT_INIT(&obj, GRN_OBJ_VECTOR);
+  size_t i;
+  const grn_cgo_text *values = (const grn_cgo_text *)value->ptr;
+  for (i = 0; i < value->size; i++) {
+    grn_vector_add_element(ctx, &obj, values[i].ptr, values[i].size,
+                           0, obj.header.domain);
+  }
+  grn_rc rc = grn_obj_set_value(ctx, column, id, &obj, GRN_OBJ_SET);
+  GRN_OBJ_FIN(ctx, &obj);
+  return rc == GRN_SUCCESS;
+}
+
+grn_bool grn_cgo_column_get_bool(grn_ctx *ctx, grn_obj *column,
+                                 grn_id id, grn_bool *value) {
+  grn_obj value_obj;
+  GRN_BOOL_INIT(&value_obj, 0);
+  grn_obj_get_value(ctx, column, id, &value_obj);
+  *value = GRN_BOOL_VALUE(&value_obj);
+  GRN_OBJ_FIN(ctx, &value_obj);
+  return GRN_TRUE;
+}
+
+grn_bool grn_cgo_column_get_int(grn_ctx *ctx, grn_obj *column,
+                                grn_id id, int64_t *value) {
+  grn_obj value_obj;
+  GRN_INT64_INIT(&value_obj, 0);
+  grn_obj_get_value(ctx, column, id, &value_obj);
+  *value = GRN_INT64_VALUE(&value_obj);
+  GRN_OBJ_FIN(ctx, &value_obj);
+  return GRN_TRUE;
+}
+
+grn_bool grn_cgo_column_get_float(grn_ctx *ctx, grn_obj *column,
+                                  grn_id id, double *value) {
+  grn_obj value_obj;
+  GRN_FLOAT_INIT(&value_obj, 0);
+  grn_obj_get_value(ctx, column, id, &value_obj);
+  *value = GRN_FLOAT_VALUE(&value_obj);
+  GRN_OBJ_FIN(ctx, &value_obj);
+  return GRN_TRUE;
+}
+
+grn_bool grn_cgo_column_get_geo_point(grn_ctx *ctx, grn_obj *column,
+                                      grn_id id, grn_geo_point *value) {
+  grn_obj value_obj;
+  GRN_WGS84_GEO_POINT_INIT(&value_obj, 0);
+  grn_obj_get_value(ctx, column, id, &value_obj);
+  GRN_GEO_POINT_VALUE(&value_obj, value->latitude, value->longitude);
+  GRN_OBJ_FIN(ctx, &value_obj);
+  return GRN_TRUE;
+}
+
+grn_bool grn_cgo_column_get_text(grn_ctx *ctx, grn_obj *column,
+                                 grn_id id, grn_cgo_text *value) {
+  grn_obj value_obj;
+  GRN_TEXT_INIT(&value_obj, 0);
+  grn_obj_get_value(ctx, column, id, &value_obj);
+  size_t size = GRN_TEXT_LEN(&value_obj);
+  if (size <= value->size) {
+    memcpy(value->ptr, GRN_TEXT_VALUE(&value_obj), size);
+  }
+  value->size = size;
+  GRN_OBJ_FIN(ctx, &value_obj);
+  return GRN_TRUE;
+}
+
+grn_bool grn_cgo_column_get_bool_vector(grn_ctx *ctx, grn_obj *column,
+                                        grn_id id, grn_cgo_vector *value) {
+  grn_obj value_obj;
+  GRN_BOOL_INIT(&value_obj, GRN_OBJ_VECTOR);
+  grn_obj_get_value(ctx, column, id, &value_obj);
+  size_t size_in_bytes = GRN_BULK_VSIZE(&value_obj);
+  size_t size = size_in_bytes / sizeof(grn_bool);
+  if (size <= value->size) {
+    memcpy(value->ptr, GRN_BULK_HEAD(&value_obj), size_in_bytes);
+  }
+  value->size = size;
+  GRN_OBJ_FIN(ctx, &value_obj);
+  return GRN_TRUE;
+}
+
+grn_bool grn_cgo_column_get_int_vector(grn_ctx *ctx, grn_obj *column,
+                                       grn_id id, grn_cgo_vector *value) {
+  grn_obj value_obj;
+  GRN_INT64_INIT(&value_obj, GRN_OBJ_VECTOR);
+  grn_obj_get_value(ctx, column, id, &value_obj);
+  size_t size_in_bytes = GRN_BULK_VSIZE(&value_obj);
+  size_t size = size_in_bytes / sizeof(int64_t);
+  if (size <= value->size) {
+    memcpy(value->ptr, GRN_BULK_HEAD(&value_obj), size_in_bytes);
+  }
+  value->size = size;
+  GRN_OBJ_FIN(ctx, &value_obj);
+  return GRN_TRUE;
+}
+
+grn_bool grn_cgo_column_get_float_vector(grn_ctx *ctx, grn_obj *column,
+                                         grn_id id, grn_cgo_vector *value) {
+  grn_obj value_obj;
+  GRN_FLOAT_INIT(&value_obj, GRN_OBJ_VECTOR);
+  grn_obj_get_value(ctx, column, id, &value_obj);
+  size_t size_in_bytes = GRN_BULK_VSIZE(&value_obj);
+  size_t size = size_in_bytes / sizeof(double);
+  if (size <= value->size) {
+    memcpy(value->ptr, GRN_BULK_HEAD(&value_obj), size_in_bytes);
+  }
+  value->size = size;
+  GRN_OBJ_FIN(ctx, &value_obj);
+  return GRN_TRUE;
+}
+
+grn_bool grn_cgo_column_get_geo_point_vector(grn_ctx *ctx, grn_obj *column,
+                                             grn_id id, grn_cgo_vector *value) {
+  grn_obj value_obj;
+  GRN_WGS84_GEO_POINT_INIT(&value_obj, GRN_OBJ_VECTOR);
+  grn_obj_get_value(ctx, column, id, &value_obj);
+  size_t size_in_bytes = GRN_BULK_VSIZE(&value_obj);
+  size_t size = size_in_bytes / sizeof(grn_geo_point);
+  if (size <= value->size) {
+    memcpy(value->ptr, GRN_BULK_HEAD(&value_obj), size_in_bytes);
+  }
+  value->size = size;
+  GRN_OBJ_FIN(ctx, &value_obj);
+  return GRN_TRUE;
+}
+
+grn_bool grn_cgo_column_get_text_vector(grn_ctx *ctx, grn_obj *column,
+                                        grn_id id, grn_cgo_vector *value) {
+  grn_obj value_obj;
+  GRN_TEXT_INIT(&value_obj, GRN_OBJ_VECTOR);
+  grn_obj_get_value(ctx, column, id, &value_obj);
+  size_t size = grn_vector_size(ctx, &value_obj);
+  if (size <= value->size) {
+    size_t i;
+    for (i = 0; i < size; i++) {
+      // NOTE: grn_vector_get_element() assigns the address of the text body
+      //       to text_ptr, but the body may be overwritten in the next call.
+      const char *text_ptr;
+      unsigned int text_size = grn_vector_get_element(ctx, &value_obj, i,
+                                                      &text_ptr, NULL, NULL);
+      grn_cgo_text *text = &((grn_cgo_text *)value->ptr)[i];
+      if (text_size <= text->size) {
+        memcpy(text->ptr, text_ptr, text_size);
+      }
+      text->size = text_size;
+    }
+  }
+  value->size = size;
+  GRN_OBJ_FIN(ctx, &value_obj);
+  return GRN_TRUE;
+}
+
+grn_bool grn_cgo_column_get_bools(grn_ctx *ctx, grn_obj *column, size_t n,
+                                  const int64_t *ids, grn_bool *values) {
+  grn_obj value_obj;
+  GRN_BOOL_INIT(&value_obj, 0);
+  size_t i;
+  for (i = 0; i < n; i++) {
+    GRN_BULK_REWIND(&value_obj);
+    grn_obj_get_value(ctx, column, (grn_id)ids[i], &value_obj);
+    values[i] = GRN_BOOL_VALUE(&value_obj);
+  }
+  GRN_OBJ_FIN(ctx, &value_obj);
+  return GRN_TRUE;
+}

  Added: grn_cgo.h (+148 -0) 100644
===================================================================
--- /dev/null
+++ grn_cgo.h    2015-06-19 14:34:28 +0900 (53bb968)
@@ -0,0 +1,148 @@
+#ifndef GRN_CGO_H
+#define GRN_CGO_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <groonga.h>
+
+typedef struct {
+  char *ptr;
+  size_t size;
+} grn_cgo_text;
+
+typedef struct {
+  void *ptr;
+  size_t size;
+} grn_cgo_vector;
+
+// grn_cgo_find_table() finds a table with the given name.
+// If found, an object associated with the table is returned.
+// If not found, NULL is returned.
+grn_obj *grn_cgo_find_table(grn_ctx *ctx, const char *name, int name_len);
+
+typedef struct {
+  grn_id  data_type;  // Data type (GRN_DB_VOID, GRN_DB_BOOL, etc.).
+                      // If the type is table reference, the key type of the
+                      // referenced table is stored.
+  int     dimension;  // Vector depth, 0 means the type is scalar.
+  grn_obj *ref_table; // The referenced table of table reference.
+} grn_cgo_type_info;
+
+// grn_cgo_table_get_key_info() gets information of the table key.
+grn_bool grn_cgo_table_get_key_info(grn_ctx *ctx, grn_obj *table,
+                                    grn_cgo_type_info *key_info);
+// grn_cgo_table_get_value_info() gets information of the table value.
+grn_bool grn_cgo_table_get_value_info(grn_ctx *ctx, grn_obj *table,
+                                      grn_cgo_type_info *value_info);
+// grn_cgo_column_get_value_info() gets information of the column value.
+grn_bool grn_cgo_column_get_value_info(grn_ctx *ctx, grn_obj *column,
+                                       grn_cgo_type_info *value_info);
+
+// grn_cgo_table_get_name() returns the name of table.
+// On success, a non-NULL pointer is returned and it must be freed by free().
+// On failure, NULL is returned.
+char *grn_cgo_table_get_name(grn_ctx *ctx, grn_obj *table);
+
+typedef struct {
+  grn_id   id;       // Row ID, GRN_ID_NIL means the info is invalid.
+  grn_bool inserted; // Inserted or not.
+} grn_cgo_row_info;
+
+// grn_cgo_table_insert_void() inserts an empty row.
+grn_cgo_row_info grn_cgo_table_insert_void(grn_ctx *ctx, grn_obj *table);
+// grn_cgo_table_insert_bool() inserts a row with Bool key.
+grn_cgo_row_info grn_cgo_table_insert_bool(grn_ctx *ctx, grn_obj *table,
+                                           grn_bool key);
+// grn_cgo_table_insert_int() inserts a row with Int key.
+grn_cgo_row_info grn_cgo_table_insert_int(grn_ctx *ctx, grn_obj *table,
+                                          int64_t key);
+// grn_cgo_table_insert_float() inserts a row with Float key.
+grn_cgo_row_info grn_cgo_table_insert_float(grn_ctx *ctx, grn_obj *table,
+                                            double key);
+// grn_cgo_table_insert_geo_point() inserts a row with GeoPoint key.
+grn_cgo_row_info grn_cgo_table_insert_geo_point(grn_ctx *ctx, grn_obj *table,
+                                                grn_geo_point key);
+// grn_cgo_table_insert_text() inserts a row with Text key.
+grn_cgo_row_info grn_cgo_table_insert_text(grn_ctx *ctx, grn_obj *table,
+                                           const grn_cgo_text *key);
+
+// grn_cgo_column_set_bool() assigns a Bool value.
+grn_bool grn_cgo_column_set_bool(grn_ctx *ctx, grn_obj *column,
+                                 grn_id id, grn_bool value);
+// grn_cgo_column_set_int() assigns an Int value.
+grn_bool grn_cgo_column_set_int(grn_ctx *ctx, grn_obj *column,
+                                grn_id id, int64_t value);
+// grn_cgo_column_set_float() assigns a Float value.
+grn_bool grn_cgo_column_set_float(grn_ctx *ctx, grn_obj *column,
+                                  grn_id id, double value);
+// grn_cgo_column_set_geo_point() assigns a GeoPoint value.
+grn_bool grn_cgo_column_set_geo_point(grn_ctx *ctx, grn_obj *column,
+                                      grn_id id, grn_geo_point value);
+// grn_cgo_column_set_text() assigns a Text value.
+grn_bool grn_cgo_column_set_text(grn_ctx *ctx, grn_obj *column,
+                                 grn_id id, const grn_cgo_text *value);
+// grn_cgo_column_set_bool_vector() assigns a Bool vector.
+grn_bool grn_cgo_column_set_bool_vector(grn_ctx *ctx, grn_obj *column,
+                                        grn_id id,
+                                        const grn_cgo_vector *value);
+// grn_cgo_column_set_int_vector() assigns an Int vector.
+grn_bool grn_cgo_column_set_int_vector(grn_ctx *ctx, grn_obj *column,
+                                       grn_id id,
+                                       const grn_cgo_vector *value);
+// grn_cgo_column_set_float_vector() assigns a Float vector.
+grn_bool grn_cgo_column_set_float_vector(grn_ctx *ctx, grn_obj *column,
+                                         grn_id id,
+                                         const grn_cgo_vector *value);
+// grn_cgo_column_set_geo_point_vector() assigns a GeoPoint vector.
+grn_bool grn_cgo_column_set_geo_point_vector(grn_ctx *ctx, grn_obj *column,
+                                             grn_id id,
+                                             const grn_cgo_vector *value);
+// grn_cgo_column_set_text_vector() assigns a Text vector.
+// value must refer to an array of grn_cgo_text.
+grn_bool grn_cgo_column_set_text_vector(grn_ctx *ctx, grn_obj *column,
+                                        grn_id id,
+                                        const grn_cgo_vector *value);
+
+// grn_cgo_column_get_X_vector() sets *(X *)(value.ptr)[i] if value->size >=
+// the actual vector size.
+// In the case of Text, bodies are copied to (X *)(value.ptr)[i].ptr if
+// (X *)(value.ptr)[i].size >= the actual body size.
+// Then, grn_cgo_column_get_X_vector() sets value->size.
+
+// grn_cgo_column_get_bool() gets a stored Bool value.
+grn_bool grn_cgo_column_get_bool(grn_ctx *ctx, grn_obj *column,
+                                 grn_id id, grn_bool *value);
+// grn_cgo_column_get_int() gets a stored Int value.
+grn_bool grn_cgo_column_get_int(grn_ctx *ctx, grn_obj *column,
+                                grn_id id, int64_t *value);
+// grn_cgo_column_get_float() gets a stored Float value.
+grn_bool grn_cgo_column_get_float(grn_ctx *ctx, grn_obj *column,
+                                  grn_id id, double *value);
+// grn_cgo_column_get_geo_point() gets a stored GeoPoint value.
+grn_bool grn_cgo_column_get_geo_point(grn_ctx *ctx, grn_obj *column,
+                                      grn_id id, grn_geo_point *value);
+// grn_cgo_column_get_text() gets a stored Text value.
+grn_bool grn_cgo_column_get_text(grn_ctx *ctx, grn_obj *column,
+                                 grn_id id, grn_cgo_text *value);
+// grn_cgo_column_get_bool_vector() gets a stored Bool vector.
+grn_bool grn_cgo_column_get_bool_vector(grn_ctx *ctx, grn_obj *column,
+                                        grn_id id, grn_cgo_vector *value);
+// grn_cgo_column_get_int_vector() gets a stored Int vector.
+grn_bool grn_cgo_column_get_int_vector(grn_ctx *ctx, grn_obj *column,
+                                        grn_id id, grn_cgo_vector *value);
+// grn_cgo_column_get_float_vector() gets a stored Float vector.
+grn_bool grn_cgo_column_get_float_vector(grn_ctx *ctx, grn_obj *column,
+                                         grn_id id, grn_cgo_vector *value);
+// grn_cgo_column_get_geo_point_vector() gets a stored GeoPoint vector.
+grn_bool grn_cgo_column_get_geo_point_vector(grn_ctx *ctx, grn_obj *column,
+                                             grn_id id, grn_cgo_vector *value);
+// grn_cgo_column_get_text_vector() gets a stored Text vector.
+// value must refer to an array of grn_cgo_text.
+grn_bool grn_cgo_column_get_text_vector(grn_ctx *ctx, grn_obj *column,
+                                        grn_id id, grn_cgo_vector *value);
+
+grn_bool grn_cgo_column_get_bools(grn_ctx *ctx, grn_obj *column, size_t n,
+                                  const int64_t *ids, grn_bool *values);
+
+#endif  // GRN_CGO_H

  Added: grn_test.go (+1128 -0) 100644
===================================================================
--- /dev/null
+++ grn_test.go    2015-06-19 14:34:28 +0900 (1a190f6)
@@ -0,0 +1,1128 @@
+package gnx
+
+import (
+	"fmt"
+	"io/ioutil"
+	"math/rand"
+	"os"
+	"reflect"
+	"strconv"
+	"testing"
+)
+
+// createTempGrnDB() creates a database for tests.
+// The database must be removed with removeTempGrnDB().
+func createTempGrnDB(tb testing.TB) (string, string, *GrnDB) {
+	dirPath, err := ioutil.TempDir("", "grn_test")
+	if err != nil {
+		tb.Fatalf("ioutil.TempDir() failed: %v", err)
+	}
+	dbPath := dirPath + "/db"
+	db, err := CreateGrnDB(dbPath)
+	if err != nil {
+		os.RemoveAll(dirPath)
+		tb.Fatalf("CreateGrnDB() failed: %v", err)
+	}
+	return dirPath, dbPath, db
+}
+
+// removeTempGrnDB() removes a database created with createTempGrnDB().
+func removeTempGrnDB(tb testing.TB, dirPath string, db *GrnDB) {
+	if err := db.Close(); err != nil {
+		os.RemoveAll(dirPath)
+		tb.Fatalf("GrnDB.Close() failed: %v", err)
+	}
+	if err := os.RemoveAll(dirPath); err != nil {
+		tb.Fatalf("os.RemoveAll() failed: %v", err)
+	}
+}
+
+// createTempGrnTable() creates a database and a table for tests.
+// createTempGrnTable() uses createTempGrnDB() to create a database, so the
+// database must be removed with removeTempGrnDB().
+func createTempGrnTable(tb testing.TB, name string, options *TableOptions) (
+	string, string, *GrnDB, *GrnTable) {
+	dirPath, dbPath, db := createTempGrnDB(tb)
+	table, err := db.CreateTable(name, options)
+	if err != nil {
+		removeTempGrnDB(tb, dirPath, db)
+		tb.Fatalf("GrnDB.CreateTable() failed: %v", err)
+	}
+	return dirPath, dbPath, db, table
+}
+
+// createTempGrnColumn() creates a database, a table, and a column for tests.
+// createTempGrnColumn() uses createTempGrnDB() to create a database, so the
+// database must be removed with removeTempGrnDB().
+func createTempGrnColumn(tb testing.TB, tableName string,
+	tableOptions *TableOptions, columnName string, valueType string,
+	columnOptions *ColumnOptions) (
+	string, string, *GrnDB, *GrnTable, *GrnColumn) {
+	dirPath, dbPath, db, table := createTempGrnTable(tb, tableName, tableOptions)
+	column, err := table.CreateColumn(columnName, valueType, columnOptions)
+	if err != nil {
+		removeTempGrnDB(tb, dirPath, db)
+		tb.Fatalf("GrnDB.CreateTable() failed: %v", err)
+	}
+	return dirPath, dbPath, db, table, column
+}
+
+func TestCreateGrnDB(t *testing.T) {
+	dirPath, _, db := createTempGrnDB(t)
+	removeTempGrnDB(t, dirPath, db)
+}
+
+func TestOpenGrnDB(t *testing.T) {
+	dirPath, dbPath, db := createTempGrnDB(t)
+	db2, err := OpenGrnDB(dbPath)
+	if err != nil {
+		t.Fatalf("OpenGrnDB() failed: %v", err)
+	}
+	db2.Close()
+	removeTempGrnDB(t, dirPath, db)
+}
+
+func testGrnDBCreateTableWithKey(t *testing.T, keyType string) {
+	options := NewTableOptions()
+	options.TableType = PatTable
+	options.KeyType = keyType
+	dirPath, _, db, _ := createTempGrnTable(t, "Table", options)
+	removeTempGrnDB(t, dirPath, db)
+}
+
+func testGrnDBCreateTableWithValue(t *testing.T, valueType string) {
+	options := NewTableOptions()
+	options.TableType = PatTable
+	options.ValueType = valueType
+	dirPath, _, db, _ := createTempGrnTable(t, "Table", options)
+	removeTempGrnDB(t, dirPath, db)
+}
+
+func testGrnDBCreateTableWithRefKey(t *testing.T, keyType string) {
+	options := NewTableOptions()
+	options.TableType = PatTable
+	options.KeyType = keyType
+	dirPath, _, db, _ := createTempGrnTable(t, "To", options)
+	defer removeTempGrnDB(t, dirPath, db)
+
+	options = NewTableOptions()
+	options.TableType = PatTable
+	options.KeyType = "To"
+	_, err := db.CreateTable("From", options)
+	if err != nil {
+		t.Fatalf("GrnDB.CreateTable() failed: %v", err)
+	}
+}
+
+func testGrnDBCreateTableWithRefValue(t *testing.T, keyType string) {
+	options := NewTableOptions()
+	options.TableType = PatTable
+	options.KeyType = keyType
+	dirPath, _, db, _ := createTempGrnTable(t, "To", options)
+	defer removeTempGrnDB(t, dirPath, db)
+
+	options = NewTableOptions()
+	options.ValueType = ""
+	_, err := db.CreateTable("From", options)
+	if err != nil {
+		t.Fatalf("GrnDB.CreateTable() failed: %v", err)
+	}
+}
+
+func TestGrnDBCreateTableWithoutKeyValue(t *testing.T) {
+	dirPath, _, db, _ := createTempGrnTable(t, "Table", nil)
+	removeTempGrnDB(t, dirPath, db)
+}
+
+func TestGrnDBCreateTableWithBoolKey(t *testing.T) {
+	testGrnDBCreateTableWithKey(t, "Bool")
+}
+
+func TestGrnDBCreateTableWithIntKey(t *testing.T) {
+	testGrnDBCreateTableWithKey(t, "Int")
+}
+
+func TestGrnDBCreateTableWithFloatKey(t *testing.T) {
+	testGrnDBCreateTableWithKey(t, "Float")
+}
+
+func TestGrnDBCreateTableWithGeoPointKey(t *testing.T) {
+	testGrnDBCreateTableWithKey(t, "GeoPoint")
+}
+
+func TestGrnDBCreateTableWithTextKey(t *testing.T) {
+	testGrnDBCreateTableWithKey(t, "Text")
+}
+
+func TestGrnDBCreateTableWithBoolValue(t *testing.T) {
+	testGrnDBCreateTableWithValue(t, "Bool")
+}
+
+func TestGrnDBCreateTableWithIntValue(t *testing.T) {
+	testGrnDBCreateTableWithValue(t, "Int")
+}
+
+func TestGrnDBCreateTableWithFloatValue(t *testing.T) {
+	testGrnDBCreateTableWithValue(t, "Float")
+}
+
+func TestGrnDBCreateTableWithGeoPointValue(t *testing.T) {
+	testGrnDBCreateTableWithValue(t, "GeoPoint")
+}
+
+func TestGrnDBCreateTableWithBoolRefKey(t *testing.T) {
+	testGrnDBCreateTableWithRefKey(t, "Bool")
+}
+
+func TestGrnDBCreateTableWithIntRefKey(t *testing.T) {
+	testGrnDBCreateTableWithRefKey(t, "Int")
+}
+
+func TestGrnDBCreateTableWithFloatRefKey(t *testing.T) {
+	testGrnDBCreateTableWithRefKey(t, "Float")
+}
+
+func TestGrnDBCreateTableWithGeoPointRefKey(t *testing.T) {
+	testGrnDBCreateTableWithRefKey(t, "GeoPoint")
+}
+
+func TestGrnDBCreateTableWithTextRefKey(t *testing.T) {
+	testGrnDBCreateTableWithRefKey(t, "Text")
+}
+
+func TestGrnDBCreateTableWithBoolRefValue(t *testing.T) {
+	testGrnDBCreateTableWithRefValue(t, "Bool")
+}
+
+func TestGrnDBCreateTableWithIntRefValue(t *testing.T) {
+	testGrnDBCreateTableWithRefValue(t, "Int")
+}
+
+func TestGrnDBCreateTableWithFloatRefValue(t *testing.T) {
+	testGrnDBCreateTableWithRefValue(t, "Float")
+}
+
+func TestGrnDBCreateTableWithGeoPointRefValue(t *testing.T) {
+	testGrnDBCreateTableWithRefValue(t, "GeoPoint")
+}
+
+func TestGrnDBCreateTableWithTextRefValue(t *testing.T) {
+	testGrnDBCreateTableWithRefValue(t, "Text")
+}
+
+func generateRandomKey(keyType string) interface{} {
+	switch keyType {
+	case "Bool":
+		if (rand.Int() & 1) == 1 {
+			return True
+		} else {
+			return False
+		}
+	case "Int":
+		return Int(rand.Int63())
+	case "Float":
+		return Float(rand.Float64())
+	case "GeoPoint":
+		const (
+			MinLatitude  = 73531000
+			MaxLatitude  = 164006000
+			MinLongitude = 439451000
+			MaxLongitude = 554351000
+		)
+		latitude := MinLatitude + rand.Intn(MaxLatitude-MinLatitude+1)
+		longitude := MinLongitude + rand.Intn(MaxLongitude-MinLongitude+1)
+		return GeoPoint{int32(latitude), int32(longitude)}
+	case "Text":
+		return Text(strconv.Itoa(rand.Int()))
+	default:
+		return nil
+	}
+}
+
+func testGrnTableInsertRow(t *testing.T, keyType string) {
+	options := NewTableOptions()
+	if keyType != "" {
+		options.TableType = PatTable
+	}
+	options.KeyType = keyType
+	dirPath, _, db, table := createTempGrnTable(t, "Table", options)
+	defer removeTempGrnDB(t, dirPath, db)
+
+	count := 0
+	for i := 0; i < 100; i++ {
+		inserted, _, err := table.InsertRow(generateRandomKey(keyType))
+		if err != nil {
+			t.Fatalf("GrnTable.InsertRow() failed: %v", err)
+		}
+		if inserted {
+			count++
+		}
+	}
+	t.Logf("keyType = <%s>, count = %d", keyType, count)
+}
+
+func TestGrnTableInsertRowWithoutKey(t *testing.T) {
+	testGrnTableInsertRow(t, "")
+}
+
+func TestGrnTableInsertRowWithBoolKey(t *testing.T) {
+	testGrnTableInsertRow(t, "Bool")
+}
+
+func TestGrnTableInsertRowWithIntKey(t *testing.T) {
+	testGrnTableInsertRow(t, "Int")
+}
+
+func TestGrnTableInsertRowWithFloatKey(t *testing.T) {
+	testGrnTableInsertRow(t, "Float")
+}
+
+func TestGrnTableInsertRowWithGeoPointKey(t *testing.T) {
+	testGrnTableInsertRow(t, "GeoPoint")
+}
+
+func TestGrnTableInsertRowWithTextKey(t *testing.T) {
+	testGrnTableInsertRow(t, "Text")
+}
+
+func testGrnTableCreateScalarColumn(t *testing.T, valueType string) {
+	dirPath, _, db, table, _ :=
+		createTempGrnColumn(t, "Table", nil, "Value", valueType, nil)
+	defer removeTempGrnDB(t, dirPath, db)
+
+	if column, err := table.FindColumn("_id"); err != nil {
+		t.Fatalf("Table.FindColumn() failed: %v", err)
+	} else {
+		t.Logf("_id: %+v", column)
+	}
+	if column, err := table.FindColumn("Value"); err != nil {
+		t.Fatalf("Table.FindColumn() failed: %v", err)
+	} else {
+		t.Logf("Value: %+v", column)
+	}
+}
+
+func testGrnTableCreateVectorColumn(t *testing.T, valueType string) {
+	options := NewColumnOptions()
+	options.ColumnType = VectorColumn
+	dirPath, _, db, table, _ :=
+		createTempGrnColumn(t, "Table", nil, "Value", valueType, options)
+	defer removeTempGrnDB(t, dirPath, db)
+
+	if column, err := table.FindColumn("_id"); err != nil {
+		t.Fatalf("Table.FindColumn() failed: %v", err)
+	} else {
+		t.Logf("_id: %+v", column)
+	}
+	if column, err := table.FindColumn("Value"); err != nil {
+		t.Fatalf("Table.FindColumn() failed: %v", err)
+	} else {
+		t.Logf("Value: %+v", column)
+	}
+}
+
+func testGrnTableCreateScalarRefColumn(t *testing.T, keyType string) {
+	options := NewTableOptions()
+	options.TableType = PatTable
+	options.KeyType = keyType
+	dirPath, _, db, table, _ :=
+		createTempGrnColumn(t, "Table", options, "Value", "Table", nil)
+	defer removeTempGrnDB(t, dirPath, db)
+
+	if column, err := table.FindColumn("Value"); err != nil {
+		t.Fatalf("Table.FindColumn() failed: %v", err)
+	} else {
+		t.Logf("Value: %+v", column)
+	}
+	if column, err := table.FindColumn("Value._id"); err != nil {
+		t.Fatalf("Table.FindColumn() failed: %v", err)
+	} else {
+		t.Logf("Value._id: %+v", column)
+	}
+	if column, err := table.FindColumn("Value._key"); err != nil {
+		t.Fatalf("Table.FindColumn() failed: %v", err)
+	} else {
+		t.Logf("Value._key: %+v", column)
+	}
+}
+
+func testGrnTableCreateVectorRefColumn(t *testing.T, keyType string) {
+	tableOptions := NewTableOptions()
+	tableOptions.TableType = PatTable
+	tableOptions.KeyType = keyType
+	columnOptions := NewColumnOptions()
+	columnOptions.ColumnType = VectorColumn
+	dirPath, _, db, table, _ :=
+		createTempGrnColumn(t, "Table", tableOptions, "Value", "Table", columnOptions)
+	defer removeTempGrnDB(t, dirPath, db)
+
+	if column, err := table.FindColumn("Value"); err != nil {
+		t.Fatalf("Table.FindColumn() failed: %v", err)
+	} else {
+		t.Logf("Value: %+v", column)
+	}
+	if column, err := table.FindColumn("Value._id"); err != nil {
+		t.Fatalf("Table.FindColumn() failed: %v", err)
+	} else {
+		t.Logf("Value._id: %+v", column)
+	}
+	if column, err := table.FindColumn("Value._key"); err != nil {
+		t.Fatalf("Table.FindColumn() failed: %v", err)
+	} else {
+		t.Logf("Value._key: %+v", column)
+	}
+}
+
+func TestGrnTableCreateColumnForBool(t *testing.T) {
+	testGrnTableCreateScalarColumn(t, "Bool")
+}
+
+func TestGrnTableCreateColumnForInt(t *testing.T) {
+	testGrnTableCreateScalarColumn(t, "Int")
+}
+
+func TestGrnTableCreateColumnForFloat(t *testing.T) {
+	testGrnTableCreateScalarColumn(t, "Float")
+}
+
+func TestGrnTableCreateColumnForGeoPoint(t *testing.T) {
+	testGrnTableCreateScalarColumn(t, "GeoPoint")
+}
+
+func TestGrnTableCreateColumnForText(t *testing.T) {
+	testGrnTableCreateScalarColumn(t, "Text")
+}
+
+func TestGrnTableCreateColumnForBoolVector(t *testing.T) {
+	testGrnTableCreateVectorColumn(t, "Bool")
+}
+
+func TestGrnTableCreateColumnForIntVector(t *testing.T) {
+	testGrnTableCreateVectorColumn(t, "Int")
+}
+
+func TestGrnTableCreateColumnForFloatVector(t *testing.T) {
+	testGrnTableCreateVectorColumn(t, "Float")
+}
+
+func TestGrnTableCreateColumnForGeoPointVector(t *testing.T) {
+	testGrnTableCreateVectorColumn(t, "GeoPoint")
+}
+
+func TestGrnTableCreateColumnForTextVector(t *testing.T) {
+	testGrnTableCreateVectorColumn(t, "Text")
+}
+
+func TestGrnTableCreateColumnForRefToBool(t *testing.T) {
+	testGrnTableCreateScalarRefColumn(t, "Bool")
+}
+
+func TestGrnTableCreateColumnForRefToInt(t *testing.T) {
+	testGrnTableCreateScalarRefColumn(t, "Int")
+}
+
+func TestGrnTableCreateColumnForRefToFloat(t *testing.T) {
+	testGrnTableCreateScalarRefColumn(t, "Float")
+}
+
+func TestGrnTableCreateColumnForRefToGeoPoint(t *testing.T) {
+	testGrnTableCreateScalarRefColumn(t, "GeoPoint")
+}
+
+func TestGrnTableCreateColumnForRefToText(t *testing.T) {
+	testGrnTableCreateScalarRefColumn(t, "Text")
+}
+
+func TestGrnTableCreateColumnForRefToBoolVector(t *testing.T) {
+	testGrnTableCreateVectorRefColumn(t, "Bool")
+}
+
+func TestGrnTableCreateColumnForRefToIntVector(t *testing.T) {
+	testGrnTableCreateVectorRefColumn(t, "Int")
+}
+
+func TestGrnTableCreateColumnForRefToFloatVector(t *testing.T) {
+	testGrnTableCreateVectorRefColumn(t, "Float")
+}
+
+func TestGrnTableCreateColumnForRefToGeoPointVector(t *testing.T) {
+	testGrnTableCreateVectorRefColumn(t, "GeoPoint")
+}
+
+func TestGrnTableCreateColumnForRefToTextVector(t *testing.T) {
+	testGrnTableCreateVectorRefColumn(t, "Text")
+}
+
+func generateRandomValue(valueType string) interface{} {
+	switch valueType {
+	case "Bool":
+		if (rand.Int() & 1) == 1 {
+			return True
+		} else {
+			return False
+		}
+	case "Int":
+		return Int(rand.Int63())
+	case "Float":
+		return Float(rand.Float64())
+	case "GeoPoint":
+		const (
+			MinLatitude  = 73531000
+			MaxLatitude  = 164006000
+			MinLongitude = 439451000
+			MaxLongitude = 554351000
+		)
+		latitude := MinLatitude + rand.Intn(MaxLatitude-MinLatitude+1)
+		longitude := MinLongitude + rand.Intn(MaxLongitude-MinLongitude+1)
+		return GeoPoint{int32(latitude), int32(longitude)}
+	case "Text":
+		return Text(strconv.Itoa(rand.Int()))
+	default:
+		return nil
+	}
+}
+
+func generateRandomVectorValue(valueType string) interface{} {
+	size := rand.Int() % 10
+	switch valueType {
+	case "Bool":
+		value := make([]Bool, size)
+		for i := 0; i < size; i++ {
+			if (rand.Int() & 1) == 1 {
+				value[i] = True
+			}
+		}
+		return value
+	case "Int":
+		value := make([]Int, size)
+		for i := 0; i < size; i++ {
+			value[i] = Int(rand.Int63())
+		}
+		return value
+	case "Float":
+		value := make([]Float, size)
+		for i := 0; i < size; i++ {
+			value[i] = Float(rand.Float64())
+		}
+		return value
+	case "GeoPoint":
+		const (
+			MinLatitude  = 73531000
+			MaxLatitude  = 164006000
+			MinLongitude = 439451000
+			MaxLongitude = 554351000
+		)
+		value := make([]GeoPoint, size)
+		for i := 0; i < size; i++ {
+			latitude := MinLatitude + rand.Intn(MaxLatitude-MinLatitude+1)
+			longitude := MinLongitude + rand.Intn(MaxLongitude-MinLongitude+1)
+			value[i] = GeoPoint{int32(latitude), int32(longitude)}
+		}
+		return value
+	case "Text":
+		value := make([]Text, size)
+		for i := 0; i < size; i++ {
+			value[i] = Text(strconv.Itoa(rand.Int()))
+		}
+		return value
+	default:
+		return nil
+	}
+}
+
+func testGrnColumnSetValueForScalar(t *testing.T, valueType string) {
+	dirPath, _, db, table, column :=
+		createTempGrnColumn(t, "Table", nil, "Value", valueType, nil)
+	defer removeTempGrnDB(t, dirPath, db)
+
+	for i := 0; i < 100; i++ {
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			t.Fatalf("GrnTable.InsertRow() failed: %v", err)
+		}
+		if err := column.SetValue(id, generateRandomValue(valueType)); err != nil {
+			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+		}
+	}
+
+	bytes, _ := db.Query("select Table --limit 3")
+	t.Logf("valueType = <%s>, result = %s", valueType, string(bytes))
+}
+
+func testGrnColumnSetValueForVector(t *testing.T, valueType string) {
+	options := NewColumnOptions()
+	options.ColumnType = VectorColumn
+	dirPath, _, db, table, column :=
+		createTempGrnColumn(t, "Table", nil, "Value", valueType, options)
+	defer removeTempGrnDB(t, dirPath, db)
+
+	for i := 0; i < 100; i++ {
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			t.Fatalf("GrnTable.InsertRow() failed: %v", err)
+		}
+		if err := column.SetValue(id, generateRandomVectorValue(valueType)); err != nil {
+			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+		}
+	}
+
+	bytes, _ := db.Query("select Table --limit 3")
+	t.Logf("valueType = <%s>, result = %s", valueType, string(bytes))
+}
+
+func TestGrnColumnSetValueForBool(t *testing.T) {
+	testGrnColumnSetValueForScalar(t, "Bool")
+}
+
+func TestGrnColumnSetValueForInt(t *testing.T) {
+	testGrnColumnSetValueForScalar(t, "Int")
+}
+
+func TestGrnColumnSetValueForFloat(t *testing.T) {
+	testGrnColumnSetValueForScalar(t, "Float")
+}
+
+func TestGrnColumnSetValueForGeoPoint(t *testing.T) {
+	testGrnColumnSetValueForScalar(t, "GeoPoint")
+}
+
+func TestGrnColumnSetValueForText(t *testing.T) {
+	testGrnColumnSetValueForScalar(t, "Text")
+}
+
+func TestGrnColumnSetValueForBoolVector(t *testing.T) {
+	testGrnColumnSetValueForVector(t, "Bool")
+}
+
+func TestGrnColumnSetValueForIntVector(t *testing.T) {
+	testGrnColumnSetValueForVector(t, "Int")
+}
+
+func TestGrnColumnSetValueForFloatVector(t *testing.T) {
+	testGrnColumnSetValueForVector(t, "Float")
+}
+
+func TestGrnColumnSetValueForGeoPointVector(t *testing.T) {
+	testGrnColumnSetValueForVector(t, "GeoPoint")
+}
+
+func TestGrnColumnSetValueForTextVector(t *testing.T) {
+	testGrnColumnSetValueForVector(t, "Text")
+}
+
+func testGrnColumnGetValueForScalar(t *testing.T, valueType string) {
+	dirPath, _, db, table, column :=
+		createTempGrnColumn(t, "Table", nil, "Value", valueType, nil)
+	defer removeTempGrnDB(t, dirPath, db)
+
+	for i := 0; i < 100; i++ {
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			t.Fatalf("GrnTable.InsertRow() failed: %v", err)
+		}
+		value := generateRandomValue(valueType)
+		if err := column.SetValue(id, value); err != nil {
+			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+		}
+		if storedValue, err := column.GetValue(id); err != nil {
+			t.Fatalf("GrnColumn.GetValue() failed: %v", err)
+		} else if !reflect.DeepEqual(value, storedValue) {
+			t.Fatalf("GrnColumn.GetValue() failed: value = %v, storedValue = %v",
+				value, storedValue)
+		}
+	}
+}
+
+func testGrnColumnGetValueForVector(t *testing.T, valueType string) {
+	options := NewColumnOptions()
+	options.ColumnType = VectorColumn
+	dirPath, _, db, table, column :=
+		createTempGrnColumn(t, "Table", nil, "Value", valueType, options)
+	defer removeTempGrnDB(t, dirPath, db)
+
+	for i := 0; i < 100; i++ {
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			t.Fatalf("GrnTable.InsertRow() failed: %v", err)
+		}
+		value := generateRandomVectorValue(valueType)
+		if err := column.SetValue(id, value); err != nil {
+			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+		}
+		if storedValue, err := column.GetValue(id); err != nil {
+			t.Fatalf("GrnColumn.GetValue() failed: %v", err)
+		} else if !reflect.DeepEqual(value, storedValue) {
+			t.Fatalf("GrnColumn.GetValue() failed: value = %v, storedValue = %v",
+				value, storedValue)
+		}
+	}
+
+	bytes, _ := db.Query("select Table --limit 3")
+	t.Logf("valueType = <%s>, result = %s", valueType, string(bytes))
+}
+
+func TestGrnColumnGetValueForBool(t *testing.T) {
+	testGrnColumnGetValueForScalar(t, "Bool")
+}
+
+func TestGrnColumnGetValueForInt(t *testing.T) {
+	testGrnColumnGetValueForScalar(t, "Int")
+}
+
+func TestGrnColumnGetValueForFloat(t *testing.T) {
+	testGrnColumnGetValueForScalar(t, "Float")
+}
+
+func TestGrnColumnGetValueForGeoPoint(t *testing.T) {
+	testGrnColumnGetValueForScalar(t, "GeoPoint")
+}
+
+func TestGrnColumnGetValueForText(t *testing.T) {
+	testGrnColumnGetValueForScalar(t, "Text")
+}
+
+func TestGrnColumnGetValueForBoolVector(t *testing.T) {
+	testGrnColumnGetValueForVector(t, "Bool")
+}
+
+func TestGrnColumnGetValueForIntVector(t *testing.T) {
+	testGrnColumnGetValueForVector(t, "Int")
+}
+
+func TestGrnColumnGetValueForFloatVector(t *testing.T) {
+	testGrnColumnGetValueForVector(t, "Float")
+}
+
+func TestGrnColumnGetValueForGeoPointVector(t *testing.T) {
+	testGrnColumnGetValueForVector(t, "GeoPoint")
+}
+
+func TestGrnColumnGetValueForTextVector(t *testing.T) {
+	testGrnColumnGetValueForVector(t, "Text")
+}
+
+var numTestRows = 100000
+
+func benchmarkGrnColumnSetValueForScalar(b *testing.B, valueType string) {
+	b.StopTimer()
+	dirPath, _, db, table :=
+		createTempGrnTable(b, "Table", nil)
+	defer removeTempGrnDB(b, dirPath, db)
+	ids := make([]Int, numTestRows)
+	values := make([]interface{}, numTestRows)
+	for i, _ := range ids {
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			b.Fatalf("Table.InsertRow() failed: %s", err)
+		}
+		ids[i] = id
+		values[i] = generateRandomValue(valueType)
+	}
+
+	for i := 0; i < b.N; i++ {
+		column, err := table.CreateColumn(fmt.Sprintf("V%d", i), valueType, nil)
+		if err != nil {
+			b.Fatalf("Table.CreateColumn() failed(): %s", err)
+		}
+		b.StartTimer()
+		for i, id := range ids {
+			if err := column.SetValue(id, values[i]); err != nil {
+				b.Fatalf("Column.SetValue() failed: %s", err)
+			}
+			ids[i] = id
+		}
+		b.StopTimer()
+	}
+}
+
+func benchmarkGrnColumnSetValueForVector(b *testing.B, valueType string) {
+	b.StopTimer()
+	dirPath, _, db, table :=
+		createTempGrnTable(b, "Table", nil)
+	defer removeTempGrnDB(b, dirPath, db)
+	ids := make([]Int, numTestRows)
+	values := make([]interface{}, numTestRows)
+	for i, _ := range ids {
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			b.Fatalf("Table.InsertRow() failed: %s", err)
+		}
+		ids[i] = id
+		values[i] = generateRandomVectorValue(valueType)
+	}
+
+	for i := 0; i < b.N; i++ {
+		options := NewColumnOptions()
+		options.ColumnType = VectorColumn
+		column, err := table.CreateColumn(fmt.Sprintf("V%d", i), valueType, options)
+		if err != nil {
+			b.Fatalf("Table.CreateColumn() failed(): %s", err)
+		}
+		b.StartTimer()
+		for i, id := range ids {
+			if err := column.SetValue(id, values[i]); err != nil {
+				b.Fatalf("Column.SetValue() failed: %s", err)
+			}
+			ids[i] = id
+		}
+		b.StopTimer()
+	}
+}
+
+func BenchmarkGrnColumnSetValueForBool(b *testing.B) {
+	benchmarkGrnColumnSetValueForScalar(b, "Bool")
+}
+
+func BenchmarkGrnColumnSetValueForInt(b *testing.B) {
+	benchmarkGrnColumnSetValueForScalar(b, "Int")
+}
+
+func BenchmarkGrnColumnSetValueForFloat(b *testing.B) {
+	benchmarkGrnColumnSetValueForScalar(b, "Float")
+}
+
+func BenchmarkGrnColumnSetValueForGeoPoint(b *testing.B) {
+	benchmarkGrnColumnSetValueForScalar(b, "GeoPoint")
+}
+
+func BenchmarkGrnColumnSetValueForText(b *testing.B) {
+	benchmarkGrnColumnSetValueForScalar(b, "Text")
+}
+
+func BenchmarkGrnColumnSetValueForBoolVector(b *testing.B) {
+	benchmarkGrnColumnSetValueForVector(b, "Bool")
+}
+
+func BenchmarkGrnColumnSetValueForIntVector(b *testing.B) {
+	benchmarkGrnColumnSetValueForVector(b, "Int")
+}
+
+func BenchmarkGrnColumnSetValueForFloatVector(b *testing.B) {
+	benchmarkGrnColumnSetValueForVector(b, "Float")
+}
+
+func BenchmarkGrnColumnSetValueForGeoPointVector(b *testing.B) {
+	benchmarkGrnColumnSetValueForVector(b, "GeoPoint")
+}
+
+func BenchmarkGrnColumnSetValueForTextVector(b *testing.B) {
+	benchmarkGrnColumnSetValueForVector(b, "Text")
+}
+
+func benchmarkGrnColumnGetValueForScalar(b *testing.B, valueType string) {
+	dirPath, _, db, table, column :=
+		createTempGrnColumn(b, "Table", nil, "Value", valueType, nil)
+	defer removeTempGrnDB(b, dirPath, db)
+	ids := make([]Int, numTestRows)
+	for i, _ := range ids {
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			b.Fatalf("Table.InsertRow() failed: %s", err)
+		}
+		if err := column.SetValue(id, generateRandomValue(valueType)); err != nil {
+			b.Fatalf("Column.SetValue() failed: %s", err)
+		}
+		ids[i] = id
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		for _, id := range ids {
+			if _, err := column.GetValue(id); err != nil {
+				b.Fatalf("Column.GetValue() failed: %s", err)
+			}
+		}
+	}
+}
+
+func benchmarkGrnColumnGetValueForVector(b *testing.B, valueType string) {
+	options := NewColumnOptions()
+	options.ColumnType = VectorColumn
+	dirPath, _, db, table, column :=
+		createTempGrnColumn(b, "Table", nil, "Value", valueType, options)
+	defer removeTempGrnDB(b, dirPath, db)
+	ids := make([]Int, numTestRows)
+	for i, _ := range ids {
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			b.Fatalf("Table.InsertRow() failed: %s", err)
+		}
+		if err := column.SetValue(id, generateRandomVectorValue(valueType)); err != nil {
+			b.Fatalf("Column.SetValue() failed: %s", err)
+		}
+		ids[i] = id
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		for _, id := range ids {
+			if _, err := column.GetValue(id); err != nil {
+				b.Fatalf("Column.GetValue() failed: %s", err)
+			}
+		}
+	}
+}
+
+func BenchmarkGrnColumnGetValueForBool(b *testing.B) {
+	benchmarkGrnColumnGetValueForScalar(b, "Bool")
+}
+
+func BenchmarkGrnColumnGetValueForInt(b *testing.B) {
+	benchmarkGrnColumnGetValueForScalar(b, "Int")
+}
+
+func BenchmarkGrnColumnGetValueForFloat(b *testing.B) {
+	benchmarkGrnColumnGetValueForScalar(b, "Float")
+}
+
+func BenchmarkGrnColumnGetValueForGeoPoint(b *testing.B) {
+	benchmarkGrnColumnGetValueForScalar(b, "GeoPoint")
+}
+
+func BenchmarkGrnColumnGetValueForText(b *testing.B) {
+	benchmarkGrnColumnGetValueForScalar(b, "Text")
+}
+
+func BenchmarkGrnColumnGetValueForBoolVector(b *testing.B) {
+	benchmarkGrnColumnGetValueForVector(b, "Bool")
+}
+
+func BenchmarkGrnColumnGetValueForIntVector(b *testing.B) {
+	benchmarkGrnColumnGetValueForVector(b, "Int")
+}
+
+func BenchmarkGrnColumnGetValueForFloatVector(b *testing.B) {
+	benchmarkGrnColumnGetValueForVector(b, "Float")
+}
+
+func BenchmarkGrnColumnGetValueForGeoPointVector(b *testing.B) {
+	benchmarkGrnColumnGetValueForVector(b, "GeoPoint")
+}
+
+func BenchmarkGrnColumnGetValueForTextVector(b *testing.B) {
+	benchmarkGrnColumnGetValueForVector(b, "Text")
+}
+
+func benchmarkGrnDBSelectForScalar(b *testing.B, valueType string) {
+	dirPath, _, db, table, column :=
+		createTempGrnColumn(b, "Table", nil, "Value", valueType, nil)
+	defer removeTempGrnDB(b, dirPath, db)
+	ids := make([]Int, numTestRows)
+	for i, _ := range ids {
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			b.Fatalf("Table.InsertRow() failed: %s", err)
+		}
+		if err := column.SetValue(id, generateRandomValue(valueType)); err != nil {
+			b.Fatalf("Column.SetValue() failed: %s", err)
+		}
+		ids[i] = id
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		_, err := db.Query("select Table --output_columns Value --limit -1 --cache no")
+		if err != nil {
+			b.Fatalf("DB.Query() failed: %s", err)
+		}
+	}
+}
+
+func benchmarkGrnDBSelectForVector(b *testing.B, valueType string) {
+	options := NewColumnOptions()
+	options.ColumnType = VectorColumn
+	dirPath, _, db, table, column :=
+		createTempGrnColumn(b, "Table", nil, "Value", valueType, options)
+	defer removeTempGrnDB(b, dirPath, db)
+	ids := make([]Int, numTestRows)
+	for i, _ := range ids {
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			b.Fatalf("Table.InsertRow() failed: %s", err)
+		}
+		if err := column.SetValue(id, generateRandomVectorValue(valueType)); err != nil {
+			b.Fatalf("Column.SetValue() failed: %s", err)
+		}
+		ids[i] = id
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		bytes, err := db.Query("select Table --output_columns Value --limit -1 --cache no")
+		if err != nil {
+			b.Fatalf("DB.Query() failed: %s", err)
+		}
+		if len(bytes) < numTestRows * 5 {
+			b.Fatalf("DB.Query() failed: %s", err)
+		}
+	}
+}
+
+func BenchmarkGrnDBSelectForBool(b *testing.B) {
+	benchmarkGrnDBSelectForScalar(b, "Bool")
+}
+
+func BenchmarkGrnDBSelectForInt(b *testing.B) {
+	benchmarkGrnDBSelectForScalar(b, "Int")
+}
+
+func BenchmarkGrnDBSelectForFloat(b *testing.B) {
+	benchmarkGrnDBSelectForScalar(b, "Float")
+}
+
+func BenchmarkGrnDBSelectForGeoPoint(b *testing.B) {
+	benchmarkGrnDBSelectForScalar(b, "GeoPoint")
+}
+
+func BenchmarkGrnDBSelectForText(b *testing.B) {
+	benchmarkGrnDBSelectForScalar(b, "Text")
+}
+
+func BenchmarkGrnDBSelectForBoolVector(b *testing.B) {
+	benchmarkGrnDBSelectForVector(b, "Bool")
+}
+
+func BenchmarkGrnDBSelectForIntVector(b *testing.B) {
+	benchmarkGrnDBSelectForVector(b, "Int")
+}
+
+func BenchmarkGrnDBSelectForFloatVector(b *testing.B) {
+	benchmarkGrnDBSelectForVector(b, "Float")
+}
+
+func BenchmarkGrnDBSelectForGeoPointVector(b *testing.B) {
+	benchmarkGrnDBSelectForVector(b, "GeoPoint")
+}
+
+func BenchmarkGrnDBSelectForTextVector(b *testing.B) {
+	benchmarkGrnDBSelectForVector(b, "Text")
+}
+
+func benchmarkGrnColumnGetValuesForScalar(b *testing.B, valueType string) {
+	dirPath, _, db, table, column :=
+		createTempGrnColumn(b, "Table", nil, "Value", valueType, nil)
+	defer removeTempGrnDB(b, dirPath, db)
+	ids := make([]Int, numTestRows)
+	for i, _ := range ids {
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			b.Fatalf("Table.InsertRow() failed: %s", err)
+		}
+		if err := column.SetValue(id, generateRandomValue(valueType)); err != nil {
+			b.Fatalf("Column.SetValue() failed: %s", err)
+		}
+		ids[i] = id
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		if _, err := column.GetValues(ids); err != nil {
+			b.Fatalf("Column.GetValues() failed: %s", err)
+		}
+	}
+}
+
+func BenchmarkGrnColumnGetValuesForBool(b *testing.B) {
+	benchmarkGrnColumnGetValuesForScalar(b, "Bool")
+}
+
+func TestBuildDB(t *testing.T) {
+	db, err := CreateGrnDB("/tmp/groonga/db")
+	if err != nil {
+		t.Fatalf("CreateGrnDB() failed: %v", err)
+	}
+//	tableOptions := NewTableOptions()
+//	tableOptions.TableType = PatTable
+//	tableOptions.KeyType = "Int"
+//	table, err := db.CreateTable("Table", tableOptions)
+//	if err != nil {
+//		t.Fatalf("GrnDB.CreateTable() failed: %v", err)
+//	}
+	table, err := db.CreateTable("Table", nil)
+	if err != nil {
+		t.Fatalf("GrnDB.CreateTable() failed: %v", err)
+	}
+	column, err := table.CreateColumn("X", "Int", nil)
+	if err != nil {
+		t.Fatalf("GrnDB.CreateColumn() failed: %v", err)
+	}
+	column2, err := table.CreateColumn("Y", "Int", nil)
+	if err != nil {
+		t.Fatalf("GrnDB.CreateColumn() failed: %v", err)
+	}
+	column3, err := table.CreateColumn("Z", "Int", nil)
+	if err != nil {
+		t.Fatalf("GrnDB.CreateColumn() failed: %v", err)
+	}
+	column4, err := table.CreateColumn("A", "Bool", nil)
+	if err != nil {
+		t.Fatalf("GrnDB.CreateColumn() failed: %v", err)
+	}
+	column5, err := table.CreateColumn("B", "Float", nil)
+	if err != nil {
+		t.Fatalf("GrnDB.CreateColumn() failed: %v", err)
+	}
+//	column6, err := table.CreateColumn("C", "Time", nil)
+//	if err != nil {
+//		t.Fatalf("GrnDB.CreateColumn() failed: %v", err)
+//	}
+	column7, err := table.CreateColumn("D", "Text", nil)
+	if err != nil {
+		t.Fatalf("GrnDB.CreateColumn() failed: %v", err)
+	}
+	column8, err := table.CreateColumn("E", "GeoPoint", nil)
+	if err != nil {
+		t.Fatalf("GrnDB.CreateColumn() failed: %v", err)
+	}
+	const MaxID = 1000000
+	for {
+//		_, id, err := table.InsertRow(Int(rand.Int63() % 100000000))
+		_, id, err := table.InsertRow(nil)
+		if err != nil {
+			t.Fatalf("GrnTable.InsertRow() failed: %v", err)
+		}
+		if (id == MaxID) {
+		  break
+		}
+	}
+	for id := 1; id <= MaxID; id++ {
+		if err := column.SetValue(Int(id), Int(rand.Int63() % 100)); err != nil {
+			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+		}
+		if err := column2.SetValue(Int(id), Int(rand.Int63() % 100)); err != nil {
+			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+		}
+		if err := column3.SetValue(Int(id), Int(rand.Int63() % 100)); err != nil {
+			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+		}
+		boolValue := False
+		if (rand.Int() & 1) == 1 {
+		  boolValue = True
+		}
+		if err := column4.SetValue(Int(id), boolValue); err != nil {
+			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+		}
+		if err := column5.SetValue(Int(id), Float(float64(rand.Int31()))); err != nil {
+//		if err := column5.SetValue(Int(id), Float(rand.Float64())); err != nil {
+			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+		}
+//		if err := column6.SetValue(Int(id), Int(rand.Int63() / 1000)); err != nil {
+//			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+//		}
+		if err := column7.SetValue(Int(id), Text(strconv.Itoa(rand.Int()) + "\nABC")); err != nil {
+			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+		}
+		const (
+			MinLatitude  = 73531000
+			MaxLatitude  = 164006000
+			MinLongitude = 439451000
+			MaxLongitude = 554351000
+		)
+		latitude := MinLatitude + rand.Intn(MaxLatitude-MinLatitude+1)
+		longitude := MinLongitude + rand.Intn(MaxLongitude-MinLongitude+1)
+		geoValue := GeoPoint{int32(latitude), int32(longitude)}
+		if err := column8.SetValue(Int(id), geoValue); err != nil {
+			t.Fatalf("GrnColumn.SetValue() failed: %v", err)
+		}
+	}
+}

  Added: options.go (+72 -0) 100644
===================================================================
--- /dev/null
+++ options.go    2015-06-19 14:34:28 +0900 (4d984fb)
@@ -0,0 +1,72 @@
+package gnx
+
+//import (
+//	""
+//)
+
+// -- TableOptions --
+
+// Constants for TableOptions.
+type TableType int
+
+const (
+	ArrayTable = TableType(iota)
+	HashTable
+	PatTable
+	DatTable
+)
+
+// http://groonga.org/docs/reference/commands/table_create.html
+type TableOptions struct {
+	TableType
+	WithSIS          bool     // KEY_WITH_SIS
+	KeyType          string   // http://groonga.org/docs/reference/types.html
+	ValueType        string   // http://groonga.org/docs/reference/types.html
+	DefaultTokenizer string   // http://groonga.org/docs/reference/tokenizers.html
+	Normalizer       string   // http://groonga.org/docs/reference/normalizers.html
+	TokenFilters     []string // http://groonga.org/docs/reference/token_filters.html
+}
+
+// NewTableOptions() creates a new TableOptions object with the default
+// settings.
+func NewTableOptions() *TableOptions {
+	var options TableOptions
+	return &options
+}
+
+// -- ColumnOptions --
+
+// Constants for ColumnOptions.
+type ColumnType int
+
+const (
+	ScalarColumn = ColumnType(iota)
+	VectorColumn
+	IndexColumn
+)
+
+// Constants for ColumnOptions.
+type CompressionType int
+
+const (
+	NoCompression = CompressionType(iota)
+	ZlibCompression
+	LzoCompression
+)
+
+// http://groonga.org/ja/docs/reference/commands/column_create.html
+type ColumnOptions struct {
+	ColumnType
+	CompressionType
+	WithSection  bool // WITH_SECTION
+	WithWeight   bool // WITH_WEIGHT
+	WithPosition bool // WITH_POSITION
+	Source       string
+}
+
+// NewColumnOptions() creates a new ColumnOptions object with the default
+// settings.
+func NewColumnOptions() *ColumnOptions {
+	var options ColumnOptions
+	return &options
+}




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