oracle.kv.impl.query.compiler.ExprPromote Maven / Gradle / Ivy
/*-
* Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle NoSQL
* Database made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle NoSQL Database for a copy of the license and
* additional information.
*/
package oracle.kv.impl.query.compiler;
import oracle.kv.impl.api.table.FieldDefImpl;
import oracle.kv.impl.api.table.FieldValueImpl;
import oracle.kv.impl.query.QueryException;
import oracle.kv.impl.query.types.ExprType;
import oracle.kv.impl.query.types.ExprType.Quantifier;
import oracle.kv.impl.query.types.ExprType.TypeCode;
import oracle.kv.impl.query.types.TypeManager;
/*
* This is an internal expr. Its main purpose is to do type checking and
* type promotion on the arguments of function-call expressions (ExprFnCall).
* Its semantics are as follows:
*
* a. Check that the cardinality of the input set conforms with the quantifier
* of the target type.
*
* b. Check that each value on the input set is a subtype of the target type,
* or is promotable to the target type. If so, the promotion is performed
* via casting. The following promotions are allowed:
* - Integer to Float or Double
* - Long to Float or Double
*
* c. Raise an error if either of the above checks fail.
*
* d. Pass on to the parent expression each input value (or the corresponding
* promoted value) that passes the type checks.
*/
class ExprPromote extends Expr {
private Expr theInput;
private ExprType theTargetType;
/*
* Inject a promote expr between the given pair of parent and child exprs.
* The target type is the result type that the parent expects from the
* child. A promote expr is actually created only if the type of the child
* is not a subtype of the target type.
*
* The parent must be null if the child is not yet connected to the parent.
* Typically this happens when the method is called from the constructor of
* the parent expr.
*/
static Expr create(Expr parent, Expr child, ExprType targetType) {
if (child.getKind() == ExprKind.CONST) {
FieldValueImpl val = ((ExprConst)child).getValue();
FieldDefImpl valDef = val.getDefinition();
FieldValueImpl newVal = TypeManager.promote(val, targetType);
if (newVal == null) {
throw new QueryException(
"Cannot promote item " + val +
"\nof type :\n" + valDef +
"\nto type :\n" + targetType, child.getLocation());
}
((ExprConst)child).setValue(newVal);
return child;
}
ExprType childType = child.getType();
if (childType.isSubType(targetType)) {
return child;
}
/*
* Throw exception if the intersection of the input and target types
* is empty and the input type is not promotable to the target type.
*/
if (!TypeManager.typesIntersect(childType, targetType)) {
TypeCode cc = childType.getCode();
TypeCode tc = targetType.getCode();
if ((cc == TypeCode.INT || cc == TypeCode.LONG) &&
(tc == TypeCode.FLOAT || tc == TypeCode.DOUBLE)) {
// int and long are normally promotable to float and double
} else if (cc == TypeCode.STRING && tc == TypeCode.ENUM) {
// string may be promotable to enum
} else {
throw new QueryException(
"Cannot promote type :\n" + childType +
"\nto type :\n" + targetType, child.getLocation());
}
}
if (parent != null) {
child.removeParent(parent, false/*deep*/);
}
Expr promoteExpr = new ExprPromote(
child.getQCB(), child.getSctx(), child, targetType);
if (parent != null) {
promoteExpr.addParent(parent);
}
return promoteExpr;
}
ExprPromote(
QueryControlBlock qcb,
StaticContext sctx,
Expr input,
ExprType type) {
super(qcb, sctx, ExprKind.PROMOTE, input.getLocation());
theTargetType = type;
theInput = input;
theInput.addParent(this);
}
@Override
int getNumChildren() {
return 1;
}
@Override
Expr getInput() {
return theInput;
}
void setInput(Expr newExpr, boolean destroy) {
theInput.removeParent(this, destroy);
theInput = newExpr;
newExpr.addParent(this);
setLocation(newExpr.getLocation());
}
ExprType getTargetType() {
return theTargetType;
}
@Override
ExprType computeType() {
ExprType inType = theInput.getType();
ExprType inputItemType = inType.getItemType();
ExprType targetItemType = theTargetType.getItemType();
Quantifier q = TypeManager.getIntersectionQuant(
inType.getQuantifier(), theTargetType.getQuantifier());
if (inputItemType.isSubType(targetItemType)) {
return TypeManager.createType(inputItemType, q);
}
return TypeManager.createType(targetItemType, q);
}
@Override
public boolean mayReturnNULL() {
return theInput.mayReturnNULL();
}
@Override
void displayContent(StringBuilder sb, QueryFormatter formatter) {
formatter.indent(sb);
sb.append(theTargetType);
sb.append(",\n");
theInput.display(sb, formatter);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy