Skip to content

Add minimal sql support #144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
- Go modules support (#91)
- queue-utube handling (#85)
- Master discovery (#113)
- SQL support (#62)

### Fixed

Expand Down
20 changes: 18 additions & 2 deletions config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,25 @@ box.cfg{

box.once("init", function()
local s = box.schema.space.create('test', {
id = 512,
id = 517,
if_not_exists = true,
})
s:create_index('primary', {type = 'tree', parts = {1, 'uint'}, if_not_exists = true})

local sp = box.schema.space.create('SQL_TEST', {
id = 519,
if_not_exists = true,
format = {
{name = "NAME0", type = "unsigned"},
{name = "NAME1", type = "string"},
{name = "NAME2", type = "string"},
}
})
sp:create_index('primary', {type = 'tree', parts = {1, 'uint'}, if_not_exists = true})
sp:insert{1, "test", "test"}

local st = box.schema.space.create('schematest', {
id = 514,
id = 516,
temporary = true,
if_not_exists = true,
field_count = 7,
Expand Down Expand Up @@ -75,6 +87,10 @@ box.once("init", function()
box.schema.user.grant('test', 'read,write', 'space', 'test')
box.schema.user.grant('test', 'read,write', 'space', 'schematest')
box.schema.user.grant('test', 'read,write', 'space', 'test_perf')

-- grants for sql tests
box.schema.user.grant('test', 'create,read,write,drop,alter', 'space')
box.schema.user.grant('test', 'create', 'sequence')
end)

local function func_name()
Expand Down
1 change: 1 addition & 0 deletions connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Connector interface {
Call(functionName string, args interface{}) (resp *Response, err error)
Call17(functionName string, args interface{}) (resp *Response, err error)
Eval(expr string, args interface{}) (resp *Response, err error)
Execute(expr string, args interface{}) (resp *Response, err error)

GetTyped(space, index interface{}, key interface{}, result interface{}) (err error)
SelectTyped(space, index interface{}, offset, limit, iterator uint32, key interface{}, result interface{}) (err error)
Expand Down
16 changes: 16 additions & 0 deletions const.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
EvalRequest = 8
UpsertRequest = 9
Call17Request = 10
ExecuteRequest = 11
PingRequest = 64
SubscribeRequest = 66

Expand All @@ -29,6 +30,19 @@ const (
KeyDefTuple = 0x28
KeyData = 0x30
KeyError = 0x31
KeyMetaData = 0x32
KeySQLText = 0x40
KeySQLBind = 0x41
KeySQLInfo = 0x42

KeyFieldName = 0x00
KeyFieldType = 0x01
KeyFieldColl = 0x02
KeyFieldIsNullable = 0x03
KeyIsAutoincrement = 0x04
KeyFieldSpan = 0x05
KeySQLInfoRowCount = 0x00
KeySQLInfoAutoincrementIds = 0x01

// https://github.com/fl00r/go-tarantool-1.6/issues/2

Expand All @@ -49,4 +63,6 @@ const (
OkCode = uint32(0)
ErrorCodeBit = 0x8000
PacketLengthBytes = 5
ErSpaceExistsCode = 0xa
IteratorCode = 0x14
)
2 changes: 1 addition & 1 deletion example_custom_unpacking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func Example_customUnpacking() {
log.Fatalf("Failed to connect: %s", err.Error())
}

spaceNo := uint32(512)
spaceNo := uint32(517)
indexNo := uint32(0)

tuple := Tuple2{Cid: 777, Orig: "orig", Members: []Member{{"lol", "", 1}, {"wut", "", 3}}}
Expand Down
141 changes: 134 additions & 7 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tarantool_test

import (
"fmt"
"github.com/tarantool/go-tarantool/test_helpers"
"time"

"github.com/tarantool/go-tarantool"
Expand Down Expand Up @@ -31,7 +32,8 @@ func ExampleConnection_Select() {
conn.Replace(spaceNo, []interface{}{uint(1111), "hello", "world"})
conn.Replace(spaceNo, []interface{}{uint(1112), "hallo", "werld"})

resp, err := conn.Select(512, 0, 0, 100, tarantool.IterEq, []interface{}{uint(1111)})
resp, err := conn.Select(517, 0, 0, 100, tarantool.IterEq, []interface{}{uint(1111)})

if err != nil {
fmt.Printf("error in select is %v", err)
return
Expand All @@ -53,7 +55,9 @@ func ExampleConnection_SelectTyped() {
conn := example_connect()
defer conn.Close()
var res []Tuple
err := conn.SelectTyped(512, 0, 0, 100, tarantool.IterEq, tarantool.IntKey{1111}, &res)

err := conn.SelectTyped(517, 0, 0, 100, tarantool.IterEq, tarantool.IntKey{1111}, &res)

if err != nil {
fmt.Printf("error in select is %v", err)
return
Expand All @@ -73,6 +77,7 @@ func ExampleConnection_SelectTyped() {
func ExampleConnection_SelectAsync() {
conn := example_connect()
defer conn.Close()
spaceNo := uint32(517)

conn.Insert(spaceNo, []interface{}{uint(16), "test", "one"})
conn.Insert(spaceNo, []interface{}{uint(17), "test", "one"})
Expand Down Expand Up @@ -320,12 +325,12 @@ func ExampleSchema() {
}

space1 := schema.Spaces["test"]
space2 := schema.SpacesById[514]
space2 := schema.SpacesById[516]
fmt.Printf("Space 1 ID %d %s\n", space1.Id, space1.Name)
fmt.Printf("Space 2 ID %d %s\n", space2.Id, space2.Name)
// Output:
// Space 1 ID 512 test
// Space 2 ID 514 schematest
// Space 1 ID 517 test
// Space 2 ID 516 schematest
}

// Example demonstrates how to retrieve information with space schema.
Expand All @@ -344,7 +349,7 @@ func ExampleSpace() {

// Access Space objects by name or ID.
space1 := schema.Spaces["test"]
space2 := schema.SpacesById[514] // It's a map.
space2 := schema.SpacesById[516] // It's a map.
fmt.Printf("Space 1 ID %d %s %s\n", space1.Id, space1.Name, space1.Engine)
fmt.Printf("Space 1 ID %d %t\n", space1.FieldsCount, space1.Temporary)

Expand All @@ -365,10 +370,132 @@ func ExampleSpace() {
fmt.Printf("SpaceField 2 %s %s\n", spaceField2.Name, spaceField2.Type)

// Output:
// Space 1 ID 512 test memtx
// Space 1 ID 517 test memtx
// Space 1 ID 0 false
// Index 0 primary
// &{0 unsigned} &{2 string}
// SpaceField 1 name0 unsigned
// SpaceField 2 name3 unsigned
}

// To use SQL to query a tarantool instance, call Execute.
//
// Pay attention that with different types of queries (DDL, DQL, DML etc.)
// some fields of the response structure (MetaData and InfoAutoincrementIds in SQLInfo) may be nil.
func ExampleConnection_Execute() {
// Tarantool supports SQL since version 2.0.0
isLess, _ := test_helpers.IsTarantoolVersionLess(2, 0, 0)
if isLess {
return
}
server := "127.0.0.1:3013"
opts := tarantool.Opts{
Timeout: 500 * time.Millisecond,
Reconnect: 1 * time.Second,
MaxReconnects: 3,
User: "test",
Pass: "test",
}
client, err := tarantool.Connect(server, opts)
if err != nil {
fmt.Printf("Failed to connect: %s", err.Error())
}

resp, err := client.Execute("CREATE TABLE SQL_TEST (id INTEGER PRIMARY KEY, name STRING)", []interface{}{})
fmt.Println("Execute")
fmt.Println("Error", err)
fmt.Println("Code", resp.Code)
fmt.Println("Data", resp.Data)
fmt.Println("MetaData", resp.MetaData)
fmt.Println("SQL Info", resp.SQLInfo)

// there are 4 options to pass named parameters to an SQL query
// the simple map:
sqlBind1 := map[string]interface{}{
"id": 1,
"name": "test",
}

// any type of structure
sqlBind2 := struct {
Id int
Name string
}{1, "test"}

// it is possible to use []tarantool.KeyValueBind
sqlBind3 := []interface{}{
tarantool.KeyValueBind{Key: "id", Value: 1},
tarantool.KeyValueBind{Key: "name", Value: "test"},
}

// or []interface{} slice with tarantool.KeyValueBind items inside
sqlBind4 := []tarantool.KeyValueBind{
{"id", 1},
{"name", "test"},
}

// the next usage
resp, err = client.Execute("SELECT id FROM SQL_TEST WHERE id=:id AND name=:name", sqlBind1)
fmt.Println("Execute")
fmt.Println("Error", err)
fmt.Println("Code", resp.Code)
fmt.Println("Data", resp.Data)
fmt.Println("MetaData", resp.MetaData)
fmt.Println("SQL Info", resp.SQLInfo)

// the same as
resp, err = client.Execute("SELECT id FROM SQL_TEST WHERE id=:id AND name=:name", sqlBind2)
fmt.Println("Execute")
fmt.Println("Error", err)
fmt.Println("Code", resp.Code)
fmt.Println("Data", resp.Data)
fmt.Println("MetaData", resp.MetaData)
fmt.Println("SQL Info", resp.SQLInfo)

// the same as
resp, err = client.Execute("SELECT id FROM SQL_TEST WHERE id=:id AND name=:name", sqlBind3)
fmt.Println("Execute")
fmt.Println("Error", err)
fmt.Println("Code", resp.Code)
fmt.Println("Data", resp.Data)
fmt.Println("MetaData", resp.MetaData)
fmt.Println("SQL Info", resp.SQLInfo)

// the same as
resp, err = client.Execute("SELECT id FROM SQL_TEST WHERE id=:id AND name=:name", sqlBind4)
fmt.Println("Execute")
fmt.Println("Error", err)
fmt.Println("Code", resp.Code)
fmt.Println("Data", resp.Data)
fmt.Println("MetaData", resp.MetaData)
fmt.Println("SQL Info", resp.SQLInfo)

// the way to pass positional arguments to an SQL query
resp, err = client.Execute("SELECT id FROM SQL_TEST WHERE id=? AND name=?", []interface{}{2, "test"})
fmt.Println("Execute")
fmt.Println("Error", err)
fmt.Println("Code", resp.Code)
fmt.Println("Data", resp.Data)
fmt.Println("MetaData", resp.MetaData)
fmt.Println("SQL Info", resp.SQLInfo)

// the way to pass SQL expression with using custom packing/unpacking for a type
var res []Tuple
sqlInfo, metaData, err := client.ExecuteTyped("SELECT id, name, name FROM SQL_TEST WHERE id=?", []interface{}{2}, &res)
fmt.Println("ExecuteTyped")
fmt.Println("Error", err)
fmt.Println("Data", res)
fmt.Println("MetaData", metaData)
fmt.Println("SQL Info", sqlInfo)

// for using different types of parameters (positioned/named), collect all items in []interface{}
// all "named" items must be passed with tarantool.KeyValueBind{}
resp, err = client.Execute("SELECT id FROM SQL_TEST WHERE id=:id AND name=?",
[]interface{}{tarantool.KeyValueBind{"id", 1}, "test"})
fmt.Println("Execute")
fmt.Println("Error", err)
fmt.Println("Code", resp.Code)
fmt.Println("Data", resp.Data)
fmt.Println("MetaData", resp.MetaData)
fmt.Println("SQL Info", resp.SQLInfo)
}
7 changes: 7 additions & 0 deletions multi/multi.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,13 @@ func (connMulti *ConnectionMulti) Eval(expr string, args interface{}) (resp *tar
return connMulti.getCurrentConnection().Eval(expr, args)
}

// Execute passes sql expression to Tarantool for execution.
//
// Since 1.6.0
func (connMulti *ConnectionMulti) Execute(expr string, args interface{}) (resp *tarantool.Response, err error) {
return connMulti.getCurrentConnection().Execute(expr, args)
}

// GetTyped performs select (with limit = 1 and offset = 0) to box space and
// fills typed result.
func (connMulti *ConnectionMulti) GetTyped(space, index interface{}, key interface{}, result interface{}) (err error) {
Expand Down
Loading