Skip to content

Commit cf96ea1

Browse files
stevehansenclaude
andcommitted
fix: Restore implicit alias assignment for views in subquery scopes
Commit 5c2581f added a uniqueness guard to implicit alias assignment that treated the entire AST as a single scope. This broke views where the same view is referenced in multiple subqueries (e.g. OUTER APPLY), since only the first occurrence got an alias and the rest triggered "Use of tables without using an alias" errors. Revert to the v0.4.0 behavior of unconditionally assigning BaseIdentifier as the implicit alias — SQL subquery scopes allow duplicate alias names. Add regression test for the multi-scope case. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 76c7cc6 commit cf96ea1

File tree

2 files changed

+29
-18
lines changed

2 files changed

+29
-18
lines changed

src/SqlInliner.Tests/AdditionalTests.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,32 @@ public void ViewWithoutAliasGetsDefaultAlias()
4747
referenced.Alias.ShouldNotBeNull();
4848
referenced.Alias!.Value.ShouldBe("VPeople");
4949
}
50+
51+
[Test]
52+
public void SameViewInMultipleSubqueriesGetsImplicitAlias()
53+
{
54+
var connection = new DatabaseConnection();
55+
connection.AddViewDefinition(DatabaseConnection.ToObjectName("dbo", "VStatus"),
56+
"CREATE VIEW dbo.VStatus AS SELECT Id, Code FROM dbo.Statuses");
57+
58+
// VStatus is referenced twice in separate subqueries — both without explicit alias
59+
const string viewSql = @"
60+
CREATE VIEW dbo.VTest AS
61+
SELECT
62+
(SELECT TOP 1 VStatus.Code FROM dbo.VStatus WHERE VStatus.Id = t.StatusA) AS StatusA,
63+
(SELECT TOP 1 VStatus.Code FROM dbo.VStatus WHERE VStatus.Id = t.StatusB) AS StatusB
64+
FROM dbo.Items t";
65+
66+
var (view, errors) = DatabaseView.FromSql(connection, viewSql);
67+
errors.Count.ShouldBe(0);
68+
view.ShouldNotBeNull();
69+
70+
// Both references should get an implicit alias
71+
foreach (var v in view!.References.Views)
72+
v.Alias.ShouldNotBeNull();
73+
74+
// Should inline without errors
75+
var inliner = new DatabaseViewInliner(connection, viewSql, InlinerOptions.Recommended());
76+
inliner.Errors.ShouldBeEmpty();
77+
}
5078
}

src/SqlInliner/DatabaseView.cs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,8 @@ public static (DatabaseView?, IList<ParseError>) FromSql(DatabaseConnection conn
6262

6363
// TODO: Verify that we have all required properties on the ReferencesVisitor
6464

65-
var usedAliases = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
66-
foreach (var reference in references.NamedTableReferences)
67-
{
68-
if (reference.Alias != null)
69-
usedAliases.Add(reference.Alias.Value);
70-
}
71-
7265
foreach (var view in references.Views)
73-
{
74-
if (view.Alias == null)
75-
{
76-
var implicitAlias = view.SchemaObject.BaseIdentifier.Value;
77-
if (!usedAliases.Contains(implicitAlias))
78-
{
79-
view.Alias = new Identifier { Value = implicitAlias };
80-
usedAliases.Add(implicitAlias);
81-
}
82-
}
83-
}
66+
view.Alias ??= view.SchemaObject.BaseIdentifier;
8467

8568
foreach (var columnReference in references.ColumnReferences)
8669
{

0 commit comments

Comments
 (0)