Skip to content

Commit 5118883

Browse files
committed
Minor quality improvements.
1 parent 9d2fa7b commit 5118883

4 files changed

Lines changed: 129 additions & 142 deletions

File tree

SqlServerSimulator/Parser/Expression.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ private sealed class Reference(Name name) : Expression
346346
{
347347
private readonly List<string> name = [name.Value];
348348

349-
public override string Name => this.name.Last();
349+
public override string Name => this.name[^1];
350350

351351
public void AddMultiPartComponent(Name name) => this.name.Add(name.Value);
352352

SqlServerSimulator/Parser/ParserContext.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,7 @@ private bool MoveNext()
135135
{
136136
while (Tokenizer.NextToken(commandText, ref index) is Token token)
137137
{
138-
if (token is Whitespace)
139-
continue;
140-
if (token is Comment)
138+
if (token is Whitespace or Comment)
141139
continue;
142140

143141
#if DEBUG

SqlServerSimulator/Parser/Selection.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,11 @@ [.. expressions.Select(x => x.Run(columnName => getColumnValueFromRow(row, colum
9090
continue;
9191

9292
case Name name:
93-
expressions[^1] = Expression.AssignName(expressions.Last(), name);
93+
expressions[^1] = Expression.AssignName(expressions[^1], name);
9494
continue;
9595

9696
case ReservedKeyword { Keyword: Keyword.As }:
97-
expressions[^1] = Expression.AssignName(expressions.Last(), context.GetNextRequired<Name>());
97+
expressions[^1] = Expression.AssignName(expressions[^1], context.GetNextRequired<Name>());
9898
continue;
9999

100100
case ReservedKeyword { Keyword: Keyword.From }:
@@ -121,7 +121,7 @@ [.. expressions.Select(x => x.Run(columnName => getColumnValueFromRow(row, colum
121121
expressions,
122122
ApplyClauses(table.Rows, (row, columnName) =>
123123
{
124-
var columnIndex = table.Columns.FindIndex(column => Collation.Default.Equals(column.Name, columnName.Last()));
124+
var columnIndex = table.Columns.FindIndex(column => Collation.Default.Equals(column.Name, columnName[^1]));
125125
return columnIndex == -1 ? throw SimulatedSqlException.InvalidColumnName(columnName) : row[columnIndex];
126126
})
127127
));
@@ -147,7 +147,7 @@ [.. expressions.Select(x => x.Run(columnName => getColumnValueFromRow(row, colum
147147
expressions,
148148
ApplyClauses(derived.records, (row, columnName) =>
149149
{
150-
var columnIndex = Array.FindIndex(derived.columnNames, name => Collation.Default.Equals(name, columnName.Last()));
150+
var columnIndex = Array.FindIndex(derived.columnNames, name => Collation.Default.Equals(name, columnName[^1]));
151151
return columnIndex == -1 ? throw SimulatedSqlException.InvalidColumnName(columnName) : row[columnIndex];
152152
})
153153
));

SqlServerSimulator/Simulation.cs

Lines changed: 123 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -39,164 +39,153 @@ internal IEnumerable<SimulatedStatementOutcome> CreateResultSetsForCommand(Simul
3939
case Operator { Character: ';' }:
4040
continue;
4141

42-
case ReservedKeyword reserved:
43-
switch (reserved.Keyword)
42+
case ReservedKeyword { Keyword: Keyword.Set }:
43+
if (TryParseSet(context))
44+
continue;
45+
break;
46+
47+
case ReservedKeyword { Keyword: Keyword.Create }:
48+
switch (context.GetNextRequired())
4449
{
45-
case Keyword.Set:
46-
switch (context.GetNextRequired())
50+
case ReservedKeyword { Keyword: Keyword.Table }:
51+
if (context.GetNextRequired() is not Name tableName)
52+
break;
53+
54+
if (context.GetNextRequired() is not Operator { Character: '(' })
55+
break;
56+
57+
var table = new Table(tableName.Value);
58+
59+
var columns = table.Columns;
60+
bool suppressAdvanceToken;
61+
do
4762
{
48-
case UnquotedString setTarget:
49-
switch (setTarget.Value.ToUpperInvariant())
63+
suppressAdvanceToken = false;
64+
var columnName = context.GetNextRequired<Name>();
65+
var type = context.GetNextRequired<Name>();
66+
67+
var nullable = true;
68+
69+
context.MoveNextRequired();
70+
if (context.Token is ReservedKeyword next)
71+
{
72+
switch (next.Keyword)
5073
{
51-
case "IMPLICIT_TRANSACTIONS":
52-
case "NOCOUNT":
53-
switch (context.GetNextRequired())
54-
{
55-
case ReservedKeyword onOff:
56-
switch (onOff.Keyword)
57-
{
58-
case Keyword.On:
59-
case Keyword.Off:
60-
continue;
61-
}
62-
break;
63-
}
74+
case Keyword.Not:
75+
if (context.GetNextRequired() is not ReservedKeyword { Keyword: Keyword.Null })
76+
throw SimulatedSqlException.SyntaxErrorNear(context);
77+
78+
nullable = false;
79+
break;
80+
case Keyword.Null:
81+
nullable = true;
6482
break;
83+
default:
84+
throw SimulatedSqlException.SyntaxErrorNear(context);
6585
}
66-
break;
67-
}
68-
break;
86+
}
87+
else
88+
{
89+
suppressAdvanceToken = true;
90+
nullable = true;
91+
}
6992

70-
case Keyword.Create:
71-
switch (context.GetNextRequired())
72-
{
73-
case ReservedKeyword whatToCreate:
74-
switch (whatToCreate.Keyword)
75-
{
76-
case Keyword.Table:
77-
if (context.GetNextRequired() is not Name tableName)
78-
break;
79-
80-
if (context.GetNextRequired() is not Operator { Character: '(' })
81-
break;
82-
83-
var table = new Table(tableName.Value);
84-
85-
var columns = table.Columns;
86-
bool suppressAdvanceToken;
87-
do
88-
{
89-
suppressAdvanceToken = false;
90-
var columnName = context.GetNextRequired<Name>();
91-
var type = context.GetNextRequired<Name>();
92-
93-
var nullable = true;
94-
95-
context.MoveNextRequired();
96-
if (context.Token is ReservedKeyword next)
97-
{
98-
switch (next.Keyword)
99-
{
100-
case Keyword.Not:
101-
if (context.GetNextRequired() is not ReservedKeyword { Keyword: Keyword.Null })
102-
throw SimulatedSqlException.SyntaxErrorNear(context);
103-
104-
nullable = false;
105-
break;
106-
case Keyword.Null:
107-
nullable = true;
108-
break;
109-
default:
110-
throw SimulatedSqlException.SyntaxErrorNear(context);
111-
}
112-
}
113-
else
114-
{
115-
suppressAdvanceToken = true;
116-
nullable = true;
117-
}
118-
119-
columns.Add(new(columnName.Value, DataType.GetByName(type, columns.Count + 1), nullable));
120-
} while ((suppressAdvanceToken ? context.Token : context.GetNextRequired()) is Operator { Character: ',' });
121-
122-
if (context.Token is not Operator { Character: ')' })
123-
break;
124-
125-
if (!this.Tables.TryAdd(table.Name, table))
126-
throw SimulatedSqlException.ThereIsAlreadyAnObject(table.Name);
127-
128-
continue;
129-
}
130-
break;
131-
}
132-
break;
93+
columns.Add(new(columnName.Value, DataType.GetByName(type, columns.Count + 1), nullable));
94+
} while ((suppressAdvanceToken ? context.Token : context.GetNextRequired()) is Operator { Character: ',' });
13395

134-
case Keyword.Select:
135-
yield return Selection.Parse(context, 0).Results;
136-
break;
96+
if (context.Token is not Operator { Character: ')' })
97+
break;
13798

138-
case Keyword.Insert:
139-
if (context.GetNextRequired() is ReservedKeyword { Keyword: Keyword.Into })
140-
context.MoveNextRequired();
99+
if (!this.Tables.TryAdd(table.Name, table))
100+
throw SimulatedSqlException.ThereIsAlreadyAnObject(table.Name);
141101

142-
if (context.Token is not StringToken destinationTableToken)
143-
break;
102+
continue;
103+
}
104+
break;
144105

145-
if (!this.Tables.TryGetValue(destinationTableToken.Value, out var destinationTable))
146-
throw SimulatedSqlException.InvalidObjectName(destinationTableToken);
106+
case ReservedKeyword { Keyword: Keyword.Select }:
107+
yield return Selection.Parse(context, 0).Results;
108+
continue;
147109

148-
Column[] destinationColumns;
149-
if (context.GetNextRequired() is Operator { Character: '(' })
150-
{
151-
var usedColumns = new List<Column>();
152-
while (context.GetNextRequired() is StringToken column)
153-
{
154-
var columnName = column.Value;
155-
var tableColumn = destinationTable.Columns.FirstOrDefault(c => Collation.Default.Equals(c.Name, columnName))
156-
?? throw SimulatedSqlException.InvalidColumnName(columnName);
157-
usedColumns.Add(tableColumn);
158-
}
110+
case ReservedKeyword { Keyword: Keyword.Insert }:
111+
if (context.GetNextRequired() is ReservedKeyword { Keyword: Keyword.Into })
112+
context.MoveNextRequired();
159113

160-
if (context.Token is not Operator { Character: ')' })
161-
break;
114+
if (context.Token is not StringToken destinationTableToken)
115+
break;
162116

163-
destinationColumns = [.. usedColumns];
117+
if (!this.Tables.TryGetValue(destinationTableToken.Value, out var destinationTable))
118+
throw SimulatedSqlException.InvalidObjectName(destinationTableToken);
164119

165-
context.MoveNextRequired();
166-
}
167-
else
168-
{
169-
destinationColumns = [.. destinationTable.Columns];
170-
}
120+
Column[] destinationColumns;
121+
if (context.GetNextRequired() is Operator { Character: '(' })
122+
{
123+
var usedColumns = new List<Column>();
124+
while (context.GetNextRequired() is StringToken column)
125+
{
126+
var columnName = column.Value;
127+
var tableColumn = destinationTable.Columns.FirstOrDefault(c => Collation.Default.Equals(c.Name, columnName))
128+
?? throw SimulatedSqlException.InvalidColumnName(columnName);
129+
usedColumns.Add(tableColumn);
130+
}
131+
132+
if (context.Token is not Operator { Character: ')' })
133+
break;
171134

172-
if (context.Token is not ReservedKeyword { Keyword: Keyword.Values })
173-
break;
135+
destinationColumns = [.. usedColumns];
174136

175-
var sourceRows = new List<Token[]>();
137+
context.MoveNextRequired();
138+
}
139+
else
140+
{
141+
destinationColumns = [.. destinationTable.Columns];
142+
}
176143

177-
do
178-
{
179-
if (context.GetNextRequired<Operator>() is not { Character: '(' })
180-
throw SimulatedSqlException.SyntaxErrorNear(context);
144+
if (context.Token is not ReservedKeyword { Keyword: Keyword.Values })
145+
break;
181146

182-
var sourceValues = new List<Token>();
183-
while (context.GetNextRequired() is not Operator { Character: ')' })
184-
sourceValues.Add(context.Token);
147+
var sourceRows = new List<Token[]>();
185148

186-
sourceRows.Add([.. sourceValues]);
149+
do
150+
{
151+
if (context.GetNextRequired<Operator>() is not { Character: '(' })
152+
throw SimulatedSqlException.SyntaxErrorNear(context);
187153

188-
} while (context.GetNextOptional() is Operator { Character: ',' });
154+
var sourceValues = new List<Token>();
155+
while (context.GetNextRequired() is not Operator { Character: ')' })
156+
sourceValues.Add(context.Token);
189157

190-
destinationTable.ReceiveData(destinationColumns, sourceRows, context.GetVariableValue);
158+
sourceRows.Add([.. sourceValues]);
191159

192-
yield return new SimulatedNonQuery(sourceRows.Count);
193-
continue;
194-
}
195-
break;
160+
} while (context.GetNextOptional() is Operator { Character: ',' });
161+
162+
destinationTable.ReceiveData(destinationColumns, sourceRows, context.GetVariableValue);
196163

197-
default:
198-
throw SimulatedSqlException.SyntaxErrorNear(context);
164+
yield return new SimulatedNonQuery(sourceRows.Count);
165+
continue;
199166
}
167+
168+
throw SimulatedSqlException.SyntaxErrorNear(context);
200169
} // while (tokens.TryMoveNext(out var token))
201170
}
171+
172+
private static bool TryParseSet(ParserContext context)
173+
{
174+
var setTarget = context.GetNextRequired<UnquotedString>().Value;
175+
Span<char> upper = stackalloc char[setTarget.Length];
176+
return setTarget.ToUpperInvariant(upper) switch
177+
{
178+
7 => upper switch
179+
{
180+
"NOCOUNT" => context.GetNextRequired() is ReservedKeyword { Keyword: Keyword.On or Keyword.Off },
181+
_ => false
182+
},
183+
21 => upper switch
184+
{
185+
"IMPLICIT_TRANSACTIONS" => context.GetNextRequired() is ReservedKeyword { Keyword: Keyword.On or Keyword.Off },
186+
_ => false
187+
},
188+
_ => false
189+
};
190+
}
202191
}

0 commit comments

Comments
 (0)