From 4d218ef94a1d8296b4946786989bd95605593e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ant=C3=B4nio=20Duarte?= Date: Tue, 2 Jul 2019 11:42:42 -0300 Subject: [PATCH] Added support for comparisons with null fields --- sources/MVCFramework.RQL.AST2FirebirdSQL.pas | 10 ++++++-- sources/MVCFramework.RQL.AST2MSSQL.pas | 10 ++++++-- sources/MVCFramework.RQL.AST2MySQL.pas | 10 ++++++-- sources/MVCFramework.RQL.AST2PostgreSQL.pas | 10 ++++++-- sources/MVCFramework.RQL.AST2SQLite.pas | 10 ++++++-- sources/MVCFramework.RQL.Parser.pas | 24 ++++++++++++++++++-- tools/bin/rqlhistory.txt | 2 ++ 7 files changed, 64 insertions(+), 12 deletions(-) diff --git a/sources/MVCFramework.RQL.AST2FirebirdSQL.pas b/sources/MVCFramework.RQL.AST2FirebirdSQL.pas index 1258dcfd..1556c3f3 100644 --- a/sources/MVCFramework.RQL.AST2FirebirdSQL.pas +++ b/sources/MVCFramework.RQL.AST2FirebirdSQL.pas @@ -98,7 +98,10 @@ begin case aRQLFIlter.Token of tkEq: begin - Result := Format('(%s = %s)', [lDBFieldName, lValue]); + if aRQLFIlter.RightValueType = vtNull then + Result := Format('(%s IS NULL)', [lDBFieldName]) + else + Result := Format('(%s = %s)', [lDBFieldName, lValue]); end; tkLt: begin @@ -118,7 +121,10 @@ begin end; tkNe: begin - Result := Format('(%s != %s)', [lDBFieldName, lValue]); + if aRQLFIlter.RightValueType = vtNull then + Result := Format('(%s IS NOT NULL)', [lDBFieldName]) + else + Result := Format('(%s != %s)', [lDBFieldName, lValue]); end; tkContains: begin diff --git a/sources/MVCFramework.RQL.AST2MSSQL.pas b/sources/MVCFramework.RQL.AST2MSSQL.pas index db248a65..c1172c5d 100644 --- a/sources/MVCFramework.RQL.AST2MSSQL.pas +++ b/sources/MVCFramework.RQL.AST2MSSQL.pas @@ -106,7 +106,10 @@ begin case aRQLFIlter.Token of tkEq: begin - Result := Format('(%s = %s)', [lDBFieldName, lValue]); + if aRQLFIlter.RightValueType = vtNull then + Result := Format('(%s IS NULL)', [lDBFieldName]) + else + Result := Format('(%s = %s)', [lDBFieldName, lValue]); end; tkLt: begin @@ -126,7 +129,10 @@ begin end; tkNe: begin - Result := Format('(%s != %s)', [lDBFieldName, lValue]); + if aRQLFIlter.RightValueType = vtNull then + Result := Format('(%s IS NOT NULL)', [lDBFieldName]) + else + Result := Format('(%s != %s)', [lDBFieldName, lValue]); end; tkContains: begin diff --git a/sources/MVCFramework.RQL.AST2MySQL.pas b/sources/MVCFramework.RQL.AST2MySQL.pas index afa6f652..f6bfb401 100644 --- a/sources/MVCFramework.RQL.AST2MySQL.pas +++ b/sources/MVCFramework.RQL.AST2MySQL.pas @@ -97,7 +97,10 @@ begin case aRQLFIlter.Token of tkEq: begin - Result := Format('(%s = %s)', [lDBFieldName, lValue]); + if aRQLFIlter.RightValueType = vtNull then + Result := Format('(%s IS NULL)', [lDBFieldName]) + else + Result := Format('(%s = %s)', [lDBFieldName, lValue]); end; tkLt: begin @@ -117,7 +120,10 @@ begin end; tkNe: begin - Result := Format('(%s != %s)', [lDBFieldName, lValue]); + if aRQLFIlter.RightValueType = vtNull then + Result := Format('(%s IS NOT NULL)', [lDBFieldName]) + else + Result := Format('(%s != %s)', [lDBFieldName, lValue]); end; tkContains: begin diff --git a/sources/MVCFramework.RQL.AST2PostgreSQL.pas b/sources/MVCFramework.RQL.AST2PostgreSQL.pas index 7bb9c48b..6ff377ca 100644 --- a/sources/MVCFramework.RQL.AST2PostgreSQL.pas +++ b/sources/MVCFramework.RQL.AST2PostgreSQL.pas @@ -91,7 +91,10 @@ begin case aRQLFIlter.Token of tkEq: begin - Result := Format('(%s = %s)', [lDBFieldName, lValue]); + if aRQLFIlter.RightValueType = vtNull then + Result := Format('(%s IS NULL)', [lDBFieldName]) + else + Result := Format('(%s = %s)', [lDBFieldName, lValue]); end; tkLt: begin @@ -111,7 +114,10 @@ begin end; tkNe: begin - Result := Format('(%s != %s)', [lDBFieldName, lValue]); + if aRQLFIlter.RightValueType = vtNull then + Result := Format('(%s IS NOT NULL)', [lDBFieldName]) + else + Result := Format('(%s != %s)', [lDBFieldName, lValue]); end; tkContains: begin diff --git a/sources/MVCFramework.RQL.AST2SQLite.pas b/sources/MVCFramework.RQL.AST2SQLite.pas index f33a27d5..ca5e8d68 100644 --- a/sources/MVCFramework.RQL.AST2SQLite.pas +++ b/sources/MVCFramework.RQL.AST2SQLite.pas @@ -92,7 +92,10 @@ begin case aRQLFIlter.Token of tkEq: begin - Result := Format('(%s = %s)', [lDBFieldName, lValue]); + if aRQLFIlter.RightValueType = vtNull then + Result := Format('(%s IS NULL)', [lDBFieldName]) + else + Result := Format('(%s = %s)', [lDBFieldName, lValue]); end; tkLt: begin @@ -112,7 +115,10 @@ begin end; tkNe: begin - Result := Format('(%s != %s)', [lDBFieldName, lValue]); + if aRQLFIlter.RightValueType = vtNull then + Result := Format('(%s IS NOT NULL)', [lDBFieldName]) + else + Result := Format('(%s != %s)', [lDBFieldName, lValue]); end; tkContains: begin diff --git a/sources/MVCFramework.RQL.Parser.pas b/sources/MVCFramework.RQL.Parser.pas index 578ce7c9..32f75f10 100644 --- a/sources/MVCFramework.RQL.Parser.pas +++ b/sources/MVCFramework.RQL.Parser.pas @@ -78,7 +78,7 @@ type tkOpenPar, tkClosedPar, tkOpenBracket, tkCloseBracket, tkComma, tkSemicolon, tkPlus, tkMinus, tkDblQuote, tkQuote, tkSpace, tkContains, tkIn, tkUnknown); - TRQLValueType = (vtInteger, vtString, vtBoolean, vtIntegerArray, vtStringArray); + TRQLValueType = (vtInteger, vtString, vtBoolean, vtNull, vtIntegerArray, vtStringArray); TRQLCustom = class; @@ -188,6 +188,7 @@ type function MatchFieldNumericValue(out lFieldValue: string): Boolean; function MatchFieldArrayValue(out lFieldValue: string): Boolean; function MatchFieldBooleanValue(out lFieldValue: string): Boolean; + function MatchFieldNullValue(out lFieldValue: string): Boolean; function MatchSymbol(const Symbol: Char): Boolean; procedure SaveCurPos; procedure BackToLastPos; @@ -618,10 +619,12 @@ begin if MatchFieldBooleanValue(lFieldValue) then lValueType := vtBoolean + else if MatchFieldNullValue(LFieldValue) then + lValueType := vtNull else if MatchFieldNumericValue(lFieldValue) then lValueType := vtInteger else - Error('Expected numeric or boolean value'); + Error('Expected numeric, boolean or null value'); end; EatWhiteSpaces; if GetToken <> tkClosedPar then @@ -911,6 +914,23 @@ begin Exit(False); end; +function TRQL2SQL.MatchFieldNullValue(out lFieldValue: string): Boolean; +var + lChar: Char; +begin + lFieldValue := ''; + lChar := C(0).ToLower; + + if (lChar = 'n') and (C(1).ToLower = 'u') and (C(2).ToLower = 'l') and (C(3).ToLower = 'l') then + begin + Skip(4); + Result := True; + lFieldValue := 'NULL'; + end + else + Exit(False) +end; + function TRQL2SQL.MatchFieldNumericValue(out lFieldValue: string): Boolean; var lChar: Char; diff --git a/tools/bin/rqlhistory.txt b/tools/bin/rqlhistory.txt index e1a2c015..e7593f7c 100644 --- a/tools/bin/rqlhistory.txt +++ b/tools/bin/rqlhistory.txt @@ -1,3 +1,5 @@ +ne(value,null) +eq(value,null) eq(value,false) eq(value,true) in ( value , [ 1 , 2 , 3 ] )