[Groonga-commit] groonga/grngo at 316295f [master] Use new cgo structures and functions.

Back to archive index

susumu.yata null+****@clear*****
Wed Jul 22 18:43:59 JST 2015


susumu.yata	2015-07-22 18:43:59 +0900 (Wed, 22 Jul 2015)

  New Revision: 316295f753bda41f6897a5eb366310f8d78e0a4c
  https://github.com/groonga/grngo/commit/316295f753bda41f6897a5eb366310f8d78e0a4c

  Message:
    Use new cgo structures and functions.

  Modified files:
    grngo.c
    grngo.go
    grngo.h
    grngo_test.go

  Modified: grngo.c (+36 -9)
===================================================================
--- grngo.c    2015-07-22 11:48:18 +0900 (88025b2)
+++ grngo.c    2015-07-22 18:43:59 +0900 (643c154)
@@ -120,7 +120,7 @@ _grngo_new_db(void) {
   memset(db, 0, sizeof(*db));
   db->ctx = NULL;
   db->obj = NULL;
-  db->estr = NULL;
+  db->estr = db->estr_buf;
   return db;
 }
 
@@ -141,7 +141,6 @@ _grngo_create_db(grngo_db *db, const char *path) {
   if (!db->ctx) {
     return GRN_NO_MEMORY_AVAILABLE;
   }
-  db->estr = db->ctx->errbuf;
   db->obj = grn_db_create(db->ctx, path, NULL);
   if (!db->obj) {
     if (db->ctx->rc != GRN_SUCCESS) {
@@ -235,6 +234,31 @@ grngo_close_db(grngo_db *db) {
   }
 }
 
+grn_rc
+grngo_send(grngo_db *db, const char *cmd, size_t cmd_len) {
+  if (!db || (!cmd && cmd_len)) {
+    return GRN_INVALID_ARGUMENT;
+  }
+  grn_rc rc = grn_ctx_send(db->ctx, cmd, cmd_len, 0);
+  if (rc != GRN_SUCCESS) {
+    return rc;
+  }
+  return db->ctx->rc;
+}
+
+grn_rc
+grngo_recv(grngo_db *db, char **res, unsigned int *res_len) {
+  if (!db || !res || !res_len) {
+    return GRN_INVALID_ARGUMENT;
+  }
+  int flags;
+  grn_rc rc = grn_ctx_recv(db->ctx, res, res_len, &flags);
+  if (rc != GRN_SUCCESS) {
+    return rc;
+  }
+  return db->ctx->rc;
+}
+
 // -- grngo_table --
 
 static grngo_table *
@@ -497,6 +521,7 @@ _grngo_push_column(grngo_column *column, grn_obj **table,
   if (rc != GRN_SUCCESS) {
     return rc;
   }
+  grn_ctx *ctx = column->db->ctx;
   switch (obj->header.type) {
     case GRN_COLUMN_VAR_SIZE: {
       grn_obj_flags type = obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
@@ -509,17 +534,17 @@ _grngo_push_column(grngo_column *column, grn_obj **table,
     case GRN_TABLE_NO_KEY:
     case GRN_ACCESSOR:
     case GRN_COLUMN_FIX_SIZE: {
-      grn_id range = grn_obj_get_range(column->db->ctx, obj);
+      grn_id range = grn_obj_get_range(ctx, obj);
       if (range == GRN_DB_VOID) {
-        grn_obj_unlink(column->db->ctx, obj);
+        grn_obj_unlink(ctx, obj);
         return GRN_INVALID_ARGUMENT;
       } else if (range <= GRNGO_MAX_BUILTIN_TYPE_ID) {
         column->value_type = range;
         *table = NULL;
       } else {
-        grn_obj *range_obj = grn_ctx_at(column->db->ctx, range);
-        if (!grn_obj_is_table(column->db->ctx, range_obj)) {
-          grn_obj_unlink(column->db->ctx, range_obj);
+        grn_obj *range_obj = grn_ctx_at(ctx, range);
+        if (!grn_obj_is_table(ctx, range_obj)) {
+          grn_obj_unlink(ctx, range_obj);
           return GRN_INVALID_ARGUMENT;
         }
         *table = range_obj;
@@ -527,7 +552,7 @@ _grngo_push_column(grngo_column *column, grn_obj **table,
       break;
     }
     default: {
-      grn_obj_unlink(column->db->ctx, obj);
+      grn_obj_unlink(ctx, obj);
       return GRN_INVALID_ARGUMENT;
     }
   }
@@ -535,9 +560,11 @@ _grngo_push_column(grngo_column *column, grn_obj **table,
   grn_obj **new_objs = (grn_obj **)GRNGO_REALLOC(column->db, column->objs,
                                                  new_size);
   if (!new_objs) {
+    grn_obj_unlink(ctx, obj);
     return GRN_NO_MEMORY_AVAILABLE;
   }
   column->objs = new_objs;
+  column->objs[column->num_objs] = obj;
   column->num_objs++;
   return GRN_SUCCESS;
 }
@@ -608,7 +635,7 @@ grngo_open_column(grngo_table *table, const char *name, size_t name_len,
   return rc;
 }
 
-grn_rc
+void
 grngo_close_column(grngo_column *column) {
   if (column) {
     _grngo_delete_column(column);

  Modified: grngo.go (+168 -560)
===================================================================
--- grngo.go    2015-07-22 11:48:18 +0900 (15b06e3)
+++ grngo.go    2015-07-22 18:43:59 +0900 (ebe9a7e)
@@ -177,30 +177,18 @@ func rcString(rc C.grn_rc) string {
 	}
 }
 
-// newGrnError returns an error related to a Groonga or Grngo operation.
-func newGrnError(opName string, rc *C.grn_rc, ctx *C.grn_ctx) error {
-	switch {
-	case rc == nil:
-		if ctx == nil {
-			return fmt.Errorf("%s failed", opName)
-		}
-		if ctx.rc == C.GRN_SUCCESS {
-			return fmt.Errorf("%s failed: ctx.rc = %s",
-				opName, rcString(ctx.rc))
-		}
-		msg := C.GoString(&ctx.errbuf[0])
-		return fmt.Errorf("%s failed: ctx.rc = %s, ctx.errbuf = %s",
-			opName, rcString(ctx.rc), msg)
-	case ctx == nil:
-		return fmt.Errorf("%s failed: rc = %s", opName, *rc)
-	case ctx.rc == C.GRN_SUCCESS:
+// newError returns an error related to a Groonga or Grngo operation.
+func newGrnError(opName string, rc C.grn_rc, db *DB) error {
+	if db == nil {
+		return fmt.Errorf("%s failed: rc = %s", opName, rcString(rc))
+	}
+	ctx := db.c.ctx
+	if ctx.errbuf[0] == 0 {
 		return fmt.Errorf("%s failed: rc = %s, ctx.rc = %s",
-			opName, rcString(*rc), rcString(ctx.rc))
-	default:
-		msg := C.GoString(&ctx.errbuf[0])
-		return fmt.Errorf("%s failed: rc = %s, ctx.rc = %s, ctx.errbuf = %s",
-			opName, rcString(*rc), rcString(ctx.rc), msg)
+			opName, rcString(rc), rcString(ctx.rc))
 	}
+	return fmt.Errorf("%s failed: rc = %s, ctx.rc = %s, ctx.errbuf = %s",
+		opName, rcString(rc), rcString(ctx.rc), C.GoString(&ctx.errbuf[0]))
 }
 
 // newInvalidKeyTypeError returns an error for data type conflict.
@@ -398,7 +386,7 @@ func GrnInit() error {
 	if grnInitCount == 0 {
 		if !grnInitFinDisabled {
 			if rc := C.grn_init(); rc != C.GRN_SUCCESS {
-				return newGrnError("grn_init()", &rc, nil)
+				return newGrnError("grn_init()", rc, nil)
 			}
 		}
 	}
@@ -418,7 +406,7 @@ func GrnFin() error {
 	case 1:
 		if !grnInitFinDisabled {
 			if rc := C.grn_fin(); rc != C.GRN_SUCCESS {
-				return newGrnError("grn_fin()", &rc, nil)
+				return newGrnError("grn_fin()", rc, nil)
 			}
 		}
 	}
@@ -426,43 +414,18 @@ func GrnFin() error {
 	return nil
 }
 
-// openGrnCtx returns a new grn_ctx.
-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, newGrnError("grn_ctx_open()", nil, nil)
-	}
-	return ctx, nil
-}
-
-// closeGrnCtx finalizes a grn_ctx.
-func closeGrnCtx(ctx *C.grn_ctx) error {
-	rc := C.grn_ctx_close(ctx)
-	GrnFin()
-	if rc != C.GRN_SUCCESS {
-		return newGrnError("grn_ctx_close()", &rc, nil)
-	}
-	return nil
-}
-
 // -- DB --
 
 // DB is associated with a Groonga database with its context.
 type DB struct {
-	ctx    *C.grn_ctx        // The associated grn_ctx.
-	obj    *C.grn_obj        // The associated database.
+  c      *C.grngo_db       // The associated C object.
 	tables map[string]*Table // A cache to find tables by name.
 }
 
 // newDB returns a new DB.
-func newDB(ctx *C.grn_ctx, obj *C.grn_obj) *DB {
+func newDB(c *C.grngo_db) *DB {
 	db := new(DB)
-	db.ctx = ctx
-	db.obj = obj
+	db.c = c
 	db.tables = make(map[string]*Table)
 	return db
 }
@@ -473,21 +436,21 @@ func newDB(ctx *C.grn_ctx, obj *C.grn_obj) *DB {
 // Note that CreateDB initializes Groonga if the new DB will be the only one
 // and implicit initialization is not disabled.
 func CreateDB(path string) (*DB, error) {
-	ctx, err := openGrnCtx()
-	if err != nil {
+	if err := GrnInit(); err != nil {
 		return nil, err
 	}
+	pathBytes := []byte(path)
 	var cPath *C.char
-	if path != "" {
-		cPath = C.CString(path)
-		defer C.free(unsafe.Pointer(cPath))
+	if len(pathBytes) != 0 {
+		cPath = (*C.char)(unsafe.Pointer(&pathBytes[0]));
 	}
-	obj := C.grn_db_create(ctx, cPath, nil)
-	if obj == nil {
-		defer closeGrnCtx(ctx)
-		return nil, newGrnError("grn_db_create()", nil, ctx)
+	var c *C.grngo_db
+	rc := C.grngo_create_db(cPath, C.size_t(len(pathBytes)), &c);
+	if (rc != C.GRN_SUCCESS) {
+		GrnFin()
+		return nil, newGrnError("grngo_create_db()", rc, nil)
 	}
-	return newDB(ctx, obj), nil
+	return newDB(c), nil
 }
 
 // OpenDB opens an existing Groonga database and returns a new DB associated
@@ -496,53 +459,41 @@ func CreateDB(path string) (*DB, error) {
 // Note that CreateDB initializes Groonga if the new DB will be the only one
 // and implicit initialization is not disabled.
 func OpenDB(path string) (*DB, error) {
-	ctx, err := openGrnCtx()
-	if err != nil {
+	if err := GrnInit(); 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 {
-		defer closeGrnCtx(ctx)
-		return nil, newGrnError("grn_db_open()", nil, ctx)
+	pathBytes := []byte(path)
+	var cPath *C.char
+	if len(pathBytes) != 0 {
+		cPath = (*C.char)(unsafe.Pointer(&pathBytes[0]));
+	}
+	var c *C.grngo_db
+	rc := C.grngo_open_db(cPath, C.size_t(len(pathBytes)), &c);
+	if (rc != C.GRN_SUCCESS) {
+		GrnFin()
+		return nil, newGrnError("grngo_open_db()", rc, nil)
 	}
-	return newDB(ctx, obj), nil
+	return newDB(c), nil
 }
 
 // Close finalizes a DB.
 func (db *DB) Close() error {
-	rc := C.grn_obj_close(db.ctx, db.obj)
-	if rc != C.GRN_SUCCESS {
-		defer closeGrnCtx(db.ctx)
-		return newGrnError("grn_obj_close()", &rc, db.ctx)
-	}
-	return closeGrnCtx(db.ctx)
+	C.grngo_close_db(db.c)
+	return GrnFin()
 }
 
 // Refresh clears maps for Table and Column name resolution.
 //
-// If a table or column is renamed or removed, the maps may cause a name
+// If a table or column is renamed or removed, old maps can cause a name
 // resolution error. In such a case, you should use Refresh or reopen the
 // Groonga database to resolve it.
 func (db *DB) Refresh() error {
 	for _, table := range db.tables {
-		nameBytes := []byte(table.name)
-		cName := (*C.char)(unsafe.Pointer(&nameBytes[0]))
-		var tableObj *C.grn_obj
-		C.grngo_find_table(db.ctx, cName, C.size_t(len(nameBytes)), &tableObj)
-		if tableObj != table.obj {
-			continue
-		}
 		for _, column := range table.columns {
-			nameBytes := []byte(column.name)
-			cName := (*C.char)(unsafe.Pointer(&nameBytes[0]))
-			columnObj := C.grn_obj_column(db.ctx, table.obj, cName, C.uint(len(nameBytes)))
-			if columnObj == column.obj {
-				C.grn_obj_unlink(db.ctx, column.obj)
-			}
+			C.grngo_close_column(column.c)
 		}
-		C.grn_obj_unlink(db.ctx, table.obj)
+		table.columns = make(map[string]*Column)
+		C.grngo_close_table(table.c)
 	}
 	db.tables = make(map[string]*Table)
 	return nil
@@ -553,14 +504,21 @@ func (db *DB) Refresh() error {
 //
 // See http://groonga.org/docs/reference/command.html for details.
 func (db *DB) Send(command string) error {
+	command = strings.TrimSpace(command)
+	if strings.HasPrefix(command, "table_remove") ||
+		strings.HasPrefix(command, "table_rename") ||
+		strings.HasPrefix(command, "column_remove") ||
+		strings.HasPrefix(command, "column_rename") {
+		db.Refresh()
+	}
 	commandBytes := []byte(command)
 	var cCommand *C.char
 	if len(commandBytes) != 0 {
 		cCommand = (*C.char)(unsafe.Pointer(&commandBytes[0]))
 	}
-	C.grn_ctx_send(db.ctx, cCommand, C.uint(len(commandBytes)), 0)
-	if db.ctx.rc != C.GRN_SUCCESS {
-		return newGrnError("grn_ctx_send()", nil, db.ctx)
+	rc := C.grngo_send(db.c, cCommand, C.size_t(len(commandBytes)))
+	if rc != C.GRN_SUCCESS {
+		return newGrnError("grngo_send()", rc, db)
 	}
 	return nil
 }
@@ -598,15 +556,13 @@ func (db *DB) SendEx(name string, options map[string]string) error {
 //
 // See http://groonga.org/docs/reference/command.html for details.
 func (db *DB) Recv() ([]byte, error) {
-	var resultBuffer *C.char
-	var resultLength C.uint
-	var flags C.int
-	C.grn_ctx_recv(db.ctx, &resultBuffer, &resultLength, &flags)
-	if db.ctx.rc != C.GRN_SUCCESS {
-		return nil, newGrnError("grn_ctx_recv()", nil, db.ctx)
+	var res *C.char
+	var resLen C.uint
+	rc := C.grngo_recv(db.c, &res, &resLen)
+	if rc != C.GRN_SUCCESS {
+		return nil, newGrnError("grngo_recv()", rc, db)
 	}
-	result := C.GoBytes(unsafe.Pointer(resultBuffer), C.int(resultLength))
-	return result, nil
+	return C.GoBytes(unsafe.Pointer(res), C.int(resLen)), nil
 }
 
 // Query executes a Groonga command and returns the result.
@@ -734,58 +690,12 @@ func (db *DB) FindTable(name string) (*Table, error) {
 	if len(nameBytes) != 0 {
 		cName = (*C.char)(unsafe.Pointer(&nameBytes[0]))
 	}
-	var obj *C.grn_obj
-	rc := C.grngo_find_table(db.ctx, cName, C.size_t(len(nameBytes)), &obj)
-	if rc != C.GRN_SUCCESS {
-		return nil, newGrnError("grngo_find_table()", &rc, db.ctx)
-	}
-	// Check the key type.
-	var keyInfo C.grngo_table_type_info
-	rc = C.grngo_table_get_key_info(db.ctx, obj, &keyInfo)
+	var c *C.grngo_table
+	rc := C.grngo_open_table(db.c, cName, C.size_t(len(nameBytes)), &c)
 	if rc != C.GRN_SUCCESS {
-		return nil, newGrnError("grngo_table_get_key_info()", &rc, db.ctx)
+		return nil, newGrnError("grngo_find_table()", rc, db)
 	}
-	keyType := DataType(keyInfo.data_type)
-	var keyTable *Table
-	if keyInfo.ref_table != nil {
-		defer C.grn_obj_unlink(db.ctx, keyInfo.ref_table)
-		var cKeyTableName *C.char
-		rc := C.grngo_table_get_name(db.ctx, keyInfo.ref_table, &cKeyTableName)
-		if rc != C.GRN_SUCCESS {
-			return nil, newGrnError("grngo_table_get_name()", &rc, db.ctx)
-		}
-		defer C.free(unsafe.Pointer(cKeyTableName))
-		var err error
-		keyTable, err = db.FindTable(C.GoString(cKeyTableName))
-		if err != nil {
-			return nil, err
-		}
-		keyType = keyTable.keyType
-	}
-	// Check the value type.
-	var valueInfo C.grngo_table_type_info
-	rc = C.grngo_table_get_value_info(db.ctx, obj, &valueInfo)
-	if rc != C.GRN_SUCCESS {
-		return nil, newGrnError("grngo_table_get_value_info()", &rc, db.ctx)
-	}
-	valueType := DataType(valueInfo.data_type)
-	var valueTable *Table
-	if valueInfo.ref_table != nil {
-		defer C.grn_obj_unlink(db.ctx, valueInfo.ref_table)
-		var cValueTableName *C.char
-		rc := C.grngo_table_get_name(db.ctx, valueInfo.ref_table, &cValueTableName)
-		if rc != C.GRN_SUCCESS {
-			return nil, newGrnError("grngo_table_get_name()", &rc, db.ctx)
-		}
-		defer C.free(unsafe.Pointer(cValueTableName))
-		var err error
-		valueTable, err = db.FindTable(C.GoString(cValueTableName))
-		if err != nil {
-			return nil, err
-		}
-		valueType = valueTable.keyType
-	}
-	table := newTable(db, obj, name, keyType, keyTable, valueType, valueTable)
+	table := newTable(db, c, name)
 	db.tables[name] = table
 	return table, nil
 }
@@ -852,85 +762,60 @@ func (db *DB) SetValue(tableName, columnName string, id uint32, value interface{
 
 // Table is associated with a Groonga table.
 type Table struct {
-	db         *DB                // The owner DB.
-	obj        *C.grn_obj         // The associated table.
-	name       string             // The table name.
-	keyType    DataType           // The output type of keys.
-	keyTable   *Table             // Keys' reference table or nil if not available.
-	valueType  DataType           // The output type of values.
-	valueTable *Table             // Values' reference table or nil if not available.
-	columns    map[string]*Column // A cache to find columns by name.
+	db      *DB                // The owner DB.
+	c       *C.grngo_table     // The associated C object.
+	name    string             // The table name.
+	columns map[string]*Column // A cache to find columns by name.
 }
 
 // newTable returns a new Table.
-func newTable(db *DB, obj *C.grn_obj, name string, keyType DataType, keyTable *Table, valueType DataType, valueTable *Table) *Table {
+func newTable(db *DB, c *C.grngo_table, name string) *Table {
 	var table Table
 	table.db = db
-	table.obj = obj
+	table.c = c
 	table.name = name
-	table.keyType = keyType
-	table.keyTable = keyTable
-	table.valueType = valueType
-	table.valueTable = valueTable
 	table.columns = make(map[string]*Column)
 	return &table
 }
 
 // InsertRow finds or inserts a row.
 func (table *Table) InsertRow(key interface{}) (inserted bool, id uint32, err error) {
-	var result C.grngo_table_insertion_result
+	var rc C.grn_rc
+	var cInserted C.grn_bool
+	var cID C.grn_id
 	switch key := key.(type) {
 	case nil:
-		if table.keyType != Void {
-			return false, NilID, newInvalidKeyTypeError(table.keyType, Void)
-		}
-		result = C.grngo_table_insert_void(table.db.ctx, table.obj)
+		rc = C.grngo_insert_void(table.c, &cInserted, &cID)
 	case bool:
-		if table.keyType != Bool {
-			return false, NilID, newInvalidKeyTypeError(table.keyType, Bool)
-		}
-		tmpKey := C.grn_bool(C.GRN_FALSE)
+		cKey := C.grn_bool(C.GRN_FALSE)
 		if key {
-			tmpKey = C.grn_bool(C.GRN_TRUE)
+			cKey = C.grn_bool(C.GRN_TRUE)
 		}
-		result = C.grngo_table_insert_bool(table.db.ctx, table.obj, tmpKey)
+		rc = C.grngo_insert_bool(table.c, cKey, &cInserted, &cID)
 	case int64:
-		switch table.keyType {
-		case Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64, Time:
-		default:
-			return false, NilID, newInvalidKeyTypeError(table.keyType, LazyInt)
-		}
-		result = C.grngo_table_insert_int(table.db.ctx, table.obj, C.grn_builtin_type(table.keyType), C.int64_t(key))
+		cKey := C.int64_t(key)
+		rc = C.grngo_insert_int(table.c, cKey, &cInserted, &cID)
 	case float64:
-		if table.keyType != Float {
-			return false, NilID, newInvalidKeyTypeError(table.keyType, Float)
-		}
-		tmpKey := C.double(key)
-		result = C.grngo_table_insert_float(table.db.ctx, table.obj, tmpKey)
+		cKey := C.double(key)
+		rc = C.grngo_insert_float(table.c, cKey, &cInserted, &cID)
 	case []byte:
-		if table.keyType != ShortText {
-			return false, NilID, newInvalidKeyTypeError(table.keyType, Text)
-		}
-		var tmpKey C.grngo_text
+		var cKey C.grngo_text
 		if len(key) != 0 {
-			tmpKey.ptr = (*C.char)(unsafe.Pointer(&key[0]))
-			tmpKey.size = C.size_t(len(key))
+			cKey.ptr = (*C.char)(unsafe.Pointer(&key[0]))
+			cKey.size = C.size_t(len(key))
 		}
-		result = C.grngo_table_insert_text(table.db.ctx, table.obj, &tmpKey)
+		rc = C.grngo_insert_text(table.c, cKey, &cInserted, &cID)
 	case GeoPoint:
-		if (table.keyType != TokyoGeoPoint) && (table.keyType != WGS84GeoPoint) {
-			return false, NilID, newInvalidKeyTypeError(table.keyType, LazyGeoPoint)
-		}
-		tmpKey := C.grn_geo_point{C.int(key.Latitude), C.int(key.Longitude)}
-		result = C.grngo_table_insert_geo_point(table.db.ctx, table.obj, &tmpKey)
+		cKey := C.grn_geo_point{C.int(key.Latitude), C.int(key.Longitude)}
+		rc = C.grngo_insert_geo_point(table.c, cKey, &cInserted, &cID)
 	default:
 		return false, NilID, fmt.Errorf(
 			"unsupported key type: typeName = <%s>", reflect.TypeOf(key).Name())
 	}
-	if result.rc != C.GRN_SUCCESS {
-		return false, NilID, newGrnError("grngo_table_insert_*()", &result.rc, table.db.ctx)
+	if rc != C.GRN_SUCCESS {
+		return false, NilID, newGrnError("grngo_insert_*()", rc, table.db)
 	}
-	return result.inserted == C.GRN_TRUE, uint32(result.id), nil
+	return cInserted == C.GRN_TRUE, uint32(cID), nil
 }
 
 // SetValue assigns a value.
@@ -1032,103 +917,22 @@ func (table *Table) CreateColumn(name string, valueType string, options *ColumnO
 	return table.FindColumn(name)
 }
 
-// findColumn finds a column.
-func (table *Table) findColumn(name string) (*Column, 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, newGrnError("grn_obj_column()", nil, table.db.ctx)
-	}
-	var valueType DataType
-	var valueTable *Table
-	var isVector bool
-	switch name {
-	case "_id":
-		valueType = UInt32
-	case "_key":
-		valueType = table.keyType
-		valueTable = table.keyTable
-	case "_value":
-		valueType = table.valueType
-		valueTable = table.valueTable
-	default:
-		// Check the value type.
-		var valueInfo C.grngo_column_type_info
-		rc := C.grngo_column_get_value_info(table.db.ctx, obj, &valueInfo)
-		if rc != C.GRN_SUCCESS {
-			return nil, newGrnError("grngo_column_get_value_info", &rc, table.db.ctx)
-		}
-		valueType = DataType(valueInfo.data_type)
-		isVector = valueInfo.is_vector == C.GRN_TRUE
-		if valueInfo.ref_table != nil {
-			defer C.grn_obj_unlink(table.db.ctx, valueInfo.ref_table)
-			var cValueTableName *C.char
-			rc := C.grngo_table_get_name(table.db.ctx, valueInfo.ref_table, &cValueTableName)
-			if rc != C.GRN_SUCCESS {
-				return nil, newGrnError("grngo_table_get_name()", &rc, table.db.ctx)
-			}
-			defer C.free(unsafe.Pointer(cValueTableName))
-			var err error
-			valueTable, err = table.db.FindTable(C.GoString(cValueTableName))
-			if err != nil {
-				return nil, err
-			}
-			valueType = valueTable.keyType
-		}
-	}
-	column := newColumn(table, obj, name, valueType, isVector, valueTable)
-	table.columns[name] = column
-	return column, nil
-}
-
 // FindColumn finds a column.
 func (table *Table) FindColumn(name string) (*Column, 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)
+	var c *C.grngo_column
+	rc := C.grngo_open_column(table.c, cName, C.size_t(len(nameBytes)), &c)
+	if rc != C.GRN_SUCCESS {
+		return nil, newGrnError("grngo_open_column()", rc, table.db)
 	}
-	column = newColumn(table, obj, name, column.valueType, isVector, valueTable)
+	column := newColumn(table, c, name)
 	table.columns[name] = column
 	return column, nil
 }
@@ -1137,299 +941,103 @@ func (table *Table) FindColumn(name string) (*Column, error) {
 
 // Column is associated with a Groonga column or accessor.
 type Column struct {
-	table      *Table     // The owner table.
-	obj        *C.grn_obj // The associated column or accessor.
-	name       string     // The column name.
-	valueType  DataType   // The built-in data type of values.
-	isVector   bool       // Whether values are vector or not.
-	valueTable *Table     // The reference table or nil if not available.
+	table      *Table          // The owner table.
+	c          *C.grngo_column // The associated C object.
+	name       string          // The column name.
 }
 
 // newColumn returns a new Column.
-func newColumn(table *Table, obj *C.grn_obj, name string, valueType DataType, isVector bool, valueTable *Table) *Column {
+func newColumn(table *Table, c *C.grngo_column, name string) *Column {
 	var column Column
 	column.table = table
-	column.obj = obj
+	column.c = c
 	column.name = name
-	column.valueType = valueType
-	column.isVector = isVector
-	column.valueTable = valueTable
 	return &column
 }
 
-// setBool assigns a Bool value.
-func (column *Column) setBool(id uint32, value bool) error {
-	if (column.valueType != Bool) || column.isVector {
-		return newInvalidValueTypeError(column.valueType, column.isVector, Bool, false)
-	}
-	var grnValue C.grn_bool = C.GRN_FALSE
-	if value {
-		grnValue = C.GRN_TRUE
-	}
-	if ok := C.grngo_column_set_bool(column.table.db.ctx, column.obj,
-		C.grn_id(id), grnValue); ok != C.GRN_TRUE {
-		return fmt.Errorf("grngo_column_set_bool() failed")
-	}
-	return nil
-}
-
-// setInt assigns an Int value.
-func (column *Column) setInt(id uint32, value int64) error {
-	if column.isVector {
-		return newInvalidValueTypeError(column.valueType, column.isVector, LazyInt, false)
-	}
-	ctx := column.table.db.ctx
-	var ok C.grn_bool
-	switch column.valueType {
-	case Int8:
-		grnValue := C.int8_t(value)
-		ok = C.grngo_column_set_int8(ctx, column.obj, C.grn_id(id), grnValue)
-	case Int16:
-		grnValue := C.int16_t(value)
-		ok = C.grngo_column_set_int16(ctx, column.obj, C.grn_id(id), grnValue)
-	case Int32:
-		grnValue := C.int32_t(value)
-		ok = C.grngo_column_set_int32(ctx, column.obj, C.grn_id(id), grnValue)
-	case Int64:
-		grnValue := C.int64_t(value)
-		ok = C.grngo_column_set_int64(ctx, column.obj, C.grn_id(id), grnValue)
-	case UInt8:
-		grnValue := C.uint8_t(value)
-		ok = C.grngo_column_set_uint8(ctx, column.obj, C.grn_id(id), grnValue)
-	case UInt16:
-		grnValue := C.uint16_t(value)
-		ok = C.grngo_column_set_uint16(ctx, column.obj, C.grn_id(id), grnValue)
-	case UInt32:
-		grnValue := C.uint32_t(value)
-		ok = C.grngo_column_set_uint32(ctx, column.obj, C.grn_id(id), grnValue)
-	case UInt64:
-		grnValue := C.uint64_t(value)
-		ok = C.grngo_column_set_uint64(ctx, column.obj, C.grn_id(id), grnValue)
-	case Time:
-		grnValue := C.int64_t(value)
-		ok = C.grngo_column_set_time(ctx, column.obj, C.grn_id(id), grnValue)
-	default:
-		return newInvalidValueTypeError(column.valueType, column.isVector, LazyInt, false)
-	}
-	if ok != C.GRN_TRUE {
-		return fmt.Errorf("grngo_column_set_int*() failed")
-	}
-	return nil
-}
-
-// setFloat assigns a Float value.
-func (column *Column) setFloat(id uint32, value float64) error {
-	if (column.valueType != Float) || column.isVector {
-		return newInvalidValueTypeError(column.valueType, column.isVector, Float, false)
-	}
-	grnValue := C.double(value)
-	if ok := C.grngo_column_set_float(column.table.db.ctx, column.obj,
-		C.grn_id(id), grnValue); ok != C.GRN_TRUE {
-		return fmt.Errorf("grngo_column_set_float() failed")
-	}
-	return nil
-}
-
-// setText assigns a Text value.
-func (column *Column) setText(id uint32, value []byte) error {
-	switch column.valueType {
-	case ShortText, Text, LongText:
-	default:
-		return newInvalidValueTypeError(column.valueType, column.isVector, Text, false)
-	}
-	if column.isVector {
-		return newInvalidValueTypeError(column.valueType, column.isVector, Text, false)
-	}
-	var grnValue C.grngo_text
-	if len(value) != 0 {
-		grnValue.ptr = (*C.char)(unsafe.Pointer(&value[0]))
-		grnValue.size = C.size_t(len(value))
-	}
-	if ok := C.grngo_column_set_text(column.table.db.ctx, column.obj,
-		C.grn_id(id), &grnValue); ok != C.GRN_TRUE {
-		return fmt.Errorf("grngo_column_set_text() failed")
-	}
-	return nil
-}
-
-// setGeoPoint assigns a GeoPoint value.
-func (column *Column) setGeoPoint(id uint32, value GeoPoint) error {
-	switch column.valueType {
-	case TokyoGeoPoint, WGS84GeoPoint:
-	default:
-		return newInvalidValueTypeError(column.valueType, column.isVector, LazyGeoPoint, false)
-	}
-	if column.isVector {
-		return fmt.Errorf("value type conflict")
-	}
-	grnValue := C.grn_geo_point{C.int(value.Latitude), C.int(value.Longitude)}
-	if ok := C.grngo_column_set_geo_point(column.table.db.ctx, column.obj,
-		C.grn_builtin_type(column.valueType),
-		C.grn_id(id), grnValue); ok != C.GRN_TRUE {
-		return fmt.Errorf("grngo_column_set_geo_point() failed")
-	}
-	return nil
-}
-
-// setBoolVector assigns a Bool vector.
-func (column *Column) setBoolVector(id uint32, value []bool) error {
-	if (column.valueType != Bool) || !column.isVector {
-		return newInvalidValueTypeError(column.valueType, column.isVector, Bool, true)
-	}
-	grnValue := make([]C.grn_bool, len(value))
-	for i, v := range value {
-		if v {
-			grnValue[i] = C.GRN_TRUE
-		}
-	}
-	var grnVector C.grngo_vector
-	if len(grnValue) != 0 {
-		grnVector.ptr = unsafe.Pointer(&grnValue[0])
-		grnVector.size = C.size_t(len(grnValue))
-	}
-	if ok := C.grngo_column_set_bool_vector(column.table.db.ctx, column.obj,
-		C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
-		return fmt.Errorf("grngo_column_set_bool_vector() failed")
-	}
-	return nil
-}
-
-// setIntVector assigns an Int vector.
-func (column *Column) setIntVector(id uint32, value []int64) error {
-	if !column.isVector {
-		return newInvalidValueTypeError(column.valueType, column.isVector, LazyInt, true)
-	}
-	var grnVector C.grngo_vector
-	if len(value) != 0 {
-		grnVector.ptr = unsafe.Pointer(&value[0])
-		grnVector.size = C.size_t(len(value))
-	}
-	ctx := column.table.db.ctx
-	obj := column.obj
-	var ok C.grn_bool
-	switch column.valueType {
-	case Int8:
-		ok = C.grngo_column_set_int8_vector(ctx, obj, C.grn_id(id), &grnVector)
-	case Int16:
-		ok = C.grngo_column_set_int16_vector(ctx, obj, C.grn_id(id), &grnVector)
-	case Int32:
-		ok = C.grngo_column_set_int32_vector(ctx, obj, C.grn_id(id), &grnVector)
-	case Int64:
-		ok = C.grngo_column_set_int64_vector(ctx, obj, C.grn_id(id), &grnVector)
-	case UInt8:
-		ok = C.grngo_column_set_uint8_vector(ctx, obj, C.grn_id(id), &grnVector)
-	case UInt16:
-		ok = C.grngo_column_set_uint16_vector(ctx, obj, C.grn_id(id), &grnVector)
-	case UInt32:
-		ok = C.grngo_column_set_uint32_vector(ctx, obj, C.grn_id(id), &grnVector)
-	case UInt64:
-		ok = C.grngo_column_set_uint64_vector(ctx, obj, C.grn_id(id), &grnVector)
-	case Time:
-		ok = C.grngo_column_set_time_vector(ctx, obj, C.grn_id(id), &grnVector)
-	default:
-		return newInvalidValueTypeError(column.valueType, column.isVector, LazyInt, true)
-	}
-	if ok != C.GRN_TRUE {
-		return fmt.Errorf("grngo_column_set_int*_vector() failed")
-	}
-	return nil
-}
-
-// setFloatVector assigns a Float vector.
-func (column *Column) setFloatVector(id uint32, value []float64) error {
-	if (column.valueType != Float) || !column.isVector {
-		return newInvalidValueTypeError(column.valueType, column.isVector, Float, true)
-	}
-	var grnVector C.grngo_vector
-	if len(value) != 0 {
-		grnVector.ptr = unsafe.Pointer(&value[0])
-		grnVector.size = C.size_t(len(value))
-	}
-	if ok := C.grngo_column_set_float_vector(column.table.db.ctx, column.obj,
-		C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
-		return fmt.Errorf("grngo_column_set_float_vector() failed")
-	}
-	return nil
-}
-
-// setTextVector assigns a Text vector.
-func (column *Column) setTextVector(id uint32, value [][]byte) error {
-	if !column.isVector {
-		return newInvalidValueTypeError(column.valueType, column.isVector, Text, true)
-	}
-	switch column.valueType {
-	case ShortText, Text, LongText:
-	default:
-		return newInvalidValueTypeError(column.valueType, column.isVector, Text, true)
-	}
-	grnValue := make([]C.grngo_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.grngo_vector
-	if len(grnValue) != 0 {
-		grnVector.ptr = unsafe.Pointer(&grnValue[0])
-		grnVector.size = C.size_t(len(grnValue))
-	}
-	if ok := C.grngo_column_set_text_vector(column.table.db.ctx,
-		column.obj, C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
-		return fmt.Errorf("grngo_column_set_text_vector() failed")
-	}
-	return nil
-}
-
-// setGeoPointVector assigns a GeoPoint vector.
-func (column *Column) setGeoPointVector(id uint32, value []GeoPoint) error {
-	if !column.isVector {
-		return newInvalidValueTypeError(column.valueType, column.isVector, LazyGeoPoint, true)
-	}
-	switch column.valueType {
-	case TokyoGeoPoint, WGS84GeoPoint:
-	default:
-		return newInvalidValueTypeError(column.valueType, column.isVector, LazyGeoPoint, true)
-	}
-	var grnVector C.grngo_vector
-	if len(value) != 0 {
-		grnVector.ptr = unsafe.Pointer(&value[0])
-		grnVector.size = C.size_t(len(value))
-	}
-	if ok := C.grngo_column_set_geo_point_vector(column.table.db.ctx,
-		column.obj, C.grn_builtin_type(column.valueType),
-		C.grn_id(id), &grnVector); ok != C.GRN_TRUE {
-		return fmt.Errorf("grngo_column_set_geo_point_vector() failed")
-	}
-	return nil
-}
-
 // SetValue assigns a value.
 func (column *Column) SetValue(id uint32, value interface{}) error {
-	switch v := value.(type) {
+	var rc C.grn_rc
+	cID := C.grn_id(id)
+	switch value := value.(type) {
 	case bool:
-		return column.setBool(id, v)
+		cValue := C.grn_bool(C.GRN_FALSE)
+		if value {
+			cValue = C.grn_bool(C.GRN_TRUE)
+		}
+		rc = C.grngo_set_bool(column.c, cID, cValue)
 	case int64:
-		return column.setInt(id, v)
+		cValue := C.int64_t(value)
+		rc = C.grngo_set_int(column.c, cID, cValue)
 	case float64:
-		return column.setFloat(id, v)
+		cValue := C.double(value)
+		rc = C.grngo_set_float(column.c, cID, cValue)
 	case []byte:
-		return column.setText(id, v)
+		var cValue C.grngo_text
+		if len(value) != 0 {
+			cValue.ptr = (*C.char)(unsafe.Pointer(&value[0]))
+			cValue.size = C.size_t(len(value))
+		}
+		rc = C.grngo_set_text(column.c, cID, cValue)
 	case GeoPoint:
-		return column.setGeoPoint(id, v)
+		cValue := C.grn_geo_point{C.int(value.Latitude), C.int(value.Longitude)}
+		rc = C.grngo_set_geo_point(column.c, cID, cValue)
 	case []bool:
-		return column.setBoolVector(id, v)
+		vector := make([]C.grn_bool, len(value))
+		for i := 0; i < len(value); i++ {
+			if value[i] {
+				vector[i] = C.grn_bool(C.GRN_TRUE)
+			}
+		}
+		var cValue C.grngo_vector
+		if len(vector) != 0 {
+			cValue.ptr = unsafe.Pointer(&vector[0])
+			cValue.size = C.size_t(len(vector))
+		}
+		rc = C.grngo_set_bool_vector(column.c, cID, cValue)
 	case []int64:
-		return column.setIntVector(id, v)
+		var cValue C.grngo_vector
+		if len(value) != 0 {
+			cValue.ptr = unsafe.Pointer(&value[0])
+			cValue.size = C.size_t(len(value))
+		}
+		rc = C.grngo_set_int_vector(column.c, cID, cValue)
 	case []float64:
-		return column.setFloatVector(id, v)
+		var cValue C.grngo_vector
+		if len(value) != 0 {
+			cValue.ptr = unsafe.Pointer(&value[0])
+			cValue.size = C.size_t(len(value))
+		}
+		rc = C.grngo_set_float_vector(column.c, cID, cValue)
 	case [][]byte:
-		return column.setTextVector(id, v)
+		vector := make([]C.grngo_text, len(value))
+		for i := 0; i < len(value); i++ {
+			if len(value[i]) != 0 {
+				vector[i].ptr = (*C.char)(unsafe.Pointer(&value[i][0]))
+				vector[i].size = C.size_t(len(value[i]))
+			}
+		}
+		var cValue C.grngo_vector
+		if len(vector) != 0 {
+			cValue.ptr = unsafe.Pointer(&vector[0])
+			cValue.size = C.size_t(len(vector))
+		}
+		rc = C.grngo_set_text_vector(column.c, cID, cValue)
 	case []GeoPoint:
-		return column.setGeoPointVector(id, v)
+		var cValue C.grngo_vector
+		if len(value) != 0 {
+			cValue.ptr = unsafe.Pointer(&value[0])
+			cValue.size = C.size_t(len(value))
+		}
+		rc = C.grngo_set_geo_point_vector(column.c, cID, cValue)
 	default:
-		return fmt.Errorf("unsupported value type: name = <%s>", reflect.TypeOf(value).Name())
+		return fmt.Errorf("unsupported value type: name = <%s>",
+			reflect.TypeOf(value).Name())
 	}
+	if rc != C.GRN_SUCCESS {
+		return newGrnError("grngo_set_*()", rc, column.table.db)
+	}
+	return nil
 }
 
 //// getBool gets a Bool value.

  Modified: grngo.h (+4 -1)
===================================================================
--- grngo.h    2015-07-22 11:48:18 +0900 (95afd98)
+++ grngo.h    2015-07-22 18:43:59 +0900 (639d607)
@@ -37,6 +37,9 @@ grn_rc grngo_create_db(const char *path, size_t path_len, grngo_db **db);
 grn_rc grngo_open_db(const char *path, size_t path_len, grngo_db **db);
 void grngo_close_db(grngo_db *db);
 
+grn_rc grngo_send(grngo_db *db, const char *cmd, size_t cmd_len);
+grn_rc grngo_recv(grngo_db *db, char **res, unsigned int *res_len);
+
 // -- grngo_table --
 
 typedef struct {
@@ -75,7 +78,7 @@ typedef struct {
 
 grn_rc grngo_open_column(grngo_table *tbl, const char *name, size_t name_len,
                          grngo_column **column);
-grn_rc grngo_close_column(grngo_column *column);
+void grngo_close_column(grngo_column *column);
 
 grn_rc grngo_set_bool(grngo_column *column, grn_id id, grn_bool value);
 grn_rc grngo_set_int(grngo_column *column, grn_id id, int64_t value);

  Modified: grngo_test.go (+112 -120)
===================================================================
--- grngo_test.go    2015-07-22 11:48:18 +0900 (9887521)
+++ grngo_test.go    2015-07-22 18:43:59 +0900 (02b6732)
@@ -610,7 +610,7 @@ func TestTableInsertRowWithWGS84GeoPointKey(t *testing.T) {
 	testTableInsertRow(t, "WGS84GeoPoint")
 }
 
-func testTableCreateScalarColumn(t *testing.T, valueType string) {
+func testTableCreateColumn(t *testing.T, valueType string) {
 	dirPath, _, db, table, _ :=
 		createTempColumn(t, "Table", nil, "Value", valueType, nil)
 	defer removeTempDB(t, dirPath, db)
@@ -627,281 +627,273 @@ func testTableCreateScalarColumn(t *testing.T, valueType string) {
 	}
 }
 
-func testTableCreateVectorColumn(t *testing.T, valueType string) {
-	dirPath, _, db, table, _ :=
-		createTempColumn(t, "Table", nil, "Value", "[]"+valueType, nil)
-	defer removeTempDB(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 testTableCreateScalarRefColumn(t *testing.T, keyType string) {
-	options := NewTableOptions()
-	options.KeyType = keyType
-	dirPath, _, db, table, _ :=
-		createTempColumn(t, "Table", options, "Value", "Table", nil)
-	defer removeTempDB(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 testTableCreateVectorRefColumn(t *testing.T, keyType string) {
-	tableOptions := NewTableOptions()
-	tableOptions.KeyType = keyType
-	dirPath, _, db, table, _ :=
-		createTempColumn(t, "Table", tableOptions, "Value", "[]Table", nil)
-	defer removeTempDB(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 TestTableCreateColumnForBool(t *testing.T) {
-	testTableCreateScalarColumn(t, "Bool")
+	testTableCreateColumn(t, "Bool")
 }
 
 func TestTableCreateColumnForInt8(t *testing.T) {
-	testTableCreateScalarColumn(t, "Int8")
+	testTableCreateColumn(t, "Int8")
 }
 
 func TestTableCreateColumnForInt16(t *testing.T) {
-	testTableCreateScalarColumn(t, "Int16")
+	testTableCreateColumn(t, "Int16")
 }
 
 func TestTableCreateColumnForInt32(t *testing.T) {
-	testTableCreateScalarColumn(t, "Int32")
+	testTableCreateColumn(t, "Int32")
 }
 
 func TestTableCreateColumnForInt64(t *testing.T) {
-	testTableCreateScalarColumn(t, "Int64")
+	testTableCreateColumn(t, "Int64")
 }
 
 func TestTableCreateColumnForUInt8(t *testing.T) {
-	testTableCreateScalarColumn(t, "UInt8")
+	testTableCreateColumn(t, "UInt8")
 }
 
 func TestTableCreateColumnForUInt16(t *testing.T) {
-	testTableCreateScalarColumn(t, "UInt16")
+	testTableCreateColumn(t, "UInt16")
 }
 
 func TestTableCreateColumnForUInt32(t *testing.T) {
-	testTableCreateScalarColumn(t, "UInt32")
+	testTableCreateColumn(t, "UInt32")
 }
 
 func TestTableCreateColumnForUInt64(t *testing.T) {
-	testTableCreateScalarColumn(t, "UInt64")
+	testTableCreateColumn(t, "UInt64")
 }
 
 func TestTableCreateColumnForFloat(t *testing.T) {
-	testTableCreateScalarColumn(t, "Float")
+	testTableCreateColumn(t, "Float")
 }
 
 func TestTableCreateColumnForTime(t *testing.T) {
-	testTableCreateScalarColumn(t, "Time")
+	testTableCreateColumn(t, "Time")
 }
 
 func TestTableCreateColumnForShortText(t *testing.T) {
-	testTableCreateScalarColumn(t, "ShortText")
+	testTableCreateColumn(t, "ShortText")
 }
 
 func TestTableCreateColumnForText(t *testing.T) {
-	testTableCreateScalarColumn(t, "Text")
+	testTableCreateColumn(t, "Text")
 }
 
 func TestTableCreateColumnForLongText(t *testing.T) {
-	testTableCreateScalarColumn(t, "LongText")
+	testTableCreateColumn(t, "LongText")
 }
 
 func TestTableCreateColumnForTokyoGeoPoint(t *testing.T) {
-	testTableCreateScalarColumn(t, "TokyoGeoPoint")
+	testTableCreateColumn(t, "TokyoGeoPoint")
 }
 
 func TestTableCreateColumnForWGS84GeoPoint(t *testing.T) {
-	testTableCreateScalarColumn(t, "WGS84GeoPoint")
+	testTableCreateColumn(t, "WGS84GeoPoint")
 }
 
 func TestTableCreateColumnForBoolVector(t *testing.T) {
-	testTableCreateVectorColumn(t, "Bool")
+	testTableCreateColumn(t, "[]Bool")
 }
 
 func TestTableCreateColumnForInt8Vector(t *testing.T) {
-	testTableCreateVectorColumn(t, "Int8")
+	testTableCreateColumn(t, "[]Int8")
 }
 
 func TestTableCreateColumnForInt16Vector(t *testing.T) {
-	testTableCreateVectorColumn(t, "Int16")
+	testTableCreateColumn(t, "[]Int16")
 }
 
 func TestTableCreateColumnForInt32Vector(t *testing.T) {
-	testTableCreateVectorColumn(t, "Int32")
+	testTableCreateColumn(t, "[]Int32")
 }
 
 func TestTableCreateColumnForInt64Vector(t *testing.T) {
-	testTableCreateVectorColumn(t, "Int64")
+	testTableCreateColumn(t, "[]Int64")
 }
 
 func TestTableCreateColumnForUInt8Vector(t *testing.T) {
-	testTableCreateVectorColumn(t, "UInt8")
+	testTableCreateColumn(t, "[]UInt8")
 }
 
 func TestTableCreateColumnForUInt16Vector(t *testing.T) {
-	testTableCreateVectorColumn(t, "UInt16")
+	testTableCreateColumn(t, "[]UInt16")
 }
 
 func TestTableCreateColumnForUInt32Vector(t *testing.T) {
-	testTableCreateVectorColumn(t, "UInt32")
+	testTableCreateColumn(t, "[]UInt32")
 }
 
 func TestTableCreateColumnForUInt64Vector(t *testing.T) {
-	testTableCreateVectorColumn(t, "UInt64")
+	testTableCreateColumn(t, "[]UInt64")
 }
 
 func TestTableCreateColumnForFloatVector(t *testing.T) {
-	testTableCreateVectorColumn(t, "Float")
+	testTableCreateColumn(t, "[]Float")
 }
 
 func TestTableCreateColumnForTimeVector(t *testing.T) {
-	testTableCreateVectorColumn(t, "Time")
+	testTableCreateColumn(t, "[]Time")
 }
 
 func TestTableCreateColumnForShortTextVector(t *testing.T) {
-	testTableCreateVectorColumn(t, "ShortText")
+	testTableCreateColumn(t, "[]ShortText")
 }
 
 func TestTableCreateColumnForTextVector(t *testing.T) {
-	testTableCreateVectorColumn(t, "Text")
+	testTableCreateColumn(t, "[]Text")
 }
 
 func TestTableCreateColumnForLongTextVector(t *testing.T) {
-	testTableCreateVectorColumn(t, "LongText")
+	testTableCreateColumn(t, "[]LongText")
 }
 
 func TestTableCreateColumnForTokyoGeoPointVector(t *testing.T) {
-	testTableCreateVectorColumn(t, "TokyoGeoPoint")
+	testTableCreateColumn(t, "[]TokyoGeoPoint")
 }
 
 func TestTableCreateColumnForWGS84GeoPointVector(t *testing.T) {
-	testTableCreateVectorColumn(t, "WGS84GeoPoint")
+	testTableCreateColumn(t, "[]WGS84GeoPoint")
+}
+
+func testTableCreateRefColumn(t *testing.T, keyType string) {
+	valueType := "Table"
+	if strings.HasPrefix(keyType, "[]") {
+		keyType = keyType[2:]
+		valueType = "[]Table"
+	}
+	options := NewTableOptions()
+	options.KeyType = keyType
+	dirPath, _, db, table, _ :=
+		createTempColumn(t, "Table", options, "Value", valueType, nil)
+	defer removeTempDB(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 TestTableCreateColumnForRefToBool(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "Bool")
+	testTableCreateRefColumn(t, "Bool")
 }
 
 func TestTableCreateColumnForRefToInt8(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "Int8")
+	testTableCreateRefColumn(t, "Int8")
 }
 
 func TestTableCreateColumnForRefToInt16(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "Int16")
+	testTableCreateRefColumn(t, "Int16")
 }
 
 func TestTableCreateColumnForRefToInt32(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "Int32")
+	testTableCreateRefColumn(t, "Int32")
 }
 
 func TestTableCreateColumnForRefToInt64(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "Int64")
+	testTableCreateRefColumn(t, "Int64")
 }
 
 func TestTableCreateColumnForRefToUInt8(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "UInt8")
+	testTableCreateRefColumn(t, "UInt8")
 }
 
 func TestTableCreateColumnForRefToUInt16(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "UInt16")
+	testTableCreateRefColumn(t, "UInt16")
 }
 
 func TestTableCreateColumnForRefToUInt32(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "UInt32")
+	testTableCreateRefColumn(t, "UInt32")
 }
 
 func TestTableCreateColumnForRefToUInt64(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "UInt64")
+	testTableCreateRefColumn(t, "UInt64")
 }
 
 func TestTableCreateColumnForRefToFloat(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "Float")
+	testTableCreateRefColumn(t, "Float")
 }
 
 func TestTableCreateColumnForRefToTime(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "Time")
+	testTableCreateRefColumn(t, "Time")
 }
 
 func TestTableCreateColumnForRefToShortText(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "ShortText")
+	testTableCreateRefColumn(t, "ShortText")
 }
 
 func TestTableCreateColumnForRefToTokyoGeoPoint(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "TokyoGeoPoint")
+	testTableCreateRefColumn(t, "TokyoGeoPoint")
 }
 
 func TestTableCreateColumnForRefToWGS84GeoPoint(t *testing.T) {
-	testTableCreateScalarRefColumn(t, "WGS84GeoPoint")
+	testTableCreateRefColumn(t, "WGS84GeoPoint")
 }
 
 func TestTableCreateColumnForRefToBoolVector(t *testing.T) {
-	testTableCreateVectorRefColumn(t, "Bool")
+	testTableCreateRefColumn(t, "[]Bool")
+}
+
+func TestTableCreateColumnForRefToInt8Vector(t *testing.T) {
+	testTableCreateRefColumn(t, "[]Int8")
+}
+
+func TestTableCreateColumnForRefToInt16Vector(t *testing.T) {
+	testTableCreateRefColumn(t, "[]Int16")
+}
+
+func TestTableCreateColumnForRefToInt32Vector(t *testing.T) {
+	testTableCreateRefColumn(t, "[]Int32")
+}
+
+func TestTableCreateColumnForRefToInt64Vector(t *testing.T) {
+	testTableCreateRefColumn(t, "[]Int64")
+}
+
+func TestTableCreateColumnForRefToUInt8Vector(t *testing.T) {
+	testTableCreateRefColumn(t, "[]UInt8")
+}
+
+func TestTableCreateColumnForRefToUInt16Vector(t *testing.T) {
+	testTableCreateRefColumn(t, "[]UInt16")
+}
+
+func TestTableCreateColumnForRefToUInt32Vector(t *testing.T) {
+	testTableCreateRefColumn(t, "[]UInt32")
 }
 
-func TestTableCreateColumnForRefToIntVector(t *testing.T) {
-	testTableCreateVectorRefColumn(t, "Int64")
+func TestTableCreateColumnForRefToUInt64Vector(t *testing.T) {
+	testTableCreateRefColumn(t, "[]UInt64")
 }
 
 func TestTableCreateColumnForRefToFloatVector(t *testing.T) {
-	testTableCreateVectorRefColumn(t, "Float")
+	testTableCreateRefColumn(t, "[]Float")
 }
 
 func TestTableCreateColumnForRefToTimeVector(t *testing.T) {
-	testTableCreateVectorRefColumn(t, "Time")
+	testTableCreateRefColumn(t, "[]Time")
 }
 
 func TestTableCreateColumnForRefToShortTextVector(t *testing.T) {
-	testTableCreateVectorRefColumn(t, "ShortText")
+	testTableCreateRefColumn(t, "[]ShortText")
 }
 
 func TestTableCreateColumnForRefToTokyoGeoPointVector(t *testing.T) {
-	testTableCreateVectorRefColumn(t, "TokyoGeoPoint")
+	testTableCreateRefColumn(t, "[]TokyoGeoPoint")
 }
 
 func TestTableCreateColumnForRefToWGS84GeoPointVector(t *testing.T) {
-	testTableCreateVectorRefColumn(t, "WGS84GeoPoint")
+	testTableCreateRefColumn(t, "[]WGS84GeoPoint")
 }
 
 func testColumnSetValue(t *testing.T, valueType string) {
-------------- next part --------------
HTML����������������������������...
Download 



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