Skip to content
Draft
2 changes: 2 additions & 0 deletions src/vtlengine/AST/ASTConstructorModules/Expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1886,6 +1886,8 @@ def visitSubspaceClauseItem(self, ctx: Parser.SubspaceClauseItemContext):
op_node = ctx_list[1].getSymbol().text
if isinstance(ctx_list[2], Parser.ScalarWithCastContext):
right_node = Terminals().visitScalarWithCast(ctx_list[2])
elif isinstance(ctx_list[2], Parser.ScalarVarWithCastContext):
right_node = Terminals().visitScalarVarWithCast(ctx_list[2])
elif isinstance(ctx_list[2], Parser.ScalarItemContext):
right_node = Terminals().visitScalarItem(ctx_list[2])
else:
Expand Down
36 changes: 36 additions & 0 deletions src/vtlengine/AST/ASTConstructorModules/Terminals.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,8 @@ def visitScalarItem(self, ctx: Parser.ScalarItemContext):
return self.visitConstant(c)
elif isinstance(c, Parser.ScalarWithCastContext):
return self.visitScalarWithCast(c)
elif isinstance(c, Parser.ScalarVarWithCastContext):
return self.visitScalarVarWithCast(c)
else:
raise NotImplementedError

Expand Down Expand Up @@ -549,6 +551,40 @@ def visitScalarWithCast(self, ctx: Parser.ScalarWithCastContext):
# AST_ASTCONSTRUCTOR.14
raise NotImplementedError

def visitScalarVarWithCast(self, ctx: Parser.ScalarVarWithCastContext):
"""
| CAST LPAREN varID COMMA (basicScalarType) (COMMA STRING_CONSTANT)? RPAREN #scalarVarWithCast
""" # noqa E501
ctx_list = list(ctx.getChildren())
c = ctx_list[0]

token = c.getSymbol()

op = token.text
var_node = self.visitVarID(ctx_list[2])
basic_scalar_type = [self.visitBasicScalarType(ctx_list[4])]

param_node = (
[
ParamConstant(
type_="PARAM_CAST", value=ctx_list[6], **extract_token_info(ctx_list[6])
)
]
if len(ctx_list) > 6
else []
)

if len(basic_scalar_type) == 1:
children_nodes = [var_node, basic_scalar_type[0]]

return ParamOp(
op=op, children=children_nodes, params=param_node, **extract_token_info(ctx)
)

else:
# AST_ASTCONSTRUCTOR.14
raise NotImplementedError

def visitScalarSetType(self, ctx: Parser.ScalarSetTypeContext):
"""
scalarSetType: SET ('<' scalarType '>')? ;
Expand Down
1 change: 1 addition & 0 deletions src/vtlengine/AST/Grammar/Vtl.g4
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ subspaceClauseItem:
scalarItem:
constant #simpleScalar
| CAST LPAREN constant COMMA (basicScalarType) (COMMA STRING_CONSTANT)? RPAREN #scalarWithCast
| CAST LPAREN varID COMMA (basicScalarType) (COMMA STRING_CONSTANT)? RPAREN #scalarVarWithCast
;
/*END SUBSPACE CLAUSE*/
/*----------------------------------------------END CLAUSE EXPRESSION--------------------------------------*/
Expand Down
3 changes: 2 additions & 1 deletion src/vtlengine/AST/Grammar/lexer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated from Vtl.g4 by ANTLR 4.9.2
# Generated from Vtl.g4 by ANTLR 4.9.3
from antlr4 import (
Lexer as ANTLRLexer,
ATNDeserializer,
Expand Down Expand Up @@ -2132,6 +2132,7 @@ class Lexer(ANTLRLexer):

def __init__(self, input=None, output: TextIO = sys.stdout):
super().__init__(input, output)
self.checkVersion("4.9.3")
self._interp = LexerATNSimulator(
self, self.atn, self.decisionsToDFA, PredictionContextCache()
)
Expand Down
3,659 changes: 2,587 additions & 1,072 deletions src/vtlengine/AST/Grammar/parser.py

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/vtlengine/AST/VtlVisitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,10 @@ def visitSimpleScalar(self, ctx: Parser.SimpleScalarContext):
def visitScalarWithCast(self, ctx: Parser.ScalarWithCastContext):
return self.visitChildren(ctx)

# Visit a parse tree produced by Parser#scalarVarWithCast.
def visitScalarVarWithCast(self, ctx: Parser.ScalarVarWithCastContext):
return self.visitChildren(ctx)

# Visit a parse tree produced by Parser#joinClauseWithoutUsing.
def visitJoinClauseWithoutUsing(self, ctx: Parser.JoinClauseWithoutUsingContext):
return self.visitChildren(ctx)
Expand Down
6 changes: 6 additions & 0 deletions src/vtlengine/Exceptions/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@
"message": "Component {comp_name} not found in Dataset {dataset_name}.",
"description": "Occurs when a referenced component is missing from the Dataset.",
},
"1-1-1-11": {
"message": "At op {op}: Sub comparison is not allowed between components. "
"Please check sub comparison in Dataset {dataset_name} is between a Component and a "
"Scalar/Constant.",
"description": "Occurs when a sub operation attempts to compare components.",
},
"1-1-1-13": {
"message": "At op {op}: Component {comp_name} role must be '{role_1}', found '{role_2}'.",
"description": "Raised when a Dataset component has an unexpected role for the operation.",
Expand Down
7 changes: 7 additions & 0 deletions src/vtlengine/Operators/Clause.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import re
from copy import copy
from typing import List, Type, Union

Expand Down Expand Up @@ -318,6 +319,12 @@ def validate(cls, operands: List[DataComponent], dataset: Dataset) -> Dataset:
raise SemanticError("1-2-10", op=cls.op)
for operand in operands:
if operand.name not in dataset.components:
if re.match(r"__VDC_\d+__", operand.name):
raise SemanticError(
"1-1-1-11",
op=cls.op,
dataset_name=dataset_name,
)
raise SemanticError(
"1-1-1-10",
op=cls.op,
Expand Down
2 changes: 1 addition & 1 deletion src/vtlengine/Operators/Numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def apply_operation_component(cls, series: Any) -> Any:
if cls.pc_func is not None:
arr = series.values._pa_array
return pd.Series(
pd.arrays.ArrowExtensionArray(cls.pc_func(arr)), # type: ignore[attr-defined]
pd.arrays.ArrowExtensionArray(cls.pc_func(arr)), # type: ignore[attr-defined,unused-ignore]
index=series.index,
)
return super().apply_operation_component(series)
Expand Down
27 changes: 27 additions & 0 deletions tests/Cast/data/DataStructure/input/GH_539_1-1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"datasets": [
{
"name": "DS_1",
"DataStructure": [
{
"name": "Id_1",
"type": "Integer",
"nullable": false,
"role": "Identifier"
},
{
"name": "Id_2",
"type": "String",
"nullable": false,
"role": "Identifier"
},
{
"name": "Me_1",
"type": "Integer",
"nullable": true,
"role": "Measure"
}
]
}
]
}
8 changes: 8 additions & 0 deletions tests/Cast/data/DataStructure/input/GH_539_1-2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"scalars": [
{
"name": "sc_1",
"type": "Integer"
}
]
}
27 changes: 27 additions & 0 deletions tests/Cast/data/DataStructure/input/GH_539_2-1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"datasets": [
{
"name": "DS_1",
"DataStructure": [
{
"name": "Id_1",
"type": "Integer",
"nullable": false,
"role": "Identifier"
},
{
"name": "Id_2",
"type": "String",
"nullable": false,
"role": "Identifier"
},
{
"name": "Me_1",
"type": "Integer",
"nullable": true,
"role": "Measure"
}
]
}
]
}
21 changes: 21 additions & 0 deletions tests/Cast/data/DataStructure/output/GH_539_1-1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"datasets": [
{
"name": "DS_r",
"DataStructure": [
{
"name": "Id_1",
"type": "Integer",
"nullable": false,
"role": "Identifier"
},
{
"name": "Me_1",
"type": "Integer",
"nullable": true,
"role": "Measure"
}
]
}
]
}
5 changes: 5 additions & 0 deletions tests/Cast/data/Dataset/input/GH_539_1-1.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Id_1,Id_2,Me_1
1,1,10
2,1,20
1,2,30
2,2,40
3 changes: 3 additions & 0 deletions tests/Cast/data/Dataset/output/GH_539_1-1.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Id_1,Me_1
1,10
2,20
1 change: 1 addition & 0 deletions tests/Cast/data/vtl/GH_539_1.vtl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DS_r <- DS_1[sub Id_2 = cast(sc_1, string)];
1 change: 1 addition & 0 deletions tests/Cast/data/vtl/GH_539_2.vtl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DS_r <- DS_1[sub Id_2 = cast(Id_1, string)];
21 changes: 21 additions & 0 deletions tests/Cast/test_cast.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,27 @@ def test_GH_537_1(self):

self.BaseTest(code, number_inputs, references_names=reference_names)

def test_GH_539_1(self):
"""
Solves bug report in github issue #539: sub fails whith scalar as VarID casting
"""
code = "GH_539_1"
number_inputs = 2
reference_names = ["1"]
scalars = {"sc_1": 1}

self.BaseTest(code, number_inputs, references_names=reference_names, scalars=scalars)

def test_GH_539_2(self):
"""
Solves bug report in github issue #539: sub fails whith scalar as VarID casting
"""
code = "GH_539_2"
number_inputs = 1
exception_code = "1-1-1-11" # sub comparison is not allowed between components

self.NewSemanticExceptionTest(code, number_inputs, exception_code)


# ===========================================================================
# Comprehensive explicit cast tests (VTL 2.2) - Without mask
Expand Down