All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.kv.impl.query.compiler.FuncArithOp 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 java.util.Arrays;
import java.util.ArrayList;

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.QueryException.Location;
import oracle.kv.impl.query.QueryStateException;
import oracle.kv.impl.query.compiler.FunctionLib.FuncCode;
import oracle.kv.impl.query.runtime.ArithOpIter;
import oracle.kv.impl.query.runtime.ConstIter;
import oracle.kv.impl.query.runtime.PlanIter;
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;

/**
 * Arithmetic operations + - * / function implementation.
 *
 * Note: the last argument must be a constant String that contains the order
 * of the operations.
 */
public class FuncArithOp extends Function {

    FuncArithOp(FunctionLib.FuncCode code, String name) {
        super(code,
              name,
              TypeManager.ANY_JATOMIC_QSTN() /* params */,
              TypeManager.ANY_JATOMIC_QSTN() /* RetType */,
              true /*isVariadic*/);
    }

    @Override
    PlanIter codegen(
        CodeGenerator codegen,
        ExprFuncCall funcCall,
        PlanIter[] argIters) {

        int resultReg = codegen.allocateResultReg(funcCall);

        // last arg should be a const string
        assert argIters != null && argIters.length >= 3;
        assert argIters[argIters.length - 1] instanceof ConstIter;
        assert ((ConstIter)(argIters[argIters.length - 1])).getValue().isString();

        String ops = ((ConstIter)
                      (argIters[argIters.length - 1])).getValue().castAsString();

        PlanIter[] newArgIters = Arrays.copyOf(argIters, argIters.length - 1);

        return new ArithOpIter(funcCall, resultReg, theCode, newArgIters, ops);
    }

    @Override
    ExprType getRetType(ExprFuncCall caller) {

        TypeCode typeCode = TypeCode.INT;
        Quantifier quantifier = Quantifier.ONE;
        int numArgs = caller.getNumArgs();

        // last argument is the string const with the operations order
        assert caller.getArg(numArgs - 1).getType().getDef().isString();

        /*
         * Determine the TypeCode of the result for the expression by iterating
         * its components, enforcing the promotion rules for numeric types.
         */
        for (int i = 0; i < numArgs - 1; i++) {

            ExprType argType = caller.getArg(i).getType();

            switch (argType.getQuantifier()) {
            case ONE:
            case PLUS:
                break;
            case QSTN:
            case STAR:
                quantifier = ExprType.Quantifier.QSTN;
                break;
            default:
                throw new QueryStateException(
                    "Unknown Quantifier: " + argType.getQuantifier());
            }

            if (typeCode == TypeCode.ANY_ATOMIC ||
                typeCode == TypeCode.ANY_JSON_ATOMIC) {
                continue;
            }

            switch (argType.getCode()) {
            case INT:
                break;
            case LONG:
                if (typeCode == TypeCode.INT) {
                    typeCode = TypeCode.LONG;
                }
                break;
            case FLOAT:
                if (typeCode == TypeCode.INT || typeCode == TypeCode.LONG) {
                    typeCode = TypeCode.FLOAT;
                }
                break;
            case DOUBLE:
                if (typeCode == TypeCode.INT || typeCode == TypeCode.LONG ||
                    typeCode == TypeCode.FLOAT) {
                    typeCode = TypeCode.DOUBLE;
                }
                break;
            case NUMBER:
                typeCode = TypeCode.NUMBER;
                break;
            case ANY_JSON_ATOMIC:
            case JSON:
            case ANY_ATOMIC:
            case ANY:
                typeCode = TypeCode.ANY_JSON_ATOMIC;
                break;
            default:
                throw new QueryException(
                    "Operand in arithmetic operation has illegal type\n" +
                    "Operand : " + i + " type :\n" +
                    argType.getDef().getDDLString(),
                    caller.getLocation());
            }

        }

        return TypeManager.getBuiltinType(typeCode, quantifier);
    }

    @Override
    boolean mayReturnNULL(ExprFuncCall caller) {

        int numArgs = caller.getNumArgs();

        for (int i = 0; i < numArgs - 1; i++) {
            if (caller.getArg(i).mayReturnNULL()) {
                return true;
            }
        }

        return false;
    }

    static Expr createArithExpr(Expr arg1, Expr arg2, String op) {

        QueryControlBlock qcb = arg1.getQCB();
        StaticContext sctx = arg1.getSctx();
        Location loc = arg1.getLocation();

        Function func = CompilerAPI.getFuncLib().getFunc(FuncCode.OP_ADD_SUB);
        ArrayList args = new ArrayList(3);
        args.add(arg1);
        args.add(arg2);
        op = "+" + op;
        FieldValueImpl opStr = FieldDefImpl.stringDef.createString(op);
        args.add(new ExprConst(qcb, sctx, loc, opStr));

        return ExprFuncCall.create(qcb, sctx, loc, func, args);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy