DataTypeDescriptor sqlType = valueNode.getType();
TInstance type = typesTranslator.typeForSQLType(sqlType);
if (valueNode instanceof ColumnReference) {
ColumnBinding cb = (ColumnBinding)((ColumnReference)valueNode).getUserData();
if (cb == null)
throw new UnsupportedSQLException("Unsupported column", valueNode);
Joinable joinNode = joinNodes.get(cb.getFromTable());
if ((joinNode == null) &&
(cb.getFromTable() == null) &&
(projects != null) &&
(cb.getResultColumn() != null)) {
// Alias: use result column expression.
return projects.get(cb.getResultColumn().getColumnPosition()-1);
}
if (!(joinNode instanceof ColumnSource))
throw new UnsupportedSQLException("Unsupported column", valueNode);
Column column = cb.getColumn();
if (column != null)
return new ColumnExpression(((TableSource)joinNode), column,
sqlType, valueNode);
else
return new ColumnExpression(((ColumnSource)joinNode),
cb.getFromTable().getResultColumns().indexOf(cb.getResultColumn()),
sqlType, valueNode, type);
}
else if (valueNode instanceof ConstantNode) {
if (valueNode instanceof BooleanConstantNode)
return new BooleanConstantExpression((Boolean)((ConstantNode)valueNode).getValue(),
sqlType, valueNode, type);
else if (valueNode instanceof UntypedNullConstantNode) {
return ConstantExpression.typedNull(sqlType, valueNode, type);
}
else {
Object value = ((ConstantNode)valueNode).getValue();
if (value instanceof Integer) {
int ival = ((Integer)value).intValue();
if ((ival >= Byte.MIN_VALUE) && (ival <= Byte.MAX_VALUE))
value = new Byte((byte)ival);
else if ((ival >= Short.MIN_VALUE) && (ival <= Short.MAX_VALUE))
value = new Short((short)ival);
ExpressionNode constInt = new ConstantExpression(value, sqlType, valueNode, type);
return constInt;
}
if ((value instanceof String) &&
((sqlType != null) &&
(sqlType.getTypeId() == TypeId.CHAR_ID))) {
// TODO: Make a char literal into a VARCHAR instead of a CHAR.
// It shouldn't matter, but some of the overloads aren't quite
// right.
type = typesTranslator.typeForString((String) value);
}
return new ConstantExpression(value, sqlType, valueNode, type);
}
}
else if (valueNode instanceof ParameterNode) {
assert (parameters != null) && parameters.contains(valueNode) : valueNode;
return new ParameterExpression(((ParameterNode)valueNode)
.getParameterNumber(),
sqlType, valueNode, type);
}
else if (valueNode instanceof CastNode)
return new CastExpression(toExpression(((CastNode)valueNode)
.getCastOperand(),
projects),
sqlType, valueNode, type);
else if (valueNode instanceof AggregateNode) {
AggregateNode aggregateNode = (AggregateNode)valueNode;
String function = aggregateNode.getAggregateName();
ExpressionNode operand = null;
if ("COUNT(*)".equals(function)) {
function = "COUNT";
}
else {
operand = toExpression(aggregateNode.getOperand(), projects);
if (hasAggregateFunction(operand)) {
throw new UnsupportedSQLException("Cannot nest aggregate functions",
aggregateNode);
}
}
if (aggregateNode instanceof GroupConcatNode)
{
GroupConcatNode groupConcat = (GroupConcatNode) aggregateNode;
List<OrderByExpression> sorts = null;
OrderByList orderByList = groupConcat.getOrderBy();
if (orderByList != null)
{
sorts = new ArrayList<>();
for (OrderByColumn orderByColumn : orderByList)
{
ExpressionNode expression = toOrderGroupBy(orderByColumn.getExpression(), projects, "ORDER");
sorts.add(new OrderByExpression(expression,
orderByColumn.isAscending()));
}
}
return new AggregateFunctionExpression(function,
operand,
aggregateNode.isDistinct(),
sqlType, valueNode, type,
groupConcat.getSeparator(),
sorts);
}
else
return new AggregateFunctionExpression(function,
operand,
aggregateNode.isDistinct(),
sqlType, valueNode, type,
null,
null);
}
else if (isConditionExpression(valueNode)) {
return toCondition(valueNode, projects);
}
else if (valueNode instanceof UnaryOperatorNode) {
if (valueNode instanceof WindowFunctionNode) {
throw new UnsupportedSQLException("Window", valueNode);
}
UnaryOperatorNode unary = (UnaryOperatorNode)valueNode;
List<ExpressionNode> operands = new ArrayList<>(1);
operands.add(toExpression(unary.getOperand(), projects));
return new FunctionExpression(unary.getMethodName(),
operands,
sqlType, unary, type);
}
else if (valueNode instanceof BinaryOperatorNode) {
BinaryOperatorNode binary = (BinaryOperatorNode)valueNode;
List<ExpressionNode> operands = new ArrayList<>(2);
int nodeType = valueNode.getNodeType();
switch (nodeType) {
case NodeTypes.CONCATENATION_OPERATOR_NODE:
// Operator is binary but function is nary: collapse.
while (true) {
operands.add(toExpression(binary.getLeftOperand(), projects));
ValueNode right = binary.getRightOperand();
if (right.getNodeType() != nodeType) {
operands.add(toExpression(right, projects));
break;
}
binary = (BinaryOperatorNode)right;
}
break;
default:
operands.add(toExpression(binary.getLeftOperand(), projects));
operands.add(toExpression(binary.getRightOperand(), projects));
}
return new FunctionExpression(binary.getMethodName(),
operands,
sqlType, binary, type);
}
else if (valueNode instanceof TernaryOperatorNode) {
TernaryOperatorNode ternary = (TernaryOperatorNode)valueNode;
List<ExpressionNode> operands = new ArrayList<>(3);
operands.add(toExpression(ternary.getReceiver(), projects));
operands.add(toExpression(ternary.getLeftOperand(), projects));
// java null means not present
ValueNode third = ternary.getRightOperand();
if (third != null)
operands.add(toExpression(third, projects));
return new FunctionExpression(ternary.getMethodName(),
operands,
sqlType, ternary, type);
}
else if (valueNode instanceof CoalesceFunctionNode) {
CoalesceFunctionNode coalesce = (CoalesceFunctionNode)valueNode;
List<ExpressionNode> operands = new ArrayList<>();
for (ValueNode value : coalesce.getArgumentsList()) {
operands.add(toExpression(value, projects));
}
return new FunctionExpression(coalesce.getFunctionName(),
operands,
sqlType, coalesce, type);
}
else if (valueNode instanceof SubqueryNode) {
SubqueryNode subqueryNode = (SubqueryNode)valueNode;
pushEquivalenceFinder();
PlanNode subquerySelect = toQueryForSelect(subqueryNode.getResultSet(),
subqueryNode.getOrderByList(),
subqueryNode.getOffset(),
subqueryNode.getFetchFirst(),
false);
Subquery subquery = new Subquery(subquerySelect, peekEquivalenceFinder());
popEquivalenceFinder();
if ((sqlType != null) && sqlType.getTypeId().isRowMultiSet())
return new SubqueryResultSetExpression(subquery, sqlType,
subqueryNode, type);
else
return new SubqueryValueExpression(subquery, sqlType,
subqueryNode, type);
}
else if (valueNode instanceof JavaToSQLValueNode) {
return toExpression(((JavaToSQLValueNode)valueNode).getJavaValueNode(),
valueNode,
false,
projects);
}
else if (valueNode instanceof CurrentDatetimeOperatorNode) {
String functionName = FunctionsTypeComputer.currentDatetimeFunctionName((CurrentDatetimeOperatorNode)valueNode);
if (functionName == null)
throw new UnsupportedSQLException("Unsupported datetime function", valueNode);
return new FunctionExpression(functionName,
Collections.<ExpressionNode>emptyList(),
sqlType, valueNode, type);
}
else if (valueNode instanceof SpecialFunctionNode) {
String functionName = FunctionsTypeComputer.specialFunctionName((SpecialFunctionNode)valueNode);
if (functionName == null)
throw new UnsupportedSQLException("Unsupported special function", valueNode);
return new FunctionExpression(functionName,
Collections.<ExpressionNode>emptyList(),
sqlType, valueNode, type);
}
else if (valueNode instanceof ConditionalNode) {
ConditionalNode cond = (ConditionalNode)valueNode;
return new IfElseExpression(toConditions(cond.getTestCondition(), projects),
toExpression(cond.getThenNode(), projects),
toExpression(cond.getElseNode(), projects),
sqlType, cond, type);
}
else if (valueNode instanceof SimpleCaseNode) {
SimpleCaseNode caseNode = (SimpleCaseNode)valueNode;
ExpressionNode operand = toExpression(caseNode.getOperand(), projects);
int ncases = caseNode.getNumberOfCases();
ExpressionNode expr;
if (caseNode.getElseValue() != null)
expr = toExpression(caseNode.getElseValue(), projects);
else
expr = ConstantExpression.typedNull(sqlType, valueNode, type);
for (int i = ncases - 1; i >= 0; i--) {
ConditionList conds = new ConditionList(1);
conds.add(new ComparisonCondition(Comparison.EQ, operand, toExpression(caseNode.getCaseOperand(i), projects), sqlType, caseNode, type));
expr = new IfElseExpression(conds,
toExpression(caseNode.getResultValue(i), projects),
expr, sqlType, caseNode, type);
}
return expr;
}
else if (valueNode instanceof SimpleCaseNode) {
SimpleCaseNode caseNode = (SimpleCaseNode)valueNode;
ExpressionNode operand = toExpression(caseNode.getOperand(), projects);
int ncases = caseNode.getNumberOfCases();
ExpressionNode expr;
if (caseNode.getElseValue() != null)
expr = toExpression(caseNode.getElseValue(), projects);
else
expr = ConstantExpression.typedNull(sqlType, valueNode, type);
for (int i = ncases - 1; i >= 0; i--) {
ConditionList conds = new ConditionList(1);
conds.add(new ComparisonCondition(Comparison.EQ, operand, toExpression(caseNode.getCaseOperand(i), projects), sqlType, caseNode, type));
expr = new IfElseExpression(conds,
toExpression(caseNode.getResultValue(i), projects),
expr, sqlType, caseNode, type);
}
return expr;
}
else if (valueNode instanceof NextSequenceNode) {
NextSequenceNode seqNode = (NextSequenceNode)valueNode;
List<ExpressionNode> params = new ArrayList<>(2);
String schema = seqNode.getSequenceName().hasSchema() ?
seqNode.getSequenceName().getSchemaName() :
rulesContext.getDefaultSchemaName();
// Extract the (potential) schema name as the first parameter
TInstance schemaType = typesTranslator.typeForString(schema);
params.add(new ConstantExpression(
new TPreptimeValue(new Value(schemaType, schema))));
// Extract the schema name as the second parameter
String sequence = seqNode.getSequenceName().getTableName();
TInstance sequenceType = typesTranslator.typeForString(sequence);
params.add(new ConstantExpression(
new TPreptimeValue(new Value(sequenceType, sequence))));
return new FunctionExpression ("nextval", params,
sqlType, valueNode, type);
}
else if (valueNode instanceof CurrentSequenceNode) {
CurrentSequenceNode seqNode = (CurrentSequenceNode)valueNode;
List<ExpressionNode> params = new ArrayList<>(2);
String schema = seqNode.getSequenceName().hasSchema() ?
seqNode.getSequenceName().getSchemaName() :
rulesContext.getDefaultSchemaName();
// Extract the (potential) schema name as the first parameter
TInstance schemaType = typesTranslator.typeForString(schema);
params.add(new ConstantExpression(
new TPreptimeValue(new Value(schemaType, schema))));
// Extract the schema name as the second parameter
String sequence = seqNode.getSequenceName().getTableName();
TInstance sequenceType = typesTranslator.typeForString(sequence);
params.add(new ConstantExpression(
new TPreptimeValue(new Value(sequenceType, sequence))));
return new FunctionExpression ("currval", params,
sqlType, valueNode, type);
}
else if (valueNode instanceof DefaultNode) {
Column column = (Column)valueNode.getUserData();
if (column == null)
throw new DefaultOutsideInsertException(valueNode);
return new ColumnDefaultExpression(column, sqlType, valueNode, type);
}
else
throw new UnsupportedSQLException("Unsupported operand", valueNode);
}