diff --git a/server/engine/src/main/antlr4/org/eclipse/lsp/db2/parser/Db2SqlLexer.g4 b/server/engine/src/main/antlr4/org/eclipse/lsp/db2/parser/Db2SqlLexer.g4 index 0318fc40bb..2737a8c4be 100644 --- a/server/engine/src/main/antlr4/org/eclipse/lsp/db2/parser/Db2SqlLexer.g4 +++ b/server/engine/src/main/antlr4/org/eclipse/lsp/db2/parser/Db2SqlLexer.g4 @@ -728,7 +728,7 @@ TEMPORAL: T E M P O R A L; TEMPORARY : T E M P O R A R Y; THEN : T H E N; TIME : T I M E; -TIMES: T I M E S; +TIMES : T I M E S; TIMESTAMP : T I M E S T A M P; TIMEZONE : T I M E Z O N E; TO : T O; diff --git a/server/engine/src/main/antlr4/org/eclipse/lsp/db2/parser/Db2SqlParser.g4 b/server/engine/src/main/antlr4/org/eclipse/lsp/db2/parser/Db2SqlParser.g4 index 3fcbcd451e..63442c62e1 100644 --- a/server/engine/src/main/antlr4/org/eclipse/lsp/db2/parser/Db2SqlParser.g4 +++ b/server/engine/src/main/antlr4/org/eclipse/lsp/db2/parser/Db2SqlParser.g4 @@ -40,7 +40,7 @@ host_variable_usage: (USAGE IS?)? SQL TYPE IS; host_variable_array_times: OCCURS host_variable_array_size TIMES?; host_variable_array_size: T=dbs_integerliteral_expanded {validateIntegerRange($T.start, $T.text, 1, 32767);}; -sql_host_variables: result_set_locator_variable | lob_host_variables | lob_xml_host_variables +sql_host_variables: result_set_locator_variable | lob_xml_host_variables | lob_host_variables_arrays | lob_host_variables | tableLocators_variable ; result_set_locator_variable: dbs_level_01 entry_name host_variable_usage result_set_locator; @@ -51,8 +51,12 @@ lob_xml_host_variables: dbs_host_var_levels entry_name host_variable_usage xml_ lob_host_variables: dbs_integer entry_name host_variable_usage (lobWithSize | lobNoSize); +lob_host_variables_arrays: dbs_host_var_levels_arrays entry_name host_variable_usage (lobWithSize | lobNoSize) occurs_clause; + dbs_host_var_levels: dbs_level_01 | T=dbs_integer {validateIntegerRange($T.text, 2, 48);}; +dbs_host_var_levels_arrays: T=dbs_integer {validateIntegerRange($T.text, 2, 48);}; + result_set_locator: RESULT_SET_LOCATOR VARYING; tableLocators: TABLE LIKE entry_name AS LOCATOR; @@ -68,6 +72,10 @@ xml_lobNO_size: BLOB_FILE | CLOB_FILE | DBCLOB_FILE; xml_as: XML AS; +occurs_clause: OCCURS dbs_host_var_size_arrays TIMES?; + +dbs_host_var_size_arrays: T=dbs_integer {validateIntegerRange($T.text, 1, 32767);}; + entry_name : (FILLER |dbs_host_names); sqlCode : ~END_EXEC*? diff --git a/server/engine/src/main/java/org/eclipse/lsp/cobol/implicitDialects/sql/Db2SqlVisitor.java b/server/engine/src/main/java/org/eclipse/lsp/cobol/implicitDialects/sql/Db2SqlVisitor.java index a289a18fbd..5fccfac002 100644 --- a/server/engine/src/main/java/org/eclipse/lsp/cobol/implicitDialects/sql/Db2SqlVisitor.java +++ b/server/engine/src/main/java/org/eclipse/lsp/cobol/implicitDialects/sql/Db2SqlVisitor.java @@ -98,7 +98,7 @@ public List visitBinary_host_variable_array(Db2SqlParser.Binary_host_varia @Override public List visitLob_xml_host_variables(Db2SqlParser.Lob_xml_host_variablesContext ctx) { List hostVariableDefinitionNode = createHostVariableDefinitionNode(ctx, ctx.dbs_host_var_levels(), ctx.entry_name()); - if (ctx.lobWithSize() != null && ctx.lobWithSize().BINARY() != null) { + if (ctx.lobWithSize() != null) { generateVarbinVariables((VariableDefinitionNode) hostVariableDefinitionNode.get(0), ctx.lobWithSize().dbs_integer().getText(), ctx); } @@ -108,7 +108,17 @@ public List visitLob_xml_host_variables(Db2SqlParser.Lob_xml_host_variable @Override public List visitLob_host_variables(Db2SqlParser.Lob_host_variablesContext ctx) { List hostVariableDefinitionNode = createHostVariableDefinitionNode(ctx, ctx.dbs_integer(), ctx.entry_name()); - if (ctx.lobWithSize() != null && ctx.lobWithSize().BINARY() != null) { + if (ctx.lobWithSize() != null) { + generateVarbinVariables((VariableDefinitionNode) hostVariableDefinitionNode.get(0), + ctx.lobWithSize().dbs_integer().getText(), ctx); + } + return hostVariableDefinitionNode; + } + + @Override + public List visitLob_host_variables_arrays(Db2SqlParser.Lob_host_variables_arraysContext ctx) { + List hostVariableDefinitionNode = createHostVariableDefinitionNode(ctx, ctx.dbs_host_var_levels_arrays(), ctx.entry_name()); + if (ctx.lobWithSize() != null) { generateVarbinVariables((VariableDefinitionNode) hostVariableDefinitionNode.get(0), ctx.lobWithSize().dbs_integer().getText(), ctx); } @@ -171,6 +181,7 @@ private void generateVarbinVariables(VariableDefinitionNode variableDefinitionNo switch (ctx.getClass().getSimpleName()) { case "Lob_host_variablesContext": case "Lob_xml_host_variablesContext": + case "Lob_host_variables_arraysContext": suffux1 = "-LENGTH"; suffix2 = "-DATA"; break; diff --git a/server/engine/src/test/java/org/eclipse/lsp/cobol/usecases/sql/TestSqlHostVariable.java b/server/engine/src/test/java/org/eclipse/lsp/cobol/usecases/sql/TestSqlHostVariable.java index 0d382ee07c..a2069ae65b 100644 --- a/server/engine/src/test/java/org/eclipse/lsp/cobol/usecases/sql/TestSqlHostVariable.java +++ b/server/engine/src/test/java/org/eclipse/lsp/cobol/usecases/sql/TestSqlHostVariable.java @@ -137,11 +137,11 @@ public class TestSqlHostVariable { + " Data Division.\n" + " Working-Storage Section.\n" + " 01 {$*VAR-NAME1} USAGE IS SQL TYPE IS DBCLOB-FILE.\n" - + " 01 {$*VAR-NAME2} USAGE IS SQL TYPE IS BLOB (10 K).\n" - + " 01 {$*VAR-NAME3} USAGE IS SQL TYPE IS CHARACTER LARGE OBJECT (10 M).\n" - + " 01 {$*VAR-NAME4} USAGE IS SQL TYPE IS CHAR LARGE OBJECT (10 G).\n" - + " 01 {$*VAR-NAME5} USAGE IS SQL TYPE IS CLOB (20).\n" - + " 01 {$*VAR-NAME6} USAGE IS SQL TYPE IS DBCLOB (30 K).\n" + + " 01 {$*VAR2`->VAR2`->VAR2-LENGTH`->VAR2-DATA} USAGE IS SQL TYPE IS BLOB (10 K).\n" + + " 01 {$*VAR3`->VAR3`->VAR3-LENGTH`->VAR3-DATA} USAGE IS SQL TYPE IS CHARACTER LARGE OBJECT (10 M).\n" + + " 01 {$*VAR4`->VAR4`->VAR4-LENGTH`->VAR4-DATA} USAGE IS SQL TYPE IS CHAR LARGE OBJECT (10 G).\n" + + " 01 {$*VAR5`->VAR5`->VAR5-LENGTH`->VAR5-DATA} USAGE IS SQL TYPE IS CLOB (20).\n" + + " 01 {$*VAR6`->VAR6`->VAR6-LENGTH`->VAR6-DATA} USAGE IS SQL TYPE IS DBCLOB (30 K).\n" + " 01 {$*VAR-NAME7} USAGE IS SQL TYPE IS BLOB-LOCATOR.\n" + " 01 {$*VAR-NAME8} USAGE IS SQL TYPE IS CLOB-LOCATOR.\n" + " 01 {$*VAR-NAME9} USAGE IS SQL TYPE IS DBCLOB-LOCATOR.\n" @@ -159,7 +159,7 @@ public class TestSqlHostVariable { + " Data Division.\n" + " Working-Storage Section.\n" + " 01 {$*GREET}.\n" - + " 49 {$*VAR} USAGE IS SQL TYPE IS CHARACTER LARGE OBJECT (10 M).\n" + + " 49 {$*VAR`->VAR`->VAR-LENGTH`->VAR-DATA} USAGE IS SQL TYPE IS CHARACTER LARGE OBJECT (10 M).\n" + " PROCEDURE DIVISION.\n" + " DISPLAY {$VAR}."; @@ -169,11 +169,11 @@ public class TestSqlHostVariable { + " Data Division.\n" + " Working-Storage Section.\n" + " 01 {$*VAR1`->VAR1`->VAR1-LENGTH`->VAR1-DATA} USAGE IS SQL TYPE IS XML AS BINARY LARGE OBJECT (10).\n" - + " 01 {$*VAR-NAME2} USAGE IS SQL TYPE IS XML AS BLOB (10 K).\n" - + " 01 {$*VAR3} USAGE IS SQL TYPE IS XML AS CHARACTER LARGE OBJECT (10 M).\n" - + " 01 {$*VAR-NAME4} USAGE IS SQL TYPE IS XML AS CHAR LARGE OBJECT (10 G).\n" - + " 01 {$*VAR-NAME5} USAGE IS SQL TYPE IS XML AS CLOB (20).\n" - + " 01 {$*VAR-NAME6} USAGE IS SQL TYPE IS XML AS DBCLOB (30 K).\n" + + " 01 {$*VAR2`->VAR2`->VAR2-LENGTH`->VAR2-DATA} USAGE IS SQL TYPE IS XML AS BLOB (10 K).\n" + + " 01 {$*VAR3`->VAR3`->VAR3-LENGTH`->VAR3-DATA} USAGE IS SQL TYPE IS XML AS CHARACTER LARGE OBJECT (10 M).\n" + + " 01 {$*VAR4`->VAR4`->VAR4-LENGTH`->VAR4-DATA} USAGE IS SQL TYPE IS XML AS CHAR LARGE OBJECT (10 G).\n" + + " 01 {$*VAR5`->VAR5`->VAR5-LENGTH`->VAR5-DATA} USAGE IS SQL TYPE IS XML AS CLOB (20).\n" + + " 01 {$*VAR6`->VAR6`->VAR6-LENGTH`->VAR6-DATA} USAGE IS SQL TYPE IS XML AS DBCLOB (30 K).\n" + " 01 {$*VAR-NAME10} USAGE IS SQL TYPE IS XML AS BLOB-FILE.\n" + " 01 {$*VAR-NAME11} USAGE IS SQL TYPE IS XML AS CLOB-FILE.\n" + " 01 {$*VAR-NAME12} USAGE IS SQL TYPE IS XML AS DBCLOB-FILE.\n" @@ -186,7 +186,7 @@ public class TestSqlHostVariable { + " Data Division.\n" + " Working-Storage Section.\n" + " 01 {$*VAR-NAME1}.\n" - + " 04 {$*VAR} USAGE IS SQL TYPE IS XML AS CHARACTER LARGE OBJECT (10).\n" + + " 04 {$*VAR`->VAR`->VAR-LENGTH`->VAR-DATA} USAGE IS SQL TYPE IS XML AS CHARACTER LARGE OBJECT (10).\n" + " PROCEDURE DIVISION.\n" + " DISPLAY {$var-name1}."; @@ -196,9 +196,55 @@ public class TestSqlHostVariable { + " Data Division.\n" + " Working-Storage Section.\n" + " 01 {$*VAR-NAME1}.\n" - + " 49 {$*VAR|1} USAGE IS SQL TYPE IS XML AS CHARACTER LARGE OBJECT (10).\n" + + " 49 {$*VAR`->VAR`->VAR-LENGTH`->VAR-DATA|1} USAGE IS SQL TYPE IS XML AS CHARACTER LARGE OBJECT (10).\n" + " PROCEDURE DIVISION.\n" + " DISPLAY {$var-name1}."; + + public static final String LOD_VARS_ARRAYS_TEXT1 = + " Identification Division.\n" + + " Program-Id. 'TEST1'.\n" + + " Data Division.\n" + + " Working-Storage Section.\n" + + " 01 {$*VAR1}.\n" + + " 04 {$*VAR5`->VAR5`->VAR5-LENGTH`->VAR5-DATA} USAGE IS SQL TYPE IS CLOB (20) OCCURS 30 TIMES.\n" + + " 04 {$*VAR6`->VAR6`->VAR6-LENGTH`->VAR6-DATA} USAGE IS SQL TYPE IS DBCLOB (30 K) OCCURS 40.\n" + + " PROCEDURE DIVISION.\n" + + " DISPLAY {$VAR1}.\n"; + + public static final String LOD_VARS_ARRAYS_TEXT2 = + " Identification Division.\n" + + " Program-Id. 'TEST1'.\n" + + " Data Division.\n" + + " Working-Storage Section.\n" + + " 01 {$*GREET}.\n" + + " 40 {$*VAR`->VAR`->VAR-LENGTH`->VAR-DATA} USAGE IS SQL TYPE IS CLOB (10 M) OCCURS 100000 {TIMES|1}.\n" + + " PROCEDURE DIVISION.\n" + + " DISPLAY {$VAR}(1)."; + + public static final String LOD_VARS_ARRAYS_TEXT3 = + " Identification Division.\n" + + " Program-Id. 'TEST1'.\n" + + " Data Division.\n" + + " Working-Storage Section.\n" + + " 01 {$*GREET}.\n" + + " 49 {$*VAR`->VAR`->VAR-LENGTH`->VAR-DATA|1} USAGE IS SQL TYPE IS CLOB (10 M) OCCURS 35 TIMES.\n" + + " PROCEDURE DIVISION.\n" + + " DISPLAY {$VAR}(1)."; + + public static final String LOD_VARS_ARRAYS_TEXT4 = + " Identification Division.\n" + + " Program-Id. 'TEST1'.\n" + + " Data Division.\n" + + " Working-Storage Section.\n" + + " 01 {$*GREET}.\n" + + " 02 {$*VA`->VA`->VA-LENGTH`->VA-DATA} USAGE IS SQL TYPE IS BINARY LARGE OBJECT (5) OCCURS 9.\n" + + " 02 {$*VB`->VB`->VB-LENGTH`->VB-DATA} USAGE IS SQL TYPE IS BLOB (5) OCCURS 9.\n" + + " PROCEDURE DIVISION.\n" + + " DISPLAY {$VA-LENGTH}(1).\n" + + " DISPLAY {$VA-DATA}(1).\n" + + " DISPLAY {$VB-LENGTH}(1).\n" + + " DISPLAY {$VB-DATA}(1).\n"; + @Test void testSupportForResultSetLocator() { UseCaseEngine.runTest(TEXT, ImmutableList.of(), ImmutableMap.of()); @@ -304,7 +350,7 @@ void testLobVariables() { } @Test - void testLobVariables_levelError() { + void testLobVariables_level() { UseCaseEngine.runTest(LOD_VARS_TEXT1, ImmutableList.of(), ImmutableMap.of()); } @@ -331,6 +377,42 @@ void testLobXMLVariables_levelError() { )); } + @Test + void testLobVariablesArrays() { + UseCaseEngine.runTest(LOD_VARS_ARRAYS_TEXT1, ImmutableList.of(), ImmutableMap.of()); + } + + @Test + void testLobVariablesArrays_rangeError() { + UseCaseEngine.runTest(LOD_VARS_ARRAYS_TEXT2, ImmutableList.of(), ImmutableMap.of( + "1", + new Diagnostic( + new Range(), + "Allowed range is 1 to 32767", + DiagnosticSeverity.Error, + ErrorSource.PARSING.getText() + ) + )); + } + + @Test + void testLobVariablesArrays_levelError() { + UseCaseEngine.runTest(LOD_VARS_ARRAYS_TEXT3, ImmutableList.of(), ImmutableMap.of( + "1", + new Diagnostic( + new Range(), + "Allowed range is 2 to 48", + DiagnosticSeverity.Error, + ErrorSource.PARSING.getText() + ) + )); + } + + @Test + void testLobVariablesArrays_genVars1() { + UseCaseEngine.runTest(LOD_VARS_ARRAYS_TEXT4, ImmutableList.of(), ImmutableMap.of()); + } + @Test void testBinaryHostVariableArray1() { UseCaseEngine.runTest(BINARY_ARR_TEXT1, ImmutableList.of(), ImmutableMap.of());