From f2d4ad32f0e33dee1917dd716e6068359f8beaef Mon Sep 17 00:00:00 2001 From: Bruno Calza Date: Tue, 9 May 2023 09:24:39 -0300 Subject: [PATCH] adds support for alter table Signed-off-by: Bruno Calza --- go.mod | 2 +- go.sum | 20 ++------- internal/tableland/acl.go | 4 ++ pkg/client/v1/client_test.go | 19 ++++++--- .../impl/eventprocessor_replayhistory_test.go | 2 +- .../impl/executor/impl/txnscope_runsql.go | 12 +++++- .../executor/impl/txnscope_runsql_test.go | 42 +++++++++++++++++++ pkg/parsing/impl/validator.go | 3 ++ pkg/parsing/impl/validator_test.go | 28 +++++++++++++ 9 files changed, 107 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 6789882a..00a2d67d 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/sethvargo/go-limiter v0.7.2 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.2 - github.com/tablelandnetwork/sqlparser v0.0.0-20230516213554-c251484b2141 + github.com/tablelandnetwork/sqlparser v0.0.0-20230518143735-838d223866f6 github.com/textileio/cli v1.0.2 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0 go.opentelemetry.io/otel v1.14.0 diff --git a/go.sum b/go.sum index 175fa55f..25e47a10 100644 --- a/go.sum +++ b/go.sum @@ -1295,22 +1295,10 @@ github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/tablelandnetwork/sqlparser v0.0.0-20230328132500-785ebca8e351 h1:aHuHicCezduOZVQXPXFM5MJ+h73caB2OUvVjGffzIsc= -github.com/tablelandnetwork/sqlparser v0.0.0-20230328132500-785ebca8e351/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= -github.com/tablelandnetwork/sqlparser v0.0.0-20230420192826-7c549ca44bf8 h1:mC58HOJfkfPsqetYd4hpCp0ey5qb9/ZkIRZEx+d2b4U= -github.com/tablelandnetwork/sqlparser v0.0.0-20230420192826-7c549ca44bf8/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= -github.com/tablelandnetwork/sqlparser v0.0.0-20230502223534-5872144545c4 h1:YjROwj4D7PXJbKCNdpTZJM8TpfKhdFgdzzjh3RTY1wo= -github.com/tablelandnetwork/sqlparser v0.0.0-20230502223534-5872144545c4/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= -github.com/tablelandnetwork/sqlparser v0.0.0-20230502232446-6e10f18895a3 h1:QyOUHf3JEz3p3JrijVHRggaPKahuJLuxyslxlMmuXAc= -github.com/tablelandnetwork/sqlparser v0.0.0-20230502232446-6e10f18895a3/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= -github.com/tablelandnetwork/sqlparser v0.0.0-20230512140127-295f5d9328d3 h1:GG6+Ydq75q1sN+aryvtblhX/iH1QixsOzy3neOE0MOA= -github.com/tablelandnetwork/sqlparser v0.0.0-20230512140127-295f5d9328d3/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= -github.com/tablelandnetwork/sqlparser v0.0.0-20230512150513-bea6933a3c28 h1:LItobZtMndgp0gVAot6OYruJavXndkmHcJN4LaNjCLc= -github.com/tablelandnetwork/sqlparser v0.0.0-20230512150513-bea6933a3c28/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= -github.com/tablelandnetwork/sqlparser v0.0.0-20230516205558-f93193cec061 h1:hy+sHKMwf58mMdJoJO496mb8aDwiA10TmWlhNXfhHNg= -github.com/tablelandnetwork/sqlparser v0.0.0-20230516205558-f93193cec061/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= -github.com/tablelandnetwork/sqlparser v0.0.0-20230516213554-c251484b2141 h1:mLJmSw0iqfEQR6h/FxuhvDdsNNaDsu33kQkvldWhgIw= -github.com/tablelandnetwork/sqlparser v0.0.0-20230516213554-c251484b2141/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= +github.com/tablelandnetwork/sqlparser v0.0.0-20230517143402-3ab9022be0df h1:SUG49BUSuO9S6U3RjAV8a0NIDRByHj3kSt8/QR75rtI= +github.com/tablelandnetwork/sqlparser v0.0.0-20230517143402-3ab9022be0df/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= +github.com/tablelandnetwork/sqlparser v0.0.0-20230518143735-838d223866f6 h1:f8TRklEZmT4fJd7wE+oktjf4wQndJ5BqkwXOpuHrYBU= +github.com/tablelandnetwork/sqlparser v0.0.0-20230518143735-838d223866f6/go.mod h1:S+M/v3Q8X+236kQxMQziFcLId2Cscb1LzW06IUVhljE= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/textileio/cli v1.0.2 h1:qSp/x4d/9SZ93TxhgZnE5okRKqzqHqrzAwKAPjuPw50= github.com/textileio/cli v1.0.2/go.mod h1:vTlCvvVyOmXXLwddCcBg3PDavfUsCkRBZoyr6Nu1lkc= diff --git a/internal/tableland/acl.go b/internal/tableland/acl.go index 102c7ff5..bfd3263c 100644 --- a/internal/tableland/acl.go +++ b/internal/tableland/acl.go @@ -88,6 +88,8 @@ const ( OpRevoke // OpCreate is represents a CREATE query. OpCreate + // OpAlter is represents a ALTER query. + OpAlter ) // String returns the string representation of the operation. @@ -107,6 +109,8 @@ func (op Operation) String() string { return "OpRevoke" case OpCreate: return "OpCreate" + case OpAlter: + return "OpAlter" } return "" diff --git a/pkg/client/v1/client_test.go b/pkg/client/v1/client_test.go index 5739ad59..0c8914bb 100644 --- a/pkg/client/v1/client_test.go +++ b/pkg/client/v1/client_test.go @@ -20,14 +20,15 @@ func TestCreate(t *testing.T) { func TestWrite(t *testing.T) { calls := setup(t) tableName := requireCreate(t, calls) - requireWrite(t, calls, tableName) + requireReceipt(t, calls, requireInsert(t, calls, tableName), WaitFor(time.Second*10)) + requireReceipt(t, calls, requireAlter(t, calls, tableName), WaitFor(time.Second*10)) } func TestRead(t *testing.T) { t.Run("status 200", func(t *testing.T) { calls := setup(t) tableName := requireCreate(t, calls) - hash := requireWrite(t, calls, tableName) + hash := requireInsert(t, calls, tableName) requireReceipt(t, calls, hash, WaitFor(time.Second*10)) type result struct { @@ -68,7 +69,7 @@ func TestGetReceipt(t *testing.T) { t.Run("status 200", func(t *testing.T) { calls := setup(t) tableName := requireCreate(t, calls) - hash := requireWrite(t, calls, tableName) + hash := requireInsert(t, calls, tableName) requireReceipt(t, calls, hash, WaitFor(time.Second*10)) }) @@ -152,8 +153,8 @@ func TestBlockNum(t *testing.T) { // We create a table and do two inserts, that will increase our block number to 5. tableName := requireCreate(t, calls) - requireReceipt(t, calls, requireWrite(t, calls, tableName), WaitFor(time.Second*10)) - requireReceipt(t, calls, requireWrite(t, calls, tableName), WaitFor(time.Second*10)) + requireReceipt(t, calls, requireInsert(t, calls, tableName), WaitFor(time.Second*10)) + requireReceipt(t, calls, requireInsert(t, calls, tableName), WaitFor(time.Second*10)) type result struct { BlockNumber int64 `json:"bn"` @@ -171,12 +172,18 @@ func requireCreate(t *testing.T, calls clientCalls) string { return tableName } -func requireWrite(t *testing.T, calls clientCalls, table string) string { +func requireInsert(t *testing.T, calls clientCalls, table string) string { hash := calls.write(fmt.Sprintf("insert into %s (bar) values('baz')", table)) require.NotEmpty(t, hash) return hash } +func requireAlter(t *testing.T, calls clientCalls, table string) string { + hash := calls.write(fmt.Sprintf("alter table %s rename bar to foo", table)) + require.NotEmpty(t, hash) + return hash +} + func requireReceipt(t *testing.T, calls clientCalls, hash string, opts ...ReceiptOption) *apiv1.TransactionReceipt { res, found := calls.receipt(hash, opts...) require.True(t, found) diff --git a/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go b/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go index bd0fe825..52e2a4bf 100644 --- a/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go +++ b/pkg/eventprocessor/impl/eventprocessor_replayhistory_test.go @@ -43,7 +43,7 @@ func TestReplayProductionHistory(t *testing.T) { 69: "b1136bd05118349be32372509f05c240180a93d3", 137: "12b3d0aa62b4e61b10ea81c16bf050f8c27b1dca", 420: "058bd19e7874fa3c9436b0cebbcf5846f7c347f3", - 80001: "5c9709607bd9da6e5e80df04e9ec2b30b488793d", + 80001: "92e3252755054c969a1e1118a8e3743b2b1768a7", 421613: "18ae0ef43cdedc548706c61dccae533411f9d514", } diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go index d502dc97..e150afc5 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql.go @@ -81,7 +81,7 @@ func (ts *txnScope) execWriteQueries( return fmt.Errorf("executing grant stmt: %w", err) } case parsing.WriteStmt: - if err := ts.executeWriteStmt(ctx, stmt, controller, policy, beforeRowCount); err != nil { + if err := ts.executeWriteStmt(ctx, stmt, controller, policy, beforeRowCount, isOwner); err != nil { return fmt.Errorf("executing write stmt: %w", err) } default: @@ -220,7 +220,17 @@ func (ts *txnScope) executeWriteStmt( addr common.Address, policy tableland.Policy, beforeRowCount int, + isOwner bool, ) error { + if ws.Operation() == tableland.OpAlter { + if !isOwner { + return &errQueryExecution{ + Code: "ACL_NOT_OWNER", + Msg: "non owner cannot execute alter stmt", + } + } + } + controller, err := ts.getController(ctx, ws.GetTableID()) if err != nil { return fmt.Errorf("checking controller is set: %w", err) diff --git a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go index f2ee4dc7..d92730d3 100644 --- a/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go +++ b/pkg/eventprocessor/impl/executor/impl/txnscope_runsql_test.go @@ -423,6 +423,48 @@ func TestRunSQL_WriteQueriesWithPolicies(t *testing.T) { }) } +func TestRunSQL_AlterTable(t *testing.T) { + t.Parallel() + ctx := context.Background() + + ex, _ := newExecutorWithStringTable(t, 0) + + bs, err := ex.NewBlockScope(ctx, 0) + require.NoError(t, err) + + policy := ethereum.ITablelandControllerPolicy{ + AllowInsert: true, + AllowUpdate: true, + AllowDelete: true, + WhereClause: "", + WithCheck: "", + UpdatableColumns: nil, + } + + // create an event where isOwner is false + event := ðereum.ContractRunSQL{ + Caller: common.HexToAddress("0xb451cee4A42A652Fe77d373BAe66D42fd6B8D8FF"), + IsOwner: false, + TableId: big.NewInt(100), + Statement: "ALTER TABLE foo_1337_100 ADD COLUMN bar text", + Policy: policy, + } + + var hashBytes [common.HashLength]byte + binary.LittleEndian.PutUint64(hashBytes[:], rand.Uint64()) + txnHash := common.BytesToHash(hashBytes[:]) + + txnResult, err := bs.ExecuteTxnEvents( + context.Background(), + eventfeed.TxnEvents{ + TxnHash: txnHash, + Events: []interface{}{event}, + }, + ) + require.NoError(t, err) + require.Contains(t, *txnResult.Error, "non owner cannot execute alter stmt") +} + func TestRunSQL_RowCountLimit(t *testing.T) { t.Parallel() ctx := context.Background() diff --git a/pkg/parsing/impl/validator.go b/pkg/parsing/impl/validator.go index a7012e18..e3daf9cd 100644 --- a/pkg/parsing/impl/validator.go +++ b/pkg/parsing/impl/validator.go @@ -166,6 +166,9 @@ func (pp *QueryValidator) ValidateMutatingQuery( if _, ok := s.(*sqlparser.Delete); ok { mutatingStmt.operation = tableland.OpDelete } + if _, ok := s.(*sqlparser.AlterTable); ok { + mutatingStmt.operation = tableland.OpAlter + } ret[i] = &writeStmt{mutatingStmt} case sqlparser.GrantOrRevokeStatement: if _, ok := s.(*sqlparser.Grant); ok { diff --git a/pkg/parsing/impl/validator_test.go b/pkg/parsing/impl/validator_test.go index bdacf3a8..df773a20 100644 --- a/pkg/parsing/impl/validator_test.go +++ b/pkg/parsing/impl/validator_test.go @@ -218,6 +218,34 @@ func TestWriteQuery(t *testing.T) { expErrType: nil, }, + // ALTER TABLE + { + name: "valid alter table", + query: "ALTER TABLE a_4_10 RENAME COLUMN a to b", + tableID: big.NewInt(10), + chainID: 4, + namePrefix: "a", + expErrType: nil, + }, + + { + name: "valid alter table", + query: "ALTER TABLE a_4_10 ADD COLUMN a int", + tableID: big.NewInt(10), + chainID: 4, + namePrefix: "a", + expErrType: nil, + }, + + { + name: "valid alter table", + query: "ALTER TABLE a_4_10 DROP COLUMN a", + tableID: big.NewInt(10), + chainID: 4, + namePrefix: "a", + expErrType: nil, + }, + // Only reference a single table { name: "update different tables",