Skip to content

Commit f77e15f

Browse files
committed
Initial support for derived tables.
1 parent b9fe9ae commit f77e15f

3 files changed

Lines changed: 42 additions & 3 deletions

File tree

SqlServerSimulator.Tests/SelectTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,8 @@ public void SelectTwoColumns()
222222
[DataRow("select ,", ",")]
223223
public void SelectSyntaxErrorsAreCorrect(string commandText, string nearSyntax) =>
224224
new Simulation().ValidateSyntaxError(commandText, nearSyntax);
225+
226+
[TestMethod]
227+
public void SelectFromDerivedTable() =>
228+
Assert.AreEqual(1, new Simulation().ExecuteScalar("select x from ( select 1 as x ) as x"));
225229
}

SqlServerSimulator/Parser/Selection.cs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ internal sealed class Selection
88

99
private Selection(SimulatedResultSet results) => this.Results = results;
1010

11-
public static Selection Parse(Simulation simulation, IEnumerator<Token> tokens, ref Token? token, Func<string, object?> getVariableValue)
11+
public static Selection Parse(Simulation simulation, IEnumerator<Token> tokens, ref Token? token, Func<string, object?> getVariableValue, uint depth)
1212
{
1313
token = tokens.RequireNext();
1414

@@ -27,6 +27,12 @@ public static Selection Parse(Simulation simulation, IEnumerator<Token> tokens,
2727
case Comma:
2828
continue;
2929

30+
case CloseParentheses:
31+
if (depth == 0)
32+
throw SimulatedSqlException.SyntaxErrorNear(token);
33+
34+
goto case null;
35+
3036
case null: // "Select" with no "From".
3137
return new(new(
3238
columnIndexes,
@@ -61,7 +67,36 @@ public static Selection Parse(Simulation simulation, IEnumerator<Token> tokens,
6167
table.Rows.Select<object?[], object?[]>(row => [..expressions.Select(x => x.Run(columnName =>
6268
{
6369
var columnIndex = table.Columns.FindIndex(column => Collation.Default.Equals(column.Name, columnName.Last()));
64-
return columnIndex == -1 ? throw SimulatedSqlException.InvalidColumnName(columnName) : row[columnIndex]; }))])));
70+
return columnIndex == -1 ? throw SimulatedSqlException.InvalidColumnName(columnName) : row[columnIndex];
71+
}))])
72+
));
73+
74+
case OpenParentheses:
75+
if ((token = tokens.RequireNext()) is not UnquotedString maybeSelect || maybeSelect.Parse() != Keyword.Select)
76+
throw SimulatedSqlException.SyntaxErrorNear(token);
77+
78+
{
79+
var derived = Selection.Parse(simulation, tokens, ref token, getVariableValue, depth + 1).Results;
80+
81+
if ((token = tokens.RequireNext()) is UnquotedString maybeAs && maybeAs.Parse() == Keyword.As)
82+
{
83+
if (token is not UnquotedString)
84+
break;
85+
}
86+
else
87+
{
88+
break;
89+
}
90+
91+
return new(new(
92+
columnIndexes,
93+
derived.Select<object?[], object?[]>(row => [..expressions.Select(x => x.Run(columnName =>
94+
{
95+
var columnIndex = Array.FindIndex(derived.columnNames, name => Collation.Default.Equals(name, columnName.Last()));
96+
return columnIndex == -1 ? throw SimulatedSqlException.InvalidColumnName(columnName) : row[columnIndex];
97+
}))])
98+
));
99+
}
65100
}
66101

67102
throw new NotSupportedException($"Simulated selection processor expected a source table, found {token}.");

SqlServerSimulator/Simulation.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ internal IEnumerable<SimulatedStatementOutcome> CreateResultSetsForCommand(Simul
218218
break;
219219

220220
case Keyword.Select:
221-
yield return Selection.Parse(this, tokens, ref token, getVariableValue).Results;
221+
yield return Selection.Parse(this, tokens, ref token, getVariableValue, 0).Results;
222222
break;
223223

224224
case Keyword.Insert:

0 commit comments

Comments
 (0)