susumu.yata
null+****@clear*****
Fri May 1 10:32:07 JST 2015
susumu.yata 2015-05-01 10:32:07 +0900 (Fri, 01 May 2015) New Revision: 426c46b917a21862d443552ceec52a00a2de9417 https://github.com/groonga/grnxx/commit/426c46b917a21862d443552ceec52a00a2de9417 Message: Gnx: implement GrnColumn.SetValue() and add tests. Modified files: go3/gnx/grn.go go3/gnx/grn_cgo.c go3/gnx/grn_cgo.h go3/gnx/grn_test.go Modified: go3/gnx/grn.go (+184 -0) =================================================================== --- go3/gnx/grn.go 2015-05-01 04:06:02 +0900 (cfa3983) +++ go3/gnx/grn.go 2015-05-01 10:32:07 +0900 (391ec03) @@ -771,3 +771,187 @@ func newGrnColumn(table *GrnTable, obj *C.grn_obj, name string, 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()) + } +} Modified: go3/gnx/grn_cgo.c (+127 -0) =================================================================== --- go3/gnx/grn_cgo.c 2015-05-01 04:06:02 +0900 (c120c36) +++ go3/gnx/grn_cgo.c 2015-05-01 10:32:07 +0900 (7e3300f) @@ -195,3 +195,130 @@ 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; +} Modified: go3/gnx/grn_cgo.h (+41 -0) =================================================================== --- go3/gnx/grn_cgo.h 2015-05-01 04:06:02 +0900 (a9a25da) +++ go3/gnx/grn_cgo.h 2015-05-01 10:32:07 +0900 (aa07704) @@ -11,6 +11,11 @@ typedef struct { size_t size; } grn_cgo_text; +typedef struct { + const 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. @@ -62,4 +67,40 @@ grn_cgo_row_info grn_cgo_table_insert_geo_point(grn_ctx *ctx, grn_obj *table, 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. +grn_bool grn_cgo_column_set_text_vector(grn_ctx *ctx, grn_obj *column, + grn_id id, + const grn_cgo_vector *value); + #endif // GRN_CGO_H Modified: go3/gnx/grn_test.go (+129 -0) =================================================================== --- go3/gnx/grn_test.go 2015-05-01 04:06:02 +0900 (507108c) +++ go3/gnx/grn_test.go 2015-05-01 10:32:07 +0900 (438c68a) @@ -291,3 +291,132 @@ func TestGrnTableCreateColumn(t *testing.T) { testGrnTableCreateVectorRefColumn(t, "GeoPoint") testGrnTableCreateVectorRefColumn(t, "Text") } + +func generateRandomScalarValue(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 testGrnColumnSetScalarValue(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, generateRandomScalarValue(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 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 testGrnColumnSetVectorValue(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 TestGrnColumnSetValue(t *testing.T) { + testGrnColumnSetScalarValue(t, "Bool") + testGrnColumnSetScalarValue(t, "Int") + testGrnColumnSetScalarValue(t, "Float") + testGrnColumnSetScalarValue(t, "GeoPoint") + testGrnColumnSetScalarValue(t, "Text") + + testGrnColumnSetVectorValue(t, "Bool") + testGrnColumnSetVectorValue(t, "Int") + testGrnColumnSetVectorValue(t, "Float") + testGrnColumnSetVectorValue(t, "GeoPoint") + testGrnColumnSetVectorValue(t, "Text") +} -------------- next part -------------- HTML����������������������������...Download