Skip to content

Commit e1d4156

Browse files
alliesebclaude
andcommitted
feat: add INSERT statement parsing with host variable bindings
Add structured parsing for SQL INSERT statements in embedded COBOL SQL. Introduces HostVariableBinding shared class for column-to-variable mapping. - New InsertStatement CodeElement with TableName, Columns, HostVariables, HasSubselect - New Insert AST node (GenericNode<InsertStatement>) - ANTLR grammar rule: insertStatement with insertColumnList - Remove SQL_INSERT from unsupportedSqlStatement catch-all - Full infrastructure: enum, visitor, CUP terminal/production, builder, dispatcher, listener - SqlCodeElementBuilder.CreateInsertStatement() with helper methods - Test: 4 INSERT scenarios (VALUES, schema-qualified, subselect, no column list) - Updated UnsupportedSqlStatement test expected output Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 88a507a commit e1d4156

19 files changed

Lines changed: 296 additions & 2 deletions

TypeCobol.Test/Parser/Programs/Cobol85/ExecSql/ExecInDataDivision_NoEndExec.Mix.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
 IDENTIFICATION DIVISION.
22
PROGRAM-ID. TCOMFL06.
3-
Line 3[8,21] <27, Error, Syntax> - Syntax error : extraneous input 'datadivision.' expecting {ExecStatementText, ExecStatementEnd, CommitStatement, SelectStatement, RollbackStatement, TruncateStatement, SavepointStatement, WhenEverStatement, LockTableStatement, ReleaseSavepointStatement, ConnectStatement, DropTableStatement, SetAssignmentStatement, GetDiagnosticsStatement, AlterSequenceStatement, ExecuteImmediateStatement, UnsupportedSqlStatement}
3+
Line 3[8,21] <27, Error, Syntax> - Syntax error : extraneous input 'datadivision.' expecting {ExecStatementText, ExecStatementEnd, CommitStatement, SelectStatement, RollbackStatement, TruncateStatement, SavepointStatement, WhenEverStatement, LockTableStatement, ReleaseSavepointStatement, ConnectStatement, DropTableStatement, SetAssignmentStatement, GetDiagnosticsStatement, AlterSequenceStatement, ExecuteImmediateStatement, InsertStatement, UnsupportedSqlStatement}
44
data division.
55
working-storage section.
66
*Issue #2121, this would previously throw an InvalidCastException
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--- Sql Statements ---
2+
line 11: InsertStatement
3+
- TableName = EMPLOYEE
4+
- Columns = [NAME, AGE]
5+
- HasSubselect = False
6+
- HostVariables:
7+
- IN WS-NAME -> NAME
8+
- IN WS-AGE -> AGE
9+
line 16: InsertStatement
10+
- TableName = HR.EMPLOYEE
11+
- Columns = [SALARY]
12+
- HasSubselect = False
13+
- HostVariables:
14+
- IN WS-SALARY -> SALARY
15+
line 26: InsertStatement
16+
- TableName = EMPLOYEE
17+
- Columns = <NULL>
18+
- HasSubselect = False
19+
- HostVariables:
20+
- IN WS-NAME -> <NULL>
21+
- IN WS-AGE -> <NULL>
22+
- IN WS-SALARY -> <NULL>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
IDENTIFICATION DIVISION.
2+
PROGRAM-ID. TSTINSRT.
3+
DATA DIVISION.
4+
WORKING-STORAGE SECTION.
5+
01 WS-NAME PIC X(30).
6+
01 WS-AGE PIC 9(3).
7+
01 WS-SALARY PIC 9(7)V99.
8+
PROCEDURE DIVISION.
9+
* Simple INSERT with host variables
10+
EXEC SQL
11+
INSERT INTO EMPLOYEE (NAME, AGE)
12+
VALUES (:WS-NAME, :WS-AGE)
13+
END-EXEC
14+
* INSERT with schema-qualified table
15+
EXEC SQL
16+
INSERT INTO HR.EMPLOYEE (SALARY)
17+
VALUES (:WS-SALARY)
18+
END-EXEC
19+
* INSERT with subselect
20+
EXEC SQL
21+
INSERT INTO ARCHIVE.EMPLOYEE (NAME, AGE)
22+
SELECT NAME, AGE FROM EMPLOYEE
23+
END-EXEC
24+
* INSERT without column list
25+
EXEC SQL
26+
INSERT INTO EMPLOYEE
27+
VALUES (:WS-NAME, :WS-AGE, :WS-SALARY)
28+
END-EXEC
29+
GOBACK.
30+
END PROGRAM TSTINSRT.
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1-
--- Sql Statements ---
1+
--- Sql Statements ---
2+
line 14: InsertStatement
3+
- TableName = TABLE1
4+
- Columns = [COL1, COL2]
5+
- HasSubselect = False
6+
- HostVariables:
7+
- IN WS-VAR1 -> COL1
8+
- IN WS-VAR2 -> COL2
29
line 47: RollbackStatement
310
- SavePointClause = <NULL>

TypeCobol.Test/Utils/Comparators.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using TypeCobol.Compiler.Parser;
88
using TypeCobol.Compiler.Preprocessor;
99
using TypeCobol.Compiler.Scanner;
10+
using TypeCobol.Compiler.Sql.CodeElements;
1011
using TypeCobol.Compiler.Sql.CodeElements.Statements;
1112
using TypeCobol.Compiler.Sql.Model;
1213
using TypeCobol.Compiler.Text;
@@ -713,6 +714,11 @@ private void DumpObject(string name, object value)
713714
SqlObject.DumpProperty(_writer, name, value, 0);
714715
}
715716

717+
private void DumpString(string name, string value)
718+
{
719+
_writer.WriteLine($"- {name} = {value ?? "<NULL>"}");
720+
}
721+
716722
public override bool Visit(SelectStatement selectStatement)
717723
{
718724
_writer.WriteLine($"line {selectStatement.Line}: {nameof(SelectStatement)}");
@@ -835,6 +841,47 @@ public override bool Visit(ExecuteImmediateStatement executeImmediateStatement)
835841
DumpObject(nameof(executeImmediateStatement.StatementExpression), executeImmediateStatement.StatementExpression);
836842
return true;
837843
}
844+
845+
public override bool Visit(InsertStatement insertStatement)
846+
{
847+
_writer.WriteLine($"line {insertStatement.Line}: {nameof(InsertStatement)}");
848+
DumpString(nameof(insertStatement.TableName), insertStatement.TableName);
849+
DumpStringList(nameof(insertStatement.Columns), insertStatement.Columns);
850+
DumpObject(nameof(insertStatement.HasSubselect), insertStatement.HasSubselect);
851+
DumpHostVariableBindings(insertStatement.HostVariables);
852+
return true;
853+
}
854+
855+
public override bool Visit(UnsupportedSqlStatement unsupportedSqlStatement)
856+
{
857+
_writer.WriteLine($"line {unsupportedSqlStatement.Line}: {nameof(UnsupportedSqlStatement)}");
858+
DumpString(nameof(unsupportedSqlStatement.SqlKeyword), unsupportedSqlStatement.SqlKeyword);
859+
return true;
860+
}
861+
862+
private void DumpStringList(string name, IList<string> values)
863+
{
864+
if (values == null)
865+
{
866+
_writer.WriteLine($"- {name} = <NULL>");
867+
return;
868+
}
869+
_writer.WriteLine($"- {name} = [{string.Join(", ", values)}]");
870+
}
871+
872+
private void DumpHostVariableBindings(IList<HostVariableBinding> bindings, string name = "HostVariables")
873+
{
874+
if (bindings == null || bindings.Count == 0)
875+
{
876+
_writer.WriteLine($"- {name} = <NONE>");
877+
return;
878+
}
879+
_writer.WriteLine($"- {name}:");
880+
foreach (var b in bindings)
881+
{
882+
_writer.WriteLine($" - {b.Direction} {b.VariableName} -> {b.ColumnName ?? "<NULL>"}");
883+
}
884+
}
838885
}
839886

840887
public string Format(CompilationUnit compilationResult, IncrementalChangesHistory history)

TypeCobol/AntlrGrammar/CobolCodeElements.g4

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ codeElement:
228228
| getDiagnosticsStatement
229229
| alterSequenceStatement
230230
| executeImmediateStatement
231+
| insertStatement
231232
| unsupportedSqlStatement
232233

233234
// [TYPECOBOL]
@@ -8531,6 +8532,15 @@ executeImmediateStatement : SQL_EXECUTE SQL_IMMEDIATE (sqlVariable | stringExpre
85318532
//TODO extend stringExpression to support all expressions that yield a string (i.e string concat, function calls returning text,...)
85328533
stringExpression: AlphanumericLiteral;
85338534

8535+
// INSERT statement
8536+
// See Documentation [https://www.ibm.com/docs/en/db2-for-zos/12?topic=statements-insert]
8537+
insertStatement:
8538+
SQL_INSERT SQL_INTO tableOrViewOrCorrelationName
8539+
insertColumnList?
8540+
(SQL_VALUES LeftParenthesisSeparator repeatedSourceValue RightParenthesisSeparator | fullselect);
8541+
insertColumnList:
8542+
LeftParenthesisSeparator column_name (SQL_CommaSeparator column_name)* RightParenthesisSeparator;
8543+
85348544
// Catch-all rule for SQL statements without dedicated grammar rules.
85358545
// Must be listed LAST among SQL alternatives in codeElement so that
85368546
// supported statements are tried first.

TypeCobol/Compiler/CodeElements/CobolLanguageLevelVisitor.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,8 @@ bool IsStopVisitingChildren
414414
bool Visit([NotNull] ExecuteImmediate executeImmediate);
415415
bool Visit([NotNull] UnsupportedSqlStatement unsupportedSqlStatement);
416416
bool Visit([NotNull] UnsupportedSql unsupportedSql);
417+
bool Visit([NotNull] InsertStatement insertStatement);
418+
bool Visit([NotNull] Insert insert);
417419
}
418420

419421

@@ -1674,5 +1676,13 @@ public virtual bool Visit([NotNull] UnsupportedSql unsupportedSql)
16741676
{
16751677
return true;
16761678
}
1679+
public virtual bool Visit([NotNull] InsertStatement insertStatement)
1680+
{
1681+
return true;
1682+
}
1683+
public virtual bool Visit([NotNull] Insert insert)
1684+
{
1685+
return true;
1686+
}
16771687
}
16781688
}

TypeCobol/Compiler/CodeElements/CodeElementType.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ public enum CodeElementType
176176
GetDiagnosticsStatement,
177177
AlterSequenceStatement,
178178
ExecuteImmediateStatement,
179+
InsertStatement,
179180
UnsupportedSqlStatement,
180181

181182
// [TYPECOBOL]

TypeCobol/Compiler/CodeElements/StatementElement.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ public enum StatementType
144144
GetDiagnosticsStatement,
145145
AlterSequenceStatement,
146146
ExecuteImmediateStatement,
147+
InsertStatement,
147148
UnsupportedSqlStatement
148149

149150
}

TypeCobol/Compiler/CupParser/NodeBuilder/IProgramClassBuilder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,7 @@ public interface IProgramClassBuilder
890890
/// </summary>
891891
/// <param name="unsupportedSql">The corresponding UnsupportedSql Statement Code Element</param>
892892
void OnUnsupportedSqlStatement([NotNull] UnsupportedSqlStatement unsupportedSql);
893+
void OnInsertStatement([NotNull] InsertStatement insert);
893894
#endregion
894895
}
895896
}

0 commit comments

Comments
 (0)