Skip to content

Commit 8d9ec55

Browse files
authored
Merge pull request #596 from dolthub/zachmu/discard
Implemented DISCARD
2 parents fb68084 + ff0c0a8 commit 8d9ec55

File tree

5 files changed

+174
-10
lines changed

5 files changed

+174
-10
lines changed

server/ast/discard.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,19 @@ import (
2020
vitess "github.com/dolthub/vitess/go/vt/sqlparser"
2121

2222
"github.com/dolthub/doltgresql/postgres/parser/sem/tree"
23+
"github.com/dolthub/doltgresql/server/node"
2324
)
2425

2526
// nodeDiscard handles *tree.Discard nodes.
26-
func nodeDiscard(node *tree.Discard) (vitess.Statement, error) {
27-
if node == nil {
27+
func nodeDiscard(discard *tree.Discard) (vitess.Statement, error) {
28+
if discard == nil {
2829
return nil, nil
2930
}
30-
return nil, fmt.Errorf("DISCARD is not yet supported")
31+
if discard.Mode != tree.DiscardModeAll {
32+
return nil, fmt.Errorf("unhandled DISCARD mode: %v", discard.Mode)
33+
}
34+
35+
return vitess.InjectedStatement{
36+
Statement: node.DiscardStatement{},
37+
}, nil
3138
}

server/connection_handler.go

100755100644
Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"github.com/dolthub/doltgresql/postgres/parser/parser"
4040
"github.com/dolthub/doltgresql/server/ast"
4141
pgexprs "github.com/dolthub/doltgresql/server/expression"
42+
"github.com/dolthub/doltgresql/server/node"
4243
pgtypes "github.com/dolthub/doltgresql/server/types"
4344
)
4445

@@ -347,15 +348,29 @@ func (h *ConnectionHandler) handleQuery(message messages.Query) error {
347348
delete(h.preparedStatements, "")
348349
delete(h.portals, "")
349350

350-
// The Deallocate message does not get passed to the engine, since we handle allocation / deallocation of
351-
// prepared statements at this layer
351+
// Certain statement types get handled directly by the handler instead of being passed to the engine
352+
err, handled = h.handleQueryOutsideEngine(query)
353+
if handled {
354+
return err
355+
}
356+
357+
return h.query(query)
358+
}
359+
360+
// handleQueryOutsideEngine handles any queries that should be handled by the handler directly, rather than being
361+
// passed to the engine. Returns true if the query was handled and any error that occurred while doing so.
362+
func (h *ConnectionHandler) handleQueryOutsideEngine(query ConvertedQuery) (error, bool) {
352363
switch stmt := query.AST.(type) {
353364
case *sqlparser.Deallocate:
354365
// TODO: handle ALL keyword
355-
return h.deallocatePreparedStatement(stmt.Name, h.preparedStatements, query, h.Conn())
366+
return h.deallocatePreparedStatement(stmt.Name, h.preparedStatements, query, h.Conn()), true
367+
case sqlparser.InjectedStatement:
368+
switch stmt.Statement.(type) {
369+
case node.DiscardStatement:
370+
return h.discardAll(query, h.Conn()), true
371+
}
356372
}
357-
358-
return h.query(query)
373+
return nil, false
359374
}
360375

361376
// handleParse handles a parse message, returning any error that occurs
@@ -497,7 +512,13 @@ func (h *ConnectionHandler) handleExecute(message messages.Execute) error {
497512
return connection.Send(h.Conn(), messages.EmptyQueryResponse{})
498513
}
499514

500-
err := h.handler.(mysql.ExtendedHandler).ComExecuteBound(context.Background(), h.mysqlConn, query.String, portalData.BoundPlan, spoolRowsCallback(h.Conn(), &complete, true))
515+
// Certain statement types get handled directly by the handler instead of being passed to the engine
516+
err, handled := h.handleQueryOutsideEngine(query)
517+
if handled {
518+
return err
519+
}
520+
521+
err = h.handler.(mysql.ExtendedHandler).ComExecuteBound(context.Background(), h.mysqlConn, query.String, portalData.BoundPlan, spoolRowsCallback(h.Conn(), &complete, true))
501522
if err != nil {
502523
return err
503524
}
@@ -979,3 +1000,18 @@ func (h *ConnectionHandler) bindParams(
9791000

9801001
return plan, fields, err
9811002
}
1003+
1004+
// discardAll handles the DISCARD ALL command
1005+
func (h *ConnectionHandler) discardAll(query ConvertedQuery, conn net.Conn) error {
1006+
err := h.handler.ComResetConnection(h.mysqlConn)
1007+
if err != nil {
1008+
return err
1009+
}
1010+
1011+
commandComplete := messages.CommandComplete{
1012+
Query: query.String,
1013+
Tag: query.StatementTag,
1014+
}
1015+
1016+
return connection.Send(conn, commandComplete)
1017+
}

server/node/discard.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package node
2+
3+
import (
4+
"github.com/dolthub/go-mysql-server/sql"
5+
"github.com/dolthub/vitess/go/vt/sqlparser"
6+
)
7+
8+
// DiscardStatement is just a marker type, since all functionality is handled by the connection handler,
9+
// rather than the engine. It has to conform to the sql.ExecSourceRel interface to be used in the handler, but this
10+
// functionality is all unused.
11+
type DiscardStatement struct{}
12+
13+
var _ sqlparser.Injectable = DiscardStatement{}
14+
var _ sql.ExecSourceRel = DiscardStatement{}
15+
16+
func (d DiscardStatement) Resolved() bool {
17+
return true
18+
}
19+
20+
func (d DiscardStatement) String() string {
21+
return "DISCARD ALL"
22+
}
23+
24+
func (d DiscardStatement) Schema() sql.Schema {
25+
return nil
26+
}
27+
28+
func (d DiscardStatement) Children() []sql.Node {
29+
return nil
30+
}
31+
32+
func (d DiscardStatement) WithChildren(children ...sql.Node) (sql.Node, error) {
33+
return d, nil
34+
}
35+
36+
func (d DiscardStatement) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool {
37+
return true
38+
}
39+
40+
func (d DiscardStatement) IsReadOnly() bool {
41+
return true
42+
}
43+
44+
func (d DiscardStatement) RowIter(ctx *sql.Context, r sql.Row) (sql.RowIter, error) {
45+
panic("DISCARD ALL should be handled by the connection handler")
46+
}
47+
48+
func (d DiscardStatement) WithResolvedChildren(children []any) (any, error) {
49+
return d, nil
50+
}

testing/generation/command_docs/output/discard_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import "testing"
1818

1919
func TestDiscard(t *testing.T) {
2020
tests := []QueryParses{
21-
Parses("DISCARD ALL"),
21+
Converts("DISCARD ALL"),
2222
Unimplemented("DISCARD PLANS"),
2323
Unimplemented("DISCARD SEQUENCES"),
2424
Unimplemented("DISCARD TEMPORARY"),

testing/go/session_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package _go
2+
3+
import (
4+
"testing"
5+
6+
"github.com/dolthub/go-mysql-server/sql"
7+
)
8+
9+
func TestDiscard(t *testing.T) {
10+
RunScripts(t, []ScriptTest{
11+
{
12+
Name: "Test discard",
13+
SetUpScript: []string{
14+
`CREATE temporary TABLE test (a INT)`,
15+
`insert into test values (1)`,
16+
},
17+
Assertions: []ScriptTestAssertion{
18+
{
19+
Query: "select * from test",
20+
Expected: []sql.Row{
21+
{1},
22+
},
23+
},
24+
{
25+
Query: "DISCARD ALL",
26+
Expected: []sql.Row{},
27+
},
28+
{
29+
Query: "select * from test",
30+
ExpectedErr: "table not found",
31+
},
32+
},
33+
},
34+
{
35+
Name: "Test discard errors",
36+
SetUpScript: []string{
37+
`CREATE temporary TABLE test (a INT)`,
38+
`insert into test values (1)`,
39+
},
40+
Assertions: []ScriptTestAssertion{
41+
{
42+
Query: "DISCARD SEQUENCES",
43+
ExpectedErr: "unimplemented",
44+
},
45+
{
46+
Query: "select * from test",
47+
Expected: []sql.Row{
48+
{1},
49+
},
50+
},
51+
},
52+
},
53+
{
54+
Name: "Test discard in transaction",
55+
SetUpScript: []string{
56+
`CREATE temporary TABLE test (a INT)`,
57+
`insert into test values (1)`,
58+
},
59+
Assertions: []ScriptTestAssertion{
60+
{
61+
Query: "BEGIN",
62+
},
63+
{
64+
Query: "DISCARD ALL",
65+
ExpectedErr: "DISCARD ALL cannot run inside a transaction block",
66+
Skip: true, // not yet implemented
67+
},
68+
},
69+
},
70+
})
71+
}

0 commit comments

Comments
 (0)