From 57ee74348fd240457f4a910be50c18cf12629ec1 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Wed, 3 Nov 2021 13:08:12 +0530 Subject: [PATCH 1/3] added failing e2e test for locking function prepare Signed-off-by: Harshit Gangal --- .../endtoend/preparestmt/stmt_methods_test.go | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/go/test/endtoend/preparestmt/stmt_methods_test.go b/go/test/endtoend/preparestmt/stmt_methods_test.go index a2e079b579b..56621aeda09 100644 --- a/go/test/endtoend/preparestmt/stmt_methods_test.go +++ b/go/test/endtoend/preparestmt/stmt_methods_test.go @@ -379,3 +379,39 @@ func TestSelectDBA(t *testing.T) { } require.Equal(t, 2, rowCount) } + +func TestSelectLock(t *testing.T) { + defer cluster.PanicHandler(t) + dbo := Connect(t) + defer dbo.Close() + + // Get Lock + prepare, err := dbo.Prepare("select get_lock(?, ?)") + require.NoError(t, err) + + rows, err := prepare.Query("a", 100000) + require.NoError(t, err) + + var resultBytes sql.RawBytes + require.True(t, rows.Next(), "no rows found") + err = rows.Scan(&resultBytes) + require.NoError(t, err) + assert.Equal(t, "1", string(resultBytes)) + + // for connection to be reused. + err = rows.Close() + require.NoError(t, err) + + // Release Lock + prepare, err = dbo.Prepare("select release_lock(?)") + require.NoError(t, err) + + rows, err = prepare.Query("a") + require.NoError(t, err) + defer rows.Close() + + require.True(t, rows.Next(), "no rows found") + err = rows.Scan(&resultBytes) + require.NoError(t, err) + assert.Equal(t, "1", string(resultBytes)) +} From b77c105aa9a6249ae4f0dc82315764aeddacb800 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Wed, 3 Nov 2021 13:09:11 +0530 Subject: [PATCH 2/3] implements GetFields method on lock primitive Signed-off-by: Harshit Gangal --- go/vt/vtgate/engine/lock.go | 17 ++++++++++++----- go/vt/vtgate/planbuilder/select.go | 2 ++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/go/vt/vtgate/engine/lock.go b/go/vt/vtgate/engine/lock.go index dccd6354af9..af14984bda4 100644 --- a/go/vt/vtgate/engine/lock.go +++ b/go/vt/vtgate/engine/lock.go @@ -38,6 +38,8 @@ type Lock struct { // Query specifies the query to be executed. Query string + FieldQuery string + noInputs noTxNeeded @@ -60,6 +62,10 @@ func (l *Lock) GetTableName() string { // TryExecute is part of the Primitive interface func (l *Lock) TryExecute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, _ bool) (*sqltypes.Result, error) { + return l.execLock(vcursor, l.Query, bindVars) +} + +func (l *Lock) execLock(vcursor VCursor, query string, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) { rss, _, err := vcursor.ResolveDestinations(l.Keyspace.Name, nil, []key.Destination{l.TargetDestination}) if err != nil { return nil, err @@ -68,11 +74,11 @@ func (l *Lock) TryExecute(vcursor VCursor, bindVars map[string]*querypb.BindVari return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "lock query can be routed to single shard only: %v", rss) } - query := &querypb.BoundQuery{ - Sql: l.Query, + boundQuery := &querypb.BoundQuery{ + Sql: query, BindVariables: bindVars, } - return vcursor.ExecuteLock(rss[0], query) + return vcursor.ExecuteLock(rss[0], boundQuery) } // TryStreamExecute is part of the Primitive interface @@ -86,12 +92,13 @@ func (l *Lock) TryStreamExecute(vcursor VCursor, bindVars map[string]*querypb.Bi // GetFields is part of the Primitive interface func (l *Lock) GetFields(vcursor VCursor, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) { - return nil, vterrors.New(vtrpc.Code_UNIMPLEMENTED, "not implements in lock primitive") + return l.execLock(vcursor, l.FieldQuery, bindVars) } func (l *Lock) description() PrimitiveDescription { other := map[string]interface{}{ - "Query": l.Query, + "Query": l.Query, + "FieldQuery": l.FieldQuery, } return PrimitiveDescription{ OperatorType: "Lock", diff --git a/go/vt/vtgate/planbuilder/select.go b/go/vt/vtgate/planbuilder/select.go index 8f42a682254..07a9e027f60 100644 --- a/go/vt/vtgate/planbuilder/select.go +++ b/go/vt/vtgate/planbuilder/select.go @@ -343,10 +343,12 @@ func buildLockingPrimitive(sel *sqlparser.Select, vschema ContextVSchema) (engin if err != nil { return nil, err } + buf := sqlparser.NewTrackedBuffer(sqlparser.FormatImpossibleQuery).WriteNode(sel) return &engine.Lock{ Keyspace: ks, TargetDestination: key.DestinationKeyspaceID{0}, Query: sqlparser.String(sel), + FieldQuery: buf.String(), }, nil } From fac219151a35071cdfe0acb72d4f7de72beec176 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Wed, 3 Nov 2021 13:11:42 +0530 Subject: [PATCH 3/3] fix plan test output Signed-off-by: Harshit Gangal --- .../planbuilder/testdata/lock_cases.txt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/go/vt/vtgate/planbuilder/testdata/lock_cases.txt b/go/vt/vtgate/planbuilder/testdata/lock_cases.txt index c2629626d67..e4591cd9a2b 100644 --- a/go/vt/vtgate/planbuilder/testdata/lock_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/lock_cases.txt @@ -10,6 +10,7 @@ "Sharded": false }, "TargetDestination": "KeyspaceID(00)", + "FieldQuery": "select get_lock('xyz', 10) from dual where 1 != 1", "Query": "select get_lock('xyz', 10) from dual" } } @@ -27,11 +28,30 @@ Gen4 plan same as above "Sharded": false }, "TargetDestination": "KeyspaceID(00)", + "FieldQuery": "select is_free_lock('xyz') from dual where 1 != 1", "Query": "select is_free_lock('xyz') from dual" } } Gen4 plan same as above +# get_lock from dual prepare query +"select get_lock(?, ?)" +{ + "QueryType": "SELECT", + "Original": "select get_lock(?, ?)", + "Instructions": { + "OperatorType": "Lock", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "TargetDestination": "KeyspaceID(00)", + "FieldQuery": "select get_lock(:v1, :v2) from dual where 1 != 1", + "Query": "select get_lock(:v1, :v2) from dual" + } +} +Gen4 plan same as above + # lock tables read "lock tables t as x read local" {