@@ -263,6 +263,24 @@ private static bool EvaluateSimpleCondition(Dictionary<string, object> row, stri
263263 {
264264 var key = parts [ 0 ] . Trim ( ) ;
265265 var op = parts [ 1 ] . Trim ( ) ;
266+
267+ // Handle IS NOT NULL (parts: key, IS, NOT, NULL)
268+ if ( op . Equals ( "IS" , StringComparison . OrdinalIgnoreCase )
269+ && parts . Length >= 4
270+ && parts [ 2 ] . Trim ( ) . Equals ( "NOT" , StringComparison . OrdinalIgnoreCase )
271+ && parts [ 3 ] . Trim ( ) . Equals ( "NULL" , StringComparison . OrdinalIgnoreCase ) )
272+ {
273+ return row . TryGetValue ( key , out var v ) && v is not null && v is not DBNull ;
274+ }
275+
276+ // Handle IS NULL (parts: key, IS, NULL)
277+ if ( op . Equals ( "IS" , StringComparison . OrdinalIgnoreCase )
278+ && parts . Length >= 3
279+ && parts [ 2 ] . Trim ( ) . Equals ( "NULL" , StringComparison . OrdinalIgnoreCase ) )
280+ {
281+ return ! row . TryGetValue ( key , out var v ) || v is null || v is DBNull ;
282+ }
283+
266284 var value = parts [ 2 ] . Trim ( ) . Trim ( '\' ' ) ;
267285
268286 if ( value . Equals ( "NULL" , StringComparison . OrdinalIgnoreCase ) )
@@ -292,18 +310,42 @@ private static bool EvaluateComplexCondition(Dictionary<string, object> row, str
292310 {
293311 var key = parts [ i ] . Trim ( ) ;
294312 var op = parts [ i + 1 ] . Trim ( ) ;
295- var value = parts [ i + 2 ] . Trim ( ) . Trim ( '\' ' ) ;
296313
297- if ( value . Equals ( "NULL" , StringComparison . OrdinalIgnoreCase ) )
314+ bool expr ;
315+ int consumed ;
316+
317+ // Handle IS NOT NULL (4 tokens: key IS NOT NULL)
318+ if ( op . Equals ( "IS" , StringComparison . OrdinalIgnoreCase )
319+ && i + 3 < parts . Length
320+ && parts [ i + 2 ] . Trim ( ) . Equals ( "NOT" , StringComparison . OrdinalIgnoreCase )
321+ && parts [ i + 3 ] . Trim ( ) . Equals ( "NULL" , StringComparison . OrdinalIgnoreCase ) )
298322 {
299- value = null ;
323+ expr = row . TryGetValue ( key , out var v ) && v is not null && v is not DBNull ;
324+ consumed = 4 ;
300325 }
301-
302- bool expr = false ;
303- if ( row . ContainsKey ( key ) )
326+ // Handle IS NULL (3 tokens: key IS NULL)
327+ else if ( op . Equals ( "IS" , StringComparison . OrdinalIgnoreCase )
328+ && parts [ i + 2 ] . Trim ( ) . Equals ( "NULL" , StringComparison . OrdinalIgnoreCase ) )
304329 {
305- var rowValue = row [ key ] ;
306- expr = EvaluateOperator ( rowValue , op , value ) ;
330+ expr = ! row . TryGetValue ( key , out var v ) || v is null || v is DBNull ;
331+ consumed = 3 ;
332+ }
333+ else
334+ {
335+ var value = parts [ i + 2 ] . Trim ( ) . Trim ( '\' ' ) ;
336+
337+ if ( value . Equals ( "NULL" , StringComparison . OrdinalIgnoreCase ) )
338+ {
339+ value = null ;
340+ }
341+
342+ expr = false ;
343+ if ( row . ContainsKey ( key ) )
344+ {
345+ var rowValue = row [ key ] ;
346+ expr = EvaluateOperator ( rowValue , op , value ) ;
347+ }
348+ consumed = 3 ;
307349 }
308350
309351 if ( current is null )
@@ -320,7 +362,7 @@ private static bool EvaluateComplexCondition(Dictionary<string, object> row, str
320362 }
321363
322364 // Move index to next token after this expression
323- i += 3 ;
365+ i += consumed ;
324366 // Read logical connector if present
325367 if ( i < parts . Length )
326368 {
0 commit comments