susumu.yata
null+****@clear*****
Fri Jun 19 22:07:53 JST 2015
susumu.yata 2015-06-19 22:07:53 +0900 (Fri, 19 Jun 2015) New Revision: b631b44d5a7d02f4c39d056fabc683995a9994ec https://github.com/groonga/grnxx/commit/b631b44d5a7d02f4c39d056fabc683995a9994ec Message: Remove files no longer required. Removed files: go/.gitignore go/benchmark.go go/benchmark2.go go/gnx/gnx.go go/gnx/grnxx/grnxx.cpp go/gnx/grnxx/grnxx.go go/gnx/grnxx/grnxx.h go/gnx/grnxx/grnxx_test.go go/gnx/groonga/groonga.go go/gnx/groonga/groonga_test.go go/gnxConsole.go go/groongaConsole.go go2/.gitignore go2/benchmark.go go2/gnx/gnx.cpp go2/gnx/gnx.go go2/gnx/gnx.h go2/gnxTest.go go3/gnx/gnx.go go3/gnx/gnx_cgo.c go3/gnx/gnx_cgo.h go3/gnx/gnx_test.go go3/gnx/grn.go go3/gnx/grn_cgo.c go3/gnx/grn_cgo.h go3/gnx/grn_test.go go3/gnx/grnxx.go go3/gnx/grnxx_cgo.cpp go3/gnx/grnxx_cgo.h go3/gnx/options.go new-interface/adjuster.hpp new-interface/column.hpp new-interface/cursor.hpp new-interface/datum.hpp new-interface/db.hpp new-interface/error.hpp new-interface/expression-builder.hpp new-interface/expression.hpp new-interface/filter.hpp new-interface/index.hpp new-interface/library.hpp new-interface/merger.hpp new-interface/order.hpp new-interface/pipeline-builder.hpp new-interface/pipeline.hpp new-interface/record-set.hpp new-interface/sorter-builder.hpp new-interface/sorter.hpp new-interface/table.hpp new-interface/types.hpp Deleted: go/.gitignore (+0 -6) 100644 =================================================================== --- go/.gitignore 2015-05-26 11:06:34 +0900 (02ca9df) +++ /dev/null @@ -1,6 +0,0 @@ -*.prof -benchmark -benchmark2 -gnxConsole -groongaConsole -temp/ Deleted: go/benchmark.go (+0 -177) 100644 =================================================================== --- go/benchmark.go 2015-05-26 11:06:34 +0900 (ee64e90) +++ /dev/null @@ -1,177 +0,0 @@ -package main - -import "./gnx" - -import "encoding/json" -import "flag" -import "fmt" -import "log" -import "math/rand" -import "os" -import "runtime" -import "runtime/pprof" -import "strconv" -import "strings" -import "time" -import "unicode" - -var flagMode = flag.String("mode", "run", "mode (run or print)") -var flagLoad = flag.String("load", "load", "load type (load or gnx_load)") -var flagKey = flag.String("key", "", "key data type") -var flagColumns = flag.String("columns", "Bool,Int16,Float,ShortText", - "comma-separated column data types") -var flagRows = flag.Int("rows", 1000000, "number of rows") -var flagBlock = flag.Int("block", 10, "number of rows per command") -var flagPartition = flag.Int("partition", 1, "number of groonga DBs") -var flagCPU = flag.Int("cpu", 1, "number of CPU cores") -var flagProfile = flag.String("profile", "benchmark.prof", - "path of profile data") - -func generateValue(typeName string) interface{} { - switch typeName { - case "Bool": - return (rand.Int() % 2) == 1 - case "Int8": - return int8(rand.Int() % 128) - case "Int16": - return int16(rand.Int() % 32768) - case "Int32": - return rand.Int31() - case "Int64": - return rand.Int63() - case "UInt8": - return uint8(rand.Int() % 256) - case "UInt16": - return uint16(rand.Int() % 65536) - case "UInt32": - return rand.Uint32() - case "UInt64": - return uint64(rand.Int63()) - case "Float": - return rand.Float64() - case "ShortText", "Text", "LongText": - return strconv.Itoa(int(rand.Int31())) - default: - log.Fatalln("unsupported data type: name =", typeName) - return nil - } -} - -func generateCommands() []string { - var commands []string - if *flagKey == "" { - commands = append(commands, "table_create Table TABLE_NO_KEY") - } else { - commands = append(commands, - fmt.Sprintf("table_create Table TABLE_PAT_KEY %s", *flagKey)) - } - - var columnTypes []string - var columnNames []string - if *flagColumns != "" { - tokens := strings.Split(*flagColumns, ",") - for _, token := range tokens { - columnType := strings.TrimFunc(token, unicode.IsSpace) - if columnType != "" { - columnTypes = append(columnTypes, columnType) - columnName := fmt.Sprintf("Col%d", len(columnNames)) - columnNames = append(columnNames, columnName) - commands = append(commands, - fmt.Sprintf("column_create Table %s COLUMN_SCALAR %s", - columnName, columnType)) - } - } - } - - columnsOption := strings.Join(columnNames, ",") - numValues := len(columnNames) - if *flagKey != "" { - if columnsOption == "" { - columnsOption = "_key" - } else { - columnsOption = "_key," + columnsOption - } - numValues += 1 - } - loadPrefix := fmt.Sprintf("%s --table Table --columns '%s' --values ", - *flagLoad, columnsOption) - for i := 0; i < *flagRows; i += *flagBlock { - var blockValues [][]interface{} - for j := 0; (j < *flagBlock) && ((i + j) < *flagRows); j++ { - var rowValues []interface{} - if *flagKey != "" { - rowValues = append(rowValues, generateValue(*flagKey)) - } - for _, columnType := range columnTypes { - rowValues = append(rowValues, generateValue(columnType)) - } - blockValues = append(blockValues, rowValues) - } - bytes, err := json.Marshal(blockValues) - if err != nil { - log.Fatalln(err) - } - commands = append(commands, loadPrefix+"'"+string(bytes)+"'") - } - return commands -} - -func runCommands(commands []string) { - file, err := os.Create(*flagProfile) - if err != nil { - log.Fatalln(err) - } - defer file.Close() - if err := pprof.StartCPUProfile(file); err != nil { - log.Fatalln(err) - } - defer pprof.StopCPUProfile() - - db, dir, err := gnx.CreateTempDB("", "benchmark", *flagPartition) - if err != nil { - log.Fatalln(err) - } - defer os.RemoveAll(dir) - defer db.Close() - startTime := time.Now() - for _, command := range commands { - if _, err := db.Query(command); err != nil { - log.Fatalln(err) - } - } - endTime := time.Now() - fmt.Println("elapsed:", endTime.Sub(startTime)) -} - -func printCommands(commands []string) { - db, dir, err := gnx.CreateTempDB("", "benchmark", *flagPartition) - if err != nil { - log.Fatalln(err) - } - defer os.RemoveAll(dir) - defer db.Close() - for _, command := range commands { - fmt.Println(command) -// if _, err := db.Query(command); err != nil { -// log.Fatalln(err) -// } - } -} - -func main() { - flag.Parse() - if *flagCPU == 0 { - runtime.GOMAXPROCS(runtime.NumCPU()) - } else { - runtime.GOMAXPROCS(*flagCPU) - } - commands := generateCommands() - switch *flagMode { - case "run": - runCommands(commands) - case "print": - printCommands(commands) - default: - log.Fatalln("undefined mode") - } -} Deleted: go/benchmark2.go (+0 -202) 100644 =================================================================== --- go/benchmark2.go 2015-05-26 11:06:34 +0900 (2f2e48d) +++ /dev/null @@ -1,202 +0,0 @@ -package main - -import "./gnx" - -import "bufio" -import "encoding/json" -import "flag" -import "fmt" -import "log" -import "math/rand" -import "os" -import "runtime" -import "runtime/pprof" -import "strconv" -import "strings" -import "time" -import "unicode" - -var flagMode = flag.String("mode", "run", "mode (run or print)") -var flagLoad = flag.String("load", "load", "load type (load or gnx_load)") -var flagKey = flag.String("key", "", "key data type") -var flagColumns = flag.String("columns", "Bool,Int16,Float,Text", - "comma-separated column data types") -var flagRows = flag.Int("rows", 1000000, "number of rows") -var flagBlock = flag.Int("block", 10, "number of rows per command") -var flagPartition = flag.Int("partition", 1, "number of groonga DBs") -var flagCPU = flag.Int("cpu", 1, "number of CPU cores") -var flagProfile = flag.String("profile", "benchmark.prof", - "path of profile data") - -func generateValue(typeName string) interface{} { - switch typeName { - case "Bool": - return (rand.Int() % 2) == 1 - case "Int8": - return int8(rand.Int() % 128) - case "Int16": - return int16(rand.Int() % 32768) - case "Int32": - return rand.Int31() - case "Int64": - return rand.Int63() - case "UInt8": - return uint8(rand.Int() % 256) - case "UInt16": - return uint16(rand.Int() % 65536) - case "UInt32": - return rand.Uint32() - case "UInt64": - return uint64(rand.Int63()) - case "Float": - return rand.Float64() - case "ShortText", "Text", "LongText": - return strconv.Itoa(int(rand.Int31())) - default: - log.Fatalln("unsupported data type: name =", typeName) - return nil - } -} - -func generateCommands() []string { - var commands []string - if *flagKey == "" { - commands = append(commands, "table_create Table TABLE_NO_KEY") - } else { - commands = append(commands, - fmt.Sprintf("table_create Table TABLE_PAT_KEY %s", *flagKey)) - } - - var columnTypes []string - var columnNames []string - if *flagColumns != "" { - tokens := strings.Split(*flagColumns, ",") - for _, token := range tokens { - columnType := strings.TrimFunc(token, unicode.IsSpace) - if columnType != "" { - columnID := len(columnTypes) - columnTypes = append(columnTypes, columnType) - columnName := fmt.Sprintf("Col%d", columnID) - columnNames = append(columnNames, columnName) - commands = append(commands, - fmt.Sprintf("column_create Table %s COLUMN_SCALAR %s", - columnName, columnType)) - switch columnType { - case "Text", "LongText": - const tokenizerOption = "--default_tokenizer TokenBigram" - commands = append(commands, fmt.Sprintf( - "table_create Idx%d TABLE_PAT_KEY ShortText %s", - columnID, tokenizerOption)) - commands = append(commands, fmt.Sprintf( - "column_create Idx%d Idx COLUMN_INDEX|WITH_POSITION Table Col%d", - columnID, columnID)) - } - } - } - } - - columnsOption := strings.Join(columnNames, ",") - numValues := len(columnNames) - if *flagKey != "" { - if columnsOption == "" { - columnsOption = "_key" - } else { - columnsOption = "_key," + columnsOption - } - numValues += 1 - } - loadPrefix := fmt.Sprintf("%s --table Table --columns '%s' --values ", - *flagLoad, columnsOption) - scanner := bufio.NewScanner(os.Stdin) - for i := 0; i < *flagRows; i += *flagBlock { - var blockValues [][]interface{} - for j := 0; (j < *flagBlock) && ((i + j) < *flagRows); j++ { - var rowValues []interface{} - if *flagKey != "" { - rowValues = append(rowValues, generateValue(*flagKey)) - } - for _, columnType := range columnTypes { - switch columnType { - case "Text", "LongText": - if scanner.Scan() { - rowValues = append(rowValues, scanner.Text()) - } else { - rowValues = append(rowValues, generateValue(columnType)) - } - default: - rowValues = append(rowValues, generateValue(columnType)) - } - } - blockValues = append(blockValues, rowValues) - } - bytes, err := json.Marshal(blockValues) - if err != nil { - log.Fatalln(err) - } - block := string(bytes) - block = strings.Replace(block, "\\", "\\\\", -1) - block = strings.Replace(block, "'", "\\'", -1) - commands = append(commands, loadPrefix+"'"+block+"'") - } - return commands -} - -func runCommands(commands []string) { - file, err := os.Create(*flagProfile) - if err != nil { - log.Fatalln(err) - } - defer file.Close() - if err := pprof.StartCPUProfile(file); err != nil { - log.Fatalln(err) - } - defer pprof.StopCPUProfile() - - db, dir, err := gnx.CreateTempDB("", "benchmark", *flagPartition) - if err != nil { - log.Fatalln(err) - } - defer os.RemoveAll(dir) - defer db.Close() - startTime := time.Now() - for _, command := range commands { - if _, err := db.Query(command); err != nil { - log.Fatalln(err) - } - } - endTime := time.Now() - fmt.Println("elapsed:", endTime.Sub(startTime)) -} - -func printCommands(commands []string) { - db, dir, err := gnx.CreateTempDB("", "benchmark", *flagPartition) - if err != nil { - log.Fatalln(err) - } - defer os.RemoveAll(dir) - defer db.Close() - for _, command := range commands { - fmt.Println(command) -// if _, err := db.Query(command); err != nil { -// log.Fatalln(err) -// } - } -} - -func main() { - flag.Parse() - if *flagCPU == 0 { - runtime.GOMAXPROCS(runtime.NumCPU()) - } else { - runtime.GOMAXPROCS(*flagCPU) - } - commands := generateCommands() - switch *flagMode { - case "run": - runCommands(commands) - case "print": - printCommands(commands) - default: - log.Fatalln("undefined mode") - } -} Deleted: go/gnx/gnx.go (+0 -997) 100644 =================================================================== --- go/gnx/gnx.go 2015-05-26 11:06:34 +0900 (e4c4340) +++ /dev/null @@ -1,997 +0,0 @@ -package gnx - -import "./grnxx" -import "./groonga" -import "encoding/binary" -import "encoding/json" -import "fmt" -import "hash/fnv" -import "io/ioutil" -import "math" -import "math/rand" -import "os" -import "runtime" -import "strconv" -import "strings" -import "time" -import "unicode" - -type DB struct { - groongaDBs []*groonga.DB - grnxxDB *grnxx.DB -} - -func CreateDB(path string, n int) (*DB, error) { - if n <= 0 { - return nil, fmt.Errorf("invalid parameter: n = %d", n) - } - groongaDBs := make([]*groonga.DB, n) - for i := 0; i < n; i++ { - dbPath := path - if i != 0 { - dbPath += strconv.Itoa(i) - } - groongaDB, err := groonga.CreateDB(dbPath) - if err != nil { - for j := 0; j < i; j++ { - groongaDBs[j].Close() - } - return nil, err - } - groongaDBs[i] = groongaDB - } - return &DB{groongaDBs, nil}, nil -} - -func CreateTempDB(dir, prefix string, n int) (*DB, string, error) { - if n <= 0 { - return nil, "", fmt.Errorf("invalid parameter: n = %d", n) - } - tempDir, err := ioutil.TempDir(dir, prefix) - if err != nil { - return nil, "", err - } - db, err := CreateDB(tempDir+"/db", n) - if err != nil { - os.RemoveAll(tempDir) - return nil, "", err - } - return db, tempDir, nil -} - -func OpenDB(path string) (*DB, error) { - var groongaDBs []*groonga.DB - for i := 0; ; i++ { - dbPath := path - if i != 0 { - dbPath += strconv.Itoa(i) - } - groongaDB, err := groonga.OpenDB(dbPath) - if err != nil { - if i == 0 { - return nil, err - } - break - } - groongaDBs = append(groongaDBs, groongaDB) - } - return &DB{groongaDBs, nil}, nil -} - -func (db *DB) Close() error { - for i := 0; i < len(db.groongaDBs); i++ { - db.groongaDBs[i].Close() - } - if db.grnxxDB != nil { - db.grnxxDB.Close() - } - return nil -} - -func (db *DB) gnxLoad(command string) ([]byte, error) { - _, options, err := db.ParseCommand(command) - if err != nil { - return nil, err - } - columnsOption, ok := options["columns"] - if !ok { - return nil, fmt.Errorf("columns option missing") - } - idPos := -1 - keyPos := -1 - var columns []string - columnNames := strings.Split(columnsOption, ",") - for i := 0; i < len(columnNames); i++ { - columnName := strings.TrimFunc(columnNames[i], unicode.IsSpace) - if len(columnName) != 0 { - switch columnName { - case "_id": - if idPos != -1 { - return nil, fmt.Errorf("_id appeared more than once") - } - idPos = len(columns) - case "_key": - if keyPos != -1 { - return nil, fmt.Errorf("_key appeared more than once") - } - keyPos = len(columns) - } - columns = append(columns, columnName) - } - } - if (idPos != -1) && (keyPos != -1) { - return nil, fmt.Errorf("both _id and _key appeared") - } - - valuesOption, ok := options["values"] - if !ok { - return nil, fmt.Errorf("values option missing") - } - var mergedValues [][]interface{} - if err = json.Unmarshal([]byte(valuesOption), &mergedValues); err != nil { - return nil, err - } - values := make([][][]interface{}, len(db.groongaDBs)) - switch { - case idPos != -1: - // NOTE: Groonga does not support array-style values with _id. - for i := 0; i < len(mergedValues); i++ { - id := int(mergedValues[i][idPos].(float64)) - if id <= 0 { - return nil, fmt.Errorf("invalid ID: id = %d", id) - } - mergedValues[i][idPos] = ((id - 1) / len(values)) + 1 - db := (id - 1) % len(values) - values[db] = append(values[db], mergedValues[i]) - } - case keyPos != -1: - for i := 0; i < len(mergedValues); i++ { - switch value := mergedValues[i][keyPos].(type) { - case float64: - hasher := fnv.New32a() - err := binary.Write(hasher, binary.LittleEndian, value) - if err != nil { - return nil, err - } - db := int(hasher.Sum32()) % len(values) - values[db] = append(values[db], mergedValues[i]) - case string: - hasher := fnv.New32a() - if _, err := hasher.Write([]byte(value)); err != nil { - return nil, err - } - db := int(hasher.Sum32()) % len(values) - values[db] = append(values[db], mergedValues[i]) - default: - return nil, fmt.Errorf("unsupported key type") - } - } - default: - for i := 0; i < len(mergedValues); i++ { - db := rand.Int() % len(values) - values[db] = append(values[db], mergedValues[i]) - } - } - - if runtime.GOMAXPROCS(0) == 1 { - total := 0 - for i := 0; i < len(db.groongaDBs); i++ { - if len(values[i]) != 0 { - bytes, err := json.Marshal(values[i]) - if err != nil { - return nil, err - } - options["values"] = string(bytes) -// fmt.Println("options:", options) - count, err := db.groongaDBs[i].Load(options) - if err != nil { - return nil, err - } - total += count - } - } - return []byte(strconv.Itoa(total)), nil - } else { - var channels []chan int - for i := 0; i < len(db.groongaDBs); i++ { - if len(values[i]) != 0 { - channel := make(chan int) - go func(channel chan int, db *groonga.DB, options map[string]string, - values [][]interface{}) { - newOptions := make(map[string]string) - for key, value := range options { - newOptions[key] = value - } - bytes, err := json.Marshal(values) - if err != nil { - channel <- 0 - return - } - newOptions["values"] = string(bytes) -// fmt.Println("options:", newOptions) - count, err := db.Load(newOptions) - if err != nil { - channel <- 0 - return - } - channel <- count - close(channel) - return - }(channel, db.groongaDBs[i], options, values[i]) - channels = append(channels, channel) - } - } - count := 0 - for _, channel := range channels { - count += <-channel - } - return []byte(strconv.Itoa(count)), nil - } -} - -type Output struct { - Name string - Type string - Values interface{} -} - -func (db *DB) groongaSelect(options map[string]string) ([]byte, error) { - options["cache"] = "no" - outputColumns, err := db.groongaDBs[0].Select(options) - if err != nil { - return nil, err - } - if len(outputColumns) == 0 { - return nil, fmt.Errorf("no output columns") - } - for i := 0; i < len(outputColumns); i++ { - if outputColumns[i].Name == "_id" { - values := outputColumns[i].Values.([]uint32) - for j := 0; j < len(values); j++ { - values[j] = uint32(((int(values[j]) - 1) * len(db.groongaDBs)) + 1) - } - } - } - for i := 1; i < len(db.groongaDBs); i++ { - result, err := db.groongaDBs[i].Select(options) - if err != nil { - return nil, err - } - for j := 0; j < len(result); j++ { - switch newValues := result[j].Values.(type) { - case []bool: - values := outputColumns[j].Values.([]bool) - values = append(values, newValues...) - outputColumns[j].Values = values - case []int8: - values := outputColumns[j].Values.([]int8) - values = append(values, newValues...) - outputColumns[j].Values = values - case []int16: - values := outputColumns[j].Values.([]int16) - values = append(values, newValues...) - outputColumns[j].Values = values - case []int32: - values := outputColumns[j].Values.([]int32) - values = append(values, newValues...) - outputColumns[j].Values = values - case []int64: - values := outputColumns[j].Values.([]int64) - values = append(values, newValues...) - outputColumns[j].Values = values - case []uint8: - values := outputColumns[j].Values.([]uint8) - values = append(values, newValues...) - outputColumns[j].Values = values - case []uint16: - values := outputColumns[j].Values.([]uint16) - values = append(values, newValues...) - outputColumns[j].Values = values - case []uint32: - if result[j].Name == "_id" { - for k := 0; k < len(newValues); k++ { - newValues[k] = - uint32(((int(newValues[k]) - 1) * len(db.groongaDBs)) + i + 1) - } - } - values := outputColumns[j].Values.([]uint32) - values = append(values, newValues...) - outputColumns[j].Values = values - case []uint64: - values := outputColumns[j].Values.([]uint64) - values = append(values, newValues...) - outputColumns[j].Values = values - case []float64: - values := outputColumns[j].Values.([]float64) - values = append(values, newValues...) - outputColumns[j].Values = values - case []time.Time: - values := outputColumns[j].Values.([]time.Time) - values = append(values, newValues...) - outputColumns[j].Values = values - case []string: - values := outputColumns[j].Values.([]string) - values = append(values, newValues...) - outputColumns[j].Values = values - } - } - } - - bytes, err := json.Marshal(outputColumns) - if err != nil { - return nil, err - } - return bytes, nil -} - -//func (db *DB) groongaSelect(options map[string]string) ([]byte, error) { -// options["cache"] = "no" -// count := 0 -// results := make([][][][]interface{}, len(db.groongaDBs)) -// for i := 0; i < len(results); i++ { -// bytes, err := db.groongaDBs[i].QueryEx("select", options) -// if err != nil { -// return nil, err -// } -// if err = json.Unmarshal(bytes, &results[i]); err != nil { -// return nil, err -// } -// count += len(results[i][0]) - 2 -// } -// var ids []int -// for i := 0; i < len(results[0][0][1]); i++ { -// name := results[0][0][1][i].([]interface{})[0].(string) -// if name == "_id" { -// ids = append(ids, i) -// } -// } -// mergedResult := make([][]interface{}, 1) -// mergedResult[0] = make([]interface{}, count+2) -// mergedResult[0][0] = []int{count} -// mergedResult[0][1] = results[0][0][1] -// output := mergedResult[0][2:] -// for i := 0; i < len(results); i++ { -// input := results[i][0][2:] -// for j := 0; j < len(input); j++ { -// output[j] = input[j] -// for _, idPos := range ids { -// id := int(input[j][idPos].(float64)) -// input[j][idPos] = ((id - 1) * len(results)) + i + 1 -// } -// } -// output = output[len(input):] -// } -// bytes, err := json.Marshal(mergedResult) -// if err != nil { -// return nil, err -// } -// return bytes, nil -//} - -func (db *DB) grnxxSelect(options map[string]string) ([]byte, error) { -// fmt.Println("grnxxSelect: options:", options) - if db.grnxxDB == nil { - return nil, fmt.Errorf("grnxx not available") - } - - table := db.grnxxDB.FindTable(options["table"]) - if table == nil { - return nil, fmt.Errorf("table not found: name = %s", options["table"]) - } - builder, err := grnxx.CreatePipelineBuilder(table) - if err != nil { - return nil, err - } - defer builder.Close() - cursor, err := table.CreateCursor(nil) - if err != nil { - return nil, err - } - builder.PushCursor(cursor) - - filterString, ok := options["grnxx_filter"] - if !ok { - filterString = "TRUE" - } - offset := 0 - offsetString, ok := options["grnxx_offset"] - if ok { - offset, err = strconv.Atoi(offsetString) - if err != nil { - return nil, err - } - } - limit := math.MaxInt32 - limitString, ok := options["grnxx_limit"] - if ok { - limit, err = strconv.Atoi(limitString) - if err != nil { - return nil, err - } - } - filter, err := grnxx.ParseExpression(table, filterString) - if err != nil { - return nil, err - } - if err = builder.PushFilter(filter, offset, limit); err != nil { - return nil, err - } - - pipeline, err := builder.Release(nil) - if err != nil { - return nil, err - } - defer pipeline.Close() - records, err := pipeline.Flush() - if err != nil { - return nil, err - } -// fmt.Println("records:", records) - - var outputs []Output - optionValue, ok := options["grnxx_output_columns"] - if ok { - values := strings.Split(optionValue, ",") - for _, value := range values { - value = strings.TrimFunc(value, unicode.IsSpace) - if len(value) != 0 { - outputs = append(outputs, Output{Name: value}) - } - } - } else { - outputs = append(outputs, Output{Name: "_id"}) - numColumns := table.NumColumns() - for i := 0; i < numColumns; i++ { - outputs = append(outputs, Output{Name: table.GetColumn(i).Name()}) - } - } -// fmt.Println("outputs:", outputs) - - for i := 0; i < len(outputs); i++ { - expression, err := grnxx.ParseExpression(table, outputs[i].Name) - if err != nil { - return nil, err - } - defer expression.Close() - - switch expression.DataType() { - case grnxx.BOOL: - outputs[i].Type = "Bool" - values := make([]grnxx.Bool, len(records)) - if err = expression.Evaluate(records, values); err != nil { - return nil, err - } - outputs[i].Values = values - case grnxx.INT: - outputs[i].Type = "Int" - values := make([]grnxx.Int, len(records)) - if err = expression.Evaluate(records, values); err != nil { - return nil, err - } - outputs[i].Values = values - case grnxx.FLOAT: - outputs[i].Type = "Float" - values := make([]grnxx.Float, len(records)) - if err = expression.Evaluate(records, values); err != nil { - return nil, err - } - outputs[i].Values = values - case grnxx.TEXT: - outputs[i].Type = "Text" - values := make([]grnxx.Text, len(records)) - if err = expression.Evaluate(records, values); err != nil { - return nil, err - } - outputValues := make([]string, len(records)) - for i := 0; i < len(records); i++ { - outputValues[i] = string(values[i]) - } - outputs[i].Values = outputValues - default: - return nil, fmt.Errorf("unsupported data type") - } - } -// fmt.Println("outputs:", outputs) - - bytes, err := json.Marshal(outputs) - if err != nil { - return nil, err - } - return bytes, nil -} - -func (db *DB) complexSelect(groongaOptions, grnxxOptions map[string]string) ( - []byte, error) { -// fmt.Println("groongaOptions: groongaOptions") -// fmt.Println("grnxxOptions: grnxxOptions") - if db.grnxxDB == nil { - return nil, fmt.Errorf("grnxx not available") - } - - groongaOptions["cache"] = "no" - groongaOptions["output_columns"] = "_id,_score" - var records []grnxx.Record - for i := 0; i < len(db.groongaDBs); i++ { - outputColumns, err := db.groongaDBs[i].Select(groongaOptions) - if err != nil { - return nil, err - } - rowIDs := outputColumns[0].Values.([]uint32) - scores := outputColumns[1].Values.([]int32) - newRecords := make([]grnxx.Record, len(rowIDs)) - for j := 0; j < len(rowIDs); j++ { - newRecords[j].RowID = - grnxx.Int(((int(rowIDs[j]) - 1) * len(db.groongaDBs)) + i + 1) - newRecords[j].Score = grnxx.Float(scores[j]) - } - records = append(records, newRecords...) - } - - table := db.grnxxDB.FindTable(groongaOptions["table"]) - if table == nil { - return nil, fmt.Errorf("table not found: name = %s", - groongaOptions["table"]) - } - - filterString, ok := grnxxOptions["grnxx_filter"] - if !ok { - filterString = "TRUE" - } - offset := 0 - offsetString, ok := grnxxOptions["grnxx_offset"] - if ok { - var err error - offset, err = strconv.Atoi(offsetString) - if err != nil { - return nil, err - } - } - limit := 10 - limitString, ok := grnxxOptions["grnxx_limit"] - if ok { - var err error - limit, err = strconv.Atoi(limitString) - if err != nil { - return nil, err - } - } - filter, err := grnxx.ParseExpression(table, filterString) - if err != nil { - return nil, err - } - defer filter.Close() - filter.FilterEx(&records, offset, limit) -// fmt.Println("records:", records) - - var outputs []Output - optionValue, ok := grnxxOptions["grnxx_output_columns"] - if ok { - values := strings.Split(optionValue, ",") - for _, value := range values { - value = strings.TrimFunc(value, unicode.IsSpace) - if len(value) != 0 { - outputs = append(outputs, Output{Name: value}) - } - } - } else { - outputs = append(outputs, Output{Name: "_id"}) - numColumns := table.NumColumns() - for i := 0; i < numColumns; i++ { - outputs = append(outputs, Output{Name: table.GetColumn(i).Name()}) - } - } -// fmt.Println("outputs:", outputs) - - for i := 0; i < len(outputs); i++ { - expression, err := grnxx.ParseExpression(table, outputs[i].Name) - if err != nil { - return nil, err - } - defer expression.Close() - - switch expression.DataType() { - case grnxx.BOOL: - outputs[i].Type = "Bool" - values := make([]grnxx.Bool, len(records)) - if err = expression.Evaluate(records, values); err != nil { - return nil, err - } - outputs[i].Values = values - case grnxx.INT: - outputs[i].Type = "Int" - values := make([]grnxx.Int, len(records)) - if err = expression.Evaluate(records, values); err != nil { - return nil, err - } - outputs[i].Values = values - case grnxx.FLOAT: - outputs[i].Type = "Float" - values := make([]grnxx.Float, len(records)) - if err = expression.Evaluate(records, values); err != nil { - return nil, err - } - outputs[i].Values = values - case grnxx.TEXT: - outputs[i].Type = "Text" - values := make([]grnxx.Text, len(records)) - if err = expression.Evaluate(records, values); err != nil { - return nil, err - } - outputValues := make([]string, len(records)) - for i := 0; i < len(records); i++ { - outputValues[i] = string(values[i]) - } - outputs[i].Values = outputValues - default: - return nil, fmt.Errorf("unsupported data type") - } - } -// fmt.Println("outputs:", outputs) - - bytes, err := json.Marshal(outputs) - if err != nil { - return nil, err - } - return bytes, nil -} - -func (db *DB) gnxSelect(command string) ([]byte, error) { - _, options, err := db.ParseCommand(command) - if err != nil { - return nil, err - } - groongaOptions := make(map[string]string) - grnxxOptions := make(map[string]string) - for key, value := range options { - if strings.HasPrefix(key, "grnxx_") { - grnxxOptions[key] = value - } else { - groongaOptions[key] = value - } - } - if _, ok := groongaOptions["table"]; !ok { - return nil, fmt.Errorf("table name missing") - } - if len(grnxxOptions) == 0 { - return db.groongaSelect(groongaOptions) - } else if len(groongaOptions) == 1 { - grnxxOptions["table"] = groongaOptions["table"] - return db.grnxxSelect(grnxxOptions) - } else { - return db.complexSelect(groongaOptions, grnxxOptions) - } -} - -func (db *DB) gnxSnapshot(command string) ([]byte, error) { - _, options, err := db.ParseCommand(command) - if err != nil { - return nil, err - } - - tableName, ok := options["table"] - if !ok { - return nil, fmt.Errorf("table name missing") - } - columnName, ok := options["column"] - if !ok { - return nil, fmt.Errorf("column name missing") - } -// fmt.Println("tableName:", tableName) -// fmt.Println("columnName:", columnName) - - idColumns := make([]groonga.OutputColumn, len(db.groongaDBs)) - valueColumns := make([]groonga.OutputColumn, len(db.groongaDBs)) - for i := 0; i < len(db.groongaDBs); i++ { - outputColumns, err := db.groongaDBs[i].Select(map[string]string{ - "table": tableName, "output_columns": fmt.Sprintf("_id,%s", columnName), - "limit": "-1", "cache": "no"}) - if err != nil { - return nil, err - } - if len(outputColumns) != 2 { - return nil, fmt.Errorf("column not found: name = %s", columnName) - } - if outputColumns[1].Name != columnName { - return nil, fmt.Errorf("column mismatch: actual = %s, request = %s", - outputColumns[1].Name, columnName) - } - idColumns[i] = outputColumns[0] - valueColumns[i] = outputColumns[1] - } -// fmt.Println("idColumns:", idColumns) -// fmt.Println("valueColumns:", valueColumns) - - var dataType grnxx.DataType - switch valueColumns[0].Type { - case "Bool": - dataType = grnxx.BOOL - case "Int8", "Int16", "Int32", "Int64", - "UInt8", "UInt16", "UInt32", "UInt64": - dataType = grnxx.INT - case "Float": - dataType = grnxx.FLOAT - case "Time": - dataType = grnxx.INT - case "ShortText", "Text", "LongText": - dataType = grnxx.TEXT - default: - return nil, fmt.Errorf("unsupported data type") - } - - if db.grnxxDB == nil { - if db.grnxxDB, err = grnxx.CreateDB(); err != nil { - return nil, err - } - } - table := db.grnxxDB.FindTable(tableName) - if table == nil { - if table, err = db.grnxxDB.CreateTable(tableName); err != nil { - return nil, err - } - } - column := table.FindColumn(columnName) - if column == nil { - if column, err = table.CreateColumn(columnName, dataType, nil); err != nil { - return nil, err - } - } - - for i := 0; i < len(idColumns); i++ { - ids := idColumns[i].Values.([]uint32) - for j := 0; j < len(ids); j++ { - rowID := grnxx.Int(int(ids[j] - 1) * len(idColumns) + i + 1) - if !table.TestRow(rowID) { - if err := table.InsertRowAt(rowID, nil); err != nil { - return nil, err - } - } - switch values := valueColumns[i].Values.(type) { - case []bool: - if values[j] { - err = column.Set(rowID, grnxx.TRUE) - } else { - err = column.Set(rowID, grnxx.FALSE) - } - case []int8: - err = column.Set(rowID, grnxx.Int(values[j])) - case []int16: - err = column.Set(rowID, grnxx.Int(values[j])) - case []int32: - err = column.Set(rowID, grnxx.Int(values[j])) - case []int64: - err = column.Set(rowID, grnxx.Int(values[j])) - case []uint8: - err = column.Set(rowID, grnxx.Int(values[j])) - case []uint16: - err = column.Set(rowID, grnxx.Int(values[j])) - case []uint32: - err = column.Set(rowID, grnxx.Int(values[j])) - case []uint64: - err = column.Set(rowID, grnxx.Int(values[j])) - case []float64: - err = column.Set(rowID, grnxx.Float(values[j])) - case []time.Time: - err = column.Set(rowID, grnxx.Int(values[j].UnixNano() / 1000)) - case []string: - err = column.Set(rowID, grnxx.Text(values[j])) - } - if err != nil { - return nil, err - } - } - } - return []byte("true"), nil -} - -func (db *DB) Query(command string) ([]byte, error) { - name, _, ok, err := db.tokenizeCommand(command) - if err != nil { - return nil, err - } - if !ok { - return []byte{}, nil - } - switch name { - case "gnx_load": - return db.gnxLoad(command) - case "gnx_select": - return db.gnxSelect(command) - case "gnx_snapshot": - return db.gnxSnapshot(command) - default: - // Query the command to all DBs. - if name == "select" { - command += " --cache no" - } - results := make([][]byte, len(db.groongaDBs)) - count := 1 - for i := 0; i < len(results); i++ { - bytes, err := db.groongaDBs[i].Query(command) - if err != nil { - return nil, err - } - results[i] = bytes - count += len(bytes) + 1 - } - bytes := make([]byte, 0, count) - bytes = append(bytes, '[') - bytes = append(bytes, results[0]...) - for i := 1; i < len(results); i++ { - bytes = append(bytes, ',') - bytes = append(bytes, results[i]...) - } - bytes = append(bytes, ']') - return bytes, nil - } -} - -func (db *DB) tokenizeCommand(s string) (string, string, bool, error) { - s = strings.TrimLeftFunc(s, unicode.IsSpace) - if len(s) == 0 { - return "", "", false, nil - } - switch s[0] { - case '#': - return "", "", false, nil - case '\'', '"': - quote := s[0] - pos := 1 - hasBackslash := false - for pos < len(s) { - if s[pos] == quote { - break - } else if s[pos] == '\\' { - hasBackslash = true - pos++ - } - pos++ - } - if pos >= len(s) { - return "", "", false, fmt.Errorf("quote missing") - } - token := s[1:pos] - if hasBackslash { - bytes := make([]byte, len(token)) - count := 0 - for i := 0; i < len(token); i++ { - if token[i] == '\\' { - i++ - } - bytes[count] = token[i] - count++ - } - token = string(bytes[:count]) - } - return token, s[pos+1:], true, nil - default: - pos := strings.IndexFunc(s, unicode.IsSpace) - if pos == -1 { - pos = len(s) - } - return s[0:pos], s[pos:], true, nil - } -} - -func (db *DB) tokenizeCommandAll(command string) ([]string, error) { - var tokens []string - s := command - for { - token, rest, ok, err := db.tokenizeCommand(s) - if err != nil { - return nil, err - } - if !ok { - break - } - tokens = append(tokens, token) - s = rest - } - return tokens, nil -} - -var commandOptionKeys = map[string][]string{ - "cache_limit": {"max"}, - "check": {"obj"}, - "column_create": {"table", "name", "flags", "type", "source"}, - "column_list": {"table"}, - "column_remove": {"table", "name"}, - "column_rename": {"table", "name", "new_name"}, - "define_selector": { - "name", "table", "match_columns", "query", "filter", "scorer", "sortby", - "output_columns", "offset", "limit", "drilldown", "drilldown_sortby", - "drilldown_output_columns", "drilldown_offset", "drilldown_limit"}, - "defrag": {"objname", "threshold"}, - "delete": {"table", "key", "id", "filter"}, - "dump": {"tables"}, - "gnx_load": {"values", "table", "columns", "ifexists", "input_type"}, - "gnx_select": { - "table", "match_columns", "query", "filter", "scorer", "sortby", - "output_columns", "offset", "limit", "drilldown", "drilldown_sortby", - "drilldown_output_columns", "drilldown_offset", "drilldown_limit", - "cache", "match_escalation_threshold", "query_expansion", "query_flags", - "query_expander", "adjuster", "drilldown_calc_types", - "drilldown_calc_target", - "grnxx_filter", "grnxx_output_columns", "grnxx_offset", "grnxx_limit"}, - "gnx_snapshot": {"table", "column"}, - "load": {"values", "table", "columns", "ifexists", "input_type"}, - "lock_clear": {"target_name"}, - "log_level": {"level"}, - "log_put": {"level", "message"}, - "log_reopen": {}, - "logical_count": { - "logical_table", "shared_key", "min", "min_border", "max", "max_border", - "filter"}, - "normalize": {"normalizer", "string", "flags"}, - "normalizer_list": {}, - "quit": {}, - // "range_filter": {}, - "register": {"path"}, - "request_cancel": {"id"}, - "ruby_eval": {"script"}, - "ruby_load": {"path"}, - "select": { - "table", "match_columns", "query", "filter", "scorer", "sortby", - "output_columns", "offset", "limit", "drilldown", "drilldown_sortby", - "drilldown_output_columns", "drilldown_offset", "drilldown_limit", - "cache", "match_escalation_threshold", "query_expansion", "query_flags", - "query_expander", "adjuster", "drilldown_calc_types", - "drilldown_calc_target"}, - "shutdown": {}, - "status": {}, - "suggest": {"types", "table", "column", "query", "sortby", "output_columns", - "offset", "limit", "frequency_threshold", - "conditional_probability_threshold", "prefix_search"}, - "table_create": { - "name", "flag", "key_type", "value_type", "default_tokenizer", - "normalizer", "token_filters"}, - "table_list": {}, - "table_remove": {"name"}, - "table_tokenize": {"table", "string", "flags", "mode"}, - "tokenize": { - "tokenizer", "string", "normalizer", "flags", "mode", "token_filters"}, - "tokenizer_list": {}, - "truncate": {"target_name"}} - -func (db *DB) parseCommandOptions(name string, tokens []string) ( - map[string]string, error) { - args := make([]string, 0) - options := make(map[string]string) - for i := 0; i < len(tokens); i++ { - if strings.HasPrefix(tokens[i], "--") { - key := tokens[i][2:] - i++ - if i >= len(tokens) { - return nil, fmt.Errorf("option argument missing") - } - options[key] = tokens[i] - } else { - args = append(args, tokens[i]) - } - } - keys := commandOptionKeys[name] - end := len(keys) - if end > len(args) { - end = len(args) - } - for i := 0; i < end; i++ { - options[keys[i]] = args[i] - } - return options, nil -} - -func (db *DB) ParseCommand(command string) (string, map[string]string, error) { - tokens, err := db.tokenizeCommandAll(command) - if err != nil { - return "", nil, err - } - if len(tokens) == 0 { - return "", nil, nil - } - // Parse tokens. - name := tokens[0] - options, err := db.parseCommandOptions(name, tokens[1:]) - if err != nil { - return "", nil, err - } - return name, options, nil -} Deleted: go/gnx/grnxx/grnxx.cpp (+0 -1058) 100644 =================================================================== --- go/gnx/grnxx/grnxx.cpp 2015-05-26 11:06:34 +0900 (f2505c6) +++ /dev/null @@ -1,1058 +0,0 @@ -#include "grnxx.h" - -#include <grnxx/db.hpp> -#include <grnxx/expression.hpp> -#include <grnxx/library.hpp> -#include <grnxx/pipeline.hpp> - -extern "C" { - -// -- Library -- - -const char *grnxx_package() { - return grnxx::Library::package(); -} - -const char *grnxx_version() { - return grnxx::Library::version(); -} - -// -- Component -- - -struct grnxx_db { - grnxx::DB *db() { - return reinterpret_cast<grnxx::DB *>(this); - } -}; - -struct grnxx_table { - grnxx::Table *table() { - return reinterpret_cast<grnxx::Table *>(this); - } -}; - -struct grnxx_column { - grnxx::Column *column() { - return reinterpret_cast<grnxx::Column *>(this); - } -}; - -struct grnxx_index { - grnxx::Index *index() { - return reinterpret_cast<grnxx::Index *>(this); - } -}; - -struct grnxx_cursor { - grnxx::Cursor *cursor() { - return reinterpret_cast<grnxx::Cursor *>(this); - } -}; - -struct grnxx_expression { - grnxx::Expression *expression() { - return reinterpret_cast<grnxx::Expression *>(this); - } -}; - -struct grnxx_expression_builder { - grnxx::ExpressionBuilder *builder() { - return reinterpret_cast<grnxx::ExpressionBuilder *>(this); - } -}; - -struct grnxx_sorter { - grnxx::Sorter *sorter() { - return reinterpret_cast<grnxx::Sorter *>(this); - } -}; - -struct grnxx_merger { - grnxx::Merger *merger() { - return reinterpret_cast<grnxx::Merger *>(this); - } -}; - -struct grnxx_pipeline { - grnxx::Pipeline *pipeline() { - return reinterpret_cast<grnxx::Pipeline *>(this); - } -}; - -struct grnxx_pipeline_builder { - grnxx::PipelineBuilder *builder() { - return reinterpret_cast<grnxx::PipelineBuilder *>(this); - } -}; - -// -- Utility -- - -static grnxx::Datum grnxx_value_to_datum(grnxx::DataType data_type, - const void *value) { - if (!value) { - return grnxx::Datum(grnxx::NA()); - } - switch (data_type) { - case GRNXX_BOOL: { - const grnxx_bool *x = static_cast<const grnxx_bool *>(value); - return grnxx::Datum((*x == GRNXX_BOOL_NA) ? grnxx::Bool::na() : - grnxx::Bool(*x != GRNXX_BOOL_FALSE)); - } - case GRNXX_INT: { - return grnxx::Datum(grnxx::Int(*static_cast<const int64_t *>(value))); - } - case GRNXX_FLOAT: { - return grnxx::Datum(grnxx::Float(*static_cast<const double *>(value))); - } - case GRNXX_GEO_POINT: { - const grnxx_geo_point *geo_point = - static_cast<const grnxx_geo_point *>(value); - return grnxx::GeoPoint(grnxx::Int(geo_point->latitude), - grnxx::Int(geo_point->longitude)); - } - case GRNXX_TEXT: { - const grnxx_text *x = static_cast<const grnxx_text *>(value); - return grnxx::Text(x->data, x->size); - } - } - return grnxx::Datum(grnxx::NA()); -} - -// -- DB -- - -grnxx_db *grnxx_db_create() try { - auto db = grnxx::open_db(""); - return reinterpret_cast<grnxx_db *>(db.release()); -} catch (...) { - return nullptr; -} - -void grnxx_db_close(grnxx_db *db) { - delete db->db(); -} - -size_t grnxx_db_num_tables(grnxx_db *db) { - return db->db()->num_tables(); -} - -grnxx_table *grnxx_db_create_table(grnxx_db *db, const char *name) try { - return reinterpret_cast<grnxx_table *>(db->db()->create_table(name)); -} catch (...) { - return nullptr; -} - -bool grnxx_db_remove_table(grnxx_db *db, const char *name) try { - db->db()->remove_table(name); - return true; -} catch (...) { - return false; -} - -bool grnxx_db_rename_table(grnxx_db *db, - const char *name, - const char *new_name) try { - db->db()->rename_table(name, new_name); - return true; -} catch (...) { - return false; -} - -bool grnxx_db_reorder_table(grnxx_db *db, - const char *name, - const char *prev_name) try { - db->db()->reorder_table(name, prev_name); - return true; -} catch (...) { - return false; -} - -grnxx_table *grnxx_db_get_table(grnxx_db *db, size_t table_id) { - return reinterpret_cast<grnxx_table *>(db->db()->get_table(table_id)); -} - -grnxx_table *grnxx_db_find_table(grnxx_db *db, const char *name) { - return reinterpret_cast<grnxx_table *>(db->db()->find_table(name)); -} - -// -- Table -- - -grnxx_db *grnxx_table_db(grnxx_table *table) { - return reinterpret_cast<grnxx_db *>(table->table()->db()); -} - -const char *grnxx_table_name(grnxx_table *table, size_t *size) { - *size = table->table()->name().size(); - return table->table()->name().data(); -} - -size_t grnxx_table_num_columns(grnxx_table *table) { - return table->table()->num_columns(); -} - -grnxx_column *grnxx_table_key_column(grnxx_table *table) { - return reinterpret_cast<grnxx_column *>(table->table()->key_column()); -} - -size_t grnxx_table_num_rows(grnxx_table *table) { - return table->table()->num_rows(); -} - -int64_t grnxx_table_max_row_id(grnxx_table *table) { - return table->table()->max_row_id().raw(); -} - -bool grnxx_table_is_empty(grnxx_table *table) { - return table->table()->is_empty(); -} - -bool grnxx_table_is_full(grnxx_table *table) { - return table->table()->is_full(); -} - -grnxx_column *grnxx_table_create_column( - grnxx_table *table, - const char *name, - grnxx_data_type data_type, - const grnxx_column_options *options) try { - grnxx::ColumnOptions internal_options; - if (options) { - internal_options.reference_table_name = options->reference_table_name; - } - return reinterpret_cast<grnxx_column *>( - table->table()->create_column(name, data_type, internal_options)); -} catch (...) { - return nullptr; -} - -bool grnxx_table_remove_column(grnxx_table *table, const char *name) try { - table->table()->remove_column(name); - return true; -} catch (...) { - return false; -} - -bool grnxx_table_rename_column(grnxx_table *table, - const char *name, - const char *new_name) try { - table->table()->rename_column(name, new_name); - return true; -} catch (...) { - return false; -} - -bool grnxx_table_reorder_column(grnxx_table *table, - const char *name, - const char *prev_name) try { - table->table()->reorder_column(name, prev_name); - return true; -} catch (...) { - return false; -} - -grnxx_column *grnxx_table_get_column(grnxx_table *table, size_t column_id) { - return reinterpret_cast<grnxx_column *>( - table->table()->get_column(column_id)); -} - -grnxx_column *grnxx_table_find_column(grnxx_table *table, const char *name) { - return reinterpret_cast<grnxx_column *>(table->table()->find_column(name)); -} - -bool grnxx_table_set_key_column(grnxx_table *table, const char *name) try { - table->table()->set_key_column(name); - return true; -} catch (...) { - return false; -} - -bool grnxx_table_unset_key_column(grnxx_table *table) try { - table->table()->unset_key_column(); - return true; -} catch (...) { - return false; -} - -int64_t grnxx_table_insert_row(grnxx_table *table, const void *key) try { - auto key_column = table->table()->key_column(); - if (key_column) { - table->table()->insert_row( - grnxx_value_to_datum(key_column->data_type(), key)); - } else { - return table->table()->insert_row().raw(); - } -} catch (...) { - return grnxx::Int::raw_na(); -} - -size_t grnxx_table_insert_rows(grnxx_table *table, - size_t num_keys, - const void *keys, - int64_t *row_ids) { - size_t count = 0; - auto key_column = table->table()->key_column(); - if (key_column) { - grnxx::Datum key; - while (count < num_keys) try { - switch (key_column->data_type()) { - case GRNXX_BOOL: { - auto value = static_cast<const grnxx_bool *>(keys)[count]; - key = (value == GRNXX_BOOL_NA) ? grnxx::Bool(grnxx::NA()) : - grnxx::Bool(value == GRNXX_BOOL_TRUE); - break; - } - case GRNXX_INT: { - auto value = static_cast<const int64_t *>(keys)[count]; - key = grnxx::Int(value); - break; - } - case GRNXX_FLOAT: { - auto value = static_cast<const double *>(keys)[count]; - key = grnxx::Float(value); - break; - } - case GRNXX_GEO_POINT: { - auto value = static_cast<const grnxx_geo_point *>(keys)[count]; - key = grnxx::GeoPoint(grnxx::Int(value.latitude), - grnxx::Int(value.longitude)); - break; - } - case GRNXX_TEXT: { - auto value = static_cast<const grnxx_text *>(keys)[count]; - key = grnxx::Text(value.data, value.size); - break; - } - } - row_ids[count] = table->table()->insert_row(key).raw(); - ++count; - } catch (...) { - return count; - } - } else { - while (count < num_keys) try { - row_ids[count] = table->table()->insert_row().raw(); - ++count; - } catch (...) { - return count; - } - } - return count; -} - -bool grnxx_table_insert_row_at(grnxx_table *table, - int64_t row_id, - const void *key) try { - auto key_column = table->table()->key_column(); - if (key_column) { - table->table()->insert_row_at( - grnxx::Int(row_id), - grnxx_value_to_datum(key_column->data_type(), key)); - } else { - table->table()->insert_row_at(grnxx::Int(row_id)); - } - return true; -} catch (...) { - return false; -} - -int64_t grnxx_table_find_or_insert_row(grnxx_table *table, - const void *key, - bool *inserted) try { - auto key_column = table->table()->key_column(); - return table->table()->find_or_insert_row( - grnxx_value_to_datum(key_column->data_type(), key), inserted).raw(); -} catch (...) { - return grnxx::Int::raw_na(); -} - -bool grnxx_table_remove_row(grnxx_table *table, int64_t row_id) try { - table->table()->remove_row(grnxx::Int(row_id)); - return true; -} catch (...) { - return false; -} - -bool grnxx_table_test_row(grnxx_table *table, int64_t row_id) try { - return table->table()->test_row(grnxx::Int(row_id)); -} catch (...) { - return false; -} - -int64_t grnxx_table_find_row(grnxx_table *table, const void *key) try { - auto key_column = table->table()->key_column(); - if (!key_column) { - return grnxx::Int::raw_na(); - } - return table->table()->find_row( - grnxx_value_to_datum(key_column->data_type(), key)).raw(); -} catch (...) { - return false; -} - -grnxx_cursor *grnxx_table_create_cursor(grnxx_table *table, - const grnxx_cursor_options *options) try { - auto cursor = table->table()->create_cursor( - *reinterpret_cast<const grnxx::CursorOptions *>(options)); - return reinterpret_cast<grnxx_cursor *>(cursor.release()); -} catch (...) { - return nullptr; -} - -// -- Column -- - -grnxx_table *grnxx_column_table(grnxx_column *column) { - return reinterpret_cast<grnxx_table *>(column->column()->table()); -} - -const char *grnxx_column_name(grnxx_column *column, size_t *size) { - *size = column->column()->name().size(); - return column->column()->name().data(); -} - -grnxx_data_type grnxx_column_data_type(grnxx_column *column) { - return column->column()->data_type(); -} - -grnxx_table *grnxx_column_reference_table(grnxx_column *column) { - return reinterpret_cast<grnxx_table *>(column->column()->reference_table()); -} - -bool grnxx_column_is_key(grnxx_column *column) { - return column->column()->is_key(); -} - -size_t grnxx_column_num_indexes(grnxx_column *column) { - return column->column()->num_indexes(); -} - -grnxx_index *grnxx_column_create_index(grnxx_column *column, - const char *name, - grnxx_index_type index_type) try { - switch (index_type) { - case GRNXX_TREE_INDEX: { - return reinterpret_cast<grnxx_index *>( - column->column()->create_index(name, GRNXX_TREE_INDEX)); - } - case GRNXX_HASH_INDEX: { - return reinterpret_cast<grnxx_index *>( - column->column()->create_index(name, GRNXX_HASH_INDEX)); - } - default: { - return nullptr; - } - } -} catch (...) { - return nullptr; -} - -bool grnxx_column_remove_index(grnxx_column *column, const char *name) try { - column->column()->remove_index(name); - return true; -} catch (...) { - return false; -} - -bool grnxx_column_rename_index(grnxx_column *column, - const char *name, - const char *new_name) try { - column->column()->rename_index(name, new_name); - return true; -} catch (...) { - return false; -} - -bool grnxx_column_reorder_index(grnxx_column *column, - const char *name, - const char *prev_name) try { - column->column()->reorder_index(name, prev_name); - return true; -} catch (...) { - return false; -} - -grnxx_index *grnxx_column_get_index(grnxx_column *column, size_t index_id) { - return reinterpret_cast<grnxx_index *>( - column->column()->get_index(index_id)); -} - -grnxx_index *grnxx_column_find_index(grnxx_column *column, const char *name) { - return reinterpret_cast<grnxx_index *>(column->column()->find_index(name)); -} - -bool grnxx_column_set(grnxx_column *column, - int64_t row_id, - const void *value) try { - if (!value) { - column->column()->set(grnxx::Int(row_id), grnxx::NA()); - return true; - } - column->column()->set( - grnxx::Int(row_id), - grnxx_value_to_datum(column->column()->data_type(), value)); - return true; -} catch (...) { - return false; -} - -bool grnxx_column_get(grnxx_column *column, int64_t row_id, void *value) try { - grnxx::Datum datum; - column->column()->get(grnxx::Int(row_id), &datum); - switch (column->column()->data_type()) { - case GRNXX_BOOL: { - *static_cast<grnxx_bool *>(value) = datum.force_bool().raw(); - break; - } - case GRNXX_INT: { - *static_cast<int64_t *>(value) = datum.force_int().raw(); - break; - } - case GRNXX_FLOAT: { - *static_cast<double *>(value) = datum.force_float().raw(); - break; - } - case GRNXX_GEO_POINT: { - grnxx_geo_point *geo_point = static_cast<grnxx_geo_point *>(value); - geo_point->latitude = datum.force_geo_point().raw_latitude(); - geo_point->longitude = datum.force_geo_point().raw_longitude(); - break; - } - case GRNXX_TEXT: { - grnxx_text *text = static_cast<grnxx_text *>(value); - const grnxx::Text &stored_text = datum.force_text(); - if (stored_text.is_na()) { - text->data = nullptr; - text->size = grnxx::Text::raw_na_size(); - } else { - text->data = datum.force_text().raw_data(); - text->size = datum.force_text().raw_size(); - } - break; - } - default: { - return false; - } - } - return true; -} catch (...) { - return false; -} - -bool grnxx_column_contains(grnxx_column *column, const void *value) try { - if (!value) { - return column->column()->contains(grnxx::NA()); - } - return column->column()->contains( - grnxx_value_to_datum(column->column()->data_type(), value)); -} catch (...) { - return false; -} - -int64_t grnxx_column_find_one(grnxx_column *column, const void *value) try { - if (!value) { - return column->column()->find_one(grnxx::NA()).raw(); - } - return column->column()->find_one( - grnxx_value_to_datum(column->column()->data_type(), value)).raw(); -} catch (...) { - return grnxx::Int::raw_na(); -} - -// -- Index -- - -grnxx_column *grnxx_index_column(grnxx_index *index) { - return reinterpret_cast<grnxx_column *>(index->index()->column()); -} - -const char *grnxx_index_name(grnxx_index *index, size_t *size) { - *size = index->index()->name().size(); - return index->index()->name().data(); -} - -grnxx_index_type grnxx_index_index_type(grnxx_index *index) { - switch (index->index()->type()) { - case GRNXX_TREE_INDEX: { - return GRNXX_TREE_INDEX; - } - case GRNXX_HASH_INDEX: { - return GRNXX_HASH_INDEX; - } - } -} - -size_t grnxx_index_num_entries(grnxx_index *index) { - return index->index()->num_entries(); -} - -bool grnxx_index_test_uniqueness(grnxx_index *index) try { - return index->index()->test_uniqueness(); -} catch (...) { - return false; -} - -bool grnxx_index_contains(grnxx_index *index, const void *value) try { - auto column = index->index()->column(); - if (!value) { - return column->contains(grnxx::NA()); - } - return index->index()->contains( - grnxx_value_to_datum(column->data_type(), value)); -} catch (...) { - return false; -} - -int64_t grnxx_index_find_one(grnxx_index *index, const void *value) try { - auto column = index->index()->column(); - if (!value) { - return column->find_one(grnxx::NA()).raw(); - } - return index->index()->find_one( - grnxx_value_to_datum(column->data_type(), value)).raw(); -} catch (...) { - return grnxx::Int::raw_na(); -} - -grnxx_cursor *grnxx_index_find(grnxx_index *index, - const void *value, - const grnxx_cursor_options *options) try { - const grnxx::CursorOptions *cursor_options = - reinterpret_cast<const grnxx::CursorOptions *>(options); - return reinterpret_cast<grnxx_cursor *>(index->index()->find( - grnxx_value_to_datum(index->index()->column()->data_type(), value), - *cursor_options).release()); -} catch (...) { - return nullptr; -} - -grnxx_cursor *grnxx_index_find_in_range(grnxx_index *index, - const void *lower_bound_value, - bool lower_bound_is_inclusive, - const void *upper_bound_value, - bool upper_bound_is_inclusive, - const grnxx_cursor_options *options) try { - const grnxx::CursorOptions *cursor_options = - reinterpret_cast<const grnxx::CursorOptions *>(options); - grnxx::DataType data_type = index->index()->column()->data_type(); - grnxx::IndexRange range; - range.set_lower_bound( - grnxx_value_to_datum(data_type, lower_bound_value), - lower_bound_is_inclusive ? grnxx::INCLUSIVE_END_POINT : - grnxx::EXCLUSIVE_END_POINT); - range.set_upper_bound( - grnxx_value_to_datum(data_type, upper_bound_value), - upper_bound_is_inclusive ? grnxx::INCLUSIVE_END_POINT : - grnxx::EXCLUSIVE_END_POINT); - return reinterpret_cast<grnxx_cursor *>( - index->index()->find_in_range(range, *cursor_options).release()); -} catch (...) { - return nullptr; -} - -grnxx_cursor *grnxx_index_find_starts_with(grnxx_index *index, - const void *prefix, - bool prefix_is_inclusive, - const grnxx_cursor_options *options) try { - const grnxx::CursorOptions *cursor_options = - reinterpret_cast<const grnxx::CursorOptions *>(options); - grnxx::EndPoint end_point; - if (prefix_is_inclusive) { - end_point.type = grnxx::INCLUSIVE_END_POINT; - } else { - end_point.type = grnxx::EXCLUSIVE_END_POINT; - } - end_point.value = - grnxx_value_to_datum(index->index()->column()->data_type(), prefix); - return reinterpret_cast<grnxx_cursor *>( - index->index()->find_starts_with(end_point, *cursor_options).release()); -} catch (...) { - return nullptr; -} - -grnxx_cursor *grnxx_index_find_prefixes(grnxx_index *index, - const void *value, - const grnxx_cursor_options *options) try { - const grnxx::CursorOptions *cursor_options = - reinterpret_cast<const grnxx::CursorOptions *>(options); - return reinterpret_cast<grnxx_cursor *>(index->index()->find_prefixes( - grnxx_value_to_datum(index->index()->column()->data_type(), value), - *cursor_options).release()); -} catch (...) { - return nullptr; -} - -// -- Cursor -- - -void grnxx_cursor_close(grnxx_cursor *cursor) { - delete cursor->cursor(); -} - -size_t grnxx_cursor_read(grnxx_cursor *cursor, - grnxx_record *records, - size_t size) try { - return cursor->cursor()->read(grnxx::ArrayRef<grnxx::Record>( - reinterpret_cast<grnxx::Record *>(records), size)); -} catch (...) { - return 0; -} - -// -- Expression -- - -grnxx_expression *grnxx_expression_parse(grnxx_table *table, - const char *query) try { - return reinterpret_cast<grnxx_expression *>( - grnxx::Expression::parse(table->table(), query).release()); -} catch (...) { - return nullptr; -} - -void grnxx_expression_close(grnxx_expression *expression) { - delete expression->expression(); -} - -grnxx_table *grnxx_expression_table(grnxx_expression *expression) { - return reinterpret_cast<grnxx_table *>( - const_cast<grnxx::Table *>(expression->expression()->table())); -} - -grnxx_data_type grnxx_expression_data_type(grnxx_expression *expression) { - return expression->expression()->data_type(); -} - -bool grnxx_expression_is_row_id(grnxx_expression *expression) { - return expression->expression()->is_row_id(); -} - -bool grnxx_expression_is_score(grnxx_expression *expression) { - return expression->expression()->is_score(); -} - -size_t grnxx_expression_block_size(grnxx_expression *expression) { - return expression->expression()->block_size(); -} - -bool grnxx_expression_filter(grnxx_expression *expression, - grnxx_record *records, - size_t *size, - size_t offset, - size_t limit) try { - grnxx::ArrayRef<grnxx::Record> array( - reinterpret_cast<grnxx::Record *>(records), *size); - expression->expression()->filter(array, &array, offset, limit); - *size = array.size(); - return true; -} catch (...) { - return false; -} - -bool grnxx_expression_adjust(grnxx_expression *expression, - grnxx_record *records, - size_t size) try { - grnxx::ArrayRef<grnxx::Record> array( - reinterpret_cast<grnxx::Record *>(records), size); - expression->expression()->adjust(array); - return true; -} catch (...) { - return false; -} - -bool grnxx_expression_evaluate(grnxx_expression *expression, - const grnxx_record *records, - size_t size, - void *values) try { - grnxx::ArrayCRef<grnxx::Record> internal_records( - reinterpret_cast<const grnxx::Record *>(records), size); - switch (expression->expression()->data_type()) { - case GRNXX_BOOL: { - grnxx::ArrayRef<grnxx::Bool> internal_values( - reinterpret_cast<grnxx::Bool *>(values), size); - expression->expression()->evaluate(internal_records, internal_values); - break; - } - case GRNXX_INT: { - grnxx::ArrayRef<grnxx::Int> internal_values( - reinterpret_cast<grnxx::Int *>(values), size); - expression->expression()->evaluate(internal_records, internal_values); - break; - } - case GRNXX_FLOAT: { - grnxx::ArrayRef<grnxx::Float> internal_values( - reinterpret_cast<grnxx::Float *>(values), size); - expression->expression()->evaluate(internal_records, internal_values); - break; - } - case GRNXX_GEO_POINT: { - grnxx::ArrayRef<grnxx::GeoPoint> internal_values( - reinterpret_cast<grnxx::GeoPoint *>(values), size); - expression->expression()->evaluate(internal_records, internal_values); - break; - } - case GRNXX_TEXT: { - grnxx::ArrayRef<grnxx::Text> internal_values( - reinterpret_cast<grnxx::Text *>(values), size); - expression->expression()->evaluate(internal_records, internal_values); - break; - } - default: { - return false; - } - } - return true; -} catch (...) { - return false; -} - -// -- ExpressionBuilder -- - -grnxx_expression_builder *grnxx_expression_builder_create(grnxx_table *table) try { - return reinterpret_cast<grnxx_expression_builder *>( - grnxx::ExpressionBuilder::create(table->table()).release()); -} catch (...) { - return nullptr; -} - -void grnxx_expression_builder_close(grnxx_expression_builder *builder) { - delete builder->builder(); -} - -grnxx_table *grnxx_expression_builder_table(grnxx_expression_builder *builder) { - return reinterpret_cast<grnxx_table *>( - const_cast<grnxx::Table *>(builder->builder()->table())); -} - -bool grnxx_expression_builder_push_constant(grnxx_expression_builder *builder, - grnxx_data_type data_type, - const void *value) try { - builder->builder()->push_constant(grnxx_value_to_datum(data_type, value)); - return true; -} catch (...) { - return false; -} - -bool grnxx_expression_builder_push_row_id(grnxx_expression_builder *builder) try { - builder->builder()->push_row_id(); - return true; -} catch (...) { - return false; -} - -bool grnxx_expression_builder_push_score(grnxx_expression_builder *builder) try { - builder->builder()->push_score(); - return true; -} catch (...) { - return false; -} - -bool grnxx_expression_builder_push_column(grnxx_expression_builder *builder, - const char *column_name) try { - builder->builder()->push_column(column_name); - return true; -} catch (...) { - return false; -} - -bool grnxx_expression_builder_push_operator( - grnxx_expression_builder *builder, - grnxx_operator_type operator_type) try { - builder->builder()->push_operator(operator_type); - return true; -} catch (...) { - return false; -} - -bool grnxx_expression_builder_begin_subexpression( - grnxx_expression_builder *builder) try { - builder->builder()->begin_subexpression(); - return true; -} catch (...) { - return false; -} - -bool grnxx_expression_builder_end_subexpression( - grnxx_expression_builder *builder) try { - builder->builder()->end_subexpression(); - return true; -} catch (...) { - return false; -} - -void grnxx_expression_builder_clear(grnxx_expression_builder *builder) { - builder->builder()->clear(); -} - -grnxx_expression *grnxx_expression_builder_release( - grnxx_expression_builder *builder) try { - return reinterpret_cast<grnxx_expression *>( - builder->builder()->release().release()); -} catch (...) { - return nullptr; -} - -// -- Sorter -- - -grnxx_sorter *grnxx_sorter_create(grnxx_sorter_order *orders, - size_t num_orders, - const grnxx_sorter_options *options) try { - grnxx::Array<grnxx::SorterOrder> internal_orders; - internal_orders.resize(num_orders); - for (size_t i = 0; i < num_orders; ++i) { - internal_orders[i].expression.reset(orders[i].expression->expression()); - internal_orders[i].type = orders[i].order_type; - } - grnxx::SorterOptions internal_options; - if (options) { - internal_options.offset = options->offset; - internal_options.limit = options->limit; - } - auto sorter = grnxx::Sorter::create( - std::move(internal_orders), internal_options); - return reinterpret_cast<grnxx_sorter *>(sorter.release()); -} catch (...) { - return nullptr; -} - -void grnxx_sorter_close(grnxx_sorter *sorter) { - delete sorter->sorter(); -} - -// -- Merger -- - -static grnxx::MergerOptions grnxx_merger_convert_options( - const grnxx_merger_options *options) { - grnxx::MergerOptions internal_options; - if (options) { - internal_options.logical_operator_type = options->logical_operator_type; - internal_options.score_operator_type = options->score_operator_type; - internal_options.missing_score = grnxx::Float(options->missing_score); - internal_options.offset = options->offset; - internal_options.limit = options->limit; - } - return internal_options; -} - -grnxx_merger *grnxx_merger_create(const grnxx_merger_options *options) try { - auto internal_options = grnxx_merger_convert_options(options); - auto merger = grnxx::Merger::create(std::move(internal_options)); - return reinterpret_cast<grnxx_merger *>(merger.release()); -} catch (...) { - return nullptr; -} - -void grnxx_merger_close(grnxx_merger *merger) { - delete merger->merger(); -} - -// -- Pipeline -- - -void grnxx_pipeline_close(grnxx_pipeline *pipeline) { - delete pipeline->pipeline(); -} - -grnxx_table *grnxx_pipeline_table(grnxx_pipeline *pipeline) { - return reinterpret_cast<grnxx_table *>( - const_cast<grnxx::Table *>(pipeline->pipeline()->table())); -} - -bool grnxx_pipeline_flush(grnxx_pipeline *pipeline, - grnxx_record **records, - size_t *size) try { - grnxx::Array<grnxx::Record> internal_records; - pipeline->pipeline()->flush(&internal_records); - // TODO: Deep copy should be skipped. - *records = static_cast<grnxx_record *>( - std::malloc(sizeof(grnxx_record) * internal_records.size())); - if (!*records) { - return false; - } - for (size_t i = 0; i < internal_records.size(); ++i) { - (*records)[i].row_id = internal_records[i].row_id.raw(); - (*records)[i].score = internal_records[i].score.raw(); - } - *size = internal_records.size(); - return true; -} catch (...) { - return false; -} - -// -- PipelineBuilder -- - -grnxx_pipeline_builder *grnxx_pipeline_builder_create(grnxx_table *table) try { - auto builder = grnxx::PipelineBuilder::create(table->table()); - return reinterpret_cast<grnxx_pipeline_builder *>(builder.release()); -} catch (...) { - return nullptr; -} - -void grnxx_pipeline_builder_close(grnxx_pipeline_builder *builder) { - delete builder->builder(); -} - -grnxx_table *grnxx_pipeline_builder_table(grnxx_pipeline_builder *builder) { - return reinterpret_cast<grnxx_table *>( - const_cast<grnxx::Table *>(builder->builder()->table())); -} - -bool grnxx_pipeline_builder_push_cursor(grnxx_pipeline_builder *builder, - grnxx_cursor *cursor) try { - builder->builder()->push_cursor( - std::unique_ptr<grnxx::Cursor>(cursor->cursor())); - return true; -} catch (...) { - return false; -} - -bool grnxx_pipeline_builder_push_filter(grnxx_pipeline_builder *builder, - grnxx_expression *expression, - size_t offset, - size_t limit) try { - builder->builder()->push_filter( - std::unique_ptr<grnxx::Expression>(expression->expression()), - offset, limit); - return true; -} catch (...) { - return false; -} - -bool grnxx_pipeline_builder_push_adjuster(grnxx_pipeline_builder *builder, - grnxx_expression *expression) try { - builder->builder()->push_adjuster( - std::unique_ptr<grnxx::Expression>(expression->expression())); - return true; -} catch (...) { - return false; -} - -bool grnxx_pipeline_builder_push_sorter(grnxx_pipeline_builder *builder, - grnxx_sorter *sorter) try { - builder->builder()->push_sorter( - std::unique_ptr<grnxx::Sorter>(sorter->sorter())); - return true; -} catch (...) { - return false; -} - -bool grnxx_pipeline_builder_push_merger(grnxx_pipeline_builder *builder, - const grnxx_merger_options *options) try { - auto internal_options = grnxx_merger_convert_options(options); - builder->builder()->push_merger(internal_options); - return true; -} catch (...) { - return false; -} - - -void grnxx_pipeline_builder_clear(grnxx_pipeline_builder *builder) { - builder->builder()->clear(); -} - -grnxx_pipeline *grnxx_pipeline_builder_release( - grnxx_pipeline_builder *builder, - const grnxx_pipeline_options *options) try { - grnxx::PipelineOptions internal_options; - if (options) { - // Nothing to do. - } - auto pipeline = builder->builder()->release(internal_options); - return reinterpret_cast<grnxx_pipeline *>(pipeline.release()); -} catch (...) { - return nullptr; -} - -} // extern "C" Deleted: go/gnx/grnxx/grnxx.go (+0 -1422) 100644 =================================================================== --- go/gnx/grnxx/grnxx.go 2015-05-26 11:06:34 +0900 (5cfb55d) +++ /dev/null @@ -1,1422 +0,0 @@ -package grnxx - -// #cgo CXXFLAGS: -std=c++11 -// #cgo LDFLAGS: -lgrnxx -lstdc++ -// -// #include "grnxx.h" -// -// #include <stdlib.h> -import "C" -import "fmt" -import "math" -import "reflect" -import "unsafe" - -// -- Data types -- - -type Bool uint8 -type Int int64 -type Float float64 -type GeoPoint struct { - Latitude int32 - Longitude int32 -} -type Text []byte - -type Valuer interface { - IsNA() bool -} - -func NABool() Bool { - return Bool(1) -} -func NAInt() Int { - return Int(math.MinInt64) -} -func NAFloat() Float { - return Float(math.NaN()) -} -func NAGeoPoint() GeoPoint { - return GeoPoint{math.MinInt32, math.MinInt32} -} -func NAText() Text { - return nil -} - -func (this Bool) IsNA() bool { - return this == 1 -} -func (this Int) IsNA() bool { - return this == math.MinInt64 -} -func (this Float) IsNA() bool { - return math.IsNaN(float64(this)) -} -func (this GeoPoint) IsNA() bool { - return this.Latitude == math.MinInt32 -} -func (this Text) IsNA() bool { - return this == nil -} - -func (this Text) Convert() C.grnxx_text { - switch { - case this == nil: - return C.grnxx_text{nil, C.int64_t(math.MinInt64)} - case len(this) == 0: - return C.grnxx_text{nil, C.int64_t(0)} - default: - ptr := (*C.char)(unsafe.Pointer(&this[0])) - return C.grnxx_text{ptr, C.int64_t(len(this))} - } -} - -type Record struct { - RowID Int - Score Float -} - -// -- Constants -- - -const ( - NA = Bool(1) - TRUE = Bool(3) - FALSE = Bool(0) -) - -type DataType int - -const ( - BOOL = DataType(C.GRNXX_BOOL) - INT = DataType(C.GRNXX_INT) - FLOAT = DataType(C.GRNXX_FLOAT) - GEO_POINT = DataType(C.GRNXX_GEO_POINT) - TEXT = DataType(C.GRNXX_TEXT) -) - -type IndexType int - -const ( - TREE_INDEX = IndexType(C.GRNXX_TREE_INDEX) - HASH_INDEX = IndexType(C.GRNXX_HASH_INDEX) -) - -type OrderType int - -const ( - REGULAR_ORDER = OrderType(C.GRNXX_REGULAR_ORDER) - REVERSE_ORDER = OrderType(C.GRNXX_REVERSE_ORDER) -) - -type OperatorType int - -const ( - LOGICAL_NOT = OperatorType(C.GRNXX_LOGICAL_NOT) - BITWISE_NOT = OperatorType(C.GRNXX_BITWISE_NOT) - POSITIVE = OperatorType(C.GRNXX_POSITIVE) - NEGATIVE = OperatorType(C.GRNXX_NEGATIVE) - TO_INT = OperatorType(C.GRNXX_TO_INT) - TO_FLOAT = OperatorType(C.GRNXX_TO_FLOAT) - LOGICAL_AND = OperatorType(C.GRNXX_LOGICAL_AND) - LOGICAL_OR = OperatorType(C.GRNXX_LOGICAL_OR) - EQUAL = OperatorType(C.GRNXX_EQUAL) - NOT_EQUAL = OperatorType(C.GRNXX_NOT_EQUAL) - LESS = OperatorType(C.GRNXX_LESS) - LESS_EQUAL = OperatorType(C.GRNXX_LESS_EQUAL) - GREATER = OperatorType(C.GRNXX_GREATER) - GREATER_EQUAL = OperatorType(C.GRNXX_GREATER_EQUAL) - BITWISE_AND = OperatorType(C.GRNXX_BITWISE_AND) - BITWISE_OR = OperatorType(C.GRNXX_BITWISE_OR) - BITWISE_XOR = OperatorType(C.GRNXX_BITWISE_XOR) - PLUS = OperatorType(C.GRNXX_PLUS) - MINUS = OperatorType(C.GRNXX_MINUS) - MULTIPLICATION = OperatorType(C.GRNXX_MULTIPLICATION) - DIVISION = OperatorType(C.GRNXX_DIVISION) - MODULUS = OperatorType(C.GRNXX_MODULUS) - STARTS_WITH = OperatorType(C.GRNXX_STARTS_WITH) - ENDS_WITH = OperatorType(C.GRNXX_ENDS_WITH) - CONTAINS = OperatorType(C.GRNXX_CONTAINS) - SUBSCRIPT = OperatorType(C.GRNXX_SUBSCRIPT) -) - -type MergerOperatorType int - -const ( - MERGER_AND = MergerOperatorType(C.GRNXX_MERGER_AND) - MERGER_OR = MergerOperatorType(C.GRNXX_MERGER_OR) - MERGER_XOR = MergerOperatorType(C.GRNXX_MERGER_XOR) - MERGER_PLUS = MergerOperatorType(C.GRNXX_MERGER_PLUS) - MERGER_MINUS = MergerOperatorType(C.GRNXX_MERGER_MINUS) - MERGER_MULTIPLICATION = MergerOperatorType(C.GRNXX_MERGER_MULTIPLICATION) - MERGER_LEFT = MergerOperatorType(C.GRNXX_MERGER_LEFT) - MERGER_RIGHT = MergerOperatorType(C.GRNXX_MERGER_RIGHT) - MERGER_ZERO = MergerOperatorType(C.GRNXX_MERGER_ZERO) -) - -// -- Library -- - -func Package() string { - return C.GoString(C.grnxx_package()) -} - -func Version() string { - return C.GoString(C.grnxx_version()) -} - -// -- DB -- - -type DB struct { - handle *C.grnxx_db -} - -func CreateDB() (*DB, error) { - db := C.grnxx_db_create() - if db == nil { - return nil, fmt.Errorf("grnxx_db_create() failed") - } - return &DB{db}, nil -} - -func (db *DB) Close() error { - C.grnxx_db_close(db.handle) - return nil -} - -func (db *DB) NumTables() int { - return int(C.grnxx_db_num_tables(db.handle)) -} - -func (db *DB) CreateTable(name string) (*Table, error) { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - table := C.grnxx_db_create_table(db.handle, nameCString) - if table == nil { - return nil, fmt.Errorf("grnxx_db_create_table() failed") - } - return &Table{table}, nil -} - -func (db *DB) RemoveTable(name string) error { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - if !C.grnxx_db_remove_table(db.handle, nameCString) { - return fmt.Errorf("grnxx_db_remove_table() failed") - } - return nil -} - -func (db *DB) RenameTable(name string, newName string) error { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - newNameCString := C.CString(newName) - defer C.free(unsafe.Pointer(newNameCString)) - if !C.grnxx_db_rename_table(db.handle, nameCString, newNameCString) { - return fmt.Errorf("grnxx_db_rename_table() failed") - } - return nil -} - -func (db *DB) ReorderTable(name string, prevName string) error { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - prevNameCString := C.CString(prevName) - defer C.free(unsafe.Pointer(prevNameCString)) - if !C.grnxx_db_reorder_table(db.handle, nameCString, prevNameCString) { - return fmt.Errorf("grnxx_db_reorder_table() failed") - } - return nil -} - -func (db *DB) GetTable(tableID int) *Table { - return &Table{C.grnxx_db_get_table(db.handle, C.size_t(tableID))} -} - -func (db *DB) FindTable(name string) *Table { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - table := C.grnxx_db_find_table(db.handle, nameCString) - if table == nil { - return nil - } - return &Table{table} -} - -// -- Table -- - -type Table struct { - handle *C.grnxx_table -} - -func (table *Table) DB() (db *DB) { - return &DB{C.grnxx_table_db(table.handle)} -} - -func (table *Table) Name() string { - var size C.size_t - name := C.grnxx_table_name(table.handle, &size) - return C.GoStringN(name, C.int(size)) -} - -func (table *Table) NumColumns() int { - return int(C.grnxx_table_num_columns(table.handle)) -} - -func (table *Table) KeyColumn() *Column { - column := C.grnxx_table_key_column(table.handle) - if column == nil { - return nil - } - return &Column{column} -} - -func (table *Table) NumRows() int { - return int(C.grnxx_table_num_rows(table.handle)) -} - -func (table *Table) MaxRowID() Int { - return Int(C.grnxx_table_max_row_id(table.handle)) -} - -func (table *Table) IsEmpty() bool { - return bool(C.grnxx_table_is_empty(table.handle)) -} - -func (table *Table) IsFull() bool { - return bool(C.grnxx_table_is_full(table.handle)) -} - -func (table *Table) CreateColumn( - name string, dataType DataType, options *ColumnOptions) (*Column, error) { - var internalOptions *C.grnxx_column_options - if options != nil { - cString := C.CString(options.ReferenceTableName) - defer C.free(unsafe.Pointer(cString)) - internalOptions = &C.grnxx_column_options{cString} - } - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - column := C.grnxx_table_create_column(table.handle, nameCString, - C.grnxx_data_type(dataType), internalOptions) - if column == nil { - return nil, fmt.Errorf("grnxx_table_create_column() failed") - } - return &Column{column}, nil -} - -func (table *Table) RemoveColumn(name string) error { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - if !C.grnxx_table_remove_column(table.handle, nameCString) { - return fmt.Errorf("grnxx_table_remove_column() failed") - } - return nil -} - -func (table *Table) RenameColumn(name string, newName string) error { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - newNameCString := C.CString(newName) - defer C.free(unsafe.Pointer(newNameCString)) - if !C.grnxx_table_rename_column(table.handle, nameCString, newNameCString) { - return fmt.Errorf("grnxx_table_rename_column() failed") - } - return nil -} - -func (table *Table) ReorderColumn(name string, prevName string) error { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - prevNameCString := C.CString(prevName) - defer C.free(unsafe.Pointer(prevNameCString)) - if !C.grnxx_table_reorder_column(table.handle, nameCString, prevNameCString) { - return fmt.Errorf("grnxx_table_reorder_column() failed") - } - return nil -} - -func (table *Table) GetColumn(columnID int) *Column { - return &Column{C.grnxx_table_get_column(table.handle, C.size_t(columnID))} -} - -func (table *Table) FindColumn(name string) *Column { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - column := C.grnxx_table_find_column(table.handle, nameCString) - if column == nil { - return nil - } - return &Column{column} -} - -func (table *Table) SetKeyColumn(name string) error { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - if !C.grnxx_table_set_key_column(table.handle, nameCString) { - return fmt.Errorf("grnxx_table_set_key_column() failed") - } - return nil -} - -func (table *Table) UnsetKeyColumn() error { - if !C.grnxx_table_unset_key_column(table.handle) { - return fmt.Errorf("grnxx_table_unset_key_column() failed") - } - return nil -} - -func (table *Table) InsertRow(key Valuer) (Int, error) { - var rowID C.int64_t - switch x := key.(type) { - case nil: - rowID = C.grnxx_table_insert_row(table.handle, nil) - case Bool: - rowID = C.grnxx_table_insert_row(table.handle, unsafe.Pointer(&x)) - case Int: - rowID = C.grnxx_table_insert_row(table.handle, unsafe.Pointer(&x)) - case Float: - rowID = C.grnxx_table_insert_row(table.handle, unsafe.Pointer(&x)) - case GeoPoint: - rowID = C.grnxx_table_insert_row(table.handle, unsafe.Pointer(&x)) - case Text: - text := x.Convert() - rowID = C.grnxx_table_insert_row(table.handle, unsafe.Pointer(&text)) - default: - return NAInt(), fmt.Errorf("unsupported data type") - } - if rowID < 0 { - return Int(rowID), fmt.Errorf("grnxx_table_insert_row() failed") - } - return Int(rowID), nil -} - -func (table *Table) InsertRows(keys interface{}) ([]Int, error) { - var rowIDs []Int - var count int - switch x := keys.(type) { - case []Bool: - if len(x) == 0 { - return nil, fmt.Errorf("no data") - } - rowIDs = make([]Int, len(x)) - count = int(C.grnxx_table_insert_rows(table.handle, C.size_t(len(x)), - unsafe.Pointer(&x[0]), (*C.int64_t)(unsafe.Pointer(&rowIDs[0])))) - case []Int: - if len(x) == 0 { - return nil, fmt.Errorf("no data") - } - rowIDs = make([]Int, len(x)) - count = int(C.grnxx_table_insert_rows(table.handle, C.size_t(len(x)), - unsafe.Pointer(&x[0]), (*C.int64_t)(unsafe.Pointer(&rowIDs[0])))) - case []Float: - if len(x) == 0 { - return nil, fmt.Errorf("no data") - } - rowIDs = make([]Int, len(x)) - count = int(C.grnxx_table_insert_rows(table.handle, C.size_t(len(x)), - unsafe.Pointer(&x[0]), (*C.int64_t)(unsafe.Pointer(&rowIDs[0])))) - case []GeoPoint: - if len(x) == 0 { - return nil, fmt.Errorf("no data") - } - rowIDs = make([]Int, len(x)) - count = int(C.grnxx_table_insert_rows(table.handle, C.size_t(len(x)), - unsafe.Pointer(&x[0]), (*C.int64_t)(unsafe.Pointer(&rowIDs[0])))) - case []Text: - if len(x) == 0 { - return nil, fmt.Errorf("no data") - } - internalKeys := make([]C.grnxx_text, len(x)) - for i := 0; i < len(x); i++ { - internalKeys[i].data = (*C.char)(unsafe.Pointer(&x[i][0])) - internalKeys[i].size = C.int64_t(len(x[i])) - } - rowIDs = make([]Int, len(x)) - count = int(C.grnxx_table_insert_rows(table.handle, C.size_t(len(x)), - unsafe.Pointer(&internalKeys[0]), (*C.int64_t)(unsafe.Pointer(&rowIDs[0])))) - default: - return nil, fmt.Errorf("unsupported data type") - } - if count < len(rowIDs) { - return rowIDs[:count], fmt.Errorf("grnxx_table_insert_rows() failed") - } - return rowIDs, nil -} - -func (table *Table) InsertRowAt(rowID Int, key Valuer) error { - var result C.bool - switch x := key.(type) { - case nil: - result = C.grnxx_table_insert_row_at( - table.handle, C.int64_t(rowID), nil) - case Bool: - result = C.grnxx_table_insert_row_at( - table.handle, C.int64_t(rowID), unsafe.Pointer(&x)) - case Int: - result = C.grnxx_table_insert_row_at( - table.handle, C.int64_t(rowID), unsafe.Pointer(&x)) - case Float: - result = C.grnxx_table_insert_row_at( - table.handle, C.int64_t(rowID), unsafe.Pointer(&x)) - case GeoPoint: - result = C.grnxx_table_insert_row_at( - table.handle, C.int64_t(rowID), unsafe.Pointer(&x)) - case Text: - text := x.Convert() - result = C.grnxx_table_insert_row_at( - table.handle, C.int64_t(rowID), unsafe.Pointer(&text)) - default: - return fmt.Errorf("unsupported data type") - } - if !result { - return fmt.Errorf("grnxx_table_insert_row_at() failed") - } - return nil -} - -func (table *Table) FindOrInsertRow(key Valuer) (Int, bool, error) { - var inserted C.bool - var internalRowID C.int64_t - switch x := key.(type) { - case nil: - internalRowID = C.grnxx_table_find_or_insert_row( - table.handle, nil, &inserted) - case Bool: - internalRowID = C.grnxx_table_find_or_insert_row( - table.handle, unsafe.Pointer(&x), &inserted) - case Int: - internalRowID = C.grnxx_table_find_or_insert_row( - table.handle, unsafe.Pointer(&x), &inserted) - case Float: - internalRowID = C.grnxx_table_find_or_insert_row( - table.handle, unsafe.Pointer(&x), &inserted) - case GeoPoint: - internalRowID = C.grnxx_table_find_or_insert_row( - table.handle, unsafe.Pointer(&x), &inserted) - case Text: - text := x.Convert() - internalRowID = C.grnxx_table_find_or_insert_row( - table.handle, unsafe.Pointer(&text), &inserted) - default: - return NAInt(), false, fmt.Errorf("unsupported data type") - } - rowID := Int(internalRowID) - if rowID.IsNA() { - return rowID, false, fmt.Errorf("grnxx_table_find_or_insert_row() failed") - } - return rowID, bool(inserted), nil -} - -func (table *Table) RemoveRow(rowID Int) error { - if !C.grnxx_table_remove_row(table.handle, C.int64_t(rowID)) { - return fmt.Errorf("grnxx_table_remove_row() failed") - } - return nil -} - -func (table *Table) TestRow(rowID Int) bool { - return bool(C.grnxx_table_test_row(table.handle, C.int64_t(rowID))) -} - -func (table *Table) FindRow(key Valuer) Int { - switch x := key.(type) { - case Bool: - return Int(C.grnxx_table_find_row(table.handle, unsafe.Pointer(&x))) - case Int: - return Int(C.grnxx_table_find_row(table.handle, unsafe.Pointer(&x))) - case Float: - return Int(C.grnxx_table_find_row(table.handle, unsafe.Pointer(&x))) - case GeoPoint: - return Int(C.grnxx_table_find_row(table.handle, unsafe.Pointer(&x))) - case Text: - text := x.Convert() - return Int(C.grnxx_table_find_row(table.handle, unsafe.Pointer(&text))) - } - return NAInt() -} - -func (table *Table) CreateCursor(options *CursorOptions) (*Cursor, error) { - cursor := C.grnxx_table_create_cursor( - table.handle, convertCursorOptions(options)) - if cursor == nil { - return nil, fmt.Errorf("grnxx_table_create_cursor() failed") - } - return &Cursor{cursor}, nil -} - -// -- Column -- - -type ColumnOptions struct { - ReferenceTableName string -} - -type Column struct { - handle *C.grnxx_column -} - -func (column *Column) Table() *Table { - return &Table{C.grnxx_column_table(column.handle)} -} - -func (column *Column) Name() string { - var size C.size_t - name := C.grnxx_column_name(column.handle, &size) - return C.GoStringN(name, C.int(size)) -} - -func (column *Column) DataType() DataType { - return DataType(C.grnxx_column_data_type(column.handle)) -} - -func (column *Column) ReferenceTable() *Table { - referenceTable := C.grnxx_column_reference_table(column.handle) - if referenceTable == nil { - return nil - } - return &Table{referenceTable} -} - -func (column *Column) IsKey() bool { - return bool(C.grnxx_column_is_key(column.handle)) -} - -func (column *Column) NumIndexes() int { - return int(C.grnxx_column_num_indexes(column.handle)) -} - -func (column *Column) CreateIndex(name string, indexType IndexType) (*Index, error) { - nameCString := C.CString(name) - index := C.grnxx_column_create_index(column.handle, nameCString, - C.grnxx_index_type(indexType)) - defer C.free(unsafe.Pointer(nameCString)) - if index == nil { - return nil, fmt.Errorf("grnxx_column_create_index() failed") - } - return &Index{index}, nil -} - -func (column *Column) RemoveIndex(name string) error { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - if !C.grnxx_column_remove_index(column.handle, nameCString) { - return fmt.Errorf("grnxx_column_remove_index() failed") - } - return nil -} - -func (column *Column) RenameIndex(name string, newName string) error { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - newNameCString := C.CString(newName) - defer C.free(unsafe.Pointer(newNameCString)) - if !C.grnxx_column_rename_index(column.handle, nameCString, newNameCString) { - return fmt.Errorf("grnxx_column_rename_index() failed") - } - return nil -} - -func (column *Column) ReorderIndex(name string, prevName string) error { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - prevNameCString := C.CString(prevName) - defer C.free(unsafe.Pointer(prevNameCString)) - if !C.grnxx_column_reorder_index(column.handle, nameCString, prevNameCString) { - return fmt.Errorf("grnxx_column_reorder_index() failed") - } - return nil -} - -func (column *Column) GetIndex(indexID int) *Index { - return &Index{C.grnxx_column_get_index(column.handle, C.size_t(indexID))} -} - -func (column *Column) FindIndex(name string) *Index { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - index := C.grnxx_column_find_index(column.handle, nameCString) - if index == nil { - return nil - } - return &Index{index} -} - -func (column *Column) Set(rowID Int, value Valuer) error { - switch x := value.(type) { - case nil: - if !C.grnxx_column_set(column.handle, C.int64_t(rowID), nil) { - return fmt.Errorf("grnxx_column_set() failed") - } - case Bool: - if !C.grnxx_column_set(column.handle, C.int64_t(rowID), unsafe.Pointer(&x)) { - return fmt.Errorf("grnxx_column_set() failed") - } - case Int: - if !C.grnxx_column_set(column.handle, C.int64_t(rowID), unsafe.Pointer(&x)) { - return fmt.Errorf("grnxx_column_set() failed") - } - case Float: - if !C.grnxx_column_set(column.handle, C.int64_t(rowID), unsafe.Pointer(&x)) { - return fmt.Errorf("grnxx_column_set() failed") - } - case GeoPoint: - if !C.grnxx_column_set(column.handle, C.int64_t(rowID), unsafe.Pointer(&x)) { - return fmt.Errorf("grnxx_column_set() failed") - } - case Text: - text := x.Convert() - if !C.grnxx_column_set(column.handle, C.int64_t(rowID), unsafe.Pointer(&text)) { - return fmt.Errorf("grnxx_column_set() failed") - } - default: - return fmt.Errorf("undefined type") - } - return nil -} - -func (column *Column) Get(rowID Int, value interface{}) error { - switch p := value.(type) { - case *Bool: - if !C.grnxx_column_get(column.handle, C.int64_t(rowID), unsafe.Pointer(p)) { - return fmt.Errorf("grnxx_column_get() failed") - } - case *Int: - if !C.grnxx_column_get(column.handle, C.int64_t(rowID), unsafe.Pointer(p)) { - return fmt.Errorf("grnxx_column_get() failed") - } - case *Float: - if !C.grnxx_column_get(column.handle, C.int64_t(rowID), unsafe.Pointer(p)) { - return fmt.Errorf("grnxx_column_get() failed") - } - case *GeoPoint: - if !C.grnxx_column_get(column.handle, C.int64_t(rowID), unsafe.Pointer(p)) { - return fmt.Errorf("grnxx_column_get() failed") - } - case *Text: - var text C.grnxx_text - if !C.grnxx_column_get(column.handle, C.int64_t(rowID), unsafe.Pointer(&text)) { - return fmt.Errorf("grnxx_column_get() failed") - } - if Int(text.size).IsNA() { - *p = nil - } else { - *p = C.GoBytes(unsafe.Pointer(text.data), C.int(text.size)) - } - default: - return fmt.Errorf("undefined type") - } - return nil -} - -func (column *Column) Contains(value Valuer) bool { - switch x := value.(type) { - case nil: - return bool(C.grnxx_column_contains(column.handle, nil)) - case Bool: - return bool(C.grnxx_column_contains(column.handle, unsafe.Pointer(&x))) - case Int: - return bool(C.grnxx_column_contains(column.handle, unsafe.Pointer(&x))) - case Float: - return bool(C.grnxx_column_contains(column.handle, unsafe.Pointer(&x))) - case GeoPoint: - return bool(C.grnxx_column_contains(column.handle, unsafe.Pointer(&x))) - case Text: - text := x.Convert() - return bool(C.grnxx_column_contains(column.handle, unsafe.Pointer(&text))) - } - return false -} - -func (column *Column) FindOne(value Valuer) Int { - switch x := value.(type) { - case nil: - return Int(C.grnxx_column_find_one(column.handle, nil)) - case Bool: - return Int(C.grnxx_column_find_one(column.handle, unsafe.Pointer(&x))) - case Int: - return Int(C.grnxx_column_find_one(column.handle, unsafe.Pointer(&x))) - case Float: - return Int(C.grnxx_column_find_one(column.handle, unsafe.Pointer(&x))) - case GeoPoint: - return Int(C.grnxx_column_find_one(column.handle, unsafe.Pointer(&x))) - case Text: - text := x.Convert() - return Int(C.grnxx_column_find_one(column.handle, unsafe.Pointer(&text))) - } - return NAInt() -} - -// -- Index -- - -type Index struct { - handle *C.grnxx_index -} - -func (index *Index) Column() *Column { - return &Column{C.grnxx_index_column(index.handle)} -} - -func (index *Index) Name() string { - var size C.size_t - name := C.grnxx_index_name(index.handle, &size) - return C.GoStringN(name, C.int(size)) -} - -func (index *Index) IndexType() IndexType { - return IndexType(C.grnxx_index_index_type(index.handle)) -} - -func (index *Index) NumEntries() int { - return int(C.grnxx_index_num_entries(index.handle)) -} - -func (index *Index) TestUniqueness() bool { - return bool(C.grnxx_index_test_uniqueness(index.handle)) -} - -func (index *Index) Contains(value Valuer) bool { - switch x := value.(type) { - case nil: - return bool(C.grnxx_index_contains(index.handle, nil)) - case Bool: - return bool(C.grnxx_index_contains(index.handle, unsafe.Pointer(&x))) - case Int: - return bool(C.grnxx_index_contains(index.handle, unsafe.Pointer(&x))) - case Float: - return bool(C.grnxx_index_contains(index.handle, unsafe.Pointer(&x))) - case GeoPoint: - return bool(C.grnxx_index_contains(index.handle, unsafe.Pointer(&x))) - case Text: - text := x.Convert() - return bool(C.grnxx_index_contains(index.handle, unsafe.Pointer(&text))) - } - return false -} - -func (index *Index) FindOne(value Valuer) Int { - switch x := value.(type) { - case nil: - return Int(C.grnxx_index_find_one(index.handle, nil)) - case Bool: - return Int(C.grnxx_index_find_one(index.handle, unsafe.Pointer(&x))) - case Int: - return Int(C.grnxx_index_find_one(index.handle, unsafe.Pointer(&x))) - case Float: - return Int(C.grnxx_index_find_one(index.handle, unsafe.Pointer(&x))) - case GeoPoint: - return Int(C.grnxx_index_find_one(index.handle, unsafe.Pointer(&x))) - case Text: - text := x.Convert() - return Int(C.grnxx_index_find_one(index.handle, unsafe.Pointer(&text))) - } - return NAInt() -} - -func (index *Index) Find(value Valuer, options *CursorOptions) (*Cursor, error) { - cursorOptions := convertCursorOptions(options) - var cursor *C.grnxx_cursor - switch x := value.(type) { - case nil: - cursor = C.grnxx_index_find(index.handle, nil, cursorOptions) - case Bool: - cursor = C.grnxx_index_find(index.handle, unsafe.Pointer(&x), cursorOptions) - case Int: - cursor = C.grnxx_index_find(index.handle, unsafe.Pointer(&x), cursorOptions) - case Float: - cursor = C.grnxx_index_find(index.handle, unsafe.Pointer(&x), cursorOptions) - case GeoPoint: - cursor = C.grnxx_index_find(index.handle, unsafe.Pointer(&x), cursorOptions) - case Text: - text := x.Convert() - cursor = C.grnxx_index_find(index.handle, unsafe.Pointer(&text), cursorOptions) - } - if cursor == nil { - return nil, fmt.Errorf("grnxx_index_find() failed") - } - return &Cursor{cursor}, nil -} - -func (index *Index) FindInRange( - lowerBound Valuer, lowerBoundInclusive bool, - upperBound Valuer, upperBoundInclusive bool, - options *CursorOptions) (*Cursor, error) { - cursorOptions := convertCursorOptions(options) - var lowerBoundPointer unsafe.Pointer - switch x := lowerBound.(type) { - case nil: - lowerBoundPointer = nil - case Bool: - lowerBoundPointer = unsafe.Pointer(&x) - case Int: - lowerBoundPointer = unsafe.Pointer(&x) - case Float: - lowerBoundPointer = unsafe.Pointer(&x) - case GeoPoint: - lowerBoundPointer = unsafe.Pointer(&x) - case Text: - text := x.Convert() - lowerBoundPointer = unsafe.Pointer(&text) - } - var upperBoundPointer unsafe.Pointer - switch x := upperBound.(type) { - case nil: - upperBoundPointer = nil - case Bool: - upperBoundPointer = unsafe.Pointer(&x) - case Int: - upperBoundPointer = unsafe.Pointer(&x) - case Float: - upperBoundPointer = unsafe.Pointer(&x) - case GeoPoint: - upperBoundPointer = unsafe.Pointer(&x) - case Text: - text := x.Convert() - upperBoundPointer = unsafe.Pointer(&text) - } - cursor := C.grnxx_index_find_in_range( - index.handle, lowerBoundPointer, C.bool(lowerBoundInclusive), - upperBoundPointer, C.bool(upperBoundInclusive), cursorOptions) - if cursor == nil { - return nil, fmt.Errorf("grnxx_index_find_in_range() failed") - } - return &Cursor{cursor}, nil -} - -func (index *Index) FindStartsWith( - value Valuer, inclusive bool, options *CursorOptions) (*Cursor, error) { - cursorOptions := convertCursorOptions(options) - var cursor *C.grnxx_cursor - switch x := value.(type) { - case nil: - cursor = C.grnxx_index_find_starts_with( - index.handle, nil, C.bool(inclusive), cursorOptions) - case Bool: - cursor = C.grnxx_index_find_starts_with( - index.handle, unsafe.Pointer(&x), C.bool(inclusive), cursorOptions) - case Int: - cursor = C.grnxx_index_find_starts_with( - index.handle, unsafe.Pointer(&x), C.bool(inclusive), cursorOptions) - case Float: - cursor = C.grnxx_index_find_starts_with( - index.handle, unsafe.Pointer(&x), C.bool(inclusive), cursorOptions) - case GeoPoint: - cursor = C.grnxx_index_find_starts_with( - index.handle, unsafe.Pointer(&x), C.bool(inclusive), cursorOptions) - case Text: - text := x.Convert() - cursor = C.grnxx_index_find_starts_with( - index.handle, unsafe.Pointer(&text), C.bool(inclusive), cursorOptions) - } - if cursor == nil { - return nil, fmt.Errorf("grnxx_index_find_starts_with() failed") - } - return &Cursor{cursor}, nil -} - -func (index *Index) FindPrefixes( - value Valuer, options *CursorOptions) (*Cursor, error) { - cursorOptions := convertCursorOptions(options) - var cursor *C.grnxx_cursor - switch x := value.(type) { - case nil: - cursor = C.grnxx_index_find_prefixes( - index.handle, nil, cursorOptions) - case Bool: - cursor = C.grnxx_index_find_prefixes( - index.handle, unsafe.Pointer(&x), cursorOptions) - case Int: - cursor = C.grnxx_index_find_prefixes( - index.handle, unsafe.Pointer(&x), cursorOptions) - case Float: - cursor = C.grnxx_index_find_prefixes( - index.handle, unsafe.Pointer(&x), cursorOptions) - case GeoPoint: - cursor = C.grnxx_index_find_prefixes( - index.handle, unsafe.Pointer(&x), cursorOptions) - case Text: - text := x.Convert() - cursor = C.grnxx_index_find_prefixes( - index.handle, unsafe.Pointer(&text), cursorOptions) - } - if cursor == nil { - return nil, fmt.Errorf("grnxx_index_find_prefixes() failed") - } - return &Cursor{cursor}, nil -} - -// -- Cursor -- - -// TODO: CursorOptions should be generated with NewCursorOptions(). -type CursorOptions struct { - Offset int - Limit int - OrderType OrderType -} - -func convertCursorOptions(options *CursorOptions) *C.grnxx_cursor_options { - var cursorOptions C.grnxx_cursor_options - if options == nil { - cursorOptions.offset = 0 - cursorOptions.limit = math.MaxInt32 - cursorOptions.order_type = C.GRNXX_REGULAR_ORDER - } else { - cursorOptions.offset = C.size_t(options.Offset) - cursorOptions.limit = C.size_t(options.Limit) - cursorOptions.order_type = C.grnxx_order_type(options.OrderType) - } - return &cursorOptions -} - -type Cursor struct { - handle *C.grnxx_cursor -} - -func (cursor *Cursor) Close() error { - C.grnxx_cursor_close(cursor.handle) - return nil -} - -func (cursor *Cursor) Read(records []Record) int { - if len(records) == 0 { - return 0 - } - return int(C.grnxx_cursor_read(cursor.handle, - (*C.grnxx_record)(unsafe.Pointer(&records[0])), C.size_t(len(records)))) -} - -// -- Expression -- - -type Expression struct { - handle *C.grnxx_expression -} - -func ParseExpression(table *Table, query string) (*Expression, error) { - queryCString := C.CString(query) - defer C.free(unsafe.Pointer(queryCString)) - expression := C.grnxx_expression_parse(table.handle, queryCString) - if expression == nil { - return nil, fmt.Errorf("grnxx_expression_parse() failed") - } - return &Expression{expression}, nil -} - -func (this *Expression) Close() { - C.grnxx_expression_close(this.handle) -} - -func (this *Expression) Table() *Table { - return &Table{C.grnxx_expression_table(this.handle)} -} - -func (this *Expression) DataType() DataType { - return DataType(C.grnxx_expression_data_type(this.handle)) -} - -func (this *Expression) IsRowID() bool { - return bool(C.grnxx_expression_is_row_id(this.handle)) -} - -func (this *Expression) IsScore() bool { - return bool(C.grnxx_expression_is_score(this.handle)) -} - -func (this *Expression) BlockSize() int { - return int(C.grnxx_expression_block_size(this.handle)) -} - -func (this *Expression) Filter(records *[]Record) error { - if len(*records) == 0 { - return nil - } - internalRecords := (*C.grnxx_record)(unsafe.Pointer(&(*records)[0])) - size := C.size_t(len(*records)) - if !C.grnxx_expression_filter(this.handle, internalRecords, - &size, C.size_t(0), C.size_t(math.MaxInt32)) { - return fmt.Errorf("grnxx_expression_filter() failed") - } - *records = (*records)[:int(size)] - return nil -} - -func (this *Expression) FilterEx( - records *[]Record, offset int, limit int) error { - if len(*records) == 0 { - return nil - } - internalRecords := (*C.grnxx_record)(unsafe.Pointer(&(*records)[0])) - size := C.size_t(len(*records)) - if !C.grnxx_expression_filter(this.handle, internalRecords, - &size, C.size_t(offset), C.size_t(limit)) { - return fmt.Errorf("grnxx_expression_filter() failed") - } - *records = (*records)[:int(size)] - return nil -} - -func (this *Expression) Adjust(records []Record) error { - if len(records) == 0 { - return nil - } - internalRecords := (*C.grnxx_record)(unsafe.Pointer(&records[0])) - size := C.size_t(len(records)) - if !C.grnxx_expression_adjust(this.handle, internalRecords, size) { - return fmt.Errorf("grnxx_expression_adjust() failed") - } - return nil -} - -func (this *Expression) Evaluate(records []Record, values interface{}) error { - if len(records) == 0 { - return nil - } - internalRecords := (*C.grnxx_record)(unsafe.Pointer(&records[0])) - size := C.size_t(len(records)) - var result C.bool - switch x := values.(type) { - case []Bool: - result = C.grnxx_expression_evaluate( - this.handle, internalRecords, size, unsafe.Pointer(&x[0])) - case []Int: - result = C.grnxx_expression_evaluate( - this.handle, internalRecords, size, unsafe.Pointer(&x[0])) - case []Float: - result = C.grnxx_expression_evaluate( - this.handle, internalRecords, size, unsafe.Pointer(&x[0])) - case []GeoPoint: - result = C.grnxx_expression_evaluate( - this.handle, internalRecords, size, unsafe.Pointer(&x[0])) - case []Text: - internalValues := make([]C.grnxx_text, len(records)) - result = C.grnxx_expression_evaluate( - this.handle, internalRecords, size, unsafe.Pointer(&internalValues[0])) - for i := 0; i < len(records); i++ { - // TODO: Deep-copy should not be done? - x[i] = C.GoBytes(unsafe.Pointer(internalValues[i].data), - C.int(internalValues[i].size)) - } - default: - return fmt.Errorf("unsupported data type") - } - if !result { - return fmt.Errorf("grnxx_expression_evaluate() failed") - } - return nil -} - -// -- ExpressionBuilder -- - -type ExpressionBuilder struct { - handle *C.grnxx_expression_builder -} - -func CreateExpressionBuilder(table *Table) (*ExpressionBuilder, error) { - builder := C.grnxx_expression_builder_create(table.handle) - if builder == nil { - return nil, fmt.Errorf("grnxx_expression_builder_create() failed") - } - return &ExpressionBuilder{builder}, nil -} - -func (this *ExpressionBuilder) Close() { - C.grnxx_expression_builder_close(this.handle) -} - -func (this *ExpressionBuilder) Table() *Table { - return &Table{C.grnxx_expression_builder_table(this.handle)} -} - -func (this *ExpressionBuilder) PushConstant(value Valuer) error { - var result C.bool - switch x := value.(type) { - case Bool: - result = C.grnxx_expression_builder_push_constant( - this.handle, C.GRNXX_BOOL, unsafe.Pointer(&x)) - case Int: - result = C.grnxx_expression_builder_push_constant( - this.handle, C.GRNXX_INT, unsafe.Pointer(&x)) - case Float: - result = C.grnxx_expression_builder_push_constant( - this.handle, C.GRNXX_FLOAT, unsafe.Pointer(&x)) - case GeoPoint: - result = C.grnxx_expression_builder_push_constant( - this.handle, C.GRNXX_GEO_POINT, unsafe.Pointer(&x)) - case Text: - text := x.Convert() - result = C.grnxx_expression_builder_push_constant( - this.handle, C.GRNXX_TEXT, unsafe.Pointer(&text)) - default: - return fmt.Errorf("unsupported data type") - } - if !result { - return fmt.Errorf("grnxx_expression_builder_push_constant() failed") - } - return nil -} - -func (this *ExpressionBuilder) PushRowID() error { - if !C.grnxx_expression_builder_push_row_id(this.handle) { - fmt.Errorf("grnxx_expression_builder_push_row_id() failed") - } - return nil -} - -func (this *ExpressionBuilder) PushScore() error { - if !C.grnxx_expression_builder_push_score(this.handle) { - fmt.Errorf("grnxx_expression_builder_push_score() failed") - } - return nil -} - -func (this *ExpressionBuilder) PushColumn(name string) error { - nameCString := C.CString(name) - defer C.free(unsafe.Pointer(nameCString)) - if !C.grnxx_expression_builder_push_column(this.handle, nameCString) { - fmt.Errorf("grnxx_expression_builder_push_column() failed") - } - return nil -} - -func (this *ExpressionBuilder) PushOperator(operatorType OperatorType) error { - if !C.grnxx_expression_builder_push_operator( - this.handle, C.grnxx_operator_type(operatorType)) { - fmt.Errorf("grnxx_expression_builder_push_operator() failed") - } - return nil -} - -func (this *ExpressionBuilder) BeginSubexpression() error { - if !C.grnxx_expression_builder_begin_subexpression(this.handle) { - return fmt.Errorf("grnxx_expression_builder_begin_subexpression() failed") - } - return nil -} - -func (this *ExpressionBuilder) EndSubexpression() error { - if !C.grnxx_expression_builder_end_subexpression(this.handle) { - return fmt.Errorf("grnxx_expression_builder_end_subexpression() failed") - } - return nil -} - -func (this *ExpressionBuilder) Clear() { - C.grnxx_expression_builder_clear(this.handle) -} - -func (this *ExpressionBuilder) Release() (*Expression, error) { - expression := C.grnxx_expression_builder_release(this.handle) - if expression == nil { - return nil, fmt.Errorf("grnxx_expression_builder_release() failed") - } - return &Expression{expression}, nil -} - -// -- Sorter -- - -type SorterOrder struct { - Expression *Expression - OrderType OrderType -} - -func convertSorterOrders(orders []SorterOrder) []C.grnxx_sorter_order { - internalOrders := make([]C.grnxx_sorter_order, len(orders)) - for i := 0; i < len(orders); i++ { - internalOrders[i].expression = orders[i].Expression.handle - internalOrders[i].order_type = C.grnxx_order_type(orders[i].OrderType) - } - return internalOrders -} - -type SorterOptions struct { - Offset int - Limit int -} - -func convertSorterOptions(options *SorterOptions) *C.grnxx_sorter_options { - if options == nil { - return nil - } - var internalOptions C.grnxx_sorter_options - internalOptions.offset = C.size_t(options.Offset) - internalOptions.limit = C.size_t(options.Limit) - return &internalOptions -} - -type Sorter struct { - handle *C.grnxx_sorter -} - -func CreateSorter(orders []SorterOrder, options *SorterOptions) (*Sorter, error) { - if len(orders) == 0 { - return nil, fmt.Errorf("no orders") - } - internalOrders := convertSorterOrders(orders) - sorter := C.grnxx_sorter_create( - &internalOrders[0], C.size_t(len(orders)), convertSorterOptions(options)) - if sorter == nil { - return nil, fmt.Errorf("grnxx_sorter_create() failed") - } - return &Sorter{sorter}, nil -} - -func (this *Sorter) Close() error { - C.grnxx_sorter_close(this.handle) - return nil -} - -// -- Merger -- - -type MergerOptions struct { - LogicalOperatorType MergerOperatorType - ScoreOperatorType MergerOperatorType - MissingScore Float - Offset int - Limit int -} - -func convertMergerOptions(options *MergerOptions) *C.grnxx_merger_options { - if options == nil { - return nil - } - var internalOptions C.grnxx_merger_options - internalOptions.logical_operator_type = - C.grnxx_merger_operator_type(options.LogicalOperatorType) - internalOptions.score_operator_type = - C.grnxx_merger_operator_type(options.ScoreOperatorType) - internalOptions.missing_score = C.double(options.MissingScore) - internalOptions.offset = C.size_t(options.Offset) - internalOptions.limit = C.size_t(options.Limit) - return &internalOptions -} - -type Merger struct { - handle *C.grnxx_merger -} - -func CreateMerger(options *MergerOptions) (*Merger, error) { - merger := C.grnxx_merger_create(convertMergerOptions(options)) - if merger == nil { - return nil, fmt.Errorf("grnxx_merger_create() failed") - } - return &Merger{merger}, nil -} - -func (this *Merger) Close() error { - C.grnxx_merger_close(this.handle) - return nil -} - -// -- Pipeline -- - -type Pipeline struct { - handle *C.grnxx_pipeline -} - -func (this *Pipeline) Close() error { - C.grnxx_pipeline_close(this.handle) - return nil -} - -func (this *Pipeline) Table() *Table { - return &Table{C.grnxx_pipeline_table(this.handle)} -} - -func (this *Pipeline) Flush() ([]Record, error) { - var ptr *C.grnxx_record - var size C.size_t - if !C.grnxx_pipeline_flush(this.handle, &ptr, &size) { - return nil, fmt.Errorf("grnxx_pipeline_flush() failed") - } - defer C.free(unsafe.Pointer(ptr)) - header := reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(ptr)), - Len: int(size), - Cap: int(size), - } - internalRecords := *(*[]C.grnxx_record)(unsafe.Pointer(&header)) - records := make([]Record, int(size)) - for i := 0; i < len(records); i++ { - records[i].RowID = Int(internalRecords[i].row_id) - records[i].Score = Float(internalRecords[i].score) - } - return records, nil -} - -// -- PipelineBuilder -- - -type PipelineOptions struct { -} - -func convertPipelineOptions(options *PipelineOptions) *C.grnxx_pipeline_options { - return nil -} - -type PipelineBuilder struct { - handle *C.grnxx_pipeline_builder -} - -func CreatePipelineBuilder(table *Table) (*PipelineBuilder, error) { - builder := C.grnxx_pipeline_builder_create(table.handle) - if builder == nil { - return nil, fmt.Errorf("grnxx_pipeline_builder_create() failed") - } - return &PipelineBuilder{builder}, nil -} - -func (this *PipelineBuilder) Close() error { - C.grnxx_pipeline_builder_close(this.handle) - return nil -} - -func (this *PipelineBuilder) Table() *Table { - return &Table{C.grnxx_pipeline_builder_table(this.handle)} -} - -func (this *PipelineBuilder) PushCursor(cursor *Cursor) error { - if !C.grnxx_pipeline_builder_push_cursor(this.handle, cursor.handle) { - return fmt.Errorf("grnxx_pipeline_builder_push_cursor() failed") - } - return nil -} - -func (this *PipelineBuilder) PushFilter( - expression *Expression, offset int, limit int) error { - if !C.grnxx_pipeline_builder_push_filter( - this.handle, expression.handle, C.size_t(offset), C.size_t(limit)) { - return fmt.Errorf("grnxx_pipeline_builder_push_filter() failed") - } - return nil -} - -func (this *PipelineBuilder) PushAdjuster(expression *Expression) error { - if !C.grnxx_pipeline_builder_push_adjuster(this.handle, expression.handle) { - return fmt.Errorf("grnxx_pipeline_builder_push_adjuster() failed") - } - return nil -} - -func (this *PipelineBuilder) PushSorter(sorter *Sorter) error { - if !C.grnxx_pipeline_builder_push_sorter(this.handle, sorter.handle) { - return fmt.Errorf("grnxx_pipeline_builder_push_sorter() failed") - } - return nil -} - -func (this *PipelineBuilder) PushMerger(options *MergerOptions) error { - internalOptions := convertMergerOptions(options) - if !C.grnxx_pipeline_builder_push_merger(this.handle, internalOptions) { - return fmt.Errorf("grnxx_pipeline_builder_push_merger() failed") - } - return nil -} - -func (this *PipelineBuilder) Clear() error { - C.grnxx_pipeline_builder_clear(this.handle) - return nil -} - -func (this *PipelineBuilder) Release(options *PipelineOptions) (*Pipeline, error) { - internalOptions := convertPipelineOptions(options) - pipeline := C.grnxx_pipeline_builder_release(this.handle, internalOptions) - if pipeline == nil { - return nil, fmt.Errorf("grnxx_pipeline_builder_release() failed") - } - return &Pipeline{pipeline}, nil -} Deleted: go/gnx/grnxx/grnxx.h (+0 -327) 100644 =================================================================== --- go/gnx/grnxx/grnxx.h 2015-05-26 11:06:34 +0900 (1ee051a) +++ /dev/null @@ -1,327 +0,0 @@ -#ifndef GRNXX_H -#define GRNXX_H - -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -#include <grnxx/constants.h> - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -const char *grnxx_package(void); -const char *grnxx_version(void); - -typedef struct grnxx_db grnxx_db; -typedef struct grnxx_table grnxx_table; -typedef struct grnxx_column grnxx_column; -typedef struct grnxx_index grnxx_index; -typedef struct grnxx_cursor grnxx_cursor; -typedef struct grnxx_expression grnxx_expression; -typedef struct grnxx_expression_builder grnxx_expression_builder; -typedef struct grnxx_sorter grnxx_sorter; -typedef struct grnxx_merger grnxx_merger; -typedef struct grnxx_pipeline grnxx_pipeline; -typedef struct grnxx_pipeline_builder grnxx_pipeline_builder; - -typedef uint8_t grnxx_bool; - -enum { - GRNXX_BOOL_NA = 1, - GRNXX_BOOL_TRUE = 3, - GRNXX_BOOL_FALSE = 0 -}; - -typedef struct { - int32_t latitude; - int32_t longitude; -} grnxx_geo_point; - -typedef struct { - const char *data; - int64_t size; -} grnxx_text; - -typedef struct { - int64_t row_id; - double score; -} grnxx_record; - -typedef struct { - const char *reference_table_name; -} grnxx_column_options; - -// TODO: Settings should be done by using functions? -typedef struct { - size_t offset; - size_t limit; - grnxx_order_type order_type; -} grnxx_cursor_options; - -typedef struct { - grnxx_expression *expression; - grnxx_order_type order_type; -} grnxx_sorter_order; - -// TODO: Settings should be done by using functions? -typedef struct { - size_t offset; - size_t limit; -} grnxx_sorter_options; - -// TODO: Settings should be done by using functions? -typedef struct { - grnxx_merger_operator_type logical_operator_type; - grnxx_merger_operator_type score_operator_type; - double missing_score; - size_t offset; - size_t limit; -} grnxx_merger_options; - -typedef struct { -} grnxx_pipeline_options; - -// -- DB -- - -grnxx_db *grnxx_db_create(void); -void grnxx_db_close(grnxx_db *db); - -size_t grnxx_db_num_tables(grnxx_db *db); - -grnxx_table *grnxx_db_create_table(grnxx_db *db, const char *name); -bool grnxx_db_remove_table(grnxx_db *db, const char *name); -bool grnxx_db_rename_table(grnxx_db *db, - const char *name, - const char *new_name); -bool grnxx_db_reorder_table(grnxx_db *db, - const char *name, - const char *prev_name); -grnxx_table *grnxx_db_get_table(grnxx_db *db, size_t table_id); -grnxx_table *grnxx_db_find_table(grnxx_db *db, const char *name); - -// -- Table -- - -grnxx_db *grnxx_table_db(grnxx_table *table); -const char *grnxx_table_name(grnxx_table *table, size_t *size); -size_t grnxx_table_num_columns(grnxx_table *table); -grnxx_column *grnxx_table_key_column(grnxx_table *table); -size_t grnxx_table_num_rows(grnxx_table *table); -int64_t grnxx_table_max_row_id(grnxx_table *table); -bool grnxx_table_is_empty(grnxx_table *table); -bool grnxx_table_is_full(grnxx_table *table); - -// TODO: Support references. -grnxx_column *grnxx_table_create_column(grnxx_table *table, - const char *name, - grnxx_data_type data_type, - const grnxx_column_options *options); -bool grnxx_table_remove_column(grnxx_table *table, const char *name); -bool grnxx_table_rename_column(grnxx_table *table, - const char *name, - const char *new_name); -bool grnxx_table_reorder_column(grnxx_table *table, - const char *name, - const char *prev_name); -grnxx_column *grnxx_table_get_column(grnxx_table *table, size_t column_id); -grnxx_column *grnxx_table_find_column(grnxx_table *table, const char *name); - -bool grnxx_table_set_key_column(grnxx_table *table, const char *name); -bool grnxx_table_unset_key_column(grnxx_table *table); - -int64_t grnxx_table_insert_row(grnxx_table *table, const void *key); -size_t grnxx_table_insert_rows(grnxx_table *table, - size_t num_keys, - const void *keys, - int64_t *row_ids); -bool grnxx_table_insert_row_at(grnxx_table *table, - int64_t row_id, - const void *key); -int64_t grnxx_table_find_or_insert_row(grnxx_table *table, - const void *key, - bool *inserted); -bool grnxx_table_remove_row(grnxx_table *table, int64_t row_id); -bool grnxx_table_test_row(grnxx_table *table, int64_t row_id); -int64_t grnxx_table_find_row(grnxx_table *table, const void *key); - -grnxx_cursor *grnxx_table_create_cursor(grnxx_table *table, - const grnxx_cursor_options *options); - -// -- Column -- - -grnxx_table *grnxx_column_table(grnxx_column *column); -const char *grnxx_column_name(grnxx_column *column, size_t *size); -grnxx_data_type grnxx_column_data_type(grnxx_column *column); -grnxx_table *grnxx_column_reference_table(grnxx_column *column); -bool grnxx_column_is_key(grnxx_column *column); -size_t grnxx_column_num_indexes(grnxx_column *column); - -grnxx_index *grnxx_column_create_index(grnxx_column *column, - const char *name, - grnxx_index_type index_type); -bool grnxx_column_remove_index(grnxx_column *column, const char *name); -bool grnxx_column_rename_index(grnxx_column *column, - const char *name, - const char *new_name); -bool grnxx_column_reorder_index(grnxx_column *column, - const char *name, - const char *prev_name); -grnxx_index *grnxx_column_get_index(grnxx_column *column, size_t index_id); -grnxx_index *grnxx_column_find_index(grnxx_column *column, const char *name); - -bool grnxx_column_set(grnxx_column *column, int64_t row_id, const void *value); -bool grnxx_column_get(grnxx_column *column, int64_t row_id, void *value); - -bool grnxx_column_contains(grnxx_column *column, const void *value); -int64_t grnxx_column_find_one(grnxx_column *column, const void *value); - -// -- Index -- - -grnxx_column *grnxx_index_column(grnxx_index *index); -const char *grnxx_index_name(grnxx_index *index, size_t *size); -grnxx_index_type grnxx_index_index_type(grnxx_index *index); -size_t grnxx_index_num_entries(grnxx_index *index); - -bool grnxx_index_test_uniqueness(grnxx_index *index); - -bool grnxx_index_contains(grnxx_index *index, const void *value); -int64_t grnxx_index_find_one(grnxx_index *index, const void *value); - -grnxx_cursor *grnxx_index_find(grnxx_index *index, - const void *value, - const grnxx_cursor_options *options); -grnxx_cursor *grnxx_index_find_in_range(grnxx_index *index, - const void *lower_bound_value, - bool lower_bound_is_inclusive, - const void *upper_bound_value, - bool upper_bound_is_inclusive, - const grnxx_cursor_options *options); -grnxx_cursor *grnxx_index_find_starts_with(grnxx_index *index, - const void *prefix, - bool prefix_is_inclusive, - const grnxx_cursor_options *options); -grnxx_cursor *grnxx_index_find_prefixes(grnxx_index *index, - const void *value, - const grnxx_cursor_options *options); - -// -- Cursor -- - -void grnxx_cursor_close(grnxx_cursor *cursor); - -size_t grnxx_cursor_read(grnxx_cursor *cursor, - grnxx_record *records, - size_t size); - -// -- Expression -- - -grnxx_expression *grnxx_expression_parse(grnxx_table *table, - const char *query); -void grnxx_expression_close(grnxx_expression *expression); - -grnxx_table *grnxx_expression_table(grnxx_expression *expression); -grnxx_data_type grnxx_expression_data_type(grnxx_expression *expression); -bool grnxx_expression_is_row_id(grnxx_expression *expression); -bool grnxx_expression_is_score(grnxx_expression *expression); -size_t grnxx_expression_block_size(grnxx_expression *expression); - -bool grnxx_expression_filter(grnxx_expression *expression, - grnxx_record *records, - size_t *size, - size_t offset, - size_t limit); -bool grnxx_expression_adjust(grnxx_expression *expression, - grnxx_record *records, - size_t size); -bool grnxx_expression_evaluate(grnxx_expression *expression, - const grnxx_record *records, - size_t size, - void *values); - -// -- ExpressionBuilder -- - -grnxx_expression_builder *grnxx_expression_builder_create(grnxx_table *table); -void grnxx_expression_builder_close(grnxx_expression_builder *builder); - -grnxx_table *grnxx_expression_builder_table(grnxx_expression_builder *builder); - -bool grnxx_expression_builder_push_constant(grnxx_expression_builder *builder, - grnxx_data_type data_type, - const void *value); -bool grnxx_expression_builder_push_row_id(grnxx_expression_builder *builder); -bool grnxx_expression_builder_push_score(grnxx_expression_builder *builder); -bool grnxx_expression_builder_push_column(grnxx_expression_builder *builder, - const char *column_name); -bool grnxx_expression_builder_push_operator(grnxx_expression_builder *builder, - grnxx_operator_type operator_type); - -bool grnxx_expression_builder_begin_subexpression( - grnxx_expression_builder *builder); -bool grnxx_expression_builder_end_subexpression( - grnxx_expression_builder *builder); - -void grnxx_expression_builder_clear(grnxx_expression_builder *builder); - -grnxx_expression *grnxx_expression_builder_release( - grnxx_expression_builder *builder); - -// -- Sorter -- - -// On success, the ownership of given expressions in "order" is moved to the -// created sorter object. -// On failure, given expressions are closed. -grnxx_sorter *grnxx_sorter_create(grnxx_sorter_order *orders, - size_t num_orders, - const grnxx_sorter_options *options); -void grnxx_sorter_close(grnxx_sorter *sorter); - -// -- Merger -- - -grnxx_merger *grnxx_merger_create(const grnxx_merger_options *options); -void grnxx_merger_close(grnxx_merger *merger); - -// -- Pipeline -- - -void grnxx_pipeline_close(grnxx_pipeline *pipeline); - -grnxx_table *grnxx_pipeline_table(grnxx_pipeline *pipeline); - -// On success, the starting address of records is stored into "*records". -// The caller must free the "*records". -bool grnxx_pipeline_flush(grnxx_pipeline *pipeline, - grnxx_record **records, - size_t *size); - -// -- PipelineBuilder -- - -grnxx_pipeline_builder *grnxx_pipeline_builder_create(grnxx_table *table); -void grnxx_pipeline_builder_close(grnxx_pipeline_builder *builder); - -grnxx_table *grnxx_pipeline_builder_table(grnxx_pipeline_builder *builder); - -// On success, the ownership of given objects is moved to the pipeline. -// On failure, given objects are closed. -bool grnxx_pipeline_builder_push_cursor(grnxx_pipeline_builder *builder, - grnxx_cursor *cursor); -bool grnxx_pipeline_builder_push_filter(grnxx_pipeline_builder *builder, - grnxx_expression *expression, - size_t offset, - size_t limit); -bool grnxx_pipeline_builder_push_adjuster(grnxx_pipeline_builder *builder, - grnxx_expression *expression); -bool grnxx_pipeline_builder_push_sorter(grnxx_pipeline_builder *builder, - grnxx_sorter *sorter); -bool grnxx_pipeline_builder_push_merger(grnxx_pipeline_builder *builder, - const grnxx_merger_options *options); - -void grnxx_pipeline_builder_clear(grnxx_pipeline_builder *builder); - -grnxx_pipeline *grnxx_pipeline_builder_release( - grnxx_pipeline_builder *builder, - const grnxx_pipeline_options *options); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // GRNXX_H Deleted: go/gnx/grnxx/grnxx_test.go (+0 -1845) 100644 =================================================================== --- go/gnx/grnxx/grnxx_test.go 2015-05-26 11:06:34 +0900 (289226f) +++ /dev/null @@ -1,1845 +0,0 @@ -package grnxx - -import "reflect" -import "testing" - -func TestPackage(t *testing.T) { - if Package() != "grnxx" { - t.Fatalf("Package name is wrong") - } -} - -func TestVersion(t *testing.T) { - if Version() == "" { - t.Fatalf("Version is not available") - } -} - -func TestEmptyDB(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - if db == nil { - t.Fatalf("CreateDB() returned nil") - } - numTables := db.NumTables() - if numTables != 0 { - t.Fatalf("Empty DB has tables: numTables = %v", numTables) - } - error = db.Close() - if error != nil { - t.Fatalf("DB.Close() failed: error = %v", error) - } -} - -func TestEmptyTable(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - numTables := db.NumTables() - if numTables != 1 { - t.Fatalf("DB.NumTables() returned a wrong value: numTables = %v", - numTables) - } - if table.DB().handle != db.handle { - t.Fatalf("Table.DB() returned a wrong DB") - } - name := table.Name() - if name != "Table" { - t.Fatalf("Table.Name() returned a wrong name: name = %v", name) - } - numColumns := table.NumColumns() - if numColumns != 0 { - t.Fatalf("Empty table has columns: numColumns = %v", numColumns) - } - keyColumn := table.KeyColumn() - if keyColumn != nil { - t.Fatalf("Empty column has key column") - } - numRows := table.NumRows() - if numRows != 0 { - t.Fatalf("Empty table has rows: numRows = %v", numRows) - } - maxRowID := table.MaxRowID() - if !maxRowID.IsNA() { - t.Fatalf("Empty table has valid max. row ID: maxRowID = %v", maxRowID) - } - if !table.IsEmpty() { - t.Fatalf("Empty table's IsEmpty() returned false") - } - if !table.IsFull() { - t.Fatalf("Empty table's IsFull() returned false") - } - error = db.RemoveTable("Table") - if error != nil { - t.Fatalf("DB.RemoveTable() failed: error = %v", error) - } -} - -func TestTableRename(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - error = db.RenameTable("Table", "FirstTable") - if error != nil { - t.Fatalf("DB.RenameTable() failed: error = %v", error) - } - name := table.Name() - if name != "FirstTable" { - t.Fatalf("Table name is wrong: name = %v", name) - } - table2, error := db.CreateTable("FirstTable") - if error == nil { - t.Fatalf("DB.CreateTable() could not detect name collision") - } - table2, error = db.CreateTable("SecondTable") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - name = table2.Name() - if name != "SecondTable" { - t.Fatalf("Table name is wrong: name = %v", name) - } - error = db.RenameTable("FirstTable", "SecondTable") - if error == nil { - t.Fatalf("DB.RenameTable() could not detect name collision") - } - error = db.RenameTable("FirstTable", "Table") - if error != nil { - t.Fatalf("DB.RenameTable() failed: error = %v", error) - } -} - -func TestTableReordering(t *testing.T) { - // TODO -} - -func TestEmptyColumn(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", INT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - numColumns := table.NumColumns() - if numColumns != 1 { - t.Fatalf("Table.NumColumns() returned a wrong value: numColumns = %v", - numColumns) - } - if column.Table().handle != table.handle { - t.Fatalf("Column.Table() returned a wrong table") - } - name := column.Name() - if name != "Column" { - t.Fatalf("Column.Name() returned a wrong name: name = %v", name) - } - dataType := column.DataType() - if dataType != INT { - t.Fatalf("Column.DataType() returned a wrong data type: dataType = %v", - dataType) - } - referenceTable := column.ReferenceTable() - if referenceTable != nil { - t.Fatalf("Empty column has a reference table: referenceTable.Name() = %v", - referenceTable.Name()) - } - if column.IsKey() { - t.Fatalf("Empty column is key") - } - numIndexes := column.NumIndexes() - if numIndexes != 0 { - t.Fatalf("Empty column has indexes: numIndexes = %v", numIndexes) - } - table.RemoveColumn("Column") - if error != nil { - t.Fatalf("Table.RemoveColumn() failed: error = %v", error) - } -} - -func TestColumnRename(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", INT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - error = table.RenameColumn("Column", "FirstColumn") - if error != nil { - t.Fatalf("Table.RenameColumn() failed: error = %v", error) - } - name := column.Name() - if name != "FirstColumn" { - t.Fatalf("Column name is wrong: name = %v", name) - } - column2, error := table.CreateColumn("FirstColumn", INT, nil) - if error == nil { - t.Fatalf("Table.CreateColumn() could not detect name collision") - } - column2, error = table.CreateColumn("SecondColumn", INT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - name = column2.Name() - if name != "SecondColumn" { - t.Fatalf("Column name is wrong: name = %v", name) - } - error = table.RenameColumn("FirstColumn", "SecondColumn") - if error == nil { - t.Fatalf("Table.RenameColumn() could not detect name collision") - } - error = table.RenameColumn("FirstColumn", "Column") - if error != nil { - t.Fatalf("Table.RenameColumn() failed: error = %v", error) - } -} - -func TestColumnReordering(t *testing.T) { - // TODO -} - -func TestEmptyIndex(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", INT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - index, error := column.CreateIndex("Index", TREE_INDEX) - if error != nil { - t.Fatalf("Column.CreateIndex() failed: error = %v", error) - } - numIndexes := column.NumIndexes() - if numIndexes != 1 { - t.Fatalf("Column.NumIndexes() returned a wrong value: numIndexes = %v", - numIndexes) - } - if index.Column().handle != column.handle { - t.Fatalf("Index.Column() returned a wrong column") - } - name := index.Name() - if name != "Index" { - t.Fatalf("Index.Name() returned a wrong name: name = %v", name) - } - indexType := index.IndexType() - if indexType != TREE_INDEX { - t.Fatalf("Index.IndexType() returned a wrong index type: indexType = %v", - indexType) - } - numEntries := index.NumEntries() - if numEntries != 0 { - t.Fatalf("Empty index has entries: numEntries = %v", numEntries) - } - if !index.TestUniqueness() { - t.Fatalf("Empty index's TestUniqueness() returned true") - } - column.RemoveIndex("Index") - if error != nil { - t.Fatalf("Column.RemoveIndex() failed: error = %v", error) - } -} - -func TestIndexRename(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", INT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - index, error := column.CreateIndex("Index", TREE_INDEX) - if error != nil { - t.Fatalf("Column.CreateIndex() failed: error = %v", error) - } - - error = column.RenameIndex("Index", "FirstIndex") - if error != nil { - t.Fatalf("Table.RenameIndex() failed: error = %v", error) - } - name := index.Name() - if name != "FirstIndex" { - t.Fatalf("Index name is wrong: name = %v", name) - } - index2, error := column.CreateIndex("FirstIndex", TREE_INDEX) - if error == nil { - t.Fatalf("Table.CreateIndex() could not detect name collision") - } - index2, error = column.CreateIndex("SecondIndex", TREE_INDEX) - if error != nil { - t.Fatalf("Table.CreateIndex() failed: error = %v", error) - } - name = index2.Name() - if name != "SecondIndex" { - t.Fatalf("Index name is wrong: name = %v", name) - } - error = column.RenameIndex("FirstIndex", "SecondIndex") - if error == nil { - t.Fatalf("Table.RenameIndex() could not detect name collision") - } - error = column.RenameIndex("FirstIndex", "Index") - if error != nil { - t.Fatalf("Table.RenameIndex() failed: error = %v", error) - } -} - -func TestIndexReordering(t *testing.T) { - // TODO -} - -func TestInsertRow(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - if rowID != 0 { - t.Fatalf("Table.InsertRow() returned a wrong value: rowID = %v", rowID) - } - numRows := table.NumRows() - if numRows != 1 { - t.Fatalf("Table.NumRows() returned a wrong value: numRows = %v", numRows) - } - maxRowID := table.MaxRowID() - if maxRowID != rowID { - t.Fatalf("Table.MaxRowID() returned a wrong value: maxRowID = %v", maxRowID) - } - if table.IsEmpty() { - t.Fatalf("Non-empty table's IsEmpty() returned true") - } - if !table.IsFull() { - t.Fatalf("Full table's IsFull() returned false") - } - rowID, error = table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - if rowID != 1 { - t.Fatalf("Table.InsertRow() returned a wrong value: rowID = %v", rowID) - } - error = db.RemoveTable("Table") - if error != nil { - t.Fatalf("DB.RemoveTable() failed: error = %v", error) - } - - table, error = db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", TEXT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - error = table.SetKeyColumn("Column") - if error != nil { - t.Fatalf("Table.SetKeyColumn() failed: error = %v", error) - } - rowID, error = table.InsertRow(Text("Hello")) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - if rowID != 0 { - t.Fatalf("Table.InsertRow() returned a wrong value: rowID = %v", rowID) - } - var value Text - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !reflect.DeepEqual(value, Text("Hello")) { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - rowID = table.FindRow(Text("Hello")) - if rowID != 0 { - t.Fatalf("Table.FindRow() returned a wrong value: rowID = %v", rowID) - } -} - -func TestTableInsertRows(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - rowIDs, error := table.InsertRows(make([]Int, 3)) - if error != nil { - t.Fatalf("Table.InsertRows() failed: error = %v", error) - } - if len(rowIDs) != 3 { - t.Fatalf("Table.InsertRows() failed: len(rowIDs) = %v", len(rowIDs)) - } - for i := 0; i < 3; i++ { - if rowIDs[i] != Int(i) { - t.Fatalf("Table.InsertRows() failed: i = %v, rowIDs[i] = %v", - i, rowIDs[i]) - } - } - error = db.RemoveTable("Table") - if error != nil { - t.Fatalf("DB.RemoveTable() failed: error = %v", error) - } - - table, error = db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", TEXT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - error = table.SetKeyColumn("Column") - if error != nil { - t.Fatalf("Table.SetKeyColumn() failed: error = %v", error) - } - keys := []Text{Text("Hello"), Text("World"), Text("!")} - rowIDs, error = table.InsertRows(keys) - if error != nil { - t.Fatalf("Table.InsertRows() failed: error = %v", error) - } - if len(rowIDs) != 3 { - t.Fatalf("Table.InsertRows() failed: len(rowIDs) = %v", len(rowIDs)) - } - for i := 0; i < 3; i++ { - if rowIDs[i] != Int(i) { - t.Fatalf("Table.InsertRows() failed: i = %v, rowIDs[i] = %v", - i, rowIDs[i]) - } - var value Text - error = column.Get(rowIDs[i], &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !reflect.DeepEqual(value, keys[i]) { - t.Fatalf("Column.Get() returned a wrong value: "+ - "i = %v, key = %v, value = %v", i, keys[i], value) - } - } -} - -func TestTableInsertRowAt(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - error = table.InsertRowAt(Int(100), nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - numRows := table.NumRows() - if numRows != 1 { - t.Fatalf("Table.NumRows() returned a wrong value: numRows = %v", numRows) - } - maxRowID := table.MaxRowID() - if maxRowID != 100 { - t.Fatalf("Table.MaxRowID() returned a wrong value: maxRowID = %v", maxRowID) - } - if table.IsEmpty() { - t.Fatalf("Non-empty table's IsEmpty() returned true") - } - if table.IsFull() { - t.Fatalf("Non-full table's IsFull() returned true") - } - if table.TestRow(0) { - t.Fatalf("Table.TestRow() returned true for an invalid row ID") - } - if !table.TestRow(100) { - t.Fatalf("Table.TestRow() returned false for a valid row ID") - } -} - -func TestTableFindOrInsertRow(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - _, error = table.CreateColumn("Column", TEXT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - error = table.SetKeyColumn("Column") - if error != nil { - t.Fatalf("Table.SetKeyColumn() failed: error = %v", error) - } - rowID, inserted, error := table.FindOrInsertRow(Text("Hello")) - if error != nil { - t.Fatalf("Table.FindOrInsertRow() failed: error = %v", error) - } - if (rowID != 0) || !inserted { - t.Fatalf("Table.FindOrInsertRow() returned a wrong value: "+ - "rowID = %v, inserted = %v", rowID, inserted) - } - rowID, inserted, error = table.FindOrInsertRow(Text("Hello")) - if error != nil { - t.Fatalf("Table.FindOrInsertRow() failed: error = %v", error) - } - if (rowID != 0) || inserted { - t.Fatalf("Table.FindOrInsertRow() returned a wrong value: "+ - "rowID = %v, inserted = %v", rowID, inserted) - } - rowID, inserted, error = table.FindOrInsertRow(Text("World")) - if error != nil { - t.Fatalf("Table.FindOrInsertRow() failed: error = %v", error) - } - if (rowID != 1) || !inserted { - t.Fatalf("Table.FindOrInsertRow() returned a wrong value: "+ - "rowID = %v, inserted = %v", rowID, inserted) - } -} - -func TestTableRemoveRow(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - error = table.RemoveRow(rowID) - if error != nil { - t.Fatalf("Table.RemoveRow() failed: error = %v", error) - } - numRows := table.NumRows() - if numRows != 0 { - t.Fatalf("Table.NumRows() returned a wrong value: numRows = %v", numRows) - } - maxRowID := table.MaxRowID() - if !maxRowID.IsNA() { - t.Fatalf("Table.MaxRowID() returned a wrong value: maxRowID = %v", maxRowID) - } - if !table.IsEmpty() { - t.Fatalf("Empty table's IsEmpty() returned false") - } - if !table.IsFull() { - t.Fatalf("Empty table's IsFull() returned false") - } -} - -func TestTableCreateCursor(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - rowIDs := make([]Int, 100) - for i := 0; i < 100; i++ { - rowIDs[i], error = table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - } - cursor, error := table.CreateCursor(nil) - if error != nil { - t.Fatalf("Table.CreateCursor() failed: error = %v", error) - } - defer cursor.Close() - records := make([]Record, 200) - count := cursor.Read(records) - if count != 100 { - t.Fatalf("Cursor.Read() could not read all records: count = %v", count) - } - for i := 0; i < 100; i++ { - if (rowIDs[i] != records[i].RowID) || (records[i].Score != 0.0) { - t.Fatalf("Cursor.Read() returned a wrong record: RowID = %v, Score = %v", - records[i].RowID, records[i].Score) - } - } - cursorOptions := CursorOptions{25, 50, REVERSE_ORDER} - cursor, error = table.CreateCursor(&cursorOptions) - if error != nil { - t.Fatalf("Table.CreateCursor() failed: error = %v", error) - } - defer cursor.Close() - count = cursor.Read(records) - if count != 50 { - t.Fatalf("Cursor.Read() could not read all records: count = %v", count) - } - for i := 0; i < 50; i++ { - j := 100 - 25 - i - 1 - if (rowIDs[j] != records[i].RowID) || (records[i].Score != 0.0) { - t.Fatalf("Cursor.Read() returned a wrong record: RowID = %v, Score = %v", - records[i].RowID, records[i].Score) - } - } -} - -func TestBoolColumn(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", BOOL, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - var value Bool - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - - VALUE := TRUE - error = column.Set(rowID, VALUE) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if value != VALUE { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(VALUE) { - t.Fatalf("Column.Contains() failed") - } - foundRowID := column.FindOne(VALUE) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v", foundRowID) - } - - error = column.Set(rowID, nil) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(nil) { - t.Fatalf("Column.Contains() failed") - } - foundRowID = column.FindOne(nil) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v", foundRowID) - } -} - -func TestIntColumn(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", INT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - var value Int - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - - VALUE := Int(123) - error = column.Set(rowID, VALUE) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if value != VALUE { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(VALUE) { - t.Fatalf("Column.Contains() failed") - } - foundRowID := column.FindOne(VALUE) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v", foundRowID) - } - - error = column.Set(rowID, nil) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(nil) { - t.Fatalf("Column.Contains() failed") - } - foundRowID = column.FindOne(nil) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v", foundRowID) - } -} - -func TestFloatColumn(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", FLOAT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - var value Float - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - - VALUE := Float(1.25) - error = column.Set(rowID, VALUE) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if value != VALUE { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(VALUE) { - t.Fatalf("Column.Contains() failed") - } - foundRowID := column.FindOne(VALUE) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v", foundRowID) - } - - error = column.Set(rowID, nil) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(nil) { - t.Fatalf("Column.Contains() failed") - } - foundRowID = column.FindOne(nil) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v", foundRowID) - } -} - -func TestGeoPointColumn(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", GEO_POINT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - var value GeoPoint - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - - VALUE := GeoPoint{123, 456} - error = column.Set(rowID, VALUE) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if value != VALUE { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(VALUE) { - t.Fatalf("Column.Contains() failed") - } - foundRowID := column.FindOne(VALUE) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v", foundRowID) - } - - error = column.Set(rowID, nil) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(nil) { - t.Fatalf("Column.Contains() failed") - } - foundRowID = column.FindOne(nil) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v", foundRowID) - } -} - -func TestTextColumn(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", TEXT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - var value Text - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - - VALUE := Text("Hello") - error = column.Set(rowID, VALUE) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !reflect.DeepEqual(value, VALUE) { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(VALUE) { - t.Fatalf("Column.Contains() failed") - } - foundRowID := column.FindOne(VALUE) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v", foundRowID) - } - - error = column.Set(rowID, nil) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(nil) { - t.Fatalf("Column.Contains() failed") - } - foundRowID = column.FindOne(nil) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v, rowID = %v", - foundRowID, rowID) - } -} - -func TestReferenceColumn(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", INT, &ColumnOptions{"Table"}) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - var value Int - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - - VALUE := Int(123) - error = column.Set(rowID, VALUE) - if error == nil { - t.Fatalf("Column.Set() succeeded") - } - VALUE = Int(0) - error = column.Set(rowID, VALUE) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if value != VALUE { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(VALUE) { - t.Fatalf("Column.Contains() failed") - } - foundRowID := column.FindOne(VALUE) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v", foundRowID) - } - - error = column.Set(rowID, nil) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = column.Get(rowID, &value) - if error != nil { - t.Fatalf("Column.Get() failed: error = %v", error) - } - if !value.IsNA() { - t.Fatalf("Column.Get() returned a wrong value: value = %v", value) - } - if !column.Contains(nil) { - t.Fatalf("Column.Contains() failed") - } - foundRowID = column.FindOne(nil) - if foundRowID != rowID { - t.Fatalf("Column.FindOne() failed: foundRowID = %v", foundRowID) - } -} - -func TestIntIndex(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", INT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - index, error := column.CreateIndex("Index", TREE_INDEX) - if error != nil { - t.Fatalf("Column.CreateIndex() failed: error = %v", error) - } - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - error = column.Set(rowID, Int(123)) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - error = table.SetKeyColumn("Column") - if error != nil { - t.Fatalf("Table.SetKeyColumn() failed: error = %v", error) - } - rowID, error = table.InsertRow(Int(456)) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - if !index.Contains(Int(456)) { - t.Fatalf("Index.Contains() failed") - } - foundRowID := index.FindOne(Int(456)) - if foundRowID != rowID { - t.Fatalf("Index.FindOne() failed: foundRowID = %v, rowID = %v", - foundRowID, rowID) - } - cursor, error := index.Find(Int(456), nil) - if error != nil { - t.Fatalf("Index.Find() failed: error = %v", error) - } - defer cursor.Close() - records := make([]Record, 10) - count := cursor.Read(records) - if count != 1 { - t.Fatalf("Cursor.Read() could not read a record: count = %v", count) - } - if records[0].RowID != rowID { - t.Fatalf("Cursor.Read() returned a wrong record: RowID = %v, Score = %v", - records[0].RowID, records[0].Score) - } - cursorOptions := CursorOptions{0, 2, REVERSE_ORDER} - cursor, error = index.FindInRange(Int(123), true, Int(456), true, - &cursorOptions) - if error != nil { - t.Fatalf("Index.FindInRange() failed: error = %v", error) - } - defer cursor.Close() - count = cursor.Read(records) - if count != 2 { - t.Fatalf("Cursor.Read() could not read all records: count = %v", count) - } - if records[0].RowID != 1 { - t.Fatalf("Cursor.Read() returned a wrong record: RowID = %v, Score = %v", - records[0].RowID, records[0].Score) - } - if records[1].RowID != 0 { - t.Fatalf("Cursor.Read() returned a wrong record: RowID = %v, Score = %v", - records[1].RowID, records[1].Score) - } -} - -func TestFloatIndex(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", FLOAT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - index, error := column.CreateIndex("Index", HASH_INDEX) - if error != nil { - t.Fatalf("Column.CreateIndex() failed: error = %v", error) - } - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - error = column.Set(rowID, Float(1.25)) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - rowID, error = table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - error = column.Set(rowID, Float(4.75)) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - if !index.Contains(Float(4.75)) { - t.Fatalf("Index.Contains() failed") - } - foundRowID := index.FindOne(Float(4.75)) - if foundRowID != rowID { - t.Fatalf("Index.FindOne() failed: foundRowID = %v, rowID = %v", - foundRowID, rowID) - } - cursor, error := index.Find(Float(4.75), nil) - if error != nil { - t.Fatalf("Index.Find() failed: error = %v", error) - } - defer cursor.Close() - records := make([]Record, 10) - count := cursor.Read(records) - if count != 1 { - t.Fatalf("Cursor.Read() could not read a record: count = %v", count) - } - if records[0].RowID != rowID { - t.Fatalf("Cursor.Read() returned a wrong record: RowID = %v, Score = %v", - records[0].RowID, records[0].Score) - } - cursorOptions := CursorOptions{0, 2, REVERSE_ORDER} - cursor, error = index.FindInRange(Float(1.25), true, Float(4.75), true, - &cursorOptions) - if error == nil { - t.Fatalf("Index.FindInRange() Succeeded for hash index") - } -} - -func TestTextIndex(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", TEXT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - index, error := column.CreateIndex("Index", TREE_INDEX) - if error != nil { - t.Fatalf("Column.CreateIndex() failed: error = %v", error) - } - VALUES := []Text{Text("He"), Text("Hello"), Text("World")} - for i := 0; i < len(VALUES); i++ { - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - if rowID != Int(i) { - t.Fatalf("Table.InsertRow() returned a wrong row ID: rowID = %v", rowID) - } - error = column.Set(rowID, VALUES[i]) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - } - for i := 0; i < len(VALUES); i++ { - if !index.Contains(VALUES[i]) { - t.Fatalf("Index.Contains() failed: i = %v", i) - } - rowID := index.FindOne(VALUES[i]) - if rowID != Int(i) { - t.Fatalf("Index.FindOne() failed: rowID = %v, i = %v", rowID, i) - } - } - cursor, error := index.Find(VALUES[0], nil) - if error != nil { - t.Fatalf("Index.Find() failed: error = %v", error) - } - defer cursor.Close() - records := make([]Record, 10) - count := cursor.Read(records) - if count != 1 { - t.Fatalf("Cursor.Read() failed: count = %v", count) - } - cursor, error = index.FindInRange(nil, false, nil, false, nil) - if error != nil { - t.Fatalf("Index.FindInRange() failed: error = %v", error) - } - defer cursor.Close() - count = cursor.Read(records) - if count != 3 { - t.Fatalf("Cursor.Read() failed: count = %v", count) - } - cursor, error = index.FindStartsWith(Text("He"), true, nil) - if error != nil { - t.Fatalf("Index.FindInRange() failed: error = %v", error) - } - defer cursor.Close() - count = cursor.Read(records) - if count != 2 { - t.Fatalf("Cursor.Read() failed: count = %v", count) - } - cursor, error = index.FindPrefixes(Text("Hello"), nil) - if error != nil { - t.Fatalf("Index.FindPrefixes() failed: error = %v", error) - } - defer cursor.Close() - count = cursor.Read(records) - if count != 2 { - t.Fatalf("Cursor.Read() failed: count = %v", count) - } -} - -func TestRowIDExpression(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - builder, error := CreateExpressionBuilder(table) - if error != nil { - t.Fatalf("CreateExpressionBuilder() failed: error = %v", error) - } - defer builder.Close() - error = builder.PushRowID() - if error != nil { - t.Fatalf("ExpressionBuilder.PushRowID() failed: error = %v", error) - } - expression, error := builder.Release() - if error != nil { - t.Fatalf("ExpressionBuilder.Release() failed: error = %v", error) - } - defer expression.Close() - if expression.Table().handle != table.handle { - t.Fatalf("Expression.Table() returned a wrong table") - } - if expression.DataType() != INT { - t.Fatalf("Expression.DataType() returned a wrong data type: type = %v", - expression.DataType()) - } - if !expression.IsRowID() { - t.Fatalf("Expression.IsRowID() failed") - } - if expression.IsScore() { - t.Fatalf("Expression.IsScore() failed") - } -} - -func TestScoreExpression(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - builder, error := CreateExpressionBuilder(table) - if error != nil { - t.Fatalf("CreateExpressionBuilder() failed: error = %v", error) - } - defer builder.Close() - error = builder.PushScore() - if error != nil { - t.Fatalf("ExpressionBuilder.PushScore() failed: error = %v", error) - } - expression, error := builder.Release() - if error != nil { - t.Fatalf("ExpressionBuilder.Release() failed: error = %v", error) - } - defer expression.Close() - if expression.Table().handle != table.handle { - t.Fatalf("Expression.Table() returned a wrong table") - } - if expression.DataType() != FLOAT { - t.Fatalf("Expression.DataType() returned a wrong data type: type = %v", - expression.DataType()) - } - if expression.IsRowID() { - t.Fatalf("Expression.IsRowID() failed") - } - if !expression.IsScore() { - t.Fatalf("Expression.IsScore() failed") - } -} - -func TestExpressionFilter(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", TEXT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - VALUES := []Text{Text("He"), Text("Hello"), Text("World")} - for i := 0; i < len(VALUES); i++ { - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - error = column.Set(rowID, VALUES[i]) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - } - builder, error := CreateExpressionBuilder(table) - if error != nil { - t.Fatalf("CreateExpressionBuilder() failed: error = %v", error) - } - defer builder.Close() - error = builder.PushColumn("Column") - if error != nil { - t.Fatalf("ExpressionBuilder.PushColumn() failed: error = %v", error) - } - error = builder.PushConstant(Text("Hello")) - if error != nil { - t.Fatalf("ExpressionBuilder.PushConstant() failed: error = %v", error) - } - error = builder.PushOperator(LESS_EQUAL) - if error != nil { - t.Fatalf("ExpressionBuilder.PushOperator() failed: error = %v", error) - } - expression, error := builder.Release() - if error != nil { - t.Fatalf("ExpressionBuilder.Release() failed: error = %v", error) - } - defer expression.Close() - cursor, error := table.CreateCursor(nil) - if error != nil { - t.Fatalf("Table.CreateCursor() failed: error = %v", error) - } - defer cursor.Close() - records := make([]Record, 10) - count := cursor.Read(records) - records = records[:count] - error = expression.Filter(&records) - if error != nil { - t.Fatalf("Expression.Filter() failed: error = %v", error) - } - if len(records) != 2 { - t.Fatalf("Expression.Filter() failed: len(records) = %v", len(records)) - } -} - -func TestExpressionAdjust(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", FLOAT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - VALUES := []Float{1.5, 2.0, 2.5} - for i := 0; i < len(VALUES); i++ { - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - error = column.Set(rowID, VALUES[i]) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - } - builder, error := CreateExpressionBuilder(table) - if error != nil { - t.Fatalf("CreateExpressionBuilder() failed: error = %v", error) - } - defer builder.Close() - error = builder.PushColumn("Column") - if error != nil { - t.Fatalf("ExpressionBuilder.PushColumn() failed: error = %v", error) - } - error = builder.PushColumn("Column") - if error != nil { - t.Fatalf("ExpressionBuilder.PushColumn() failed: error = %v", error) - } - error = builder.PushOperator(MULTIPLICATION) - if error != nil { - t.Fatalf("ExpressionBuilder.PushOperator() failed: error = %v", error) - } - expression, error := builder.Release() - if error != nil { - t.Fatalf("ExpressionBuilder.Release() failed: error = %v", error) - } - defer expression.Close() - cursor, error := table.CreateCursor(nil) - if error != nil { - t.Fatalf("Table.CreateCursor() failed: error = %v", error) - } - defer cursor.Close() - records := make([]Record, 10) - count := cursor.Read(records) - if count != 3 { - t.Fatalf("Cursor.Read() failed: count = %v", count) - } - records = records[:count] - error = expression.Adjust(records) - if error != nil { - t.Fatalf("Expression.Adjust() failed: error = %v", error) - } - for i := 0; i < count; i++ { - if records[i].Score != (VALUES[i] * VALUES[i]) { - t.Fatalf("Expression.Adjust() failed: "+ - "i = %v, RowID = %v, Score = %v, VALUE = %v", - i, records[i].RowID, records[i].Score, VALUES[i]) - } - } -} - -func TestExpressionEvaluate(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", INT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - VALUES := []Int{123, 456, 789} - for i := 0; i < len(VALUES); i++ { - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - error = column.Set(rowID, VALUES[i]) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - } - builder, error := CreateExpressionBuilder(table) - if error != nil { - t.Fatalf("CreateExpressionBuilder() failed: error = %v", error) - } - defer builder.Close() - error = builder.PushColumn("Column") - if error != nil { - t.Fatalf("ExpressionBuilder.PushColumn() failed: error = %v", error) - } - error = builder.PushConstant(Int(100)) - if error != nil { - t.Fatalf("ExpressionBuilder.PushConstant() failed: error = %v", error) - } - error = builder.PushOperator(PLUS) - if error != nil { - t.Fatalf("ExpressionBuilder.PushOperator() failed: error = %v", error) - } - expression, error := builder.Release() - if error != nil { - t.Fatalf("ExpressionBuilder.Release() failed: error = %v", error) - } - defer expression.Close() - cursor, error := table.CreateCursor(nil) - if error != nil { - t.Fatalf("Table.CreateCursor() failed: error = %v", error) - } - defer cursor.Close() - records := make([]Record, 10) - count := cursor.Read(records) - if count != 3 { - t.Fatalf("Cursor.Read() failed: count = %v", count) - } - records = records[:count] - values := make([]Int, count) - error = expression.Evaluate(records, values) - if error != nil { - t.Fatalf("Expression.Evaluate() failed: error = %v", error) - } - for i := 0; i < count; i++ { - if values[i] != (VALUES[i] + 100) { - t.Fatalf("Expression.Evaluate() failed: "+ - "i = %v, VALUE = %v, value = %v", i, VALUES[i], values[i]) - } - } -} - -func TestExpressionParser(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", INT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - VALUES := []Int{123, 456, 789} - for i := 0; i < len(VALUES); i++ { - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - error = column.Set(rowID, VALUES[i]) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - } - expression, error := ParseExpression(table, "Column + 100") - defer expression.Close() - cursor, error := table.CreateCursor(nil) - if error != nil { - t.Fatalf("Table.CreateCursor() failed: error = %v", error) - } - defer cursor.Close() - records := make([]Record, 10) - count := cursor.Read(records) - if count != 3 { - t.Fatalf("Cursor.Read() failed: count = %v", count) - } - records = records[:count] - values := make([]Int, count) - error = expression.Evaluate(records, values) - if error != nil { - t.Fatalf("Expression.Evaluate() failed: error = %v", error) - } - for i := 0; i < count; i++ { - if values[i] != (VALUES[i] + 100) { - t.Fatalf("Expression.Evaluate() failed: "+ - "i = %v, VALUE = %v, value = %v", i, VALUES[i], values[i]) - } - } -} - -func TestPipelineFilterAndAdjuster(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", FLOAT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - VALUES := []Float{1.5, 2.0, 2.5} - for i := 0; i < len(VALUES); i++ { - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - error = column.Set(rowID, VALUES[i]) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - } - - pipelineBuilder, error := CreatePipelineBuilder(table) - if error != nil { - t.Fatalf("CreatePipelineBuilder() failed: error = %v", error) - } - defer pipelineBuilder.Close() - cursor, error := table.CreateCursor(nil) - if error != nil { - t.Fatalf("Table.CreateCursor() failed: error = %v", error) - } - error = pipelineBuilder.PushCursor(cursor) - if error != nil { - t.Fatalf("PipelineBuilder.PushCursor() failed: error = %v", error) - } - - expressionBuilder, error := CreateExpressionBuilder(table) - if error != nil { - t.Fatalf("CreateExpressionBuilder() failed: error = %v", error) - } - defer expressionBuilder.Close() - error = expressionBuilder.PushColumn("Column") - if error != nil { - t.Fatalf("ExpressionBuilder.PushColumn() failed: error = %v", error) - } - error = expressionBuilder.PushConstant(Float(2.0)) - if error != nil { - t.Fatalf("ExpressionBuilder.PushConstant() failed: error = %v", error) - } - error = expressionBuilder.PushOperator(GREATER_EQUAL) - if error != nil { - t.Fatalf("ExpressionBuilder.PushOperator() failed: error = %v", error) - } - expression, error := expressionBuilder.Release() - if error != nil { - t.Fatalf("ExpressionBuilder.Release() failed: error = %v", error) - } - error = pipelineBuilder.PushFilter(expression, 0, 100) - if error != nil { - t.Fatalf("PipelineBuilder.PushFilter() failed: error = %v", error) - } - - error = expressionBuilder.PushColumn("Column") - if error != nil { - t.Fatalf("ExpressionBuilder.PushColumn() failed: error = %v", error) - } - error = expressionBuilder.PushColumn("Column") - if error != nil { - t.Fatalf("ExpressionBuilder.PushColumn() failed: error = %v", error) - } - error = expressionBuilder.PushOperator(MULTIPLICATION) - if error != nil { - t.Fatalf("ExpressionBuilder.PushOperator() failed: error = %v", error) - } - expression, error = expressionBuilder.Release() - if error != nil { - t.Fatalf("ExpressionBuilder.Release() failed: error = %v", error) - } - error = pipelineBuilder.PushAdjuster(expression) - if error != nil { - t.Fatalf("PipelineBuilder.PushAdjuster() failed: error = %v", error) - } - - pipeline, error := pipelineBuilder.Release(nil) - if error != nil { - t.Fatalf("PipelineBuilder.Release() failed: error = %v", error) - } - defer pipeline.Close() - records, error := pipeline.Flush() - if error != nil { - t.Fatalf("Pipeline.Flush() failed: error = %v", error) - } - if len(records) != 2 { - t.Fatalf("Pipeline.Flush() failed: len(records) = %v", len(records)) - } - if (records[0].RowID != 1) || (records[0].Score != (VALUES[1] * VALUES[1])) { - t.Fatalf("Pipeline.Flush() failed: i = %v, RowID = %v, Score = %v", - 0, records[0].RowID, records[0].Score) - } - if (records[1].RowID != 2) || (records[1].Score != (VALUES[2] * VALUES[2])) { - t.Fatalf("Pipeline.Flush() failed: i = %v, RowID = %v, Score = %v", - 1, records[1].RowID, records[1].Score) - } -} - -func TestPipelineSorterAndMerger(t *testing.T) { - db, error := CreateDB() - if error != nil { - t.Fatalf("CreateDB() failed: error = %v", error) - } - defer db.Close() - table, error := db.CreateTable("Table") - if error != nil { - t.Fatalf("DB.CreateTable() failed: error = %v", error) - } - column, error := table.CreateColumn("Column", FLOAT, nil) - if error != nil { - t.Fatalf("Table.CreateColumn() failed: error = %v", error) - } - index, error := column.CreateIndex("Index", TREE_INDEX) - if error != nil { - t.Fatalf("Table.CreateIndex() failed: error = %v", error) - } - VALUES := []Float{4.5, 1.5, 6.0, 0.0, 3.0} - for i := 0; i < len(VALUES); i++ { - rowID, error := table.InsertRow(nil) - if error != nil { - t.Fatalf("Table.InsertRow() failed: error = %v", error) - } - error = column.Set(rowID, VALUES[i]) - if error != nil { - t.Fatalf("Column.Set() failed: error = %v", error) - } - } - - pipelineBuilder, error := CreatePipelineBuilder(table) - if error != nil { - t.Fatalf("CreatePipelineBuilder() failed: error = %v", error) - } - defer pipelineBuilder.Close() - expressionBuilder, error := CreateExpressionBuilder(table) - if error != nil { - t.Fatalf("CreateExpressionBuilder() failed: error = %v", error) - } - defer expressionBuilder.Close() - - cursor, error := index.FindInRange(nil, false, Float(4.5), true, nil) - if error != nil { - t.Fatalf("index.FindInRange() failed: error = %v", error) - } - error = pipelineBuilder.PushCursor(cursor) - if error != nil { - t.Fatalf("PipelineBuilder.PushCursor() failed: error = %v", error) - } - error = expressionBuilder.PushColumn("Column") - if error != nil { - t.Fatalf("ExpressionBuilder.PushColumn() failed: error = %v", error) - } - expression, error := expressionBuilder.Release() - if error != nil { - t.Fatalf("ExpressionBuilder.Release() failed: error = %v", error) - } - error = pipelineBuilder.PushAdjuster(expression) - if error != nil { - t.Fatalf("PipelineBuilder.PushAdjuster() failed: error = %v", error) - } - - cursor, error = index.FindInRange(Float(1.5), true, nil, false, nil) - if error != nil { - t.Fatalf("index.FindInRange() failed: error = %v", error) - } - error = pipelineBuilder.PushCursor(cursor) - if error != nil { - t.Fatalf("PipelineBuilder.PushCursor() failed: error = %v", error) - } - error = expressionBuilder.PushColumn("Column") - if error != nil { - t.Fatalf("ExpressionBuilder.PushColumn() failed: error = %v", error) - } - expression, error = expressionBuilder.Release() - if error != nil { - t.Fatalf("ExpressionBuilder.Release() failed: error = %v", error) - } - error = pipelineBuilder.PushAdjuster(expression) - if error != nil { - t.Fatalf("PipelineBuilder.PushAdjuster() failed: error = %v", error) - } - - var mergerOptions MergerOptions - mergerOptions.LogicalOperatorType = MERGER_AND - mergerOptions.ScoreOperatorType = MERGER_PLUS - mergerOptions.Limit = 10 - error = pipelineBuilder.PushMerger(&mergerOptions) - if error != nil { - t.Fatalf("PipelineBuilder.PushMerger() failed: error = %v", error) - } - - error = expressionBuilder.PushRowID() - if error != nil { - t.Fatalf("ExpressionBuilder.PushRowID() failed: error = %v", error) - } - expression, error = expressionBuilder.Release() - if error != nil { - t.Fatalf("ExpressionBuilder.Release() failed: error = %v", error) - } - orders := make([]SorterOrder, 1) - orders[0].Expression = expression - orders[0].OrderType = REGULAR_ORDER - sorter, error := CreateSorter(orders, nil) - if error != nil { - t.Fatalf("CreateSorter() failed: error = %v", error) - } - error = pipelineBuilder.PushSorter(sorter) - if error != nil { - t.Fatalf("PipelineBuilder.PushSorter() failed: error = %v", error) - } - - pipeline, error := pipelineBuilder.Release(nil) - if error != nil { - t.Fatalf("PipelineBuilder.Release() failed: error = %v", error) - } - defer pipeline.Close() - records, error := pipeline.Flush() - if error != nil { - t.Fatalf("Pipeline.Flush() failed: error = %v", error) - } - if len(records) != 3 { - t.Fatalf("Pipeline.Flush() failed: len(records) = %v", len(records)) - } - if (records[0].RowID != 0) || (records[0].Score != (VALUES[0] + VALUES[0])) { - t.Fatalf("Pipeline.Flush() failed: i = %v, RowID = %v, Score = %v", - 0, records[0].RowID, records[0].Score) - } - if (records[1].RowID != 1) || (records[1].Score != (VALUES[1] + VALUES[1])) { - t.Fatalf("Pipeline.Flush() failed: i = %v, RowID = %v, Score = %v", - 1, records[1].RowID, records[1].Score) - } - if (records[2].RowID != 4) || (records[2].Score != (VALUES[4] + VALUES[4])) { - t.Fatalf("Pipeline.Flush() failed: i = %v, RowID = %v, Score = %v", - 2, records[2].RowID, records[2].Score) - } -} Deleted: go/gnx/groonga/groonga.go (+0 -863) 100644 =================================================================== --- go/gnx/groonga/groonga.go 2015-05-26 11:06:34 +0900 (4f9b4d8) +++ /dev/null @@ -1,863 +0,0 @@ -package groonga - -/* -#cgo pkg-config: groonga -#include <groonga.h> -#include <stdlib.h> -*/ -import "C" - -import "encoding/json" -import "fmt" -import "io/ioutil" -import "os" -import "strconv" -import "strings" -import "time" -import "unicode" -import "unsafe" - -var initCount = 0 - -func DisableInitCount() { - initCount = -1 -} - -func Init() error { - switch initCount { - 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) - } - } - initCount++ - return nil -} - -func Fin() error { - switch initCount { - 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) - } - } - initCount-- - return nil -} - -type DB struct { - ctx *C.grn_ctx -} - -func CreateDB(path string) (*DB, error) { - if err := Init(); err != nil { - return nil, err - } - ctx := C.grn_ctx_open(0) - if ctx == nil { - Fin() - return nil, fmt.Errorf("grn_ctx_open() failed") - } - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - if db := C.grn_db_create(ctx, cPath, nil); db == nil { - C.grn_ctx_close(ctx) - Fin() - message := C.GoString(&ctx.errbuf[0]) - return nil, fmt.Errorf("grn_db_create() failed: err = %s", message) - } - return &DB{ctx}, nil -} - -// Create a DB in a temporary directory. -// -// Example: -// db, dir, err := CreateTempDB("", "gnx") -// if err != nil { -// log.Fatalln(err) -// } -// defer os.RemoveAll(dir) -// ... -func CreateTempDB(dir, prefix string) (*DB, string, error) { - tempDir, err := ioutil.TempDir(dir, prefix) - if err != nil { - return nil, "", err - } - db, err := CreateDB(tempDir + "/db") - if err != nil { - os.RemoveAll(tempDir) - return nil, "", err - } - return db, tempDir, nil -} - -func OpenDB(path string) (*DB, error) { - if err := Init(); err != nil { - return nil, err - } - ctx := C.grn_ctx_open(0) - if ctx == nil { - Fin() - return nil, fmt.Errorf("grn_ctx_open() failed") - } - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - if db := C.grn_db_open(ctx, cPath); db == nil { - C.grn_ctx_close(ctx) - Fin() - message := C.GoString(&ctx.errbuf[0]) - return nil, fmt.Errorf("grn_db_create() failed: err = %s", message) - } - return &DB{ctx}, nil -} - -func (db *DB) Close() error { - if db.ctx == nil { - return nil - } - if rc := C.grn_ctx_close(db.ctx); rc != C.GRN_SUCCESS { - return fmt.Errorf("grn_ctx_close() failed: rc = %d", rc) - } - db.ctx = nil - Fin() // may fail - return nil -} - -func (db *DB) Send(command string) error { - cCommand := C.CString(command) - defer C.free(unsafe.Pointer(cCommand)) - rc := C.grn_ctx_send(db.ctx, cCommand, C.uint(len(command)), 0) - if (rc != C.GRN_SUCCESS) || (db.ctx.rc != C.GRN_SUCCESS) { - message := C.GoString(&db.ctx.errbuf[0]) - return fmt.Errorf( - "grn_ctx_send() failed: rc = %d, ctx.rc = %d, err = %s", - rc, db.ctx.rc, message) - } - return nil -} - -func (db *DB) 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) - if (rc != C.GRN_SUCCESS) || (db.ctx.rc != C.GRN_SUCCESS) { - message := C.GoString(&db.ctx.errbuf[0]) - return nil, fmt.Errorf( - "grn_ctx_recv() failed: rc = %d, ctx.rc = %d, err = %s", - rc, db.ctx.rc, message) - } - result := C.GoBytes(unsafe.Pointer(resultBuffer), C.int(resultLength)) - return result, nil -} - -func (db *DB) Query(command string) ([]byte, error) { - if err := db.Send(command); err != nil { - db.Recv() - return nil, err - } - return db.Recv() -} - -func (db *DB) SendEx(name string, options map[string]string) error { - if (len(name) == 0) || (strings.IndexFunc(name, unicode.IsSpace) != -1) { - return fmt.Errorf("invalid command name") - } - command := name - for key, value := range options { - if (len(key) == 0) || (strings.IndexFunc(key, unicode.IsSpace) != -1) { - return fmt.Errorf("invalid option key") - } - value = strings.Replace(value, "\\", "\\\\", -1) - value = strings.Replace(value, "'", "\\'", -1) - command += fmt.Sprintf(" --%s '%s'", key, value) - } - return db.Send(command) -} - -func (db *DB) QueryEx(name string, options map[string]string) ( - []byte, error) { - if err := db.SendEx(name, options); err != nil { - return nil, err - } - return db.Recv() -} - -func (db *DB) boolQueryEx(name string, options map[string]string) ( - bool, error) { - bytes, err := db.QueryEx(name, options) - if err != nil { - return false, err - } - return string(bytes) == "true", nil -} - -func (db *DB) intQueryEx(name string, options map[string]string) ( - int, error) { - bytes, err := db.QueryEx(name, options) - if err != nil { - return 0, err - } - value, err := strconv.Atoi(string(bytes)) - if err != nil { - return 0, err - } - return value, nil -} - -func (db *DB) CacheLimit(max int) (int, error) { - if max < 0 { - return db.intQueryEx("cache_limit", nil) - } - return db.intQueryEx("cache_limit", map[string]string{ - "max": strconv.Itoa(max)}) -} - -func (db *DB) Check(objName string) ([]byte, error) { - return db.QueryEx("check", map[string]string{"obj": objName}) -} - -func (db *DB) CreateColumn(options map[string]string) (bool, error) { - return db.boolQueryEx("column_create", options) -} - -func parseStringOrNil(value interface{}) string { - if result, ok := value.(string); ok { - return result - } - return "" -} - -type Column struct { - ID int - Name string - Path string - Type string - Flags string - Domain string - Range string - Source string -} - -func (db *DB) ColumnList(tableName string) ([]Column, error) { - bytes, err := db.QueryEx("column_list", map[string]string{ - "table": tableName}) - if err != nil { - return nil, err - } - var result [][]interface{} - if err = json.Unmarshal(bytes, &result); err != nil { - return nil, err - } - headers := make([]string, len(result[0])) - for i := 0; i < len(headers); i++ { - headers[i] = result[0][i].([]interface{})[0].(string) - } - columns := make([]Column, len(result)-1) - for i := 0; i < len(columns); i++ { - values := result[i+1] - for j := 0; j < len(values); j++ { - switch headers[j] { - case "id": - columns[i].ID = int(values[j].(float64)) - case "name": - columns[i].Name = parseStringOrNil(values[j]) - case "path": - columns[i].Path = parseStringOrNil(values[j]) - case "type": - columns[i].Type = parseStringOrNil(values[j]) - case "flags": - columns[i].Flags = parseStringOrNil(values[j]) - case "domain": - columns[i].Domain = parseStringOrNil(values[j]) - case "range": - columns[i].Range = parseStringOrNil(values[j]) - case "source": - columns[i].Source = parseStringOrNil(values[j]) - } - } - } - return columns, nil -} - -func (db *DB) RemoveColumn(tableName, columnName string) (bool, error) { - return db.boolQueryEx("column_remove", - map[string]string{"table": tableName, "name": columnName}) -} - -func (db *DB) RenameColumn(tableName, columnName, newColumnName string) ( - bool, error) { - return db.boolQueryEx("column_rename", map[string]string{ - "table": tableName, "name": columnName, "new_name": newColumnName}) -} - -func (db *DB) DefineSelector(options map[string]string) (bool, error) { - return db.boolQueryEx("define_selector", options) -} - -func (db *DB) Defrag(objName string, threshold int) (int, error) { - return db.intQueryEx("defrag", map[string]string{ - "objname": objName, "threshold": strconv.Itoa(threshold)}) -} - -func (db *DB) Delete(options map[string]string) (bool, error) { - return db.boolQueryEx("delete", options) -} - -func (db *DB) Dump(tableNames []string) ([]byte, error) { - if len(tableNames) == 0 { - return db.QueryEx("dump", nil) - } - joinedTableNames := strings.Join(tableNames, ",") - return db.QueryEx("dump", map[string]string{"tables": joinedTableNames}) -} - -func (db *DB) Load(options map[string]string) (int, error) { - return db.intQueryEx("load", options) -} - -func (db *DB) ClearLock(options map[string]string) (bool, error) { - return db.boolQueryEx("lock_clear", options) -} - -func (db *DB) SetLogLevel(level string) (bool, error) { - return db.boolQueryEx("log_level", map[string]string{"level": level}) -} - -func (db *DB) PutLog(level, message string) (bool, error) { - return db.boolQueryEx("log_put", map[string]string{ - "level": level, "message": message}) -} - -func (db *DB) ReopenLog() (bool, error) { - return db.boolQueryEx("log_reopen", nil) -} - -func (db *DB) LogicalCount(options map[string]string) (int, error) { - return db.intQueryEx("logical_count", options) -} - -func (db *DB) Normalize(normalizer, target string, flags []string) ( - string, error) { - options := map[string]string{"normalizer": normalizer, "string": target} - if len(flags) != 0 { - options["flags"] = strings.Join(flags, "|") - } - bytes, err := db.QueryEx("normalize", options) - if err != nil { - return "", err - } - var result map[string]interface{} - if err = json.Unmarshal(bytes, &result); err != nil { - return "", err - } - return result["normalized"].(string), nil -} - -func (db *DB) NormalizerList() ([]string, error) { - bytes, err := db.QueryEx("normalizer_list", nil) - if err != nil { - return nil, err - } - var result []map[string]interface{} - if err = json.Unmarshal(bytes, &result); err != nil { - return nil, err - } - normalizers := make([]string, len(result)) - for i, normalizer := range result { - normalizers[i] = normalizer["name"].(string) - } - return normalizers, nil -} - -func (db *DB) Quit() error { - _, err := db.QueryEx("log_reopen", nil) - return err -} - -// TODO: range_filter - -func (db *DB) Register(path string) (bool, error) { - return db.boolQueryEx("register", map[string]string{"path": path}) -} - -// TODO -func (db *DB) CalcelRequest(id string) ([]byte, error) { - return db.QueryEx("request_cancel", map[string]string{"id": id}) -} - -// TODO -func (db *DB) EvalRuby(script string) ([]byte, error) { - return db.QueryEx("ruby_eval", map[string]string{"script": script}) -} - -// TODO -func (db *DB) LoadRuby(path string) ([]byte, error) { - return db.QueryEx("ruby_load", map[string]string{"path": path}) -} - -type OutputColumn struct { - Name string - Type string - // []bool, [](u)int8/16/32/64, []float64, []time.Time, []string, or ???. - // TODO: Support GeoPoint. - Values interface{} -} - -func (output *OutputColumn) Count() int { - switch values := output.Values.(type) { - case []bool: - return len(values) - case []int8: - return len(values) - case []int32: - return len(values) - case []int64: - return len(values) - case []uint8: - return len(values) - case []uint16: - return len(values) - case []uint32: - return len(values) - case []uint64: - return len(values) - case []float64: - return len(values) - case []time.Time: - return len(values) - case []string: - return len(values) - default: - return 0 - } -} - -func (db *DB) Select(options map[string]string) ([]OutputColumn, error) { - bytes, err := db.QueryEx("select", options) - if err != nil { - return nil, err - } - var result [][][]interface{} - if err = json.Unmarshal(bytes, &result); err != nil { - return nil, err - } - headers := result[0][1] - outputColumns := make([]OutputColumn, len(headers)) - for i := 0; i < len(headers); i++ { - header := headers[i].([]interface{}) - outputColumns[i].Name = header[0].(string) - outputColumns[i].Type = header[1].(string) - } - records := result[0][2:] - for i := 0; i < len(outputColumns); i++ { - switch outputColumns[i].Type { - case "Bool": - values := make([]bool, len(records)) - for j := 0; j < len(records); j++ { - values[j] = records[j][i].(bool) - } - outputColumns[i].Values = values - case "Int8": - values := make([]int8, len(records)) - for j := 0; j < len(records); j++ { - values[j] = int8(records[j][i].(float64)) - } - outputColumns[i].Values = values - case "Int16": - values := make([]int16, len(records)) - for j := 0; j < len(records); j++ { - values[j] = int16(records[j][i].(float64)) - } - outputColumns[i].Values = values - case "Int32": - values := make([]int32, len(records)) - for j := 0; j < len(records); j++ { - values[j] = int32(records[j][i].(float64)) - } - outputColumns[i].Values = values - case "Int64": - values := make([]int64, len(records)) - for j := 0; j < len(records); j++ { - values[j] = int64(records[j][i].(float64)) - } - outputColumns[i].Values = values - case "UInt8": - values := make([]uint8, len(records)) - for j := 0; j < len(records); j++ { - values[j] = uint8(records[j][i].(float64)) - } - outputColumns[i].Values = values - case "UInt16": - values := make([]uint16, len(records)) - for j := 0; j < len(records); j++ { - values[j] = uint16(records[j][i].(float64)) - } - outputColumns[i].Values = values - case "UInt32": - values := make([]uint32, len(records)) - for j := 0; j < len(records); j++ { - values[j] = uint32(records[j][i].(float64)) - } - outputColumns[i].Values = values - case "UInt64": - values := make([]uint64, len(records)) - for j := 0; j < len(records); j++ { - values[j] = uint64(records[j][i].(float64)) - } - outputColumns[i].Values = values - case "Float": - values := make([]float64, len(records)) - for j := 0; j < len(records); j++ { - values[j] = records[j][i].(float64) - } - outputColumns[i].Values = values - case "Time": - values := make([]time.Time, len(records)) - for j := 0; j < len(records); j++ { - microSecondsSinceEpoch := int64(records[j][i].(float64) * 1000000.0) - values[j] = time.Unix(microSecondsSinceEpoch/1000000, - microSecondsSinceEpoch%1000000) - } - outputColumns[i].Values = values - case "ShortText", "Text", "LongText": - values := make([]string, len(records)) - for j := 0; j < len(records); j++ { - values[j] = records[j][i].(string) - } - outputColumns[i].Values = values - case "TokyoGeoPoint": // TODO - return nil, fmt.Errorf("not supported type") - case "WGS84GeoPoint": // TODO - return nil, fmt.Errorf("not supported type") - } - } - return outputColumns, nil -} - -func (db *DB) Shutdown() (bool, error) { - return db.boolQueryEx("shutdown", nil) -} - -func (db *DB) Status() (map[string]interface{}, error) { - bytes, err := db.QueryEx("status", nil) - if err != nil { - return nil, err - } - var result map[string]interface{} - if err = json.Unmarshal(bytes, &result); err != nil { - return nil, err - } - return result, nil -} - -type Candidate struct { - Query string - Score float64 -} - -func (db *DB) Suggest(options map[string]string) ( - map[string][]Candidate, error) { - bytes, err := db.QueryEx("suggest", options) - if err != nil { - return nil, err - } - var result map[string][][]interface{} - if err = json.Unmarshal(bytes, &result); err != nil { - return nil, err - } - suggestResult := make(map[string][]Candidate, len(result)) - for key, value := range result { - var candidates []Candidate - if len(value) > 2 { - value = value[2:] - candidates = make([]Candidate, len(value)) - for i := 0; i < len(value); i++ { - candidates[i].Query = value[i][0].(string) - candidates[i].Score = value[i][1].(float64) - } - } - suggestResult[key] = candidates - } - return suggestResult, nil -} - -func (db *DB) CreateTable(options map[string]string) (bool, error) { - bytes, err := db.QueryEx("table_create", options) - if err != nil { - return false, err - } - return string(bytes) == "true", nil -} - -type Table struct { - ID int - Name string - Path string - Flags string - Domain string - Range string - DefaultTokenizer string - Normalizer string -} - -func (db *DB) TableList() ([]Table, error) { - bytes, err := db.QueryEx("table_list", nil) - if err != nil { - return nil, err - } - var result [][]interface{} - if err = json.Unmarshal(bytes, &result); err != nil { - return nil, err - } - headers := make([]string, len(result[0])) - for i := 0; i < len(headers); i++ { - headers[i] = result[0][i].([]interface{})[0].(string) - } - tables := make([]Table, len(result)-1) - for i := 0; i < len(tables); i++ { - values := result[i+1] - for j := 0; j < len(values); j++ { - switch headers[j] { - case "id": - tables[i].ID = int(values[j].(float64)) - case "name": - tables[i].Name = parseStringOrNil(values[j]) - case "path": - tables[i].Path = parseStringOrNil(values[j]) - case "flags": - tables[i].Flags = parseStringOrNil(values[j]) - case "domain": - tables[i].Domain = parseStringOrNil(values[j]) - case "range": - tables[i].Range = parseStringOrNil(values[j]) - case "default_tokenizer": - tables[i].DefaultTokenizer = parseStringOrNil(values[j]) - case "normalizer": - tables[i].Normalizer = parseStringOrNil(values[j]) - } - } - } - return tables, nil -} - -func (db *DB) RemoveTable(tableName string) (bool, error) { - return db.boolQueryEx("table_remove", map[string]string{"name": tableName}) -} - -type Token struct { - Value string - Position int -} - -func (db *DB) TableTokenize(options map[string]string) ([]Token, error) { - bytes, err := db.QueryEx("table_tokenize", options) - if err != nil { - return nil, err - } - var result []Token - if err = json.Unmarshal(bytes, &result); err != nil { - return nil, err - } - return result, nil -} - -func (db *DB) Tokenize(options map[string]string) ([]Token, error) { - bytes, err := db.QueryEx("tokenize", options) - if err != nil { - return nil, err - } - var result []Token - if err = json.Unmarshal(bytes, &result); err != nil { - return nil, err - } - return result, nil -} - -func (db *DB) TokenizerList() ([]string, error) { - bytes, err := db.QueryEx("tokenizer_list", nil) - if err != nil { - return nil, err - } - var result []map[string]string - if err = json.Unmarshal(bytes, &result); err != nil { - return nil, err - } - tokenizers := make([]string, len(result)) - for i := 0; i < len(result); i++ { - tokenizers[i] = result[i]["name"] - } - return tokenizers, nil -} - -func (db *DB) Truncate(targetName string) (bool, error) { - return db.boolQueryEx("truncate", map[string]string{ - "target_name": targetName}) -} - -func (db *DB) tokenizeCommand(s string) (string, string, bool, error) { - s = strings.TrimLeftFunc(s, unicode.IsSpace) - if len(s) == 0 { - return "", "", false, nil - } - switch s[0] { - case '#': - return "", "", false, nil - case '\'', '"': - quote := s[0] - pos := 1 - hasBackslash := false - for pos < len(s) { - if s[pos] == quote { - break - } else if s[pos] == '\\' { - hasBackslash = true - pos++ - } - pos++ - } - if pos >= len(s) { - return "", "", false, fmt.Errorf("quote missing") - } - token := s[1:pos] - if hasBackslash { - bytes := make([]byte, len(token)) - count := 0 - for i := 0; i < len(token); i++ { - if token[i] == '\\' { - i++ - } - bytes[count] = token[i] - count++ - } - token = string(bytes[:count]) - } - return token, s[pos+1:], true, nil - default: - pos := strings.IndexFunc(s, unicode.IsSpace) - if pos == -1 { - pos = len(s) - } - return s[0:pos], s[pos:], true, nil - } -} - -func (db *DB) tokenizeCommandAll(command string) ([]string, error) { - var tokens []string - s := command - for { - token, rest, ok, err := db.tokenizeCommand(s) - if err != nil { - return nil, err - } - if !ok { - break - } - tokens = append(tokens, token) - s = rest - } - return tokens, nil -} - -var commandOptionKeys = map[string][]string{ - "cache_limit": {"max"}, - "check": {"obj"}, - "column_create": {"table", "name", "flags", "type", "source"}, - "column_list": {"table"}, - "column_remove": {"table", "name"}, - "column_rename": {"table", "name", "new_name"}, - "define_selector": { - "name", "table", "match_columns", "query", "filter", "scorer", "sortby", - "output_columns", "offset", "limit", "drilldown", "drilldown_sortby", - "drilldown_output_columns", "drilldown_offset", "drilldown_limit"}, - "defrag": {"objname", "threshold"}, - "delete": {"table", "key", "id", "filter"}, - "dump": {"tables"}, - "load": {"values", "table", "columns", "ifexists", "input_type"}, - "lock_clear": {"target_name"}, - "log_level": {"level"}, - "log_put": {"level", "message"}, - "log_reopen": {}, - "logical_count": { - "logical_table", "shared_key", "min", "min_border", "max", "max_border", - "filter"}, - "normalize": {"normalizer", "string", "flags"}, - "normalizer_list": {}, - "quit": {}, - // "range_filter": {}, - "register": {"path"}, - "request_cancel": {"id"}, - "ruby_eval": {"script"}, - "ruby_load": {"path"}, - "select": { - "table", "match_columns", "query", "filter", "scorer", "sortby", - "output_columns", "offset", "limit", "drilldown", "drilldown_sortby", - "drilldown_output_columns", "drilldown_offset", "drilldown_limit", - "cache", "match_escalation_threshold", "query_expansion", "query_flags", - "query_expander", "adjuster", "drilldown_calc_types", - "drilldown_calc_target"}, - "shutdown": {}, - "status": {}, - "suggest": {"types", "table", "column", "query", "sortby", "output_columns", - "offset", "limit", "frequency_threshold", - "conditional_probability_threshold", "prefix_search"}, - "table_create": { - "name", "flag", "key_type", "value_type", "default_tokenizer", - "normalizer", "token_filters"}, - "table_list": {}, - "table_remove": {"name"}, - "table_tokenize": {"table", "string", "flags", "mode"}, - "tokenize": { - "tokenizer", "string", "normalizer", "flags", "mode", "token_filters"}, - "tokenizer_list": {}, - "truncate": {"target_name"}} - -func (db *DB) parseCommandOptions(name string, tokens []string) ( - map[string]string, error) { - args := make([]string, 0) - options := make(map[string]string) - for i := 0; i < len(tokens); i++ { - if strings.HasPrefix(tokens[i], "--") { - key := tokens[i][2:] - i++ - if i >= len(tokens) { - return nil, fmt.Errorf("option argument missing") - } - options[key] = tokens[i] - } else { - args = append(args, tokens[i]) - } - } - keys := commandOptionKeys[name] - end := len(keys) - if end > len(args) { - end = len(args) - } - for i := 0; i < end; i++ { - options[keys[i]] = args[i] - } - return options, nil -} - -func (db *DB) ParseCommand(command string) (string, map[string]string, error) { - tokens, err := db.tokenizeCommandAll(command) - if err != nil { - return "", nil, err - } - if len(tokens) == 0 { - return "", nil, nil - } - // Parse tokens. - name := tokens[0] - options, err := db.parseCommandOptions(name, tokens[1:]) - if err != nil { - return "", nil, err - } - return name, options, nil -} Deleted: go/gnx/groonga/groonga_test.go (+0 -1) 100644 =================================================================== --- go/gnx/groonga/groonga_test.go 2015-05-26 11:06:34 +0900 (89681a9) +++ /dev/null @@ -1 +0,0 @@ -package groonga Deleted: go/gnxConsole.go (+0 -98) 100644 =================================================================== --- go/gnxConsole.go 2015-05-26 11:06:34 +0900 (2393d26) +++ /dev/null @@ -1,98 +0,0 @@ -package main - -import "./gnx" -import "bufio" -import "flag" -import "fmt" -import "io" -import "log" -import "os" -import "runtime/pprof" -import "strings" - -// Command-line flags. -var flagNew = flag.Bool("new", false, "create new database") -var flagTemp = flag.Bool("temp", false, "create temporary database") -var flagPartition = flag.Int("partition", 1, "the number of groonga DBs") -var flagProfile = flag.String("profile", "", "the file for cpu profiling") - -func openOrCreateDB() (*gnx.DB, string, error) { - path := "" - if flag.NArg() != 0 { - path = flag.Arg(0) - } - if *flagTemp { - db, dir, err := gnx.CreateTempDB(path, "gnx", *flagPartition) - if err != nil { - log.Println("gnx.CreateTempDB() failed: err =", err) - return nil, "", err - } - return db, dir, err - } - if *flagNew { - db, err := gnx.CreateDB(path, *flagPartition) - if err != nil { - log.Println("gnx.CreateDB() failed: err =", err) - return nil, "", err - } - return db, "", err - } - db, err := gnx.OpenDB(path) - if err != nil { - log.Println("gnx.OpenDB() failed: err =", err) - return nil, "", err - } - return db, "", err -} - -func consoleMain() int { - // Parse command-line options. - flag.Parse() - if *flagProfile != "" { - file, err := os.Create(*flagProfile) - if err != nil { - log.Println("profile failed: err =", err) - return 1 - } - pprof.StartCPUProfile(file) - defer pprof.StopCPUProfile() - } - - // Open or create a database. - db, dir, err := openOrCreateDB() - if err != nil { - return 1 - } - if len(dir) != 0 { - defer os.RemoveAll(dir) - } - defer db.Close() - - // Read lines from the standard input. - console := bufio.NewReader(os.Stdin) - for { - fmt.Print("> ") - line, err := console.ReadString('\n') - if err == io.EOF { - break - } else if err != nil { - log.Println("console error: err =", err) - return 1 - } - command := strings.TrimRight(line, "\r\n") -// name, options, err := db.ParseCommand(command) -// fmt.Println("name:", name) -// fmt.Println("options:", options) - bytes, err := db.Query(command) - if err != nil { - log.Println("query error: err =", err) - } else { - fmt.Println(string(bytes)) - } - } - return 0 -} - -func main() { - os.Exit(consoleMain()) -} Deleted: go/groongaConsole.go (+0 -94) 100644 =================================================================== --- go/groongaConsole.go 2015-05-26 11:06:34 +0900 (6f21f82) +++ /dev/null @@ -1,94 +0,0 @@ -package main - -import "./gnx/groonga" -import "bufio" -import "flag" -import "fmt" -import "io" -import "log" -import "os" -import "strings" - -// Command-line flags. -var flagNew = flag.Bool("new", false, "create new database") -var flagTemp = flag.Bool("temp", false, "create temporary database") - -func openOrCreateDB() (*groonga.DB, string, error) { - path := "" - if flag.NArg() != 0 { - path = flag.Arg(0) - } - if *flagTemp { - db, dir, err := groonga.CreateTempDB(path, "groonga") - if err != nil { - log.Println("groonga.CreateTempDB() failed: err =", err) - return nil, "", err - } - return db, dir, err - } - if *flagNew { - db, err := groonga.CreateDB(path) - if err != nil { - log.Println("groonga.CreateDB() failed: err =", err) - return nil, "", err - } - return db, "", err - } - db, err := groonga.OpenDB(path) - if err != nil { - log.Println("groonga.OpenDB() failed: err =", err) - return nil, "", err - } - return db, "", err -} - -func consoleMain() int { - // Parse command-line options. - flag.Parse() - - // Open or create a database. - db, dir, err := openOrCreateDB() - if err != nil { - return 1 - } - if len(dir) != 0 { - defer os.RemoveAll(dir) - } - defer db.Close() - - // Read lines from the standard input. - console := bufio.NewReader(os.Stdin) - for { - fmt.Print("> ") - line, err := console.ReadString('\n') - if err == io.EOF { - break - } else if err != nil { - log.Println("console error: err =", err) - return 1 - } - command := strings.TrimRight(line, "\r\n") - bytes, err := db.Query(command) - if err != nil { - log.Println("query error: err =", err) - } else { - fmt.Println(string(bytes)) - } - - name, options, err := db.ParseCommand(command) - fmt.Println("name:", name) - fmt.Println("options:", options) - if name == "select" { - records, err := db.Select(options) - if err != nil { - log.Println("select error: err =", err) - } - fmt.Println("records:", records) - } - } - return 0 -} - -func main() { - os.Exit(consoleMain()) -} Deleted: go2/.gitignore (+0 -3) 100644 =================================================================== --- go2/.gitignore 2015-05-26 11:06:34 +0900 (4bf0c25) +++ /dev/null @@ -1,3 +0,0 @@ -*.prof -benchmark -gnxTest Deleted: go2/benchmark.go (+0 -698) 100644 =================================================================== --- go2/benchmark.go 2015-05-26 11:06:34 +0900 (76739a7) +++ /dev/null @@ -1,698 +0,0 @@ -package main - -import "./gnx" - -import "bufio" -import "flag" -import "fmt" -import "log" -import "math/rand" -import "os" -import "runtime" -import "runtime/pprof" -import "strconv" -import "strings" -import "time" -import "unicode" - -var flagMode = flag.String("mode", "benchmark", "mode (run or print)") -var flagKey = flag.String("key", "", "key data type") -var flagColumns = flag.String("columns", "Bool,Int16,Float,Text", - "comma-separated column data types") -var flagRows = flag.Int("rows", 1000000, "number of rows") -var flagBlock = flag.Int("block", 10, "number of rows per command") -var flagPartition = flag.Int("partition", 1, "number of groonga DBs") -var flagCPU = flag.Int("cpu", 1, "number of CPU cores") - -var tableName = "Table" -var columnTypes []string -var columnNames []string - -func generateCommands() []string { - var commands []string - if *flagKey == "" { - commands = append(commands, - fmt.Sprintf("table_create %s TABLE_NO_KEY", tableName)) - } else { - commands = append(commands, - fmt.Sprintf("table_create %s TABLE_PAT_KEY %s", tableName, *flagKey)) - columnTypes = append(columnTypes, *flagKey) - columnNames = append(columnNames, "_key") - } - - if *flagColumns != "" { - tokens := strings.Split(*flagColumns, ",") - for _, token := range tokens { - columnType := strings.TrimFunc(token, unicode.IsSpace) - if columnType != "" { - columnID := len(columnTypes) - columnTypes = append(columnTypes, columnType) - columnName := fmt.Sprintf("Col%d", columnID) - columnNames = append(columnNames, columnName) - commands = append(commands, - fmt.Sprintf("column_create %s %s COLUMN_SCALAR %s", - tableName, columnName, columnType)) - switch columnType { - case "Text", "LongText": - const tokenizerOption = "--default_tokenizer TokenBigram" - commands = append(commands, fmt.Sprintf( - "table_create Idx%d TABLE_PAT_KEY ShortText %s", - columnID, tokenizerOption)) - commands = append(commands, fmt.Sprintf( - "column_create Idx%d Idx COLUMN_INDEX|WITH_POSITION %s Col%d", - columnID, tableName, columnID)) - } - } - } - } - return commands -} - -func generateSource(columnType string) interface{} { - switch columnType { - case "Bool": - values := make([]gnx.Bool, *flagRows) - for i := 0; i < len(values); i++ { - if (rand.Int() % 2) == 1 { - values[i] = gnx.TRUE - } else { - values[i] = gnx.FALSE - } - } - return values - case "Int8": - values := make([]gnx.Int, *flagRows) - for i := 0; i < len(values); i++ { - values[i] = gnx.Int(rand.Int() % 128) - } - return values - case "Int16": - values := make([]gnx.Int, *flagRows) - for i := 0; i < len(values); i++ { - values[i] = gnx.Int(rand.Int() % 32768) - } - return values - case "Int32": - values := make([]gnx.Int, *flagRows) - for i := 0; i < len(values); i++ { - values[i] = gnx.Int(rand.Int31()) - } - return values - case "Int64": - values := make([]gnx.Int, *flagRows) - for i := 0; i < len(values); i++ { - values[i] = gnx.Int(rand.Int31()) - } - return values - - return rand.Int63() - case "UInt8": - values := make([]gnx.Int, *flagRows) - for i := 0; i < len(values); i++ { - values[i] = gnx.Int(rand.Int() % 256) - } - return values - case "UInt16": - values := make([]gnx.Int, *flagRows) - for i := 0; i < len(values); i++ { - values[i] = gnx.Int(rand.Int() % 65536) - } - return values - case "UInt32": - values := make([]gnx.Int, *flagRows) - for i := 0; i < len(values); i++ { - values[i] = gnx.Int(rand.Uint32()) - } - return values - case "UInt64": - values := make([]gnx.Int, *flagRows) - for i := 0; i < len(values); i++ { - values[i] = gnx.Int(rand.Int63()) - } - return values - case "Float": - values := make([]gnx.Float, *flagRows) - for i := 0; i < len(values); i++ { - values[i] = gnx.Float(rand.Float64()) - } - return values - case "ShortText": - values := make([]gnx.Text, *flagRows) - for i := 0; i < len(values); i++ { - values[i] = gnx.Text(strconv.Itoa(int(rand.Int31()))) - } - return values - case "Text", "LongText": - values := make([]gnx.Text, *flagRows) - scanner := bufio.NewScanner(os.Stdin) - for i := 0; i < len(values); i++ { - if scanner.Scan() { - values[i] = gnx.Text(scanner.Text()) - } else { - values[i] = gnx.Text(strconv.Itoa(int(rand.Int31()))) - } - } - return values - default: - log.Fatalln("unsupported value type: name =", columnType) - return nil - } -} - -func generateSources() []interface{} { - var sources []interface{} - for _, columnType := range columnTypes { - sources = append(sources, generateSource(columnType)) - } - return sources -} - -func benchmarkLoad(commands []string, sources []interface{}) { - fmt.Println("benchmarkLoad()") - - var recordsList [][][]gnx.Valuer - for i := 0; i < *flagRows; i += *flagBlock { - var records [][]gnx.Valuer - for j := 0; j < *flagBlock; j++ { - id := i + j - if id >= *flagRows { - break - } - record := make([]gnx.Valuer, len(sources)) - for k, source := range sources { - switch values := source.(type) { - case []gnx.Bool: - record[k] = values[id] - case []gnx.Int: - record[k] = values[id] - case []gnx.Float: - record[k] = values[id] - case []gnx.Text: - record[k] = values[id] - default: - log.Fatalln("unsupported value type") - } - } - records = append(records, record) - } - recordsList = append(recordsList, records) - } -// fmt.Println(recordsList) - - db, dir, err := gnx.CreateTempDB("", "gnx-benchmark", *flagPartition) - if err != nil { - log.Fatalln(err) - } - defer os.RemoveAll(dir) - defer db.Close() - for _, command := range commands { - for i := 0; i < *flagPartition; i++ { -// fmt.Println(command) - if _, err := db.GroongaQuery(i, command); err != nil { - log.Fatalln(err) - } - } - } - - file, err := os.Create("Load.prof") - if err != nil { - log.Fatalln(err) - } - defer file.Close() - if err := pprof.StartCPUProfile(file); err != nil { - log.Fatalln(err) - } - defer pprof.StopCPUProfile() - - startTime := time.Now() - for _, records := range recordsList { - if _, err := db.Load(tableName, columnNames, records); err != nil { - log.Fatalln(err) - } - } - endTime := time.Now() - fmt.Println("elapsed:", endTime.Sub(startTime)) -} - -func benchmarkLoadMap(commands []string, sources []interface{}) { - fmt.Println("benchmarkLoadMap()") - - var recordMapsList [][]map[string]gnx.Valuer - for i := 0; i < *flagRows; i += *flagBlock { - var recordMaps []map[string]gnx.Valuer - for j := 0; j < *flagBlock; j++ { - id := i + j - if id >= *flagRows { - break - } - recordMap := make(map[string]gnx.Valuer) - for k, source := range sources { - switch values := source.(type) { - case []gnx.Bool: - recordMap[columnNames[k]] = values[id] - case []gnx.Int: - recordMap[columnNames[k]] = values[id] - case []gnx.Float: - recordMap[columnNames[k]] = values[id] - case []gnx.Text: - recordMap[columnNames[k]] = values[id] - default: - log.Fatalln("unsupported value type") - } - } - recordMaps = append(recordMaps, recordMap) - } - recordMapsList = append(recordMapsList, recordMaps) - } -// fmt.Println(recordMapsList) - - db, dir, err := gnx.CreateTempDB("", "gnx-benchmark", *flagPartition) - if err != nil { - log.Fatalln(err) - } - defer os.RemoveAll(dir) - defer db.Close() - for _, command := range commands { - for i := 0; i < *flagPartition; i++ { -// fmt.Println(command) - if _, err := db.GroongaQuery(i, command); err != nil { - log.Fatalln(err) - } - } - } - - file, err := os.Create("LoadMap.prof") - if err != nil { - log.Fatalln(err) - } - defer file.Close() - if err := pprof.StartCPUProfile(file); err != nil { - log.Fatalln(err) - } - defer pprof.StopCPUProfile() - - startTime := time.Now() - for _, recordMaps := range recordMapsList { - if _, err := db.LoadMap(tableName, recordMaps); err != nil { - log.Fatalln(err) - } - } - endTime := time.Now() - fmt.Println("elapsed:", endTime.Sub(startTime)) -} - -func benchmarkLoadC(commands []string, sources []interface{}) { - fmt.Println("benchmarkLoadC()") - - var columnarRecordsList [][]interface{} - for i := 0; i < *flagRows; i += *flagBlock { - columnarRecords := make([]interface{}, len(sources)) - begin := i - end := begin + *flagBlock - if end > *flagRows { - end = *flagRows - } - for j, source := range sources { - switch values := source.(type) { - case []gnx.Bool: - columnarRecords[j] = values[begin:end] - case []gnx.Int: - columnarRecords[j] = values[begin:end] - case []gnx.Float: - columnarRecords[j] = values[begin:end] - case []gnx.Text: - columnarRecords[j] = values[begin:end] - default: - log.Fatalln("unsupported value type") - } - } - columnarRecordsList = append(columnarRecordsList, columnarRecords) - } -// fmt.Println(columnarRecordsList) - - db, dir, err := gnx.CreateTempDB("", "gnx-benchmark", *flagPartition) - if err != nil { - log.Fatalln(err) - } - defer os.RemoveAll(dir) - defer db.Close() - for _, command := range commands { - for i := 0; i < *flagPartition; i++ { -// fmt.Println(command) - if _, err := db.GroongaQuery(i, command); err != nil { - log.Fatalln(err) - } - } - } - - file, err := os.Create("LoadC.prof") - if err != nil { - log.Fatalln(err) - } - defer file.Close() - if err := pprof.StartCPUProfile(file); err != nil { - log.Fatalln(err) - } - defer pprof.StopCPUProfile() - - startTime := time.Now() - for _, columnarRecords := range columnarRecordsList { - _, err := db.LoadC(tableName, columnNames, columnarRecords) - if err != nil { - log.Fatalln(err) - } - } - endTime := time.Now() - fmt.Println("elapsed:", endTime.Sub(startTime)) -} - -func benchmarkLoadCMap(commands []string, sources []interface{}) { - fmt.Println("benchmarkLoadCMap()") - - var columnarRecordsMaps []map[string]interface{} - for i := 0; i < *flagRows; i += *flagBlock { - columnarRecordsMap := make(map[string]interface{}) - begin := i - end := begin + *flagBlock - if end > *flagRows { - end = *flagRows - } - for j, source := range sources { - switch values := source.(type) { - case []gnx.Bool: - columnarRecordsMap[columnNames[j]] = values[begin:end] - case []gnx.Int: - columnarRecordsMap[columnNames[j]] = values[begin:end] - case []gnx.Float: - columnarRecordsMap[columnNames[j]] = values[begin:end] - case []gnx.Text: - columnarRecordsMap[columnNames[j]] = values[begin:end] - default: - log.Fatalln("unsupported value type") - } - } - columnarRecordsMaps = append(columnarRecordsMaps, columnarRecordsMap) - } -// fmt.Println(columnarRecordsMaps) - - db, dir, err := gnx.CreateTempDB("", "gnx-benchmark", *flagPartition) - if err != nil { - log.Fatalln(err) - } - defer os.RemoveAll(dir) - defer db.Close() - for _, command := range commands { - for i := 0; i < *flagPartition; i++ { -// fmt.Println(command) - if _, err := db.GroongaQuery(i, command); err != nil { - log.Fatalln(err) - } - } - } - - file, err := os.Create("LoadCMap.prof") - if err != nil { - log.Fatalln(err) - } - defer file.Close() - if err := pprof.StartCPUProfile(file); err != nil { - log.Fatalln(err) - } - defer pprof.StopCPUProfile() - - startTime := time.Now() - for _, columnarRecordsMap := range columnarRecordsMaps { - _, err := db.LoadCMap(tableName, columnarRecordsMap) - if err != nil { - log.Fatalln(err) - } - } - endTime := time.Now() - fmt.Println("elapsed:", endTime.Sub(startTime)) -} - -func benchmarkDirect(commands []string, sources []interface{}) { - fmt.Println("benchmarkDirect()") - -// fmt.Println(sources) - - db, dir, err := gnx.CreateTempDB("", "gnx-benchmark", *flagPartition) - if err != nil { - log.Fatalln(err) - } - defer os.RemoveAll(dir) - defer db.Close() - for _, command := range commands { - for i := 0; i < *flagPartition; i++ { -// fmt.Println(command) - if _, err := db.GroongaQuery(i, command); err != nil { - log.Fatalln(err) - } - } - } - - file, err := os.Create("Direct.prof") - if err != nil { - log.Fatalln(err) - } - defer file.Close() - if err := pprof.StartCPUProfile(file); err != nil { - log.Fatalln(err) - } - defer pprof.StopCPUProfile() - - startTime := time.Now() - var rowIDs []gnx.Int - if *flagKey == "" { - for i := 0; i < *flagRows; i++ { - _, rowID, err := db.InsertRow(tableName, nil) - if err != nil { - log.Fatalln(err) - } - rowIDs = append(rowIDs, rowID) - } - } else { - switch keys := sources[0].(type) { - case []gnx.Int: - for _, key := range keys { - _, rowID, err := db.InsertRow(tableName, key) - if err != nil { - log.Fatalln(err) - } - rowIDs = append(rowIDs, rowID) - } - case []gnx.Float: - for _, key := range keys { - _, rowID, err := db.InsertRow(tableName, key) - if err != nil { - log.Fatalln(err) - } - rowIDs = append(rowIDs, rowID) - } - case []gnx.Text: - for _, key := range keys { - _, rowID, err := db.InsertRow(tableName, key) - if err != nil { - log.Fatalln(err) - } - rowIDs = append(rowIDs, rowID) - } - default: - log.Fatalln("unsupported key type") - } - } - for i, source := range sources { - if columnNames[i] == "_key" { - continue - } - switch values := source.(type) { - case []gnx.Bool: - for j, value := range values { - err := db.SetValue(tableName, columnNames[i], rowIDs[j], value) - if err != nil { - log.Fatalln(err) - } - } - case []gnx.Int: - for j, value := range values { - err := db.SetValue(tableName, columnNames[i], rowIDs[j], value) - if err != nil { - log.Fatalln(err) - } - } - case []gnx.Float: - for j, value := range values { - err := db.SetValue(tableName, columnNames[i], rowIDs[j], value) - if err != nil { - log.Fatalln(err) - } - } - case []gnx.Text: - for j, value := range values { - err := db.SetValue(tableName, columnNames[i], rowIDs[j], value) - if err != nil { - log.Fatalln(err) - } - } - } - } - endTime := time.Now() - fmt.Println("elapsed:", endTime.Sub(startTime)) -} - -func benchmarkDirect2(commands []string, sources []interface{}) { - fmt.Println("benchmarkDirect2()") - -// fmt.Println(sources) - - db, dir, err := gnx.CreateTempDB("", "gnx-benchmark", *flagPartition) - if err != nil { - log.Fatalln(err) - } - defer os.RemoveAll(dir) - defer db.Close() - for _, command := range commands { - for i := 0; i < *flagPartition; i++ { -// fmt.Println(command) - if _, err := db.GroongaQuery(i, command); err != nil { - log.Fatalln(err) - } - } - } - - file, err := os.Create("Direct2.prof") - if err != nil { - log.Fatalln(err) - } - defer file.Close() - if err := pprof.StartCPUProfile(file); err != nil { - log.Fatalln(err) - } - defer pprof.StopCPUProfile() - - startTime := time.Now() - table, err := db.FindTable(tableName) - if err != nil { - log.Fatalln(err) - } - var columns []*gnx.Column - for _, columnName := range columnNames { - column, err := db.FindColumn(table, columnName) - if err != nil { - log.Fatalln(err) - } - columns = append(columns, column) - } - var rowIDs []gnx.Int - if *flagKey == "" { - for i := 0; i < *flagRows; i++ { - _, rowID, err := db.InsertRow2(table, nil) - if err != nil { - log.Fatalln(err) - } - rowIDs = append(rowIDs, rowID) - } - } else { - switch keys := sources[0].(type) { - case []gnx.Int: - for _, key := range keys { - _, rowID, err := db.InsertRow2(table, key) - if err != nil { - log.Fatalln(err) - } - rowIDs = append(rowIDs, rowID) - } - case []gnx.Float: - for _, key := range keys { - _, rowID, err := db.InsertRow2(table, key) - if err != nil { - log.Fatalln(err) - } - rowIDs = append(rowIDs, rowID) - } - case []gnx.Text: - for _, key := range keys { - _, rowID, err := db.InsertRow2(table, key) - if err != nil { - log.Fatalln(err) - } - rowIDs = append(rowIDs, rowID) - } - default: - log.Fatalln("unsupported key type") - } - } - for i, source := range sources { - if columnNames[i] == "_key" { - continue - } - switch values := source.(type) { - case []gnx.Bool: - for j, value := range values { - err := db.SetValue2(columns[i], rowIDs[j], value) - if err != nil { - log.Fatalln(err) - } - } - case []gnx.Int: - for j, value := range values { - err := db.SetValue2(columns[i], rowIDs[j], value) - if err != nil { - log.Fatalln(err) - } - } - case []gnx.Float: - for j, value := range values { - err := db.SetValue2(columns[i], rowIDs[j], value) - if err != nil { - log.Fatalln(err) - } - } - case []gnx.Text: - for j, value := range values { - err := db.SetValue2(columns[i], rowIDs[j], value) - if err != nil { - log.Fatalln(err) - } - } - } - } - endTime := time.Now() - fmt.Println("elapsed:", endTime.Sub(startTime)) -} - -func benchmark() { - if *flagCPU == 0 { - runtime.GOMAXPROCS(runtime.NumCPU()) - } else { - runtime.GOMAXPROCS(*flagCPU) - } - commands := generateCommands() - sources := generateSources() - - benchmarkLoad(commands, sources) - benchmarkLoadMap(commands, sources) - benchmarkLoadC(commands, sources) - benchmarkLoadCMap(commands, sources) - benchmarkDirect(commands, sources) - benchmarkDirect2(commands, sources) -} - -func print() { - commands := generateCommands() - for _, command := range commands { - fmt.Println(command) - } -} - -func main() { - flag.Parse() - switch *flagMode { - case "benchmark": - benchmark() - case "print": - print() - default: - log.Fatalln("undefined mode") - } -} Deleted: go2/gnx/gnx.cpp (+0 -355) 100644 =================================================================== --- go2/gnx/gnx.cpp 2015-05-26 11:06:34 +0900 (d1feeed) +++ /dev/null @@ -1,355 +0,0 @@ -#include "gnx.h" - -#include <string.h> - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -gnx_bool gnx_insert_row(grn_ctx *ctx, const char *table_name, - gnx_data_type key_type, const void *key, - gnx_int *row_id) { - grn_obj *table = grn_ctx_get(ctx, table_name, strlen(table_name)); - if (!table) { - *row_id = GNX_NA_INT; - return GNX_NA_BOOL; - } - return gnx_insert_row2(ctx, table, key_type, key, row_id); -} - -gnx_bool gnx_insert_row2(grn_ctx *ctx, grn_obj *table, - gnx_data_type key_type, const void *key, - gnx_int *row_id) { - // TODO: type check. - unsigned int key_size = 0; - switch (key_type) { - case GNX_NA: { - key = nullptr; - break; - } - case GNX_INT: { - key_size = sizeof(gnx_int); - break; - } - case GNX_FLOAT: { - key_size = sizeof(gnx_float); - break; - } - case GNX_GEO_POINT: { - key_size = sizeof(gnx_geo_point); - break; - } - case GNX_TEXT: { - gnx_text text = *static_cast<const gnx_text *>(key); - key = text.data; - key_size = text.size; - break; - } - default: { - *row_id = GNX_NA_INT; - return GNX_NA_BOOL; - } - } - int added; - grn_id id = grn_table_add(ctx, table, key, key_size, &added); - if (id == GRN_ID_NIL) { - *row_id = GNX_NA_INT; - return GNX_NA_BOOL; - } - *row_id = id; - return added ? GNX_TRUE : GNX_FALSE; -} - -gnx_bool gnx_set_value(grn_ctx *ctx, const char *table_name, - const char *column_name, gnx_int row_id, - gnx_data_type value_type, const void *value) { - grn_obj *table = grn_ctx_get(ctx, table_name, strlen(table_name)); - if (!table) { - return GNX_NA_BOOL; - } - grn_obj *column = grn_obj_column( - ctx, table, column_name, strlen(column_name)); - if (!column) { - return GNX_NA_BOOL; - } - return gnx_set_value2(ctx, column, row_id, value_type, value); -} - -gnx_bool gnx_set_value2(grn_ctx *ctx, grn_obj *column, gnx_int row_id, - gnx_data_type value_type, const void *value) { - grn_obj obj; - switch (value_type) { -// case GNX_NA: { -// break; -// } - case GNX_BOOL: { - GRN_BOOL_INIT(&obj, 0); - GRN_BOOL_SET(ctx, &obj, - *static_cast<const gnx_bool *>(value) == GNX_TRUE); - break; - } - case GNX_INT: { - GRN_INT64_INIT(&obj, 0); - GRN_INT64_SET(ctx, &obj, *static_cast<const gnx_int *>(value)); - break; - } - case GNX_FLOAT: { - GRN_FLOAT_INIT(&obj, 0); - GRN_FLOAT_SET(ctx, &obj, *static_cast<const gnx_float *>(value)); - break; - } - case GNX_GEO_POINT: { - gnx_geo_point geo_point = *static_cast<const gnx_geo_point *>(value); - GRN_WGS84_GEO_POINT_INIT(&obj, 0); - GRN_GEO_POINT_SET(ctx, &obj, geo_point.latitude, geo_point.longitude); - break; - } - case GNX_TEXT: { - gnx_text text = *static_cast<const gnx_text *>(value); - GRN_TEXT_INIT(&obj, 0); - GRN_TEXT_SET(ctx, &obj, text.data, text.size); - break; - } - default: { - return GNX_NA_BOOL; - } - } - grn_rc rc = grn_obj_set_value(ctx, column, row_id, &obj, GRN_OBJ_SET); - GRN_OBJ_FIN(ctx, &obj); - if (rc != GRN_SUCCESS) { - return GNX_NA_BOOL; - } - return GNX_TRUE; -} - - -gnx_int gnx_insert_rows(grn_ctx *ctx, const char *table_name, - gnx_int num_keys, gnx_data_type key_type, - const void *keys, gnx_int *row_ids, - gnx_bool *inserted) { - grn_obj *table = grn_ctx_get(ctx, table_name, strlen(table_name)); - if (!table) { - return GNX_NA_BOOL; - } - return gnx_insert_rows2(ctx, table, num_keys, key_type, keys, row_ids, - inserted); -} - -gnx_int gnx_insert_rows2(grn_ctx *ctx, grn_obj *table, - gnx_int num_keys, gnx_data_type key_type, - const void *keys, gnx_int *row_ids, - gnx_bool *inserted) { - // TODO: type check. - gnx_int count = 0; - switch (key_type) { - case GNX_NA: { - for (gnx_int i = 0; i < num_keys; ++i) { - int added; - grn_id id = grn_table_add(ctx, table, nullptr, 0, &added); - if (id == GRN_ID_NIL) { - row_ids[i] = GNX_NA_INT; - } else { - row_ids[i] = id; - ++count; - } - inserted[i] = added ? GNX_TRUE : GNX_FALSE; - } - break; - } - case GNX_INT: { - const gnx_int *int_keys = static_cast<const gnx_int *>(keys); - for (gnx_int i = 0; i < num_keys; ++i) { - int added; - grn_id id = grn_table_add(ctx, table, &int_keys[i], - sizeof(gnx_int), &added); - if (id == GRN_ID_NIL) { - row_ids[i] = GNX_NA_INT; - } else { - row_ids[i] = id; - ++count; - } - inserted[i] = added ? GNX_TRUE : GNX_FALSE; - } - break; - } - case GNX_FLOAT: { - const gnx_float *float_keys = static_cast<const gnx_float *>(keys); - for (gnx_int i = 0; i < num_keys; ++i) { - int added; - grn_id id = grn_table_add(ctx, table, &float_keys[i], - sizeof(gnx_float), &added); - if (id == GRN_ID_NIL) { - row_ids[i] = GNX_NA_INT; - } else { - row_ids[i] = id; - ++count; - } - inserted[i] = added ? GNX_TRUE : GNX_FALSE; - } - break; - } - case GNX_GEO_POINT: { - const gnx_geo_point *geo_point_keys = - static_cast<const gnx_geo_point *>(keys); - for (gnx_int i = 0; i < num_keys; ++i) { - int added; - grn_id id = grn_table_add(ctx, table, &geo_point_keys[i], - sizeof(gnx_geo_point), &added); - if (id == GRN_ID_NIL) { - row_ids[i] = GNX_NA_INT; - } else { - row_ids[i] = id; - ++count; - } - inserted[i] = added ? GNX_TRUE : GNX_FALSE; - } - break; - } - case GNX_TEXT: { - const gnx_text *text_keys = static_cast<const gnx_text *>(keys); - for (gnx_int i = 0; i < num_keys; ++i) { - const void *key = text_keys[i].data; - unsigned int key_size = text_keys[i].size; - int added; - grn_id id = grn_table_add(ctx, table, key, key_size, &added); - if (id == GRN_ID_NIL) { - row_ids[i] = GNX_NA_INT; - } else { - row_ids[i] = id; - ++count; - } - inserted[i] = added ? GNX_TRUE : GNX_FALSE; - } - break; - } - default: { - return GNX_NA_INT; - } - } - return count; -} - -gnx_int gnx_set_values(grn_ctx *ctx, const char *table_name, - const char *column_name, gnx_int num_values, - const gnx_int *row_ids, gnx_data_type value_type, - const void *values, gnx_bool *updated) { - grn_obj *table = grn_ctx_get(ctx, table_name, strlen(table_name)); - if (!table) { - return GNX_NA_BOOL; - } - grn_obj *column = grn_obj_column( - ctx, table, column_name, strlen(column_name)); - if (!column) { - return GNX_NA_BOOL; - } - return gnx_set_values2(ctx, table, column, num_values, row_ids, - value_type, values, updated); -} - -gnx_int gnx_set_values2(grn_ctx *ctx, grn_obj *table, grn_obj *column, - gnx_int num_values, const gnx_int *row_ids, - gnx_data_type value_type, const void *values, - gnx_bool *updated) { - gnx_int count = 0; - switch (value_type) { -// case GNX_NA: { -// break; -// } - case GNX_BOOL: { - grn_obj obj; - GRN_BOOL_INIT(&obj, 0); - for (gnx_int i = 0; i < num_values; ++i) { - GRN_BOOL_SET(ctx, &obj, - static_cast<const gnx_bool *>(values)[i] == GNX_TRUE); - grn_rc rc = grn_obj_set_value(ctx, column, row_ids[i], &obj, - GRN_OBJ_SET); - if (rc == GRN_SUCCESS) { - updated[i] = GNX_TRUE; - ++count; - } else { - updated[i] = GNX_FALSE; - } - } - GRN_OBJ_FIN(ctx, &obj); - break; - } - case GNX_INT: { - grn_obj obj; - GRN_INT64_INIT(&obj, 0); - for (gnx_int i = 0; i < num_values; ++i) { - GRN_INT64_SET(ctx, &obj, static_cast<const gnx_int *>(values)[i]); - grn_rc rc = grn_obj_set_value(ctx, column, row_ids[i], &obj, - GRN_OBJ_SET); - if (rc == GRN_SUCCESS) { - updated[i] = GNX_TRUE; - ++count; - } else { - updated[i] = GNX_FALSE; - } - } - GRN_OBJ_FIN(ctx, &obj); - break; - } - case GNX_FLOAT: { - grn_obj obj; - GRN_FLOAT_INIT(&obj, 0); - for (gnx_int i = 0; i < num_values; ++i) { - GRN_FLOAT_SET(ctx, &obj, static_cast<const gnx_float *>(values)[i]); - grn_rc rc = grn_obj_set_value(ctx, column, row_ids[i], &obj, - GRN_OBJ_SET); - if (rc == GRN_SUCCESS) { - updated[i] = GNX_TRUE; - ++count; - } else { - updated[i] = GNX_FALSE; - } - } - GRN_OBJ_FIN(ctx, &obj); - break; - } - case GNX_GEO_POINT: { - grn_obj obj; - GRN_WGS84_GEO_POINT_INIT(&obj, 0); - for (gnx_int i = 0; i < num_values; ++i) { - gnx_geo_point value = static_cast<const gnx_geo_point *>(values)[i]; - GRN_GEO_POINT_SET(ctx, &obj, value.latitude, value.longitude); - grn_rc rc = grn_obj_set_value(ctx, column, row_ids[i], &obj, - GRN_OBJ_SET); - if (rc == GRN_SUCCESS) { - updated[i] = GNX_TRUE; - ++count; - } else { - updated[i] = GNX_FALSE; - } - } - GRN_OBJ_FIN(ctx, &obj); - break; - } - case GNX_TEXT: { - grn_obj obj; - GRN_TEXT_INIT(&obj, 0); - for (gnx_int i = 0; i < num_values; ++i) { - gnx_text text = static_cast<const gnx_text *>(values)[i]; - GRN_TEXT_SET(ctx, &obj, text.data, text.size); - grn_rc rc = grn_obj_set_value(ctx, column, row_ids[i], &obj, - GRN_OBJ_SET); - if (rc == GRN_SUCCESS) { - updated[i] = GNX_TRUE; - ++count; - } else { - updated[i] = GNX_FALSE; - } - } - GRN_OBJ_FIN(ctx, &obj); - break; - } - default: { - return GNX_NA_INT; - } - } - return count; -} - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus Deleted: go2/gnx/gnx.go (+0 -1258) 100644 =================================================================== --- go2/gnx/gnx.go 2015-05-26 11:06:34 +0900 (d24792c) +++ /dev/null @@ -1,1258 +0,0 @@ -package gnx - -/* -#cgo CXXFLAGS: -std=c++11 -#cgo LDFLAGS: -lgrnxx -lstdc++ -#cgo pkg-config: groonga -#include <groonga.h> -#include <stdlib.h> -#include "gnx.h" -*/ -import "C" - -import ( - "encoding/binary" - "encoding/json" - "fmt" - "hash/fnv" - "io/ioutil" - "math" - "math/rand" - "os" - "strconv" - "strings" - "unsafe" -) - -// -- Data types -- - -type Bool uint8 -type Int int64 -type Float float64 -type GeoPoint struct { - Latitude int32 - Longitude int32 -} -type Text []byte -type BoolVector []Bool -type IntVector []Int -type FloatVector []Float -type GeoPointVector []GeoPoint -type TextVector []Text - -const ( - FALSE = Bool(0) - TRUE = Bool(3) -) - -type Valuer interface { - IsNA() bool -} - -func NABool() Bool { - return Bool(1) -} -func NAInt() Int { - return Int(math.MinInt64) -} -func NAFloat() Float { - return Float(math.NaN()) -} -func NAGeoPoint() GeoPoint { - return GeoPoint{math.MinInt32, math.MinInt32} -} -func NAText() Text { - return nil -} -func NABoolVector() BoolVector { - return nil -} -func NAIntVector() IntVector { - return nil -} -func NAFloatVector() FloatVector { - return nil -} -func NAGeoPointVector() GeoPointVector { - return nil -} -func NATextVector() TextVector { - return nil -} - -func (this Bool) IsNA() bool { - return this == 1 -} -func (this Int) IsNA() bool { - return this == math.MinInt64 -} -func (this Float) IsNA() bool { - return math.IsNaN(float64(this)) -} -func (this GeoPoint) IsNA() bool { - return this.Latitude == math.MinInt32 -} -func (this Text) IsNA() bool { - return this == nil -} -func (this BoolVector) IsNA() bool { - return this == nil -} -func (this IntVector) IsNA() bool { - return this == nil -} -func (this FloatVector) IsNA() bool { - return this == nil -} -func (this GeoPointVector) IsNA() bool { - return this == nil -} -func (this TextVector) IsNA() bool { - return this == nil -} - -func (this GeoPoint) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf("%dx%d", this.Latitude, this.Longitude)), nil -} -func (this Text) MarshalJSON() ([]byte, error) { - return json.Marshal(string(this)) -} - -// -- Common -- - -func countColumnarRecords(columnarRecords []interface{}) (int, error) { - numRecords := -1 - for _, columnarValues := range columnarRecords { - var thisLen int - switch values := columnarValues.(type) { - case []Bool: - thisLen = len(values) - case []Int: - thisLen = len(values) - case []Float: - thisLen = len(values) - case []GeoPoint: - thisLen = len(values) - case []Text: - thisLen = len(values) - case []BoolVector: - thisLen = len(values) - case []IntVector: - thisLen = len(values) - case []FloatVector: - thisLen = len(values) - case []GeoPointVector: - thisLen = len(values) - case []TextVector: - thisLen = len(values) - default: - return 0, fmt.Errorf("unsupported data type") - } - if numRecords == -1 { - numRecords = thisLen - } else if thisLen != numRecords { - return 0, fmt.Errorf("length conflict: numRecords = %d, thisLen = %d", - numRecords, thisLen) - } - } - if numRecords <= 0 { - return 0, fmt.Errorf("no input") - } - return numRecords, nil -} - -// -- GroongaDB -- - -type GroongaDB struct { - ctx *C.grn_ctx -} - -type GroongaTable struct { - obj *C.grn_obj -} - -type GroongaColumn struct { - obj *C.grn_obj -} - -var groongaInitCount = 0 - -func DisableGroongaInitCount() { - groongaInitCount = -1 -} - -func initGroonga() error { - switch groongaInitCount { - 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) - } - } - groongaInitCount++ - return nil -} - -func finGroonga() error { - switch groongaInitCount { - 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) - } - } - groongaInitCount-- - return nil -} - -func CreateGroongaDB(path string) (*GroongaDB, error) { - if err := initGroonga(); err != nil { - return nil, err - } - ctx := C.grn_ctx_open(0) - if ctx == nil { - finGroonga() - return nil, fmt.Errorf("grn_ctx_open() failed") - } - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - if db := C.grn_db_create(ctx, cPath, nil); db == nil { - C.grn_ctx_close(ctx) - finGroonga() - message := C.GoString(&ctx.errbuf[0]) - return nil, fmt.Errorf("grn_db_create() failed: err = %s", message) - } - return &GroongaDB{ctx}, nil -} - -// Create a DB in a temporary directory. -// -// Example: -// db, dir, err := CreateTempGroonggnx.aDB("", "gnx") -// if err != nil { -// log.Fatalln(err) -// } -// defer os.RemoveAll(dir) -// defer db.Close() -// ... -func createTempGroongaDB(dir, prefix string) (*GroongaDB, string, error) { - tempDir, err := ioutil.TempDir(dir, prefix) - if err != nil { - return nil, "", err - } - db, err := CreateGroongaDB(tempDir + "/db") - if err != nil { - os.RemoveAll(tempDir) - return nil, "", err - } - return db, tempDir, nil -} - -func OpenGroongaDB(path string) (*GroongaDB, error) { - if err := initGroonga(); err != nil { - return nil, err - } - ctx := C.grn_ctx_open(0) - if ctx == nil { - finGroonga() - return nil, fmt.Errorf("grn_ctx_open() failed") - } - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - if db := C.grn_db_open(ctx, cPath); db == nil { - C.grn_ctx_close(ctx) - finGroonga() - message := C.GoString(&ctx.errbuf[0]) - return nil, fmt.Errorf("grn_db_create() failed: err = %s", message) - } - return &GroongaDB{ctx}, nil -} - -func (db *GroongaDB) Close() error { - if db.ctx == nil { - return nil - } - if rc := C.grn_ctx_close(db.ctx); rc != C.GRN_SUCCESS { - return fmt.Errorf("grn_ctx_close() failed: rc = %d", rc) - } - db.ctx = nil - finGroonga() - return nil -} - -func (db *GroongaDB) Send(command string) error { - cCommand := C.CString(command) - defer C.free(unsafe.Pointer(cCommand)) - rc := C.grn_ctx_send(db.ctx, cCommand, C.uint(len(command)), 0) - switch { - case rc != C.GRN_SUCCESS: - return fmt.Errorf( - "grn_ctx_send() failed: rc = %d, err = %s", - rc, C.GoString(&db.ctx.errbuf[0])) - case db.ctx.rc != C.GRN_SUCCESS: - return fmt.Errorf( - "grn_ctx_send() failed: ctx.rc = %d, err = %s", - db.ctx.rc, C.GoString(&db.ctx.errbuf[0])) - } - return nil -} - -func (db *GroongaDB) checkCommandName(name string) error { - if name == "" { - return fmt.Errorf("empty command name") - } - for _, r := range name { - if (r != '_') || ((r < 'a') && (r > 'z')) { - return fmt.Errorf("invalid rune in command name") - } - } - return nil -} - -func (db *GroongaDB) checkOptionKey(name string) error { - if name == "" { - return fmt.Errorf("empty option key") - } - for _, r := range name { - if (r != '_') || ((r < 'a') && (r > 'z')) { - return fmt.Errorf("invalid rune in option key") - } - } - return nil -} - -func (db *GroongaDB) SendEx(name string, options map[string]string) error { - if err := db.checkCommandName(name); err != nil { - return err - } - parts := []string{name} - for key, value := range options { - if err := db.checkOptionKey(key); err != nil { - return err - } - value = strings.Replace(value, "\\", "\\\\", -1) - value = strings.Replace(value, "'", "\\'", -1) - parts = append(parts, fmt.Sprintf("--%s '%s'", key, value)) - } - command := strings.Join(parts, " ") - return db.Send(command) -} - -func (db *GroongaDB) 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: - return nil, fmt.Errorf( - "grn_ctx_recv() failed: rc = %d, err = %s", - rc, C.GoString(&db.ctx.errbuf[0])) - case db.ctx.rc != C.GRN_SUCCESS: - return nil, fmt.Errorf( - "grn_ctx_recv() failed: ctx.rc = %d, err = %s", - db.ctx.rc, C.GoString(&db.ctx.errbuf[0])) - } - result := C.GoBytes(unsafe.Pointer(resultBuffer), C.int(resultLength)) - return result, nil -} - -func (db *GroongaDB) Query(command string) ([]byte, error) { - err := db.Send(command) - if err != nil { - _, _ = db.Recv() - return nil, err - } - return db.Recv() -} - -func (db *GroongaDB) QueryEx( - name string, options map[string]string) ([]byte, error) { - err := db.SendEx(name, options) - if err != nil { - _, _ = db.Recv() - return nil, err - } - return db.Recv() -} - -func (db *GroongaDB) load( - tableName string, columnNames []string, records [][]Valuer) (int, error) { - jsonBytes, err := json.Marshal(records) - if err != nil { - return 0, err - } - jsonString := string(jsonBytes) - jsonString = strings.Replace(jsonString, "\\", "\\\\", -1) - jsonString = strings.Replace(jsonString, "'", "\\'", -1) - command := fmt.Sprintf("load --table '%s' --columns '%s' --values '%s'", - tableName, strings.Join(columnNames, ","), jsonString) - bytes, err := db.Query(command) - if err != nil { - return 0, err - } - return strconv.Atoi(string(bytes)) -} - -func (db *GroongaDB) loadMap( - tableName string, recordMaps []map[string]Valuer) (int, error) { - jsonBytes, err := json.Marshal(recordMaps) - if err != nil { - return 0, err - } - jsonString := string(jsonBytes) - jsonString = strings.Replace(jsonString, "\\", "\\\\", -1) - jsonString = strings.Replace(jsonString, "'", "\\'", -1) - command := fmt.Sprintf("load --table '%s' --values '%s'", - tableName, jsonString) - bytes, err := db.Query(command) - if err != nil { - return 0, err - } - return strconv.Atoi(string(bytes)) -} - -func (db *GroongaDB) loadC( - tableName string, columnNames []string, - columnarRecords []interface{}) (int, error) { - numRecords, err := countColumnarRecords(columnarRecords) - if err != nil { - return 0, err - } - - // TODO: Use cgo for JSON encoding. - records := make([][]Valuer, numRecords) - for i := 0; i < numRecords; i++ { - records[i] = make([]Valuer, len(columnNames)) - } - for i, columnarValues := range columnarRecords { - switch values := columnarValues.(type) { - case []Bool: - for j, value := range values { - records[j][i] = value - } - case []Int: - for j, value := range values { - records[j][i] = value - } - case []Float: - for j, value := range values { - records[j][i] = value - } - case []Text: - for j, value := range values { - records[j][i] = value - } - case []BoolVector: - for j, value := range values { - records[j][i] = value - } - case []IntVector: - for j, value := range values { - records[j][i] = value - } - case []FloatVector: - for j, value := range values { - records[j][i] = value - } - case []TextVector: - for j, value := range values { - records[j][i] = value - } - default: - return 0, fmt.Errorf("unsupported data type") - } - } - return db.load(tableName, columnNames, records) -} - -func (db *GroongaDB) loadCMap( - tableName string, columnarRecordsMap map[string]interface{}) (int, error) { - columnNames := make([]string, len(columnarRecordsMap)) - columnarRecords := make([]interface{}, len(columnarRecordsMap)) - i := 0 - for columnName, columnarValues := range columnarRecordsMap { - columnNames[i] = columnName - columnarRecords[i] = columnarValues - i++ - } - return db.loadC(tableName, columnNames, columnarRecords) -} - -func (db *GroongaDB) findTable(tableName string) (*GroongaTable, error) { - cTableName := C.CString(tableName) - defer C.free(unsafe.Pointer(cTableName)) - table := C.grn_ctx_get(db.ctx, cTableName, C.int(len(tableName))); - if table == nil { - return nil, fmt.Errorf("grn_ctx_get() failed") - } - return &GroongaTable{table}, nil -} - -func (db *GroongaDB) findColumn( - table *GroongaTable, columnName string) (*GroongaColumn, error) { - cColumnName := C.CString(columnName) - defer C.free(unsafe.Pointer(cColumnName)) - column := C.grn_obj_column( - db.ctx, table.obj, cColumnName, C.uint(len(columnName))) - if column == nil { - return nil, fmt.Errorf("grn_obj_column() failed") - } - return &GroongaColumn{column}, nil -} - -// -- DB -- - -type DB struct { - groongaDBs []*GroongaDB -} - -type Table struct { - groongaTables []*GroongaTable -} - -type Column struct { - groongaColumns []*GroongaColumn -} - -func CreateDB(path string, n int) (*DB, error) { - if n <= 0 { - return nil, fmt.Errorf("invalid parameter: n = %d", n) - } - groongaDBs := make([]*GroongaDB, n) - for i := 0; i < n; i++ { - dbPath := path - if i != 0 { - dbPath += strconv.Itoa(i) - } - groongaDB, err := CreateGroongaDB(dbPath) - if err != nil { - for j := 0; j < i; j++ { - groongaDBs[j].Close() - } - return nil, err - } - groongaDBs[i] = groongaDB - } - return &DB{groongaDBs}, nil -} - -func CreateTempDB(dir, prefix string, n int) (*DB, string, error) { - if n <= 0 { - return nil, "", fmt.Errorf("invalid parameter: n = %d", n) - } - tempDir, err := ioutil.TempDir(dir, prefix) - if err != nil { - return nil, "", err - } - db, err := CreateDB(tempDir+"/db", n) - if err != nil { - os.RemoveAll(tempDir) - return nil, "", err - } - return db, tempDir, nil -} - -func OpenDB(path string) (*DB, error) { - var groongaDBs []*GroongaDB - for i := 0; ; i++ { - dbPath := path - if i != 0 { - dbPath += strconv.Itoa(i) - } - groongaDB, err := OpenGroongaDB(dbPath) - if err != nil { - if i == 0 { - return nil, err - } - break - } - groongaDBs = append(groongaDBs, groongaDB) - } - return &DB{groongaDBs}, nil -} - -func (db *DB) Close() error { - for i := 0; i < len(db.groongaDBs); i++ { - db.groongaDBs[i].Close() - } - return nil -} - -func (db *DB) GroongaQuery(i int, command string) ([]byte, error) { - if (i < 0) || (i >= len(db.groongaDBs)) { - return nil, fmt.Errorf("invalid DB: i = %d", i) - } - return db.groongaDBs[i].Query(command) -} - -func (db *DB) GroongaQueryEx(i int, name string, options map[string]string) ( - []byte, error) { - if (i < 0) || (i >= len(db.groongaDBs)) { - return nil, fmt.Errorf("invalid DB: i = %d", i) - } - return db.groongaDBs[i].QueryEx(name, options) -} - -func (db *DB) checkTableName(tableName string) error { - for _, c := range tableName { - if (c != '_') && ((c < 'A') && (c > 'Z')) && ((c < 'a') && (c > 'Z')) { - return fmt.Errorf("Invalid rune in table name") - } - } - return nil -} - -func (db *DB) checkColumnName(columnName string) error { - for _, c := range columnName { - if (c != '_') && ((c < 'A') && (c > 'Z')) && ((c < 'a') && (c > 'Z')) { - return fmt.Errorf("Invalid rune in column name") - } - } - return nil -} - -func (db *DB) hashInt(value Int) int { - hasher := fnv.New32a() - binary.Write(hasher, binary.LittleEndian, value) - return int(hasher.Sum32()) -} - -func (db *DB) hashFloat(value Float) int { - hasher := fnv.New32a() - binary.Write(hasher, binary.LittleEndian, value) - return int(hasher.Sum32()) -} - -func (db *DB) hashGeoPoint(value GeoPoint) int { - hasher := fnv.New32a() - binary.Write(hasher, binary.LittleEndian, value) - return int(hasher.Sum32()) -} - -func (db *DB) hashText(value Text) int { - hasher := fnv.New32a() - hasher.Write([]byte(value)) - return int(hasher.Sum32()) -} - -func (db *DB) selectGroongaDB(key Valuer) (int, error) { - switch value := key.(type) { - case nil: - return rand.Int() % len(db.groongaDBs), nil - case Int: - return db.hashInt(value) % len(db.groongaDBs), nil - case Float: - return db.hashFloat(value) % len(db.groongaDBs), nil - case GeoPoint: - return db.hashGeoPoint(value) % len(db.groongaDBs), nil - case Text: - return db.hashText(value) % len(db.groongaDBs), nil - } - return -1, fmt.Errorf("unsupported key type") -} - -func (db *DB) load( - tableName string, columnNames []string, records [][]Valuer) (int, error) { - idID := -1 - keyID := -1 - for i, columnName := range columnNames { - switch columnName { - case "_id": - if idID != -1 { - return 0, fmt.Errorf("_id appears more than once") - } - idID = i - case "_key": - if keyID != -1 { - return 0, fmt.Errorf("_key appears more than once") - } - keyID = i - } - } - if (idID != -1) && (keyID != -1) { - return 0, fmt.Errorf("both _id and _key appear") - } - - recordsPerDBs := make([][][]Valuer, len(db.groongaDBs)) - switch { - case idID != -1: - for _, record := range records { - rowID := record[idID].(Int) - dbID := int(rowID - 1) % len(db.groongaDBs) - dummyRecord := make([]Valuer, len(record)) - copy(dummyRecord, record) - dummyRecord[idID] = Int((int(rowID - 1) / len(db.groongaDBs)) + 1) - recordsPerDBs[dbID] = append(recordsPerDBs[dbID], dummyRecord) - } - case keyID != -1: - for _, record := range records { - dbID, err := db.selectGroongaDB(record[keyID]) - if err != nil { - return 0, err - } - recordsPerDBs[dbID] = append(recordsPerDBs[dbID], record) - } - default: - for _, record := range records { - dbID, _ := db.selectGroongaDB(nil) - recordsPerDBs[dbID] = append(recordsPerDBs[dbID], record) - } - } - - // TODO: Parallel processing. - total := 0 - for i, recordsPerDB := range recordsPerDBs { - if len(recordsPerDB) != 0 { - count, err := db.groongaDBs[i].load(tableName, columnNames, recordsPerDB) - if err != nil { - return total, err - } - total += count - } - } - return total, nil -} - -func (db *DB) loadMap( - tableName string, recordMaps []map[string]Valuer) (int, error) { - recordMapsPerDBs := make([][]map[string]Valuer, len(db.groongaDBs)) - for _, recordMap := range recordMaps { - rowIDValue, hasRowID := recordMap["_id"] - keyValue, hasKey := recordMap["_key"] - if hasRowID && hasKey { - return 0, fmt.Errorf("both _id and _key appear") - } - switch { - case hasRowID: - rowID := rowIDValue.(Int) - dbID := int(rowID - 1) % len(db.groongaDBs) - dummyRecordMap := make(map[string]Valuer) - for key, value := range recordMap { - if key == "_id" { - dummyRecordMap[key] = Int((int(rowID - 1) / len(db.groongaDBs)) + 1) - } else { - dummyRecordMap[key] = value - } - } - recordMapsPerDBs[dbID] = append(recordMapsPerDBs[dbID], dummyRecordMap) - case hasKey: - dbID, err := db.selectGroongaDB(keyValue) - if err != nil { - return 0, err - } - recordMapsPerDBs[dbID] = append(recordMapsPerDBs[dbID], recordMap) - default: - dbID, _ := db.selectGroongaDB(nil) - recordMapsPerDBs[dbID] = append(recordMapsPerDBs[dbID], recordMap) - } - } - - // TODO: Parallel processing. - total := 0 - for i, recordMapsPerDB := range recordMapsPerDBs { - if len(recordMapsPerDB) != 0 { - count, err := db.groongaDBs[i].loadMap(tableName, recordMapsPerDB) - if err != nil { - return total, err - } - total += count - } - } - return total, nil -} - -func (db *DB) loadC( - tableName string, columnNames []string, - columnarRecords []interface{}) (int, error) { - numRecords, err := countColumnarRecords(columnarRecords) - if err != nil { - return 0, err - } - - idID := -1 - keyID := -1 - for i, columnName := range columnNames { - switch columnName { - case "_id": - if idID != -1 { - return 0, fmt.Errorf("_id appears more than once") - } - idID = i - case "_key": - if keyID != -1 { - return 0, fmt.Errorf("_key appears more than once") - } - keyID = i - } - } - if (idID != -1) && (keyID != -1) { - return 0, fmt.Errorf("both _id and _key appear") - } - - dbIDs := make([]int, numRecords) - numRecordsPerDBs := make([]int, len(db.groongaDBs)) - switch { - case idID != -1: - rowIDs := columnarRecords[idID].([]Int) - dummyRowIDs := make([]Int, len(rowIDs)) - for i := 0; i < numRecords; i++ { - dbIDs[i] = int(rowIDs[i] - 1) % len(db.groongaDBs) - dummyRowIDs[i] = Int((int(rowIDs[i] - 1) / len(db.groongaDBs)) + 1) - numRecordsPerDBs[dbIDs[i]]++ - } - dummyColumnarRecords := make([]interface{}, len(columnarRecords)) - copy(dummyColumnarRecords, columnarRecords) - dummyColumnarRecords[idID] = dummyRowIDs - columnarRecords = dummyColumnarRecords - case keyID != -1: - switch keys := columnarRecords[keyID].(type) { - case []Int: - for i := 0; i < numRecords; i++ { - dbIDs[i] = db.hashInt(keys[i]) % len(db.groongaDBs) - numRecordsPerDBs[dbIDs[i]]++ - } - case []Float: - for i := 0; i < numRecords; i++ { - dbIDs[i] = db.hashFloat(keys[i]) % len(db.groongaDBs) - numRecordsPerDBs[dbIDs[i]]++ - } - case []GeoPoint: - for i := 0; i < numRecords; i++ { - dbIDs[i] = db.hashGeoPoint(keys[i]) % len(db.groongaDBs) - numRecordsPerDBs[dbIDs[i]]++ - } - case []Text: - for i := 0; i < numRecords; i++ { - dbIDs[i] = db.hashText(keys[i]) % len(db.groongaDBs) - numRecordsPerDBs[dbIDs[i]]++ - } - default: - return 0, fmt.Errorf("unsupported key type") - } - default: - for i := 0; i < numRecords; i++ { - dbIDs[i] = rand.Int() % len(db.groongaDBs) - numRecordsPerDBs[dbIDs[i]]++ - } - } - - columnarRecordsPerDBs := make([][]interface{}, len(db.groongaDBs)) - for i := 0; i < len(db.groongaDBs); i++ { - columnarRecordsPerDBs[i] = make([]interface{}, len(columnarRecords)) - } - for i, columnarValues := range columnarRecords { - switch values := columnarValues.(type) { - case []Bool: - valuesPerDBs := make([][]Bool, len(db.groongaDBs)) - for j, value := range values { - dbID := dbIDs[j] - valuesPerDBs[dbID] = append(valuesPerDBs[dbID], value) - } - for j := 0; j < len(db.groongaDBs); j++ { - columnarRecordsPerDBs[j][i] = valuesPerDBs[j] - } - case []Int: - valuesPerDBs := make([][]Int, len(db.groongaDBs)) - for j, value := range values { - dbID := dbIDs[j] - valuesPerDBs[dbID] = append(valuesPerDBs[dbID], value) - } - for j := 0; j < len(db.groongaDBs); j++ { - columnarRecordsPerDBs[j][i] = valuesPerDBs[j] - } - case []Float: - valuesPerDBs := make([][]Float, len(db.groongaDBs)) - for j, value := range values { - dbID := dbIDs[j] - valuesPerDBs[dbID] = append(valuesPerDBs[dbID], value) - } - for j := 0; j < len(db.groongaDBs); j++ { - columnarRecordsPerDBs[j][i] = valuesPerDBs[j] - } - case []GeoPoint: - valuesPerDBs := make([][]GeoPoint, len(db.groongaDBs)) - for j, value := range values { - dbID := dbIDs[j] - valuesPerDBs[dbID] = append(valuesPerDBs[dbID], value) - } - for j := 0; j < len(db.groongaDBs); j++ { - columnarRecordsPerDBs[j][i] = valuesPerDBs[j] - } - case []Text: - valuesPerDBs := make([][]Text, len(db.groongaDBs)) - for j, value := range values { - dbID := dbIDs[j] - valuesPerDBs[dbID] = append(valuesPerDBs[dbID], value) - } - for j := 0; j < len(db.groongaDBs); j++ { - columnarRecordsPerDBs[j][i] = valuesPerDBs[j] - } - case []BoolVector: - valuesPerDBs := make([][]BoolVector, len(db.groongaDBs)) - for j, value := range values { - dbID := dbIDs[j] - valuesPerDBs[dbID] = append(valuesPerDBs[dbID], value) - } - for j := 0; j < len(db.groongaDBs); j++ { - columnarRecordsPerDBs[j][i] = valuesPerDBs[j] - } - case []IntVector: - valuesPerDBs := make([][]IntVector, len(db.groongaDBs)) - for j, value := range values { - dbID := dbIDs[j] - valuesPerDBs[dbID] = append(valuesPerDBs[dbID], value) - } - for j := 0; j < len(db.groongaDBs); j++ { - columnarRecordsPerDBs[j][i] = valuesPerDBs[j] - } - case []FloatVector: - valuesPerDBs := make([][]FloatVector, len(db.groongaDBs)) - for j, value := range values { - dbID := dbIDs[j] - valuesPerDBs[dbID] = append(valuesPerDBs[dbID], value) - } - for j := 0; j < len(db.groongaDBs); j++ { - columnarRecordsPerDBs[j][i] = valuesPerDBs[j] - } - case []GeoPointVector: - valuesPerDBs := make([][]GeoPointVector, len(db.groongaDBs)) - for j, value := range values { - dbID := dbIDs[j] - valuesPerDBs[dbID] = append(valuesPerDBs[dbID], value) - } - for j := 0; j < len(db.groongaDBs); j++ { - columnarRecordsPerDBs[j][i] = valuesPerDBs[j] - } - case []TextVector: - valuesPerDBs := make([][]TextVector, len(db.groongaDBs)) - for j, value := range values { - dbID := dbIDs[j] - valuesPerDBs[dbID] = append(valuesPerDBs[dbID], value) - } - for j := 0; j < len(db.groongaDBs); j++ { - columnarRecordsPerDBs[j][i] = valuesPerDBs[j] - } - default: - return 0, fmt.Errorf("unsupported data type") - } - } - - // TODO: Parallel processing. - total := 0 - for i, columnarRecordsPerDB := range columnarRecordsPerDBs { - if numRecordsPerDBs[i] != 0 { - count, err := db.groongaDBs[i].loadC( - tableName, columnNames, columnarRecordsPerDB) - if err != nil { - return total, err - } - total += count - } - } - return total, nil -} - -func (db *DB) loadCMap( - tableName string, columnarRecordsMap map[string]interface{}) (int, error) { - columnNames := make([]string, len(columnarRecordsMap)) - columnarRecords := make([]interface{}, len(columnarRecordsMap)) - i := 0 - for columnName, columnarValues := range columnarRecordsMap { - columnNames[i] = columnName - columnarRecords[i] = columnarValues - i++ - } - return db.loadC(tableName, columnNames, columnarRecords) -} - -func (db *DB) Load( - tableName string, columnNames []string, records [][]Valuer) (int, error) { - // Check arguments. - if err := db.checkTableName(tableName); err != nil { - return 0, err - } - if (len(columnNames) == 0) || (len(records) == 0) { - return 0, fmt.Errorf("no input") - } - for _, columnName := range columnNames { - if err := db.checkColumnName(columnName); err != nil { - return 0, err - } - } - for _, record := range records { - if len(record) != len(columnNames) { - return 0, fmt.Errorf( - "length conflict: len(columnNames) = %d, len(record) = %d", - len(columnNames), len(record)) - } - } - - if len(db.groongaDBs) == 1 { - return db.groongaDBs[0].load(tableName, columnNames, records) - } else { - return db.load(tableName, columnNames, records) - } -} - -func (db *DB) LoadMap( - tableName string, recordMaps []map[string]Valuer) (int, error) { - // Check arguments. - if err := db.checkTableName(tableName); err != nil { - return 0, err - } - if len(recordMaps) == 0 { - return 0, fmt.Errorf("no input") - } - for _, recordMap := range recordMaps { - for columnName, _ := range recordMap { - if err := db.checkColumnName(columnName); err != nil { - return 0, err - } - } - } - - if len(db.groongaDBs) == 1 { - return db.groongaDBs[0].loadMap(tableName, recordMaps) - } else { - return db.loadMap(tableName, recordMaps) - } -} - -func (db *DB) LoadC( - tableName string, columnNames []string, - columnarRecords []interface{}) (int, error) { - // Check arguments. - if err := db.checkTableName(tableName); err != nil { - return 0, err - } - if len(columnNames) == 0 { - return 0, fmt.Errorf("no input") - } - for _, columnName := range columnNames { - if err := db.checkColumnName(columnName); err != nil { - return 0, err - } - } - if len(columnNames) != len(columnarRecords) { - return 0, fmt.Errorf( - "length conflict: len(columnNames) = %d, len(columnarRecords) = %d", - len(columnNames), len(columnarRecords)) - } - - if len(db.groongaDBs) == 1 { - return db.groongaDBs[0].loadC(tableName, columnNames, columnarRecords) - } else { - return db.loadC(tableName, columnNames, columnarRecords) - } -} - -func (db *DB) LoadCMap( - tableName string, columnarRecordsMap map[string]interface{}) (int, error) { - // Check arguments. - if err := db.checkTableName(tableName); err != nil { - return 0, err - } - if len(columnarRecordsMap) == 0 { - return 0, fmt.Errorf("no input") - } - for columnName, _ := range columnarRecordsMap { - if err := db.checkColumnName(columnName); err != nil { - return 0, err - } - } - - if len(db.groongaDBs) == 1 { - return db.groongaDBs[0].loadCMap(tableName, columnarRecordsMap) - } else { - return db.loadCMap(tableName, columnarRecordsMap) - } -} - -func (db *DB) InsertRow(tableName string, key Valuer) (bool, Int, error) { - dbID, err := db.selectGroongaDB(key) - if err != nil { - return false, NAInt(), err - } - groongaDB := db.groongaDBs[dbID] - - var inserted C.gnx_bool - var rowID C.gnx_int - cTableName := C.CString(tableName) - defer C.free(unsafe.Pointer(cTableName)) - switch value := key.(type) { - case nil: - inserted = C.gnx_insert_row(groongaDB.ctx, cTableName, - C.GNX_NA, nil, &rowID) - case Int: - inserted = C.gnx_insert_row(groongaDB.ctx, cTableName, - C.GNX_INT, unsafe.Pointer(&value), &rowID) - case Float: - inserted = C.gnx_insert_row(groongaDB.ctx, cTableName, - C.GNX_FLOAT, unsafe.Pointer(&value), &rowID) - case GeoPoint: - inserted = C.gnx_insert_row(groongaDB.ctx, cTableName, - C.GNX_GEO_POINT, unsafe.Pointer(&value), &rowID) - case Text: - cValue := C.CString(string(value)) - defer C.free(unsafe.Pointer(cValue)) - text := C.gnx_text{cValue, C.gnx_int(len(value))} - inserted = C.gnx_insert_row(groongaDB.ctx, cTableName, - C.GNX_TEXT, unsafe.Pointer(&text), &rowID) - default: - return false, NAInt(), fmt.Errorf("unsupported key type") - } - if inserted == C.GNX_NA_BOOL { - return false, NAInt(), fmt.Errorf("gnx_insert_row() failed") - } - rowID = ((rowID - 1) * C.gnx_int(len(db.groongaDBs))) + C.gnx_int(dbID) + 1 - return inserted == C.GNX_TRUE, Int(rowID), nil -} - -func (db *DB) SetValue(tableName string, columnName string, rowID Int, - value Valuer) error { - dbID := int(rowID - 1) % len(db.groongaDBs) - rowID = ((rowID - 1) / Int(len(db.groongaDBs))) + 1 - groongaDB := db.groongaDBs[dbID] - - var ok C.gnx_bool - cTableName := C.CString(tableName) - defer C.free(unsafe.Pointer(cTableName)) - cColumnName := C.CString(columnName) - defer C.free(unsafe.Pointer(cColumnName)) - switch v := value.(type) { -// case nil: -// ok = C.gnx_set_value(groongaDB.ctx, cTableName, cColumnName, -// C.gnx_int(rowID), C.GNX_NA, nil) - case Bool: - ok = C.gnx_set_value(groongaDB.ctx, cTableName, cColumnName, - C.gnx_int(rowID), C.GNX_BOOL, unsafe.Pointer(&v)) - case Int: - ok = C.gnx_set_value(groongaDB.ctx, cTableName, cColumnName, - C.gnx_int(rowID), C.GNX_INT, unsafe.Pointer(&v)) - case Float: - ok = C.gnx_set_value(groongaDB.ctx, cTableName, cColumnName, - C.gnx_int(rowID), C.GNX_FLOAT, unsafe.Pointer(&v)) - case GeoPoint: - ok = C.gnx_set_value(groongaDB.ctx, cTableName, cColumnName, - C.gnx_int(rowID), C.GNX_GEO_POINT, unsafe.Pointer(&v)) - case Text: - cValue := C.CString(string(v)) - defer C.free(unsafe.Pointer(cValue)) - text := C.gnx_text{cValue, C.gnx_int(len(v))} - ok = C.gnx_set_value(groongaDB.ctx, cTableName, cColumnName, - C.gnx_int(rowID), C.GNX_TEXT, unsafe.Pointer(&text)) - default: - return fmt.Errorf("unsupported value type") - } - if ok != C.GNX_TRUE { - return fmt.Errorf("gnx_set_value() failed") - } - return nil -} - -func (db *DB) FindTable(tableName string) (*Table, error) { - groongaTables := make([]*GroongaTable, len(db.groongaDBs)) - for i, groongaDB := range db.groongaDBs { - groongaTable, err := groongaDB.findTable(tableName) - if err != nil { - return nil, err - } - groongaTables[i] = groongaTable - } - return &Table{groongaTables}, nil -} - -func (db *DB) FindColumn(table *Table, columnName string) (*Column, error) { - groongaColumns := make([]*GroongaColumn, len(db.groongaDBs)) - for i, groongaDB := range db.groongaDBs { - groongaColumn, err := - groongaDB.findColumn(table.groongaTables[i], columnName) - if err != nil { - return nil, err - } - groongaColumns[i] = groongaColumn - } - return &Column{groongaColumns}, nil -} - -func (db *DB) InsertRow2(table *Table, key Valuer) (bool, Int, error) { - dbID, err := db.selectGroongaDB(key) - if err != nil { - return false, NAInt(), err - } - groongaDB := db.groongaDBs[dbID] - groongaTable := table.groongaTables[dbID] - - var inserted C.gnx_bool - var rowID C.gnx_int - switch value := key.(type) { - case nil: - inserted = C.gnx_insert_row2(groongaDB.ctx, groongaTable.obj, - C.GNX_NA, nil, &rowID) - case Int: - inserted = C.gnx_insert_row2(groongaDB.ctx, groongaTable.obj, - C.GNX_INT, unsafe.Pointer(&value), &rowID) - case Float: - inserted = C.gnx_insert_row2(groongaDB.ctx, groongaTable.obj, - C.GNX_FLOAT, unsafe.Pointer(&value), &rowID) - case GeoPoint: - inserted = C.gnx_insert_row2(groongaDB.ctx, groongaTable.obj, - C.GNX_GEO_POINT, unsafe.Pointer(&value), &rowID) - case Text: - cValue := C.CString(string(value)) - defer C.free(unsafe.Pointer(cValue)) - text := C.gnx_text{cValue, C.gnx_int(len(value))} - inserted = C.gnx_insert_row2(groongaDB.ctx, groongaTable.obj, - C.GNX_TEXT, unsafe.Pointer(&text), &rowID) - default: - return false, NAInt(), fmt.Errorf("unsupported key type") - } - if inserted == C.GNX_NA_BOOL { - return false, NAInt(), fmt.Errorf("gnx_insert_row() failed") - } - rowID = ((rowID - 1) * C.gnx_int(len(db.groongaDBs))) + C.gnx_int(dbID) + 1 - return inserted == C.GNX_TRUE, Int(rowID), nil -} - -func (db *DB) SetValue2(column *Column, rowID Int, value Valuer) error { - dbID := int(rowID - 1) % len(db.groongaDBs) - rowID = ((rowID - 1) / Int(len(db.groongaDBs))) + 1 - groongaDB := db.groongaDBs[dbID] - groongaColumn := column.groongaColumns[dbID] - - var ok C.gnx_bool - switch v := value.(type) { -// case nil: -// ok = C.gnx_set_value2(groongaDB.ctx, groongaColumn.obj, -// C.gnx_int(rowID), C.GNX_NA, nil) - case Bool: - ok = C.gnx_set_value2(groongaDB.ctx, groongaColumn.obj, - C.gnx_int(rowID), C.GNX_BOOL, unsafe.Pointer(&v)) - case Int: - ok = C.gnx_set_value2(groongaDB.ctx, groongaColumn.obj, - C.gnx_int(rowID), C.GNX_INT, unsafe.Pointer(&v)) - case Float: - ok = C.gnx_set_value2(groongaDB.ctx, groongaColumn.obj, - C.gnx_int(rowID), C.GNX_FLOAT, unsafe.Pointer(&v)) - case GeoPoint: - ok = C.gnx_set_value2(groongaDB.ctx, groongaColumn.obj, - C.gnx_int(rowID), C.GNX_GEO_POINT, unsafe.Pointer(&v)) - case Text: - cValue := C.CString(string(v)) - defer C.free(unsafe.Pointer(cValue)) - text := C.gnx_text{cValue, C.gnx_int(len(v))} - ok = C.gnx_set_value2(groongaDB.ctx, groongaColumn.obj, - C.gnx_int(rowID), C.GNX_TEXT, unsafe.Pointer(&text)) - default: - return fmt.Errorf("unsupported value type") - } - if ok != C.GNX_TRUE { - return fmt.Errorf("gnx_set_value() failed") - } - return nil -} Deleted: go2/gnx/gnx.h (+0 -74) 100644 =================================================================== --- go2/gnx/gnx.h 2015-05-26 11:06:34 +0900 (ede8985) +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef GNX_H -#define GNX_H - -#include <groonga.h> -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -typedef enum gnx_data_type { - GNX_NA, - GNX_BOOL, - GNX_INT, - GNX_FLOAT, - GNX_GEO_POINT, - GNX_TEXT -} gnx_data_type; - -typedef uint8_t gnx_bool; -typedef int64_t gnx_int; -typedef double gnx_float; -//typedef grn_geo_point gnx_geo_point; -typedef struct { - int32_t latitude; - int32_t longitude; -} gnx_geo_point; -typedef struct { - const char *data; - gnx_int size; -} gnx_text; - -#define GNX_TRUE ((gnx_bool)3) -#define GNX_FALSE ((gnx_bool)0) - -#define GNX_NA_BOOL ((gnx_bool)1) -#define GNX_NA_INT (((gnx_int)1) << 63) - -gnx_bool gnx_insert_row(grn_ctx *ctx, const char *table_name, - gnx_data_type key_type, const void *key, - gnx_int *row_id); -gnx_bool gnx_insert_row2(grn_ctx *ctx, grn_obj *table, - gnx_data_type key_type, const void *key, - gnx_int *row_id); - -gnx_bool gnx_set_value(grn_ctx *ctx, const char *table_name, - const char *column_name, gnx_int row_id, - gnx_data_type value_type, const void *value); -gnx_bool gnx_set_value2(grn_ctx *ctx,grn_obj *column, gnx_int row_id, - gnx_data_type value_type, const void *value); - -gnx_int gnx_insert_rows(grn_ctx *ctx, const char *table_name, - gnx_int num_keys, gnx_data_type key_type, - const void *keys, gnx_int *row_ids, - gnx_bool *inserted); -gnx_int gnx_insert_rows2(grn_ctx *ctx, grn_obj *table, - gnx_int num_keys, gnx_data_type key_type, - const void *keys, gnx_int *row_ids, - gnx_bool *inserted); - -gnx_int gnx_set_values(grn_ctx *ctx, const char *table_name, - const char *column_name, gnx_int num_values, - const gnx_int *row_ids, gnx_data_type value_type, - const void *values, gnx_bool *updated); -gnx_int gnx_set_values2(grn_ctx *ctx, grn_obj *table, grn_obj *column, - gnx_int num_values, const gnx_int *row_ids, - gnx_data_type value_type, const void *values, - gnx_bool *updated); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // GNX_H Deleted: go2/gnxTest.go (+0 -499) 100644 =================================================================== --- go2/gnxTest.go 2015-05-26 11:06:34 +0900 (b1128cd) +++ /dev/null @@ -1,499 +0,0 @@ -package main - -import "./gnx" -import "fmt" -import "log" -import "os" - -func testA() { - log.Println("testA()") - - db, dir, err := gnx.CreateTempDB("", "gnxConsole", 1) - if err != nil { - log.Println(err) - return - } - defer os.RemoveAll(dir) - defer db.Close() - - _, err = db.GroongaQuery(0, "table_create Table TABLE_NO_KEY") - if err != nil { - log.Println(err) - return - } - - _, err = db.GroongaQuery(0, "column_create Table Value COLUMN_SCALAR Int32") - if err != nil { - log.Println(err) - return - } - - { - var records [][]gnx.Valuer - records = append(records, []gnx.Valuer{gnx.Int(1)}) - records = append(records, []gnx.Valuer{gnx.Int(2)}) - records = append(records, []gnx.Valuer{gnx.Int(3)}) - count, err := db.Load("Table", []string{"Value"}, records) - if err != nil { - log.Println(err) - return - } - fmt.Println("count:", count) - } - - { - var recordMaps []map[string]gnx.Valuer - recordMaps = append(recordMaps, map[string]gnx.Valuer{"Value":gnx.Int(10)}) - recordMaps = append(recordMaps, map[string]gnx.Valuer{"Value":gnx.Int(20)}) - recordMaps = append(recordMaps, map[string]gnx.Valuer{"Value":gnx.Int(30)}) - count, err := db.LoadMap("Table", recordMaps) - if err != nil { - log.Println(err) - return - } - fmt.Println("count:", count) - } - - { - var columnarRecords []interface{} - columnarRecords = append(columnarRecords, []gnx.Int{-1,-2,-3}) - count, err := db.LoadC("Table", []string{"Value"}, columnarRecords) - if err != nil { - log.Println(err) - return - } - fmt.Println("count:", count) - } - - { - columnarRecordsMap := make(map[string]interface{}) - columnarRecordsMap["Value"] = []gnx.Int{-10,-20,-30} - count, err := db.LoadCMap("Table", columnarRecordsMap) - if err != nil { - log.Println(err) - return - } - fmt.Println("count:", count) - } - - command := "select Table --limit -1" - jsonBytes, err := db.GroongaQuery(0, command) - if err != nil { - log.Println(err) - return - } - fmt.Println("result:", string(jsonBytes)) -} - -func testB() { - log.Println("testB()") - - db, dir, err := gnx.CreateTempDB("", "gnxConsole", 3) - if err != nil { - log.Println(err) - return - } - defer os.RemoveAll(dir) - defer db.Close() - - for i := 0; i < 3; i++ { - _, err = db.GroongaQuery(i, "table_create Table TABLE_NO_KEY") - if err != nil { - log.Println(err) - return - } - } - - for i := 0; i < 3; i++ { - _, err = db.GroongaQuery(i, "column_create Table Value COLUMN_SCALAR Int32") - if err != nil { - log.Println(err) - return - } - } - - { - var records [][]gnx.Valuer - records = append(records, []gnx.Valuer{gnx.Int(1)}) - records = append(records, []gnx.Valuer{gnx.Int(2)}) - records = append(records, []gnx.Valuer{gnx.Int(3)}) - records = append(records, []gnx.Valuer{gnx.Int(4)}) - count, err := db.Load("Table", []string{"Value"}, records) - if err != nil { - log.Println(err) - return - } - fmt.Println("count:", count) - } - - { - var records [][]gnx.Valuer - // NOTE: In fact, the IDs are ignored. - records = append(records, []gnx.Valuer{gnx.Int(1), gnx.Int(5)}) - records = append(records, []gnx.Valuer{gnx.Int(2), gnx.Int(6)}) - records = append(records, []gnx.Valuer{gnx.Int(3), gnx.Int(7)}) - records = append(records, []gnx.Valuer{gnx.Int(4), gnx.Int(8)}) - fmt.Println("records (before):", records) - count, err := db.Load("Table", []string{"_id","Value"}, records) - if err != nil { - log.Println(err) - return - } - fmt.Println("records (after):", records) - fmt.Println("count:", count) - } - - { - var recordMaps []map[string]gnx.Valuer - recordMaps = append(recordMaps, map[string]gnx.Valuer{"Value":gnx.Int(10)}) - recordMaps = append(recordMaps, map[string]gnx.Valuer{"Value":gnx.Int(20)}) - recordMaps = append(recordMaps, map[string]gnx.Valuer{"Value":gnx.Int(30)}) - recordMaps = append(recordMaps, map[string]gnx.Valuer{"Value":gnx.Int(40)}) - fmt.Println("recordMaps (before):", recordMaps) - count, err := db.LoadMap("Table", recordMaps) - if err != nil { - log.Println(err) - return - } - fmt.Println("recordMaps (after):", recordMaps) - fmt.Println("count:", count) - } - - { - var recordMaps []map[string]gnx.Valuer - recordMaps = append(recordMaps, map[string]gnx.Valuer{ - "_id":gnx.Int(1), "Value":gnx.Int(50)}) - recordMaps = append(recordMaps, map[string]gnx.Valuer{ - "_id":gnx.Int(2), "Value":gnx.Int(60)}) - recordMaps = append(recordMaps, map[string]gnx.Valuer{ - "_id":gnx.Int(3), "Value":gnx.Int(70)}) - recordMaps = append(recordMaps, map[string]gnx.Valuer{ - "_id":gnx.Int(4), "Value":gnx.Int(80)}) - fmt.Println("recordMaps (before):", recordMaps) - count, err := db.LoadMap("Table", recordMaps) - if err != nil { - log.Println(err) - return - } - fmt.Println("recordMaps (after):", recordMaps) - fmt.Println("count:", count) - } - - { - var columnarRecords []interface{} - columnarRecords = append(columnarRecords, []gnx.Int{-1,-2,-3,-4}) - count, err := db.LoadC("Table", []string{"Value"}, columnarRecords) - if err != nil { - log.Println(err) - return - } - fmt.Println("count:", count) - } - - { - var columnarRecords []interface{} - // NOTE: In fact, the IDs are ignored. - columnarRecords = append(columnarRecords, []gnx.Int{5,6,7,8}) - columnarRecords = append(columnarRecords, []gnx.Int{-5,-6,-7,-8}) - count, err := db.LoadC("Table", []string{"_id", "Value"}, columnarRecords) - if err != nil { - log.Println(err) - return - } - fmt.Println("count:", count) - } - - { - columnarRecordsMap := make(map[string]interface{}) - columnarRecordsMap["Value"] = []gnx.Int{-10,-20,-30,-40} - count, err := db.LoadCMap("Table", columnarRecordsMap) - if err != nil { - log.Println(err) - return - } - fmt.Println("count:", count) - } - - { - columnarRecordsMap := make(map[string]interface{}) - // NOTE: In fact, the IDs are ignored. - columnarRecordsMap["_id"] = []gnx.Int{9,10,11,12} - columnarRecordsMap["Value"] = []gnx.Int{-50,-60,-70,-80} - count, err := db.LoadCMap("Table", columnarRecordsMap) - if err != nil { - log.Println(err) - return - } - fmt.Println("count:", count) - } - - command := "select Table --limit -1" - for i := 0; i < 3; i++ { - jsonBytes, err := db.GroongaQuery(i, command) - if err != nil { - log.Println(err) - return - } - fmt.Printf("result[%d]: %s\n", i, string(jsonBytes)) - } -} - -func testC() { - log.Println("testC()") - - db, dir, err := gnx.CreateTempDB("", "gnxConsole", 2) - if err != nil { - log.Println(err) - return - } - defer os.RemoveAll(dir) - defer db.Close() - - { - for i := 0; i < 2; i++ { - _, err = db.GroongaQuery(i, "table_create Table TABLE_NO_KEY") - if err != nil { - log.Println(err) - return - } - } - keys := []gnx.Valuer{nil, nil, nil} - for i, key := range keys { - inserted, rowID, err := db.InsertRow("Table", key) - if err != nil { - log.Println(err) - return - } - fmt.Printf("i: %v, key: %v, inserted: %v, rowID: %v\n", - i, key, inserted, rowID) - } - command := "select Table --limit -1 --cache no" - for i := 0; i < 2; i++ { - jsonBytes, err := db.GroongaQuery(i, command) - if err != nil { - log.Println(err) - return - } - fmt.Printf("result[%d]: %s\n", i, string(jsonBytes)) - } - } - - { - for i := 0; i < 2; i++ { - _, err = db.GroongaQuery(i, "table_create Table2 TABLE_PAT_KEY Int32") - if err != nil { - log.Println(err) - return - } - } - keys := []gnx.Valuer{gnx.Int(10), gnx.Int(20), gnx.Int(30)} - for i, key := range keys { - inserted, rowID, err := db.InsertRow("Table2", key) - if err != nil { - log.Println(err) - return - } - fmt.Printf("i: %v, key: %v, inserted: %v, rowID: %v\n", - i, key, inserted, rowID) - } - command := "select Table2 --limit -1 --cache no" - for i := 0; i < 2; i++ { - jsonBytes, err := db.GroongaQuery(i, command) - if err != nil { - log.Println(err) - return - } - fmt.Printf("result[%d]: %s\n", i, string(jsonBytes)) - } - } - - { - for i := 0; i < 2; i++ { - _, err = db.GroongaQuery(i, "table_create Table3 TABLE_PAT_KEY Float") - if err != nil { - log.Println(err) - return - } - } - keys := []gnx.Valuer{gnx.Float(1.25), gnx.Float(2.5), gnx.Float(3.75)} - for i, key := range keys { - inserted, rowID, err := db.InsertRow("Table3", key) - if err != nil { - log.Println(err) - return - } - fmt.Printf("i: %v, key: %v, inserted: %v, rowID: %v\n", - i, key, inserted, rowID) - } - command := "select Table3 --limit -1 --cache no" - for i := 0; i < 2; i++ { - jsonBytes, err := db.GroongaQuery(i, command) - if err != nil { - log.Println(err) - return - } - fmt.Printf("result[%d]: %s\n", i, string(jsonBytes)) - } - } - - { - for i := 0; i < 2; i++ { - _, err = db.GroongaQuery(i, "table_create Table4 TABLE_PAT_KEY WGS84GeoPoint") - if err != nil { - log.Println(err) - return - } - } - keys := []gnx.Valuer{ - gnx.GeoPoint{100,200}, gnx.GeoPoint{300,400}, gnx.GeoPoint{500,600}} - for i, key := range keys { - inserted, rowID, err := db.InsertRow("Table4", key) - if err != nil { - log.Println(err) - return - } - fmt.Printf("i: %v, key: %v, inserted: %v, rowID: %v\n", - i, key, inserted, rowID) - } - command := "select Table4 --limit -1 --cache no" - for i := 0; i < 2; i++ { - jsonBytes, err := db.GroongaQuery(i, command) - if err != nil { - log.Println(err) - return - } - fmt.Printf("result[%d]: %s\n", i, string(jsonBytes)) - } - } - - { - for i := 0; i < 2; i++ { - _, err = db.GroongaQuery(i, "table_create Table5 TABLE_PAT_KEY ShortText") - if err != nil { - log.Println(err) - return - } - } - keys := []gnx.Valuer{gnx.Text("cat"), gnx.Text("dog"), gnx.Text("horse")} - for i, key := range keys { - inserted, rowID, err := db.InsertRow("Table5", key) - if err != nil { - log.Println(err) - return - } - fmt.Printf("i: %v, key: %v, inserted: %v, rowID: %v\n", - i, key, inserted, rowID) - } - command := "select Table5 --limit -1 --cache no" - for i := 0; i < 2; i++ { - jsonBytes, err := db.GroongaQuery(i, command) - if err != nil { - log.Println(err) - return - } - fmt.Printf("result[%d]: %s\n", i, string(jsonBytes)) - } - } -} - -func testD() { - log.Println("testD()") - - db, dir, err := gnx.CreateTempDB("", "gnxConsole", 3) - if err != nil { - log.Println(err) - return - } - defer os.RemoveAll(dir) - defer db.Close() - - for i := 0; i < 3; i++ { - _, err = db.GroongaQuery(i, "table_create Table TABLE_NO_KEY") - if err != nil { - log.Println(err) - return - } - _, err = db.GroongaQuery( - i, "column_create Table Value1 COLUMN_SCALAR Bool") - if err != nil { - log.Println(err) - return - } - _, err = db.GroongaQuery( - i, "column_create Table Value2 COLUMN_SCALAR Int32") - if err != nil { - log.Println(err) - return - } - _, err = db.GroongaQuery( - i, "column_create Table Value3 COLUMN_SCALAR Float") - if err != nil { - log.Println(err) - return - } - _, err = db.GroongaQuery( - i, "column_create Table Value4 COLUMN_SCALAR Text") - if err != nil { - log.Println(err) - return - } - } - - var rowIDs []gnx.Int - for i := 0; i < 5; i++ { - inserted, rowID, err := db.InsertRow("Table", nil) - if err != nil { - log.Println(err) - return - } - fmt.Printf("i: %v, key: %v, inserted: %v, rowID: %v\n", - i, nil, inserted, rowID) - rowIDs = append(rowIDs, rowID) - } - - values1 := []gnx.Bool{ - gnx.FALSE, gnx.TRUE, gnx.NABool(), gnx.FALSE, gnx.TRUE} - values2 := []gnx.Int{ - gnx.Int(10), gnx.Int(20), gnx.Int(30), gnx.Int(40), gnx.Int(50)} - values3 := []gnx.Float{ - gnx.Float(1.25), gnx.Float(2.5), gnx.Float(3.75), - gnx.Float(5.0), gnx.Float(6.25)} - values4 := []gnx.Text{ - gnx.Text("Apple"), gnx.Text("Banana"), gnx.Text("Orange"), - gnx.Text("Pineapple"), gnx.Text("Strawberry")} - for i, rowID := range rowIDs { - if err := db.SetValue("Table", "Value1", rowID, values1[i]); err != nil { - log.Println(err) - return - } - if err := db.SetValue("Table", "Value2", rowID, values2[i]); err != nil { - log.Println(err) - return - } - if err := db.SetValue("Table", "Value3", rowID, values3[i]); err != nil { - log.Println(err) - return - } - if err := db.SetValue("Table", "Value4", rowID, values4[i]); err != nil { - log.Println(err) - return - } - } - - command := "select Table --limit -1 --cache no" - for i := 0; i < 3; i++ { - jsonBytes, err := db.GroongaQuery(i, command) - if err != nil { - log.Println(err) - return - } - fmt.Printf("result[%d]: %s\n", i, string(jsonBytes)) - } -} - -func main() { - testA() - testB() - testC() - testD() -} Deleted: go3/gnx/gnx.go (+0 -275) 100644 =================================================================== --- go3/gnx/gnx.go 2015-05-26 11:06:34 +0900 (67ab419) +++ /dev/null @@ -1,275 +0,0 @@ -package gnx - -/* -#cgo pkg-config: groonga -#include "gnx_cgo.h" -*/ -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) - } -} - -// -- DB -- - -type DB struct { - *GrnDB - *GrnxxDB - tables map[string]*Table -} - -func newDB(grnDB *GrnDB, grnxxDB *GrnxxDB) *DB { - return &DB{grnDB, grnxxDB, make(map[string]*Table)} -} - -func CreateDB(path string) (*DB, error) { - grnDB, err := CreateGrnDB(path) - if err != nil { - return nil, err - } - return newDB(grnDB, nil), nil -} - -func OpenDB(path string) (*DB, error) { - grnDB, err := OpenGrnDB(path) - if err != nil { - return nil, err - } - return newDB(grnDB, nil), nil -} - -func (db *DB) Close() error { - var grnErr error - var grnxxErr error - if db.GrnDB != nil { - grnErr = db.GrnDB.Close() - } - if db.GrnxxDB != nil { - grnxxErr = db.GrnxxDB.Close() - } - if grnErr != nil { - return grnErr - } - return grnxxErr -} - -func (db *DB) CreateTable(name string, options *TableOptions) (*Table, error) { - // TODO - return nil, fmt.Errorf("not supported yet") -} - -func (db *DB) RemoveTable(name string) error { - // TODO - return fmt.Errorf("not supported yet") -} - -func (db *DB) RenameTable(name, newName string) error { - // TODO - return fmt.Errorf("not supported yet") -} - -func (db *DB) FindTable(name string) (*Table, error) { - if table, ok := db.tables[name]; ok { - return table, nil - } - // TODO - return nil, fmt.Errorf("not supported yet") -} - -func (db *DB) FindRow(tableName string, key interface{}) (Int, error) { - table, err := db.FindTable(tableName) - if err != nil { - return NullInt(), err - } - return table.FindRow(key) -} - -func (db *DB) InsertRow(tableName string, key interface{}) (bool, Int, error) { - table, err := db.FindTable(tableName) - if err != nil { - return false, NullInt(), err - } - return table.InsertRow(key) -} - -func (db *DB) CreateColumn(tableName, columnName, valueType string, - options *ColumnOptions) (*Column, error) { - table, err := db.FindTable(tableName) - if err != nil { - return nil, err - } - return table.CreateColumn(columnName, valueType, options) -} - -func (db *DB) RemoveColumn(tableName, columnName string) error { - table, err := db.FindTable(tableName) - if err != nil { - return err - } - return table.RemoveColumn(columnName) -} - -func (db *DB) RenameColumn(tableName, columnName, newColumnName string) error { - table, err := db.FindTable(tableName) - if err != nil { - return err - } - return table.RenameColumn(columnName, newColumnName) -} - -func (db *DB) FindColumn(tableName, columnName string) (*Column, error) { - table, err := db.FindTable(tableName) - if err != nil { - return nil, err - } - return table.FindColumn(columnName) -} - -func (db *DB) SetValue( - tableName, columnName string, id Int, value interface{}) error { - table, err := db.FindTable(tableName) - if err != nil { - return err - } - return table.SetValue(columnName, id, value) -} - -// -- Table -- - -type Table struct { - *GrnTable - *GrnxxTable - columns map[string]*Column -} - -func (table *Table) FindRow(key interface{}) (Int, error) { - // TODO - return NullInt(), fmt.Errorf("not supported yet") -} - -func (table *Table) InsertRow(key interface{}) (bool, Int, error) { - // TODO - return false, NullInt(), fmt.Errorf("not supported yet") -} - -func (table *Table) CreateColumn( - name, valueType string, options *ColumnOptions) (*Column, error) { - // TODO - return nil, fmt.Errorf("not supported yet") -} - -func (table *Table) RemoveColumn(name string) error { - // TODO - return fmt.Errorf("not supported yet") -} - -func (table *Table) RenameColumn(name, newName string) error { - // TODO - return fmt.Errorf("not supported yet") -} - -func (table *Table) FindColumn(name string) (*Column, error) { - if column, ok := table.columns[name]; ok { - return column, nil - } - // TODO - return nil, fmt.Errorf("not supported yet") -} - -func (table *Table) SetValue( - columnName string, id Int, value interface{}) error { - column, err := table.FindColumn(columnName) - if err != nil { - return err - } - return column.SetValue(id, value) -} - -// -- Column -- - -type Column struct { - *GrnColumn - *GrnxxColumn -} - -func (column *Column) SetValue(id Int, value interface{}) error { - // TODO - return fmt.Errorf("not suported yet") -} Deleted: go3/gnx/gnx_cgo.c (+0 -1) 100644 =================================================================== --- go3/gnx/gnx_cgo.c 2015-05-26 11:06:34 +0900 (3957c21) +++ /dev/null @@ -1 +0,0 @@ -#include "gnx_cgo.h" Deleted: go3/gnx/gnx_cgo.h (+0 -8) 100644 =================================================================== --- go3/gnx/gnx_cgo.h 2015-05-26 11:06:34 +0900 (970bd6b) +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef GNX_CGO_H -#define GNX_CGO_H - -#include <stdlib.h> - -#include <groonga.h> - -#endif // GNX_CGO_H Deleted: go3/gnx/gnx_test.go (+0 -1) 100644 =================================================================== --- go3/gnx/gnx_test.go 2015-05-26 11:06:34 +0900 (fa907c6) +++ /dev/null @@ -1 +0,0 @@ -package gnx Deleted: go3/gnx/grn.go (+0 -1219) 100644 =================================================================== --- go3/gnx/grn.go 2015-05-26 11:06:34 +0900 (06024c7) +++ /dev/null @@ -1,1219 +0,0 @@ -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) -} Deleted: go3/gnx/grn_cgo.c (+0 -483) 100644 =================================================================== --- go3/gnx/grn_cgo.c 2015-05-26 11:06:34 +0900 (89de52b) +++ /dev/null @@ -1,483 +0,0 @@ -#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; -} Deleted: go3/gnx/grn_cgo.h (+0 -148) 100644 =================================================================== --- go3/gnx/grn_cgo.h 2015-05-26 11:06:34 +0900 (53bb968) +++ /dev/null @@ -1,148 +0,0 @@ -#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 Deleted: go3/gnx/grn_test.go (+0 -1028) 100644 =================================================================== --- go3/gnx/grn_test.go 2015-05-26 11:06:34 +0900 (11b1994) +++ /dev/null @@ -1,1028 +0,0 @@ -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") -} Deleted: go3/gnx/grnxx.go (+0 -28) 100644 =================================================================== --- go3/gnx/grnxx.go 2015-05-26 11:06:34 +0900 (93222c5) +++ /dev/null @@ -1,28 +0,0 @@ -package gnx - -import ( - "fmt" -) - -// -- GrnxxDB -- - -type GrnxxDB struct { - // TODO -} - -func (db *GrnxxDB) Close() error { - // TODO - return fmt.Errorf("not supported yet") -} - -// -- GrnxxTable -- - -type GrnxxTable struct { - // TODO -} - -// -- GrnxxColumn -- - -type GrnxxColumn struct { - // TODO -} Deleted: go3/gnx/grnxx_cgo.cpp (+0 -1) 100644 =================================================================== --- go3/gnx/grnxx_cgo.cpp 2015-05-26 11:06:34 +0900 (0fd5c26) +++ /dev/null @@ -1 +0,0 @@ -#include "grnxx_cgo.h" Deleted: go3/gnx/grnxx_cgo.h (+0 -6) 100644 =================================================================== --- go3/gnx/grnxx_cgo.h 2015-05-26 11:06:34 +0900 (90f8462) +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef GRNXX_CGO_H -#define GRNXX_CGO_H - -// TODO - -#endif // GRNXX_CGO_H Deleted: go3/gnx/options.go (+0 -72) 100644 =================================================================== --- go3/gnx/options.go 2015-05-26 11:06:34 +0900 (4d984fb) +++ /dev/null @@ -1,72 +0,0 @@ -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 -} Deleted: new-interface/adjuster.hpp (+0 -58) 100644 =================================================================== --- new-interface/adjuster.hpp 2015-05-26 11:06:34 +0900 (e10a221) +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef GRNXX_ADJUSTER_HPP -#define GRNXX_ADJUSTER_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -struct AdjusterOptions { - AdjusterOptions(); -}; - -class Adjuster { - public: - Adjuster(); - virtual ~Adjuster(); - - // スコアの調整器を作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 返り値は std::unique_ptr なので自動的に delete される. - // 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. - // - // 新しいスコアは expression により求められる. - // 式の構築において _score を指定すれば,古いスコアを入力として使える. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された式の評価結果が真偽値ではない. - // - オプションが不正である. - // - リソースが確保できない. - static std::unique_ptr<Adjuster> create( - Error *error, - std::unique_ptr<Expression> &&expression, - const AdjusterOptions &options); - - // レコード一覧のスコアを調整する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // レコード一覧のスコアを新しいスコアに置き換える. - // 新しいスコアをレコード一覧に保存する. - // - // 有効でない行 ID を渡したときの動作は未定義である. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 評価結果をスコアに変換できない. - // - 演算において例外が発生する. - // - オーバーフローやアンダーフローが発生する. - // - ゼロによる除算が発生する. - // - NaN が発生する. - // - TODO: これらの取り扱いについては検討の余地がある. - virtual bool adjust(Error *error, - RecordSet *record_set) = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_ADJUSTER_HPP Deleted: new-interface/column.hpp (+0 -155) 100644 =================================================================== --- new-interface/column.hpp 2015-05-26 11:06:34 +0900 (aece5b4) +++ /dev/null @@ -1,155 +0,0 @@ -#ifndef GRNXX_COLUMN_HPP -#define GRNXX_COLUMN_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -class Column { - public: - // 所属するテーブルを取得する. - virtual Table *table() const = 0; - // 名前を取得する. - virtual const char *name() const = 0; - // カラムのデータ型を取得する. - virtual DataType data_type() const = 0; - // 索引 ID の最小値を取得する. - virtual IndexID min_index_id() const = 0; - // 索引 ID の最大値を取得する. - virtual IndexID max_index_id() const = 0; - // 参照先テーブルを取得する. - virtual Table *linked_table() const = 0; - // キーカラムかどうかを取得する. - virtual bool is_key() const = 0; - - // 索引を作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前が索引名の条件を満たさない. - // - 指定された名前の索引が存在する. - // - オプションの内容が不正である. - // - 十分なリソースを確保できない. - // - 索引の数が上限に達している. - virtual Index *create_index(Error *error, - const char *index_name, - IndexType index_type, - const IndexOptions &options) = 0; - // 索引を破棄する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 破棄する索引を指す Index * を保持しているときは, - // 索引を破棄する前に nullptr を代入するなどしておいた方がよい. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前の索引が存在しない. - virtual bool drop_index(Error *error, const char *index_name) = 0; - - // 索引の名前を変更する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前の索引が存在しない. - // - 指定された名前(new)が索引名の条件を満たさない. - // - 指定された名前(new)の索引が存在する. - // - 変更前後の名前が同じときは何もせずに成功とする. - virtual bool rename_index(Error *error, - const char *index_name, - const char *new_index_name) = 0; - - // 索引の順番を変更する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // index_name で指定された索引を prev_index_name の後ろに移動する. - // ただし, index_name と prev_index_name が同じときは移動せずに成功とする. - // prev_index_name が nullptr もしくは空文字列のときは先頭に移動する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前の索引が存在しない. - virtual bool reorder_index(Error *error, - const char *index_name, - const char *prev_index_name) = 0; - - // 索引を取得する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // min_index_id() 以上 max_index_id() 以下の索引 ID に対して - // 呼び出すことですべての索引を取得することができる. - // 索引 ID は削除や並び替えによって変化することに注意が必要である. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された ID が有効な範囲にない. - virtual Index *get_index(Error *error, IndexID index_id) const = 0; - - // 索引を検索する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前の索引が存在しない. - virtual Index *find_index(Error *error, const char *index_name) const = 0; - - // TODO: 機能から索引を検索する API が欲しい. - // たとえば,範囲検索に使える索引を探す,全文検索に使える索引を探すなど. - // 索引の種類(TREE_INDEX, HASH_INDEX, etc.)による検索で十分かもしれない. - - // 値を格納する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 更新しようとしている値と指定された値が同じであれば,何もせずに成功とする. - // キーカラムでは,同じ値が存在しないか確認する. - // 索引があれば,それらも更新する. - // 参照型のカラムでは,あらかじめ行 ID にしておく必要がある. - // - // TODO: 参照先のキーで入力できると便利だが,そうすると ID 指定による - // 入力はできなくなってしまう. - // 何か良い解決法がないか検討する. - // - // TODO: Datum が行 ID と整数を別の型として扱えないか検討する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された行 ID が有効でない. - // - 指定された値をカラムの型に変換できない. - // - 指定された値がカラムの制約にかかる. - // - リソースが確保できない. - // - 索引の更新に失敗する. - virtual bool set(Error *error, RowID row_id, const Datum &datum) = 0; - - // 値を取得する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 取得した値は *datum に格納する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された行 ID が有効でない. - virtual bool get(Error *error, RowID row_id, Datum *datum) const = 0; - - // 指定された条件を持たす行の ID を取得するためのカーソルを作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 返り値は std::unique_ptr なので自動的に delete される. - // 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - オプションが不正である. - // - リソースが確保できない. - virtual std::unique_ptr<Cursor> create_cursor( - Error *error, - const CursorOptions &options) const = 0; - - protected: - Column(); - virtual ~Column(); -}; - -} // namespace grnxx - -#endif // GRNXX_COLUMN_HPP Deleted: new-interface/cursor.hpp (+0 -32) 100644 =================================================================== --- new-interface/cursor.hpp 2015-05-26 11:06:34 +0900 (f1049b2) +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef GRNXX_CURSOR_HPP -#define GRNXX_CURSOR_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -class Cursor { - public: - Cursor(); - virtual ~Cursor(); - - // カーソルの位置を最大で count 進める. - // 成功すれば移動量を返す. - // 失敗したときは *error にその内容を格納し, -1 を返す. - // - // 途中で終端に到達したときは count より小さい値を返す. - virtual int64_t seek(Error *error, int64_t count) = 0; - - // カーソルの位置を最大で count 進める. - // 成功すれば移動量を返す. - // 失敗したときは *error にその内容を格納し, -1 を返す. - // - // カーソルの移動中に取得したレコードは *record_set の末尾に追加する. - // - // 途中で終端に到達したときは count より小さい値を返す. - virtual int64_t read(Error *error, int64_t count, RecordSet *record_set) = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_CURSOR_HPP Deleted: new-interface/datum.hpp (+0 -148) 100644 =================================================================== --- new-interface/datum.hpp 2015-05-26 11:06:34 +0900 (13568c0) +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef GRNXX_DATUM_HPP -#define GRNXX_DATUM_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -class Datum { - public: - // データを初期化する. - Datum() - : type_(NULL_DATUM), - null_() {} - Datum(bool value) - : type_(BOOL_DATUM), - bool_(value) {} - Datum(int64_t value) - : type_(INT_DATUM), - int_(value) {} - Datum(double value) - : type_(FLOAT_DATUM), - float_(value) {} - Datum(const std::string &value) - : type_(TEXT_DATUM), - text_(value) {} - Datum(std::string &&value) - : type_(TEXT_DATUM), - text_(value) {} - Datum(const std::vector<bool> &value) - : type_(BOOL_ARRAY_DATUM), - bool_array_(value) {} - Datum(std::vector<bool> &&value) - : type_(BOOL_ARRAY_DATUM), - bool_array_(value) {} - Datum(const std::vector<int64_t> &value) - : type_(INT_ARRAY_DATUM), - int_array_(value) {} - Datum(std::vector<int64_t> &&value) - : type_(INT_ARRAY_DATUM), - int_array_(value) {} - Datum(const std::vector<double> &value) - : type_(FLOAT_ARRAY_DATUM), - float_array_(value) {} - Datum(std::vector<double> &&value) - : type_(FLOAT_ARRAY_DATUM), - float_array_(value) {} - Datum(const std::vector<std::string> &value) - : type_(TEXT_ARRAY_DATUM), - text_array_(value) {} - Datum(std::vector<std::string> &&value) - : type_(TEXT_ARRAY_DATUM), - text_array_(value) {} - // データを破棄する. - ~Datum() { - clear(); - } - - // ムーブ. - Datum(Datum &&datum); - // ムーブ. - Datum &operator=(Datum &&datum); - - // 種類を返す. - DataType type() const { - return type_; - } - - // 真偽値を代入する. - Datum &operator=(bool value); - // 整数を代入する. - Datum &operator=(int64_t value); - // 浮動小数点数を代入する. - Datum &operator=(double value); - // 文字列を代入する. - Datum &operator=(const std::string &value); - // 真偽値の配列を代入する. - Datum &operator=(const std::vector<bool> &value); - // 整数の配列を代入する. - Datum &operator=(const std::vector<int64_t> &value); - // 浮動小数点数の配列を代入する. - Datum &operator=(const std::vector<double> &value); - // 文字列の配列を代入する. - Datum &operator=(const std::vector<std::string> &value); - - Datum &operator=(std::string &&value); - // 真偽値の配列を代入する. - Datum &operator=(std::vector<bool> &&value); - // 整数の配列を代入する. - Datum &operator=(std::vector<int64_t> &&value); - // 浮動小数点数の配列を代入する. - Datum &operator=(std::vector<double> &&value); - // 文字列の配列を代入する. - Datum &operator=(std::vector<std::string> &&value); - - // 真偽値として参照する. - const bool &as_bool() const { - return bool_; - } - // 整数として参照する. - const int64_t &as_int() const { - return int_; - } - // 浮動小数点数として参照する. - const double &as_float() const { - return float_; - } - // 文字列として参照する. - const std::string &as_text() const { - return text_; - } - // 真偽値の配列として参照する. - const std::vector<bool> &as_bool_array() const { - return bool_array_; - } - // 整数の配列として参照する. - const std::vector<int64_t> &as_int_array() const { - return int_array_; - } - // 浮動小数点数の配列として参照する. - const std::vector<double> &as_float_array() const { - return float_array_; - } - // 文字列の配列として参照する. - const std::vector<std::string> &as_text_array() const { - return text_array_; - } - - // データを破棄する. - void clear(); - - private: - DataType type_; - union { - std::nullptr_t null_; - bool bool_; - int64_t int_; - double float_; - std::string text_; - std::vector<bool> bool_array_; - std::vector<int64_t> int_array_; - std::vector<double> float_array_; - std::vector<std::string> text_array_; - }; -}; - -} // namespace grnxx - -#endif // GRNXX_DATUM_HPP Deleted: new-interface/db.hpp (+0 -158) 100644 =================================================================== --- new-interface/db.hpp 2015-05-26 11:06:34 +0900 (eed85f3) +++ /dev/null @@ -1,158 +0,0 @@ -#ifndef GRNXX_DB_HPP -#define GRNXX_DB_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -class DB { - public: - DB(); - virtual ~DB(); - - // テーブル ID の最小値を取得する. - virtual TableID min_table_id() const = 0; - // テーブル ID の最大値を取得する. - virtual TableID max_table_id() const = 0; - - // テーブルを作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前がテーブル名の条件を満たさない. - // - 指定された名前のテーブルが存在する. - // - オプションの内容が不正である. - // - 十分なリソースを確保できない. - // - テーブルの数が上限に達している. - virtual Table *create_table(Error *error, - const char *table_name, - const TableOptions &table_options) = 0; - - // テーブルを破棄する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 破棄するテーブルを指す Table * を保持しているときは, - // テーブルを破棄する前に nullptr を代入するなどしておいた方がよい. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前のテーブルが存在しない. - // - 依存関係を解決できない. - virtual bool drop_table(Error *error, - const char *table_name) = 0; - - // テーブルの名前を変更する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前のテーブルが存在しない. - // - 指定された名前(new)がテーブル名の条件を満たさない. - // - 指定された名前(new)のテーブルが存在する. - // - 変更前後の名前が同じときは何もせずに成功とする. - // - 索引の更新に失敗する. - virtual bool rename_table(Error *error, - const char *table_name, - const char *new_table_name) = 0; - - // テーブルの順番を変更する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // table_name で指定されたテーブルを prev_table_name の後ろに移動する. - // ただし, table_name と prev_table_name が同じときは移動せずに成功とする. - // prev_table_name が nullptr もしくは空文字列のときは先頭に移動する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前のテーブルが存在しない. - virtual bool reorder_table(Error *error, - const char *table_name, - const char *prev_table_name) = 0; - - // テーブルを取得する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // min_table_id() 以上 max_table_id() 以下のテーブル ID に対して - // 呼び出すことですべてのテーブルを取得することができる. - // テーブル ID は削除や並び替えによって変化することに注意が必要である. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された ID が有効な範囲にない. - virtual Table *get_table(Error *error, TableID table_id) const = 0; - - // テーブルを検索する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前のテーブルが存在しない. - virtual Table *find_table(Error *error, const char *table_name) const = 0; - - // データベースの内容をファイルに出力する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // path が nullptr もしくは空文字列のときは関連付けられているパスを用いる. - // - // 上書き保存では,一時ファイルを作成してから名前を変更する. - // 別名で保存するときは,共有メモリの内容も保存する必要がある. - // 環境によっては Copy-on-Write なファイル・コピーが使えるかもしれない. - // - // ファイルへの保存という機会を利用して隙間を埋めることができる. - // 最適化の有無や圧縮方法などはオプションで指定するものとする. - // - // 共有メモリの内容をフラッシュするだけというオプションも考えられる. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前のファイルに到達できない. - // - ディレクトリを作成するオプションがあると便利かもしれない. - // - 指定された名前のファイルが存在する. - // - 上書きを許可するオプションは欲しい. - // - 指定された名前のファイルに対するアクセス権限がない. - // - 作業領域が確保できない. - // - ディスクの空き容量が足りない. - virtual bool save(Error *error, - const char *path, - const DBOptions &options) const = 0; -}; - -// データベースを開く,もしくは作成する. -// 成功すれば有効なオブジェクトへのポインタを返す. -// 失敗したときは *error にその内容を格納し, nullptr を返す. -// -// path が nullptr もしくは空文字列のときは一時データベースを作成する. -// -// 返り値は std::unique_ptr なので自動的に delete される. -// 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. -// -// 失敗する状況としては,以下のようなものが挙げられる. -// - データベースを開くように指示されたのに,指定された名前のファイルが存在しない. -// - データベースを作成するように指示されたのに,指定された名前のファイルが存在する. -// - 指定された名前のファイルに到達できない. -// - ディレクトリを作成するオプションがあると便利かもしれない. -// - 指定された名前のファイルに対するアクセス権限がない. -// - 指定された名前のファイルがデータベースのファイルではない. -// - データベースを構成するファイルが存在しない. -std::unique_ptr<DB> open_db(Error *error, - const char *path, - const DBOptions &options); - -// データベースを削除する. -// 成功すれば true を返す. -// 失敗したときは *error にその内容を格納し, false を返す. -// -// 失敗する状況としては,以下のようなものが挙げられる. -// - 指定された名前のファイルが存在しない. -// - 指定された名前のファイルに対するアクセス権限がない. -// - 指定された名前のファイルがデータベースのファイルではない. -// - データベースを構成するファイルが存在しない. -// - 一部のファイルが欠けていても強制的に残りを削除するオプションは欲しい. -// - データベースを開かずにパスのみから推論して削除したいケースもありうる. -// - ファイルの削除に失敗する. -bool drop_db(Error *error, const char *path, const DBOptions &options); - -} // namespace grnxx - -#endif // GRNXX_DB_HPP Deleted: new-interface/error.hpp (+0 -46) 100644 =================================================================== --- new-interface/error.hpp 2015-05-26 11:06:34 +0900 (deb4720) +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef GRNXX_ERROR_HPP -#define GRNXX_ERROR_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -// 以下の実装では, Error のサイズが大きいため,値渡しには向かない. -// また,再帰呼出しするような関数では,内部で Error を定義するのは危険かもしれない. -// スタック領域を使い切れば致命的なエラーになる. -// その代わり,基本的にはスタック領域を使うため, -// メモリ確保によるオーバーヘッドは発生しないというメリットがある. -// -// Error の中身はポインタだけにし,必要なときにメモリを確保するという実装も考えられる. -// メッセージの長さに制限を持たせる必要がなくなるものの, -// 代わりに Trivial でないコンストラクタとデストラクタが必要になる. -// -// find() の Not found や insert_row() の Key already exists みたいなのにも -// 使うのであれば, message_ の生成がネックになりうる. -class Error { - public: - // エラーがない状態を示すように初期化する. - Error(); - ~Error(); - - // __LINE__ により得られる行番号を取得する. - int line() const; - // __FILE__ により得られるファイル名を取得する. - const char *file() const; - // __func__, __FUNCTION__, __PRETTY_FUNCTION__ により得られる関数名を取得する. - const char *function() const; - // エラーメッセージを取得する. - const char *message() const; - -// private: -// constexpr int MESSAGE_SIZE = 256; - -// int line_; // __LINE__ -// const char *file_; // __FILE__ -// const char *function_; // __FUNCTION__ or __func__ -// char message_[MESSAGE_SIZE]; -}; - -} // namespace grnxx - -#endif // GRNXX_ERROR_HPP Deleted: new-interface/expression-builder.hpp (+0 -128) 100644 =================================================================== --- new-interface/expression-builder.hpp 2015-05-26 11:06:34 +0900 (241e7df) +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef GRNXX_EXPRESSION_BUILDER_HPP -#define GRNXX_EXPRESSION_BUILDER_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -enum DivisionByZeroHandling { - // ゼロによる整数除算が発生すると失敗する. - FAIL_ON_DIVISION_BY_ZERO, - - // ゼロによる整数除算をデフォルト値に置き換える. - REPLACE_DIVISION_BY_ZERO_WITH_DEFAULT -}; - -enum OverflowHandling { - // オーバーフローが発生すると失敗する. - FAIL_ON_OVERFLOW, - - // オーバーフローが発生するとデフォルト値に置き換える. - REPLACE_OVERFLOW_WITH_DEFAULT, - - // オーバーフローが発生すると未定義の動作になる. - // INT64_MIN / -1 で落ちないようにする. - IGNORE_OVERFLOW -}; - -enum NullDereferenceHandling { - // NULL を参照しようとすると失敗する. - FAIL_ON_NULL_DEREFERENCE, - - // NULL を参照するとデフォルト値に置き換える. - REPLACE_NULL_DEREFERENCE_WITH_DEFAULT -}; - -enum NaNHandling { - // NaN が出現すると失敗する. - FAIL_ON_NAN, - - // NaN が出現するとデフォルト値(0.0)に置き換える. - REPLACE_NAN_WITH_DEFAULT -}; - -struct ExpressionOptions { - // ゼロによる除算の扱い. - DivisionByZeroHandling division_by_zero_handling; - - // オーバーフローの扱い. - OverflowHandling overflow_handling; - - // NULL 参照の扱い. - NullDereferenceHandling null_dereference_handling; - - // NaN の扱い. - NaNHandling nan_handling; - - ExpressionOptions(); -}; - -// 後置記法(逆ポーランド記法)に基づいて式のオブジェクトを構築する. -class ExpressionBuilder { - public: - ExpressionBuilder(); - virtual ~ExpressionBuilder(); - - // 所属するテーブルを取得する. - virtual Table *table() const = 0; - // 評価結果の型を取得する. - virtual DataType data_type() const = 0; - - // 定数をスタックに積む. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された定数が不正である. - // - リソースを確保できない. - virtual bool push_datum(Error *error, const Datum &datum) = 0; - - // カラムをスタックに積む. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // column_name に "_id" を指定すれば行 ID に対応する擬似カラム, - // "_score" を指定すればスコアに対応する擬似カラムをスタックに積む. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定されたカラムが存在しない. - // - リソースを確保できない. - virtual bool push_column(Error *error, const char *column_name) = 0; - - // 演算子に対応する被演算子をスタックから降ろし,演算子をスタックに積む. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 被演算子はあらかじめスタックに積んでおく必要があり, - // 被演算子の型や数に問題があるときは失敗する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 演算子と被演算子が対応していない. - // - 被演算子がスタックに存在しない. - // - 演算子が求める引数の型と被演算子の型が異なる. - // - リソースを確保できない. - virtual bool push_operator(Error *error, OperatorType operator_type) = 0; - - // 保持しているノードやスタックを破棄する. - virtual void clear() = 0; - - // 構築中の式を完成させ,その所有権を取得する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 所有権を返すため,保持しているノードやスタックは破棄する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - スタックの要素数が一つでない. - // - 何も積まれていない. - // - 積まれたものが使われずに残っている. - // - 式が完成していないことを示す. - // - リソースを確保できない. - virtual std::unique_ptr<Expression> release( - Error *error, - const ExpressionOptions &options) = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_EXPRESSION_BUILDER_HPP Deleted: new-interface/expression.hpp (+0 -38) 100644 =================================================================== --- new-interface/expression.hpp 2015-05-26 11:06:34 +0900 (d012ac0) +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef GRNXX_EXPRESSION_HPP -#define GRNXX_EXPRESSION_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -class ExpressionNode; - -class Expression { - public: - Expression(); - virtual ~Expression(); - - // 評価結果の型を取得する. - virtual DataType data_type() const = 0; - - // TODO: 実際の使い方に合わせて修正する. - // - // 行の一覧に対する評価結果を取得する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 演算において例外が発生する. - // - オーバーフローやアンダーフローが発生する. - // - ゼロによる除算が発生する. - // - NaN が発生する. - // - TODO: これらの取り扱いについては検討の余地がある. - // - リソースが確保できない. - virtual bool evaluate(Error *error, - const RecordSet &record_set, - Data *values) = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_EXPRESSION_HPP Deleted: new-interface/filter.hpp (+0 -62) 100644 =================================================================== --- new-interface/filter.hpp 2015-05-26 11:06:34 +0900 (25d8ae5) +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef GRNXX_FILTER_HPP -#define GRNXX_FILTER_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -struct FilterOptions { - // フィルタを通過するようなレコードの内,先頭の offset 件は破棄する. - // 0 以上でなければならない. - int64_t offset; - - // フィルタを通過したレコードが limit 件に到達した時点で残りの入力は破棄する. - // 1 以上でなければならない. - int64_t limit; - - FilterOptions(); -}; - -class Filter { - public: - Filter(); - virtual ~Filter(); - - // フィルタを作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 返り値は std::unique_ptr なので自動的に delete される. - // 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された式の評価結果が真偽値ではない. - // - オプションが不正である. - // - リソースが確保できない. - static std::unique_ptr<Filter> create( - Error *error, - std::unique_ptr<Expression> &&expression, - const FilterOptions &options); - - // レコードの一覧をフィルタにかける. - // 成功すればフィルタにかけて残ったレコード数を返す. - // 失敗したときは *error にその内容を格納し, -1 を返す. - // - // 評価結果が真になるレコードのみを残し,前方に詰めて隙間をなくす. - // フィルタにかける前後で順序関係は維持される. - // - // 有効でない行 ID を渡したときの動作は未定義である. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 演算において例外が発生する. - // - オーバーフローやアンダーフローが発生する. - // - ゼロによる除算が発生する. - // - NaN が発生する. - // - TODO: これらの取り扱いについては検討の余地がある. - virtual int64_t filter(Error *error, - RecordSet *record_set) = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_FILTER_HPP Deleted: new-interface/index.hpp (+0 -39) 100644 =================================================================== --- new-interface/index.hpp 2015-05-26 11:06:34 +0900 (dcd17a9) +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef GRNXX_INDEX_HPP -#define GRNXX_INDEX_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -class Index { - public: - Index(); - virtual ~Index(); - - // 所属するカラムを取得する. - virtual Column *column() const = 0; - // 名前を取得する. - virtual const std::string &name() const = 0; - // 種類を取得する. - virtual IndexType type() const = 0; - - // 指定された条件を持たす行の ID を取得するためのカーソルを作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 返り値は std::unique_ptr なので自動的に delete される. - // 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - オプションが不正である. - // - リソースが確保できない. - // - // TODO: 有効なオプションを取得できるようにしたい. - virtual std::unique_ptr<Cursor> create_cursor( - Error *error, - const CursorOptions &options) const = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_INDEX_HPP Deleted: new-interface/library.hpp (+0 -18) 100644 =================================================================== --- new-interface/library.hpp 2015-05-26 11:06:34 +0900 (f1dae24) +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef GRNXX_LIBRARY_HPP -#define GRNXX_LIBRARY_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -class Library { - public: - // ライブラリの名前を返す. - static const char *package(); - // ライブラリのバージョンを返す. - static const char *version(); -}; - -} // namespace grnxx - -#endif // GRNXX_LIBRARY_HPP Deleted: new-interface/merger.hpp (+0 -145) 100644 =================================================================== --- new-interface/merger.hpp 2015-05-26 11:06:34 +0900 (4651d2e) +++ /dev/null @@ -1,145 +0,0 @@ -#ifndef GRNXX_MERGER_HPP -#define GRNXX_MERGER_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -// TODO: オプションの名前などは後で調整する. - -enum MergeLogicalOperator { - // 両方に含まれるレコードを残す. - MERGE_LOGICAL_AND, - - // どちらか一方もしくは両方に含まれるレコードを残す. - MERGE_LOGICAL_OR, - - // 一方には含まれていて,もう一方には含まれていないものを残す. - MERGE_LOGICAL_XOR, - - // 一つ目の入力には含まれていて,二つ目の入力には含まれていないものを残す. - MERGE_LOGICAL_SUB, - - // 一つ目の入力をそのまま残して,スコアの合成のみをおこなう. - MERGE_LOGICAL_LHS -}; - -enum MergeScoreOperator { - // スコアを加算する. - MERGE_SCORE_ADD, - - // スコアを減算する. - MERGE_SCORE_SUB, - - // スコアを乗算する. - MERGE_SCORE_MUL - - // 減算は Adjuster との組み合わせでも実現できるものの, - // Merger でサポートした方が便利かつ効率的になる. -}; - -enum MergeResultOrder { - // 出力の順序は一つ目の入力に準拠する. - MERGE_ORDER_AS_IS, - - // 出力の順序は任意とする. - MERGE_ORDER_ARBITRARY -}; - -struct MergerOptions { - // レコードの合成方法. - MergeLogicalOperator logical_operator; - - // スコアの合成に用いる演算子. - MergeLogicalOperator score_operator; - - // 出力の順序. - MergeResultOrder result_order; - - MergerOptions(); -}; - -class Merger { - public: - Merger(); - virtual ~Merger(); - - // TODO: 入力の順序によって実装を切り替える. - // - // TODO: 一気に合成するときは,入力の数によって実装を切り替えたい. - // - // 合成器を作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 返り値は std::unique_ptr なので自動的に delete される. - // 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - オプションが不正である. - // - リソースが確保できない. - static std::unique_ptr<Merger> create(Error *error, - std::unique_ptr<Order> &&lhs_order, - std::unique_ptr<Order> &&rhs_order, - const MergerOptions &options); - - // 合成の入出力となるレコードの一覧を設定する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 合成の途中で呼び出したときは,途中経過を破棄して新たな合成を開始する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 不正なレコードの一覧が指定された. - virtual bool reset(Error *error, - RecordSet *lhs_record_set, - RecordSet *rhs_record_set, - RecordSet *result_record_set) = 0; - - // 合成を進める. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 入力が行 ID 順でないなど,入力がすべて揃ってからでなければ - // 合成に取り掛かれないときは何もせずに成功する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 入出力が設定されていない. - // - 合成が既に完了している. - // - 演算で例外が発生する. - // - 不正なレコードの一覧が指定された. - virtual bool progress(Error *error) = 0; - - // 合成の仕上げをおこなう. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 入力がすべて揃ったものとして合成の仕上げをおこなう. - // offset, limit の指定があるときは,有効な範囲だけが残る. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 入出力が設定されていない. - // - 合成が既に完了している. - // - 演算で例外が発生する. - // - リソースを確保できない. - virtual bool finish(Error *error) = 0; - - // レコードの一覧を合成する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // reset(), finish() を呼び出すことで合成をおこなう. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 不正なレコードの一覧が指定された. - // - 演算で例外が発生する. - // - リソースを確保できない. - virtual bool merge(Error *error, - RecordSet *lhs_record_set, - RecordSet *rhs_record_set, - RecordSet *result_record_set) = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_MERGER_HPP Deleted: new-interface/order.hpp (+0 -75) 100644 =================================================================== --- new-interface/order.hpp 2015-05-26 11:06:34 +0900 (9505dac) +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef GRNXX_ORDER_HPP -#define GRNXX_ORDER_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -enum OrderType { - // 基本的に昇順となる. - REGULAR_ORDER, - - // 基本的に降順となる. - REVERSE_ORDER - - // 浮動小数点数については,単項演算子 '-' を使うことで降順にできる. - // 整数については,最小値がオーバーフローするので使うべきではない. - // 文字列については,単項演算子 '-' をサポートしない. - // 真偽値については,単項演算子 '-' の代わりに '!' が使える. -}; - -struct OrderOptions { - OrderType type; - - OrderOptions(); -}; - -struct OrderUnit { - std::unique_ptr<Expression> &&expression; - OrderType type; -}; - -class Order { - public: - Order(); - ~Order(); -}; - -class OrderBuilder { - public: - OrderBuilder(); - virtual ~OrderBuilder(); - - // 整列条件に追加する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 整列条件は末尾に追加していくため,優先度の高い整列条件から順に - // 追加しなければならない.行 ID を最後の整列条件として追加することにより, - // 整列結果を安定させることができる. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された式の評価結果の型が整列条件として使えない. - // - 指定されたオプションが不正である. - // - リソースを確保できない. - virtual bool push(Error *error, - std::unique_ptr<Expression> &&expression, - const OrderOptions &options) = 0; - - // 保持している整列条件を破棄する. - virtual void clear() = 0; - - // 構築中の順序を完成させ,その所有権を取得する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 所有権を返すため,保持している整列条件は破棄する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - リソースを確保できない. - virtual std::unique_ptr<Order> release(Error *error) = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_ORDER_HPP Deleted: new-interface/pipeline-builder.hpp (+0 -123) 100644 =================================================================== --- new-interface/pipeline-builder.hpp 2015-05-26 11:06:34 +0900 (98fa9be) +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef GRNXX_PIPELINE_BUILDER_HPP -#define GRNXX_PIPELINE_BUILDER_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -struct PipelineOptions { - PipelineOptions(); -}; - -// 後置記法(逆ポーランド記法)に基づいてパイプラインを構築する. -class PipelineBuilder { - public: - PipelineBuilder(); - virtual ~PipelineBuilder(); - - // 所属するテーブルを取得する. - virtual Table *table() const = 0; - - // カーソルをスタックに積む. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定されたカーソルが不正である. - // - リソースを確保できない. - virtual bool push_cursor(Error *error, - std::unique_ptr<Cursor> &&cursor) = 0; - - // 入力をスタックから降ろし,代わりにフィルタを積む. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 入力はあらかじめスタックに積んでおく必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定されたフィルタが不正である. - // - 入力が存在しない. - // - リソースを確保できない. - virtual bool push_filter(Error *error, - std::unique_ptr<Expression> &&expression, - const FilterOptions &options) = 0; - - // 入力をスタックから降ろし,代わりにスコアの Adjuster を積む. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 入力はあらかじめスタックに積んでおく必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された Adjuster が不正である. - // - 入力が存在しない. - // - リソースを確保できない. - virtual bool push_adjuster(Error *error, - std::unique_ptr<Expression> &&expression, - const AdjusterOptions &options) = 0; - - // TODO: 将来的な検討案. - // - // 入力をスタックから降ろし,代わりにスコアの Normalizer を積む. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 入力はあらかじめスタックに積んでおく必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された Normalizer が不正である. - // - 入力が存在しない. - // - リソースを確保できない. -// virtual bool push_normalizer(Error *error, -// std::unique_ptr<Normalizer> &&normalizer) = 0; - - // 入力をスタックから降ろし,代わりに整列器を積む. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 入力はあらかじめスタックに積んでおく必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された整列器が不正である. - // - 入力が存在しない. - // - リソースを確保できない. - virtual bool push_sorter(Error *error, - std::unique_ptr<Order> &&order, - const SorterOptions &options) = 0; - - // 二つの入力をスタックから降ろし,代わりに合成器を積む. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 入力はあらかじめスタックに積んでおく必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された合成器が不正である. - // - 入力が存在しない. - // - リソースを確保できない. - virtual bool push_merger(Error *error, - const MergerOptions &options) = 0; - - // 保持しているノードやスタックを破棄する. - virtual void clear() = 0; - - // 構築中のパイプラインを完成させ,その所有権を取得する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 所有権を返すため,保持しているカーソルなどは破棄する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - スタックの要素数が一つでない. - // - 何も積まれていない. - // - 積まれたものが使われずに残っている. - // - パイプラインが完成していないことを示す. - // - リソースを確保できない. - virtual std::unique_ptr<Pipeline> release( - Error *error, - const PipelineOptions &options) = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_PIPELINE_BUILDER_HPP Deleted: new-interface/pipeline.hpp (+0 -28) 100644 =================================================================== --- new-interface/pipeline.hpp 2015-05-26 11:06:34 +0900 (5e54808) +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef GRNXX_PIPELINE_HPP -#define GRNXX_PIPELINE_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -class Pipeline { - public: - Pipeline(); - virtual ~Pipeline(); - - // パイプラインを通してレコードの一覧を取得する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // パイプラインは使い捨てなので,二回目の呼び出しは失敗する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 演算において例外が発生する. - // - リソースを確保できない. - virtual bool flush(Error *error, - RecordSet *record_set) = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_PIPELINE_HPP Deleted: new-interface/record-set.hpp (+0 -38) 100644 =================================================================== --- new-interface/record-set.hpp 2015-05-26 11:06:34 +0900 (279630c) +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef GRNXX_RECORD_SET_HPP -#define GRNXX_RECORD_SET_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -struct Record { - RowID row_id; - double score; -}; - -class RecordSet { - public: - RecordSet(); - ~RecordSet(); - - // 所属するテーブルを取得する. - Table *table() const; - // レコード数を取得する. - int64_t num_records() const; - - // レコードを取得する. - // 不正なレコード ID を指定したときの動作は未定義である. - Record get(int64_t i) const; - - // 行 ID を取得する. - // 不正なレコード ID を指定したときの動作は未定義である. - RowID get_row_id(int64_t i) const; - - // スコアを取得する. - // 不正なレコード ID を指定したときの動作は未定義である. - double get_score(int64_t i) const; -}; - -} // namespace grnxx - -#endif // GRNXX_RECORD_SET_HPP Deleted: new-interface/sorter-builder.hpp (+0 -79) 100644 =================================================================== --- new-interface/sorter-builder.hpp 2015-05-26 11:06:34 +0900 (8300c60) +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef GRNXX_SORTER_HPP -#define GRNXX_SORTER_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -enum SortOrder { - ASCENDING_ORDER, - DESCENDING_ORDER -}; - -struct SorterOptions { - // 整列後のレコード一覧から先頭の offset 件を破棄する. - // 0 以上でなければならない. - int64_t offset; - - // limit 件を超える分については破棄する. - // 1 以上でなければならない. - int64_t limit; - - SorterOptions(); -}; - -class Sorter { - public: - Sorter(); - virtual ~Sorter(); - - // 前提条件を追加する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 何らかの条件にしたがって整列済みのときに指定する. - // 新しい条件は末尾に追加される. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 式の評価結果が大小関係を持たない型になる. - // - リソースを確保できない. - virtual bool add_precondition(Error *error, - std::unique_ptr<Expression> &&expression, - SortOrder order) const = 0; - - // 整列条件を追加する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 新しい条件は末尾に追加されるため, - // 優先順位の高い整列条件から順に追加しなければならない. - // 行 ID を最後に加えれば安定な整列になる. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 式の評価結果が大小関係を持たない型になる. - // - リソースを確保できない. - virtual bool add_condition(Error *error, - std::unique_ptr<Expression> &&expression, - SortOrder order) const = 0; - - // すべての条件を破棄する. - virtual void clear(); - - // 構築中の整列器を完成させ,その所有権を取得する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 所有権を返すため,保持している条件などは破棄する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 整列条件が何も指定されていない. - // - オプションが不正である. - // - リソースを確保できない. - virtual std::unique_ptr<Sorter> release( - Error *error, - const SorterOptions &options) const = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_SORTER_HPP Deleted: new-interface/sorter.hpp (+0 -94) 100644 =================================================================== --- new-interface/sorter.hpp 2015-05-26 11:06:34 +0900 (3c480c0) +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef GRNXX_SORTER_HPP -#define GRNXX_SORTER_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -struct SorterOptions { - // 整列結果から上位 offset 件を破棄する. - // 0 以上でなければならない. - int64_t offset; - // 整列結果から最大 limit 件を取得する. - // 1 以上でなければならない. - int64_t limit; - - SorterOptions(); -}; - -class Sorter { - public: - Sorter(); - virtual ~Sorter(); - - // 整列器を作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 返り値は std::unique_ptr なので自動的に delete される. - // 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された式の評価結果が真偽値ではない. - // - オプションが不正である. - // - リソースが確保できない. - static std::unique_ptr<Sorter> create( - Error *error, - std::unique_ptr<Order> &&order, - const SorterOptions &options); - - // 整列の対象となるレコードの一覧を設定する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 整列の途中で呼び出したときは,途中経過を破棄して新たな整列を開始する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 不正なレコードの一覧が指定された. - virtual bool reset(Error *error, RecordSet *record_set) = 0; - - // 整列を進める. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // offset, limit の指定がないなど,入力がすべて揃ってからでなければ - // 整列に取り掛かれないときは何もせずに成功する. - // - // 整列済みの範囲以外を新たな入力として整列を進める. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 対象が設定されていない. - // - 整列が既に完了している. - // - 演算で例外が発生する. - virtual bool progress(Error *error) = 0; - - // 整列の仕上げをおこなう. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 入力がすべて揃ったものとして整列の仕上げをおこなう. - // offset, limit の指定があるときは,有効な範囲だけが残る. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 対象が設定されていない. - // - 整列が既に完了している. - // - 演算で例外が発生する. - // - リソースを確保できない. - virtual bool finish(Error *error) = 0; - - // レコードの一覧を整列する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // reset(), finish() を呼び出すことで整列をおこなう. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 不正なレコードの一覧が指定された. - // - 演算で例外が発生する. - // - リソースを確保できない. - virtual bool sort(Error *error, RecordSet *record_set) = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_SORTER_HPP Deleted: new-interface/table.hpp (+0 -321) 100644 =================================================================== --- new-interface/table.hpp 2015-05-26 11:06:34 +0900 (81eb6fa) +++ /dev/null @@ -1,321 +0,0 @@ -#ifndef GRNXX_TABLE_HPP -#define GRNXX_TABLE_HPP - -#include "grnxx/types.hpp" - -namespace grnxx { - -class Table { - public: - // 所属するデータベースを取得する. - virtual DB *db() const = 0; - // 名前を取得する. - virtual const char *name() const = 0; - // カラム ID の最小値を取得する. - virtual ColumnID min_column_id() const = 0; - // カラム ID の最大値を取得する. - virtual ColumnID max_column_id() const = 0; - // キーカラムを取得する. - // キーカラムが存在しないときは nullptr を返す. - virtual Column *key_column() const = 0; - // 行 ID の最小値を取得する. - virtual RowID min_row_id() const = 0; - // 行 ID の最大値を取得する. - virtual RowID max_row_id() const = 0; - - // カラムを作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前がカラム名の条件を満たさない. - // - 指定された名前のカラムが存在する. - // - オプションの内容が不正である. - // - 十分なリソースを確保できない. - // - カラムの数が上限に達している. - virtual Column *create_column(Error *error, - const char *column_name, - DataType data_type, - const ColumnOptions &column_options) = 0; - // カラムを破棄する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 破棄するカラムを指す Column * を保持しているときは, - // カラムを破棄する前に nullptr を代入するなどしておいた方がよい. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前のカラムが存在しない. - // - 依存関係を解決できない. - virtual bool drop_column(Error *error, const char *column_name) = 0; - - // カラムの名前を変更する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前のカラムが存在しない. - // - 指定された名前(new)がカラム名の条件を満たさない. - // - 指定された名前(new)のカラムが存在する. - // - 変更前後の名前が同じときは何もせずに成功とする. - // - 索引の更新に失敗する. - virtual bool rename_column(Error *error, - const char *column_name, - const char *new_column_name) = 0; - - // カラムの順番を変更する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // column_name で指定されたカラムを prev_column_name の後ろに移動する. - // ただし, column_name と prev_column_name が同じときは移動せずに成功とする. - // prev_column_name が nullptr もしくは空文字列のときは先頭に移動する. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前のカラムが存在しない. - virtual bool reorder_column(Error *error, - const char *column_name, - const char *prev_column_name) = 0; - - // カラムを取得する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // min_column_id() 以上 max_column_id() 以下のカラム ID に対して - // 呼び出すことですべてのカラムを取得することができる. - // カラム ID は削除や並び替えによって変化することに注意が必要である. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された ID が有効な範囲にない. - virtual Column *get_column(Error *error, ColumnID column_id) const = 0; - - // カラムを検索する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された名前のカラムが存在しない. - virtual Column *find_column(Error *error, const char *column_name) const = 0; - - // キーカラムを設定する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - キーカラムが存在している. - // - 指定された名前のカラムが存在しない. - // - 指定されたカラムの型がキーとしてサポートされていない. - // - 指定されたカラムに同じ値が複数存在する. - // - 一時領域を確保できない. - virtual bool set_key_column(Error *error, const char *column_name) = 0; - - // キーカラムを解除する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - キーカラムが存在しない. - virtual bool unset_key_column(Error *error) = 0; - - // 新しい行を追加する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 指定された行 ID が有効な場合,もしくは指定されたキーを持つ行が存在する場合, - // その行 ID を *result_row_id に格納する. - // 指定された行 ID が NULL_ROW_ID であれば,追加する行の ID は自動で選択する. - // このとき,選択した行 ID を *result_row_id に格納する. - // ただし,指定された行が存在する以外の理由で行の追加に失敗したときは - // NULL_ROW_ID を *result_row_id に格納する. - // - // まとめると,返り値によって行の追加に成功したかどうかがわかり, - // *result_row_id により該当する行が存在するかどうかがわかる. - // - // TODO: 将来的な検討案. - // 行 ID の再利用を無効化するオプションがあると便利かもしれない. - // 追加により割り当てられる行 ID は常に昇順という保証があれば, - // 行 ID を降順に取り出すだけで新しい行から順に走査することができる. - // 時刻カラムに対する索引で対応するより,ずっと効率的である. - // ただし,頻繁に削除すると隙間だらけになって効率が落ちる. - // オプションとしてはよさそう. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された ID が行 ID の最小値より小さいか最大値 + 1 より大きい. - // - キーカラムが存在しないとき - // - 指定された ID を持つ行が存在する. - // - キーカラムが存在するとき - // - 指定された ID を持つ行が存在する. - // - 指定されたキーをキーカラムの型に変換できない. - // - 指定されたキーを持つ行が存在する. - // - 行数が上限に達している. - // - 索引の更新に失敗する. - // - リソースを確保できない. - virtual bool insert_row(Error *error, - RowID request_row_id, - const Datum &key, - RowID *result_row_id) = 0; - - // 行を削除する. - // 成功すれば true を返す. - // 失敗したときは *error にその内容を格納し, false を返す. - // - // 依存関係の解決が許されているときは,参照元を NULL にする. - // 参照元が配列になっているときは,当該要素を取り除いて前方に詰める. - // - // TODO: 将来的な検討案. - // 依存関係の解決に関する情報は,参照型のカラムに持たせることを検討中. - // SQL の ON DELETE + RESTRICT, CASCADE, SET NULL, NO ACTION に - // 相当するが, NO ACTION は本当に何もしないのもありかもしれない. - // Groonga では NULL にする. - // - // TODO: 将来的な検討案. - // 参照元が配列のときは別に検討する必要がある. - // 位置によって意味が変わるような使い方では問題があるため, - // SET NULL も使えると嬉しいかもしれない. - // Groonga では該当する参照を取り除いて前方に詰める. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - 指定された行が無効である. - // - 指定された行は参照されている. - // - 依存関係を解決できるときは削除をおこなう. - // - 依存関係の解決に失敗した. - // - // TODO: 将来的な検討案. - // 不要になった(参照されなくなった)タグを削除するような用途を考えると, - // 削除可能な行をすべて削除するという操作が実現できると便利そうである. - // デフラグに似た専用のインタフェースを提供すべきかもしれない. - virtual bool delete_row(Error *error, RowID row_id) = 0; - - // 行の有効性を確認する. - // 指定された行が有効であれば true を返す. - // 指定された行が無効であれば false を返す. - // - // 更新する行を ID で指定されたときなどに用いる. - // - // 無効と判定される条件としては,以下のようなものが挙げられる. - // - 指定された行 ID が有効範囲にない. - // - 指定された行は削除されてから再利用されていない. - virtual bool test_row(Error *error, RowID row_id) const = 0; - - // キーカラムを持つテーブルから行を検索する. - // 成功すれば有効な行 ID を返す. - // 失敗したときは *error にその内容を格納し, NULL_ROW_ID を返す. - // - // 更新する行をキーで指定されたときなどに使う. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - キーカラムが存在しない. - // - 指定されたキーをキーカラムの型に変換できない. - // - 指定されたキーを持つ行が存在しない. - virtual RowID find_row(Error *error, const Datum &key) const = 0; - - // 行 ID を昇順もしくは降順に取得するためのカーソルを作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 返り値は std::unique_ptr なので自動的に delete される. - // 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - オプションが不正である. - // - リソースが確保できない. - virtual std::unique_ptr<Cursor> create_cursor( - Error *error, - const CursorOptions &options) const = 0; - - // 式を構築するためのオブジェクトを作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 検索結果の絞り込み,スコアの調整や出力の指定, - // 整列条件やグループ化条件の指定に用いる. - // - // 返り値は std::unique_ptr なので自動的に delete される. - // 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. - // - // TODO: 将来的な検討案. - // クエリ文字列をパースして式を構築するインタフェースが欲しい. - // テストやデバッグに使うのであれば,最適化などは必要ない. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - リソースが確保できない. - virtual std::unique_ptr<ExpressionBuilder> create_expression_builder( - Error *error) const = 0; - - // 順序を構築するためのオブジェクトを作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 順序は整列器や合成器を作成するときに使用する. - // - // 返り値は std::unique_ptr なので自動的に delete される. - // 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - リソースが確保できない. - virtual std::unique_ptr<OrderBuilder> create_order_builder( - Error *error) const = 0; - - // パイプラインを構築するためのオブジェクトを作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // パイプラインはカーソルやフィルタ,整列器などにより構成される木構造であり, - // クエリの内部データ構造および実行エンジンに相当する. - // クエリが実際に処理されるのはパイプラインの flush() を呼び出したときである. - // - // 返り値は std::unique_ptr なので自動的に delete される. - // 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - リソースが確保できない. - virtual std::unique_ptr<PipelineBuilder> create_pipeline_builder( - Error *error) const = 0; - - // 分類器を作成する. - // 成功すれば有効なオブジェクトへのポインタを返す. - // 失敗したときは *error にその内容を格納し, nullptr を返す. - // - // 返り値は std::unique_ptr なので自動的に delete される. - // 自動で delete されて困るときは release() で生のポインタを取り出す必要がある. - // - // 時刻を月や曜日でグループ化したり,値を 100 ずつグループ化したりするのは, - // グループ化の条件を Expression で指定できるようにすることで実現する. - // 課題は曜日などの情報を得るのにかかるオーバーヘッドを減らすことである. - // - // TODO: グループの数は未知なので,呼び出し側で確保した領域に - // グループの情報を格納するというインタフェースが使いにくい. - // そのため, Grouper に領域を確保させるか, - // グループ化の結果を少しずつ取り出せるようにするなどの工夫が必要である. - // - // TODO: 配列型の要素単位でグループ化する場合, - // 入力された行 ID の一覧を整列する方法では対処できない. - // そのため, Grouper で適当なデータ構造を用意する必要がある. - // - // TODO: 将来的な検討案. - // 参照型のカラム ref_col があるとき,グループ化の条件を ref_col にすれば - // 行 ID によるグループ化をおこない, ref_col._key にすれば - // 参照先のキーによるグループ化をおこなうという案がある. - // グループの順序や NULL の扱いに差が出る. - // - // TODO: 将来的な検討案. - // 各グループの構成要素が必要かどうか,構成要素の数が必要かどうか, - // などのオプションによって実装を切り替えることが望ましい. - // たとえば,構成要素が不要であればハッシュ表がよさそうである. - // - // 失敗する状況としては,以下のようなものが挙げられる. - // - オプションが不正である. - // - リソースが確保できない. - virtual std::unique_ptr<Grouper> create_grouper( - Error *error, - Expression *expression, - const GrouperOptions &options) const = 0; - - protected: - Table(); - virtual ~Table(); -}; - -} // namespace grnxx - -#endif // GRNXX_TABLE_HPP Deleted: new-interface/types.hpp (+0 -98) 100644 =================================================================== --- new-interface/types.hpp 2015-05-26 11:06:34 +0900 (7121757) +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef GRNXX_TYPES_HPP -#define GRNXX_TYPES_HPP - -#include <algorithm> -#include <cstdint> -#include <cstring> -#include <iosfwd> -#include <limits> -#include <map> -#include <memory> -#include <set> -#include <string> -#include <unordered_map> -#include <vector> - -namespace grnxx { - -using std::int8_t; -using std::int16_t; -using std::int32_t; -using std::int64_t; - -using std::uint8_t; -using std::uint16_t; -using std::uint32_t; -using std::uint64_t; - -using std::size_t; - -using TableID = int64_t; -using ColumnID = int64_t; -using IndexID = int64_t; -using RowID = int64_t; - -constexpr RowID NULL_ROW_ID = RowID(0); -constexpr RowID MIN_ROW_ID = RowID(1); -constexpr RowID MAX_ROW_ID = (RowID(1) << 40) - 1; - -struct DBOptions; -struct TableOptions; -struct ColumnOptions; -struct IndexOptions; - -class DB; -class Table; -class Column; -class Index; -class Datum; - -enum DataType { - // 無効な型. - INVALID_DATA, - - // 真偽値. - BOOLEAN_DATA, - // 64-bit 符号あり整数. - INTEGER_DATA, - // 倍精度浮動小数点数. - FLOAT_DATA, - // 時刻(The Unix Epoch からの経過マイクロ秒数). - TIME_DATA, - // 経緯度(ミリ秒単位). - GEO_POINT_DATA, - // 文字列. - TEXT_DATA, - // 参照. - REFERENCE_DATA, - - // 上述の型を配列にしたもの. - BOOLEAN_ARRAY_DATA, - INTEGER_ARRAY_DATA, - FLOAT_ARRAY_DATA, - TIME_ARRAY_DATA, - GEO_POINT_ARRAY_DATA, - TEXT_ARRAY_DATA, - REFERENCE_ARRAY_DATA -}; - -std::ostream &operator<<(std::ostream &stream, DataType data_type); - -enum IndexType { - // 木構造にもとづく索引. - // 範囲検索をサポートする. - TREE_INDEX, - - // ハッシュ表にもとづく索引. - // TREE_INDEX と比べると,データの登録・削除と完全一致検索が速い代わり, - // 範囲検索などには向かない(あるいは使えない). - HASH_INDEX - - // TODO: 全文検索用の索引は,こちらの索引に加えるか,まったく別の索引として扱う. -}; - -std::ostream &operator<<(std::ostream &stream, IndexType index_type); - -} // namespace grnxx - -#endif // GRNXX_TYPES_HPP