@@ -106,22 +106,12 @@ [.. expressions.Select(x => x.Run(columnName => getColumnValueFromRow(row, colum
106106 if ( ! context . Simulation . HeapTables . TryGetValue ( tableName . Value , out var heapTable ) )
107107 throw SimulatedSqlException . InvalidObjectName ( tableName ) ;
108108
109- if ( context . GetNextOptional ( ) is not null )
110- {
111- if ( context . Token is ReservedKeyword { Keyword : Keyword . As } )
112- {
113- if ( context . Token is not ReservedKeyword )
114- break ;
115- }
116- else
117- {
118- break ;
119- }
120- }
109+ while ( context . GetNextOptional ( ) is ReservedKeyword { Keyword : Keyword . Where } )
110+ excluders . Add ( BooleanExpression . Parse ( Expression . Parse ( context . MoveNextRequiredReturnSelf ( ) ) , context ) ) ;
121111
122- return excluders . Count > 0 ? throw new NotSupportedException ( "WHERE isn't supported on the page-storage backend yet." )
123- : topCount is not null ? throw new NotSupportedException ( "TOP isn't supported on the page-storage backend yet." )
124- : new ( BuildHeapProjection ( heapTable , expressions ) ) ;
112+ return topCount is not null
113+ ? throw new NotSupportedException ( "TOP isn't supported on the page-storage backend yet." )
114+ : new ( BuildHeapProjection ( heapTable , expressions , excluders ) ) ;
125115 }
126116
127117 if ( ! context . Simulation . Tables . TryGetValue ( tableName . Value , out var table ) && ! context . Simulation . SystemTables . Value . TryGetValue ( tableName . Value , out table ) )
@@ -190,7 +180,7 @@ [.. expressions.Select(x => x.Run(columnName => getColumnValueFromRow(row, colum
190180 ExitWhileTokenLoop :
191181
192182 if ( context . Simulation . Backend == StorageBackend . Pages )
193- return new ( BuildSynthesizedSqlRow ( expressions ) ) ;
183+ return new ( BuildSynthesizedSqlRow ( expressions , excluders ) ) ;
194184
195185 return new ( new SimulatedResultSet (
196186 expressions ,
@@ -202,9 +192,11 @@ [.. expressions.Select(x => x.Run(columnName => getColumnValueFromRow(row, colum
202192 /// Builds the page-backend result for a tableless SELECT (synthesized
203193 /// constant-row branch). The row is encoded into the page-row format and
204194 /// the bytes are handed to the result set; decoding happens lazily per
205- /// column when the reader navigates it.
195+ /// column when the reader navigates it. Any <paramref name="excluders"/>
196+ /// are evaluated against the synthesized row; if any returns false the
197+ /// result is empty.
206198 /// </summary>
207- private static SimulatedSqlResultSet BuildSynthesizedSqlRow ( List < Expression > expressions )
199+ private static SimulatedSqlResultSet BuildSynthesizedSqlRow ( List < Expression > expressions , List < BooleanExpression > excluders )
208200 {
209201 var values = new SqlValue [ expressions . Count ] ;
210202 var schema = new SqlType [ expressions . Count ] ;
@@ -217,6 +209,12 @@ private static SimulatedSqlResultSet BuildSynthesizedSqlRow(List<Expression> exp
217209 columnNames [ i ] = expressions [ i ] . Name ;
218210 }
219211
212+ foreach ( var excluder in excluders )
213+ {
214+ if ( ! excluder . RunSql ( column => throw SimulatedSqlException . InvalidColumnName ( column ) ) )
215+ return new SimulatedSqlResultSet ( schema , columnNames , [ ] ) ;
216+ }
217+
220218 return new SimulatedSqlResultSet ( schema , columnNames , [ RowEncoder . EncodeRow ( schema , values ) ] ) ;
221219 }
222220
@@ -234,7 +232,7 @@ private static SimulatedSqlResultSet BuildSynthesizedSqlRow(List<Expression> exp
234232 /// requires a static type-of resolver on <see cref="Expression"/> and is
235233 /// deferred.
236234 /// </remarks>
237- private static SimulatedSqlResultSet BuildHeapProjection ( HeapTable heapTable , List < Expression > expressions )
235+ private static SimulatedSqlResultSet BuildHeapProjection ( HeapTable heapTable , List < Expression > expressions , List < BooleanExpression > excluders )
238236 {
239237 var outputSchema = new SqlType [ expressions . Count ] ;
240238 var outputColumnNames = new string [ expressions . Count ] ;
@@ -252,34 +250,47 @@ private static SimulatedSqlResultSet BuildHeapProjection(HeapTable heapTable, Li
252250 outputColumnNames [ i ] = expressions [ i ] . Name ;
253251 }
254252
255- return new SimulatedSqlResultSet ( outputSchema , outputColumnNames , ProjectHeapRows ( heapTable , expressions , outputSchema ) ) ;
253+ return new SimulatedSqlResultSet ( outputSchema , outputColumnNames , ProjectHeapRows ( heapTable , expressions , excluders , outputSchema ) ) ;
256254 }
257255
258- private static IEnumerable < byte [ ] > ProjectHeapRows ( HeapTable heapTable , List < Expression > expressions , SqlType [ ] outputSchema )
256+ private static IEnumerable < byte [ ] > ProjectHeapRows ( HeapTable heapTable , List < Expression > expressions , List < BooleanExpression > excluders , SqlType [ ] outputSchema )
259257 {
260258 foreach ( var rowBytes in heapTable . Rows )
261259 {
262260 var bytes = rowBytes ;
263- var projected = new SqlValue [ expressions . Count ] ;
264- for ( var i = 0 ; i < expressions . Count ; i ++ )
261+
262+ SqlValue ResolveColumn ( List < string > name )
265263 {
266- projected [ i ] = expressions [ i ] . RunSql ( name =>
264+ var columnIndex = - 1 ;
265+ for ( var j = 0 ; j < heapTable . Columns . Count ; j ++ )
267266 {
268- var columnIndex = - 1 ;
269- for ( var j = 0 ; j < heapTable . Columns . Count ; j ++ )
267+ if ( Collation . Default . Equals ( heapTable . Columns [ j ] . Name , name [ ^ 1 ] ) )
270268 {
271- if ( Collation . Default . Equals ( heapTable . Columns [ j ] . Name , name [ ^ 1 ] ) )
272- {
273- columnIndex = j ;
274- break ;
275- }
269+ columnIndex = j ;
270+ break ;
276271 }
272+ }
273+
274+ return columnIndex == - 1
275+ ? throw SimulatedSqlException . InvalidColumnName ( name )
276+ : RowDecoder . DecodeColumn ( heapTable . Schema , bytes , columnIndex ) ;
277+ }
277278
278- return columnIndex == - 1
279- ? throw SimulatedSqlException . InvalidColumnName ( name )
280- : RowDecoder . DecodeColumn ( heapTable . Schema , bytes , columnIndex ) ;
281- } ) ;
279+ var include = true ;
280+ foreach ( var excluder in excluders )
281+ {
282+ if ( ! excluder . RunSql ( ResolveColumn ) )
283+ {
284+ include = false ;
285+ break ;
286+ }
282287 }
288+ if ( ! include )
289+ continue ;
290+
291+ var projected = new SqlValue [ expressions . Count ] ;
292+ for ( var i = 0 ; i < expressions . Count ; i ++ )
293+ projected [ i ] = expressions [ i ] . RunSql ( ResolveColumn ) ;
283294
284295 yield return RowEncoder . EncodeRow ( outputSchema , projected ) ;
285296 }
0 commit comments