diff --git a/go.mod b/go.mod index 4d6139ba20..7cf60ea2dc 100644 --- a/go.mod +++ b/go.mod @@ -9,10 +9,10 @@ require ( github.com/dolthub/dolt/go v0.40.5-0.20260108000424-ed62ee89285b github.com/dolthub/eventsapi_schema v0.0.0-20250915094920-eadfd39051ca github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 - github.com/dolthub/go-mysql-server v0.20.1-0.20260108224859-4dd05696542e + github.com/dolthub/go-mysql-server v0.20.1-0.20260110001532-5eb9ccaba8a1 github.com/dolthub/pg_query_go/v6 v6.0.0-20251215122834-fb20be4254d1 github.com/dolthub/sqllogictest/go v0.0.0-20240618184124-ca47f9354216 - github.com/dolthub/vitess v0.0.0-20260108222406-f8a2587c4954 + github.com/dolthub/vitess v0.0.0-20260109110924-205efc8530f1 github.com/fatih/color v1.13.0 github.com/goccy/go-json v0.10.2 github.com/gogo/protobuf v1.3.2 diff --git a/go.sum b/go.sum index 1b855f2b2b..659cd46fc2 100644 --- a/go.sum +++ b/go.sum @@ -238,8 +238,8 @@ github.com/dolthub/fslock v0.0.3 h1:iLMpUIvJKMKm92+N1fmHVdxJP5NdyDK5bK7z7Ba2s2U= github.com/dolthub/fslock v0.0.3/go.mod h1:QWql+P17oAAMLnL4HGB5tiovtDuAjdDTPbuqx7bYfa0= github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 h1:zxMsH7RLiG+dlZ/y0LgJHTV26XoiSJcuWq+em6t6VVc= github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790/go.mod h1:F3cnm+vMRK1HaU6+rNqQrOCyR03HHhR1GWG2gnPOqaE= -github.com/dolthub/go-mysql-server v0.20.1-0.20260108224859-4dd05696542e h1:OKp5W4bgSJIAKESEtBtyOWF85HwvE7UIe+T204v5EN0= -github.com/dolthub/go-mysql-server v0.20.1-0.20260108224859-4dd05696542e/go.mod h1:2bgnal91FRGVdJyirmUSMCd1Tp3Ci8dTDsrJWkTp/hs= +github.com/dolthub/go-mysql-server v0.20.1-0.20260110001532-5eb9ccaba8a1 h1:n2BXaNdJZWPu7Bpeeb0gSxG0fHqfFWCiO2Agcyygndo= +github.com/dolthub/go-mysql-server v0.20.1-0.20260110001532-5eb9ccaba8a1/go.mod h1:ZODUC6XlqCx3DgHl6x7cWwMR0uq7XzVU0adsJvjZJTY= github.com/dolthub/gozstd v0.0.0-20240423170813-23a2903bca63 h1:OAsXLAPL4du6tfbBgK0xXHZkOlos63RdKYS3Sgw/dfI= github.com/dolthub/gozstd v0.0.0-20240423170813-23a2903bca63/go.mod h1:lV7lUeuDhH5thVGDCKXbatwKy2KW80L4rMT46n+Y2/Q= github.com/dolthub/ishell v0.0.0-20240701202509-2b217167d718 h1:lT7hE5k+0nkBdj/1UOSFwjWpNxf+LCApbRHgnCA17XE= @@ -250,8 +250,8 @@ github.com/dolthub/pg_query_go/v6 v6.0.0-20251215122834-fb20be4254d1 h1:GY17cGA4 github.com/dolthub/pg_query_go/v6 v6.0.0-20251215122834-fb20be4254d1/go.mod h1:qnrZP3/1slFl2Bq5yw38HLOsArZareGwdpEceriblLc= github.com/dolthub/sqllogictest/go v0.0.0-20240618184124-ca47f9354216 h1:JWkKRE4EHUcEVQCMRBej8DYxjYjRz/9MdF/NNQh0o70= github.com/dolthub/sqllogictest/go v0.0.0-20240618184124-ca47f9354216/go.mod h1:e/FIZVvT2IR53HBCAo41NjqgtEnjMJGKca3Y/dAmZaA= -github.com/dolthub/vitess v0.0.0-20260108222406-f8a2587c4954 h1:VN2ZjnYPyxcAN/XetvcdumFbI2Ad/Gb47Qwdo9REY3A= -github.com/dolthub/vitess v0.0.0-20260108222406-f8a2587c4954/go.mod h1:FLWqdXsAeeBQyFwDjmBVu0GnbjI2MKeRf3tRVdJEKlI= +github.com/dolthub/vitess v0.0.0-20260109110924-205efc8530f1 h1:souetbYNBRHrt9y990VGD1jkzCIQ0jC+gxMdFOEjL+g= +github.com/dolthub/vitess v0.0.0-20260109110924-205efc8530f1/go.mod h1:FLWqdXsAeeBQyFwDjmBVu0GnbjI2MKeRf3tRVdJEKlI= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= diff --git a/server/ast/select_clause.go b/server/ast/select_clause.go index 7f0953afea..f71a7b38e0 100644 --- a/server/ast/select_clause.go +++ b/server/ast/select_clause.go @@ -15,7 +15,6 @@ package ast import ( - "github.com/cockroachdb/errors" "github.com/dolthub/go-mysql-server/sql/expression" vitess "github.com/dolthub/vitess/go/vt/sqlparser" @@ -160,8 +159,17 @@ PostJoinRewrite: } } } + distinct := node.Distinct + var distinctOn vitess.Exprs if len(node.DistinctOn) > 0 { - return nil, errors.Errorf("DISTINCT ON is not yet supported") + distinct = true + distinctOn = make(vitess.Exprs, len(node.DistinctOn)) + for i, expr := range node.DistinctOn { + distinctOn[i], err = nodeExpr(ctx, expr) + if err != nil { + return nil, err + } + } } where, err := nodeWhere(ctx, node.Where) if err != nil { @@ -180,7 +188,10 @@ PostJoinRewrite: return nil, err } return &vitess.Select{ - QueryOpts: vitess.QueryOpts{Distinct: node.Distinct}, + QueryOpts: vitess.QueryOpts{ + Distinct: distinct, + DistinctOn: distinctOn, + }, SelectExprs: selectExprs, From: from, Where: where, diff --git a/testing/go/select_test.go b/testing/go/select_test.go index 6fc2040d04..1f8eb00191 100755 --- a/testing/go/select_test.go +++ b/testing/go/select_test.go @@ -23,6 +23,113 @@ import ( // TestSelect covers SELECT syntax not covered by our MySQL select tests func TestSelect(t *testing.T) { RunScripts(t, []ScriptTest{ + { + Name: "SELECT DISTINCT ON", + SetUpScript: []string{ + "CREATE TABLE test (v1 INT4, v2 INT4);", + "INSERT INTO test VALUES (1, 3), (1, 4), (2, 3), (2, 4);", + "CREATE TABLE test2 (v1 INT4, v2 INT4, v3 INT4);", + "INSERT INTO test2 VALUES (1, 3, 5), (2, 3, 5), (1, 4, 5), (2, 4, 5);", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "SELECT * FROM test ORDER BY v1, v2;", + Expected: []sql.Row{ + {1, 3}, + {1, 4}, + {2, 3}, + {2, 4}, + }, + }, + { + Query: "SELECT DISTINCT * FROM test ORDER BY v1, v2;", + Expected: []sql.Row{ + {1, 3}, + {1, 4}, + {2, 3}, + {2, 4}, + }, + }, + { + Query: "SELECT DISTINCT ON(v1) * FROM test ORDER BY v1, v2;", + Expected: []sql.Row{ + {1, 3}, + {2, 3}, + }, + }, + { + Query: "SELECT DISTINCT ON(v2) * FROM test ORDER BY v2, v1;", + Expected: []sql.Row{ + {1, 3}, + {1, 4}, + }, + }, + { + Query: "SELECT DISTINCT ON(v1) * FROM test ORDER BY v2, v1;", + ExpectedErr: sql.ErrDistinctOnMatchOrderBy.Message, + }, + { + Query: "SELECT DISTINCT ON(v2) * FROM test ORDER BY v2 DESC, v1 DESC;", + Expected: []sql.Row{ + {2, 4}, + {2, 3}, + }, + }, + { + Query: "SELECT DISTINCT ON(v2, v1) * FROM test2 ORDER BY v1, v2;", + Expected: []sql.Row{ + {1, 3, 5}, + {1, 4, 5}, + {2, 3, 5}, + {2, 4, 5}, + }, + }, + { + Query: "SELECT DISTINCT ON(v2, v1) * FROM test2 ORDER BY v1, v2 DESC;", + Expected: []sql.Row{ + {1, 4, 5}, + {1, 3, 5}, + {2, 4, 5}, + {2, 3, 5}, + }, + }, + { + Query: "SELECT DISTINCT ON(v2, v1) * FROM test2 ORDER BY v1, v2 LIMIT 1;", + Expected: []sql.Row{ + {1, 3, 5}, + }, + }, + { + Query: "SELECT DISTINCT ON(v2, v1) * FROM test2 ORDER BY v1, v2 DESC LIMIT 1;", + Expected: []sql.Row{ + {1, 4, 5}, + }, + }, + { + Query: "SELECT DISTINCT ON(v1, v2, v3) * FROM test2 ORDER BY v1, v2;", + Expected: []sql.Row{ + {1, 3, 5}, + {1, 4, 5}, + {2, 3, 5}, + {2, 4, 5}, + }, + }, + { + Query: "SELECT DISTINCT ON(v3) v1 FROM test2;", + Expected: []sql.Row{ + {1}, + }, + }, + { + Query: "SELECT DISTINCT ON(v1, v3) * FROM test2 ORDER BY v1, v2;", + ExpectedErr: sql.ErrDistinctOnMatchOrderBy.Message, + }, + { + Query: "SELECT DISTINCT ON(v2) * FROM test2 ORDER BY v1, v2;", + ExpectedErr: sql.ErrDistinctOnMatchOrderBy.Message, + }, + }, + }, { Name: "select values", Assertions: []ScriptTestAssertion{