Skip to content
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

cherry-pick 2.0: sql: use a reusable name resolution algo for star expansions #24842

Merged
merged 1 commit into from
Apr 16, 2018
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
10 changes: 1 addition & 9 deletions pkg/sql/data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,19 +506,11 @@ func expandStar(
}
}
case *tree.AllColumnsSelector:
tn, err := tree.NormalizeTableName(&sel.TableName)
if err != nil {
return nil, nil, err
}
resolver := sqlbase.ColumnResolver{Sources: src}
numRes, _, _, err := resolver.FindSourceMatchingName(ctx, tn)
_, _, err := sel.Resolve(ctx, &resolver)
if err != nil {
return nil, nil, err
}
if numRes == tree.NoResults {
return nil, nil, pgerror.NewErrorf(pgerror.CodeUndefinedColumnError,
"no data source named %q", tree.ErrString(&tn))
}
ds := src[resolver.ResolverState.SrcIdx]
colSet := ds.SourceAliases[resolver.ResolverState.ColSetIdx].ColumnSet
for i, ok := colSet.Next(0); ok; i, ok = colSet.Next(i + 1) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/sql/logictest/testdata/logic_test/insert
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ INSERT INTO return AS r VALUES (5, 6)
statement ok
INSERT INTO return VALUES (5, 6) RETURNING test.return.a

statement error no data source named "x"
statement error no data source matches pattern: x.\*
INSERT INTO return VALUES (1, 2) RETURNING x.*[1]

statement error column name "x" not found
Expand Down
25 changes: 23 additions & 2 deletions pkg/sql/logictest/testdata/logic_test/select
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,28 @@ SELECT kv.* FROM kv
----
a NULL

query error no data source named "foo"
# Regression tests for #24169
query TT
SELECT test.kv.* FROM kv
----
a NULL

query TT
SELECT test.public.kv.* FROM kv
----
a NULL

query TT
SELECT test.public.kv.* FROM test.kv
----
a NULL

query TT
SELECT test.kv.* FROM test.public.kv
----
a NULL

query error no data source matches pattern: foo.\*
SELECT foo.* FROM kv

query error cannot use "\*" without a FROM clause
Expand All @@ -156,7 +177,7 @@ SELECT 1, * FROM nocols
query error "kv.*" cannot be aliased
SELECT kv.* AS foo FROM kv

query error no data source named "bar.kv"
query error no data source matches pattern: bar.kv.\*
SELECT bar.kv.* FROM kv

# Don't panic with invalid names (#8024)
Expand Down
30 changes: 30 additions & 0 deletions pkg/sql/sem/tree/name_resolution.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,36 @@ type ColumnResolutionResult interface {
ColumnResolutionResult()
}

// Resolve performs name resolution for a qualified star using a resolver.
func (a *AllColumnsSelector) Resolve(
ctx context.Context, r ColumnItemResolver,
) (srcName *TableName, srcMeta ColumnSourceMeta, err error) {
prefix := makeTableNameFromUnresolvedName(&a.TableName)

// Is there a data source with this prefix?
var res NumResolutionResults
res, srcName, srcMeta, err = r.FindSourceMatchingName(ctx, prefix)
if err != nil {
return nil, nil, err
}
if res == NoResults && a.TableName.NumParts == 2 {
// No, but name of form db.tbl.*?
// Special rule for compatibility with CockroachDB v1.x:
// search name db.public.tbl.* instead.
prefix.ExplicitCatalog = true
prefix.CatalogName = prefix.SchemaName
prefix.SchemaName = PublicSchemaName
res, srcName, srcMeta, err = r.FindSourceMatchingName(ctx, prefix)
if err != nil {
return nil, nil, err
}
}
if res == NoResults {
return nil, nil, newSourceNotFoundError("no data source matches pattern: %s", a)
}
return srcName, srcMeta, nil
}

// Resolve performs name resolution for a column item using a resolver.
func (c *ColumnItem) Resolve(
ctx context.Context, r ColumnItemResolver,
Expand Down
61 changes: 61 additions & 0 deletions pkg/sql/sem/tree/name_resolution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,67 @@ func newFakeSource() *fakeSource {
}
}

func TestResolveQualifiedStar(t *testing.T) {
testCases := []struct {
in string
tnout string
csout string
err string
}{
{`a.*`, ``, ``, `no data source matches pattern: a.*`},
{`foo.*`, ``, ``, `ambiguous table name: foo`},
{`db1.public.foo.*`, `db1.public.foo`, `x`, ``},
{`db1.foo.*`, `db1.public.foo`, `x`, ``},
{`dbx.foo.*`, ``, ``, `no data source matches pattern: dbx.foo.*`},
{`kv.*`, `db1.public.kv`, `k, v`, ``},
}
fakeFrom := newFakeSource()
for _, tc := range testCases {
t.Run(tc.in, func(t *testing.T) {
fakeFrom.t = t
tnout, csout, err := func() (string, string, error) {
stmt, err := parser.ParseOne(fmt.Sprintf("SELECT %s", tc.in))
if err != nil {
return "", "", err
}
v := stmt.(*tree.Select).Select.(*tree.SelectClause).Exprs[0].Expr.(tree.VarName)
c, err := v.NormalizeVarName()
if err != nil {
return "", "", err
}
acs, ok := c.(*tree.AllColumnsSelector)
if !ok {
return "", "", fmt.Errorf("var name %s (%T) did not resolve to AllColumnsSelector, found %T instead",
v, v, c)
}
tn, res, err := acs.Resolve(context.Background(), fakeFrom)
if err != nil {
return "", "", err
}
cs, ok := res.(colsRes)
if !ok {
return "", "", fmt.Errorf("fake resolver did not return colsRes, found %T instead", res)
}
nl := tree.NameList(cs)
return tn.String(), nl.String(), nil
}()
if !testutils.IsError(err, tc.err) {
t.Fatalf("%s: expected %s, but found %v", tc.in, tc.err, err)
}
if tc.err != "" {
return
}

if tc.tnout != tnout {
t.Fatalf("%s: expected tn %s, but found %s", tc.in, tc.tnout, tnout)
}
if tc.csout != csout {
t.Fatalf("%s: expected cs %s, but found %s", tc.in, tc.csout, csout)
}
})
}
}

func TestResolveColumnItem(t *testing.T) {
testCases := []struct {
in string
Expand Down