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

oracle.nosql.driver.query.FuncCollectIter Maven / Gradle / Ivy

/*-
 * Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 *  https://oss.oracle.com/licenses/upl/
 */

package oracle.nosql.driver.query;

import java.io.IOException;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;

import oracle.nosql.driver.values.ArrayValue;
import oracle.nosql.driver.values.FieldValue;
import oracle.nosql.driver.util.ByteInputStream;
import oracle.nosql.driver.util.SizeOf;

public class FuncCollectIter extends PlanIter {

    static class CompareFunction implements Comparator {

        final RuntimeControlBlock theRCB;
        final SortSpec theSortSpec;

        CompareFunction(RuntimeControlBlock rcb) {

            theRCB = rcb;
            theSortSpec = new SortSpec();
        }

        @Override
        public int compare(FieldValue v1, FieldValue v2) {

            return Compare.compareTotalOrder(theRCB, v1, v2, theSortSpec);
        }
    }

    static class WrappedValue {

        public FieldValue theValue;

        WrappedValue(FieldValue value) {
            theValue = value;
        }

        @Override
        public boolean equals(Object other) {
            WrappedValue o = (WrappedValue)other;
            return Compare.equal(this.theValue, o.theValue);
        }

        @Override
        public int hashCode() {
            return Compare.hashcode(theValue);
        }

        public long sizeof() {
            return SizeOf.OBJECT_OVERHEAD +
                   SizeOf.OBJECT_REF_OVERHEAD +
                   theValue.sizeof();
        }
    }

    private class CollectIterState extends PlanIterState {

        final CompareFunction theComparator;

        ArrayValue theArray;

        HashSet theValues;

        long theMemoryConsumption;

        RuntimeControlBlock theRCB;

        CollectIterState(RuntimeControlBlock rcb) {

            super();
            theComparator = new CompareFunction(rcb);
            theArray = new ArrayValue();
            theValues = new HashSet(128);
            theRCB = rcb;
        }

        @Override
        public void reset(PlanIter iter) {
            super.reset(iter);
            theArray = new ArrayValue();
            theValues.clear();
            theRCB.decMemoryConsumption(theMemoryConsumption);
            theMemoryConsumption = 0;
        }

        @Override
        public void close() {
            super.close();
            theArray = null;
            theValues = null;
        }
    }

    private final boolean theIsDistinct;

    private final PlanIter theInput;

    FuncCollectIter(ByteInputStream in, short serialVersion) throws IOException {
        super(in, serialVersion);
        theIsDistinct = in.readBoolean();
        theInput = deserializeIter(in, serialVersion);
    }

    @Override
    public PlanIterKind getKind() {
        return PlanIterKind.FN_COLLECT;
    }

    @Override
    PlanIter getInputIter() {
        return theInput;
    }

    @Override
    public void open(RuntimeControlBlock rcb) {
        rcb.setState(theStatePos, new CollectIterState(rcb));
        theInput.open(rcb);
    }

    @Override
    public void reset(RuntimeControlBlock rcb) {

        theInput.reset(rcb);
        /*
         * Don't reset the state of "this". Resetting the state is done in
         * method getAggrValue below.
         */
    }

    @Override
    public void close(RuntimeControlBlock rcb) {

        PlanIterState state = rcb.getState(theStatePos);
        if (state == null) {
            return;
        }

        theInput.close(rcb);
        state.close();
    }

    @Override
    public boolean next(RuntimeControlBlock rcb) {

        CollectIterState state = (CollectIterState)rcb.getState(theStatePos);

        if (state.isDone()) {
            return false;
        }

        while (true) {

            boolean more = theInput.next(rcb);

            if (!more) {
                return true;
            }

            FieldValue val = rcb.getRegVal(theInput.getResultReg());

            if (rcb.getTraceLevel() >= 2) {
                rcb.trace("Collecting value " + val);
            }

            aggregate(rcb, val);
        }
    }

    void aggregate(RuntimeControlBlock rcb, FieldValue val) {

        CollectIterState state = (CollectIterState)rcb.getState(theStatePos);

        if (val.isNull() || val.isEMPTY()) {
            return;
        }

        if (theIsDistinct) {
            ArrayValue arr = (ArrayValue)val;
            int size = arr.size();
            for (int i = 0; i < size; ++i) {
                WrappedValue wval = new WrappedValue(arr.get(i));
                state.theValues.add(wval);
                long sz = wval.sizeof();
                rcb.incMemoryConsumption(sz);
                state.theMemoryConsumption += sz;
            }
        } else {
            ArrayValue arr = (ArrayValue)val;
            state.theArray.addAll(arr.iterator());
            long sz = arr.sizeof() + arr.size() * SizeOf.OBJECT_REF_OVERHEAD;
            rcb.incMemoryConsumption(sz);
            state.theMemoryConsumption += sz;
        }
    }

    @Override
    FieldValue getAggrValue(RuntimeControlBlock rcb, boolean reset) {

        CollectIterState state = (CollectIterState)rcb.getState(theStatePos);

        ArrayValue res;

        if (theIsDistinct) {
            res = new ArrayValue();
            Iterator iter = state.theValues.iterator();
            while (iter.hasNext()) {
                res.add(iter.next().theValue);
            }
        } else {
            res = state.theArray;
        }

        if (rcb.getRequest().inTestMode()) {
            res.sort(state.theComparator);
        }

        if (rcb.getTraceLevel() >= 3) {
            rcb.trace("Collected values " + res);
        }

        if (reset) {
            state.reset(this);
        }
        return res;
    }

    @Override
    protected void displayContent(StringBuilder sb, QueryFormatter formatter) {

        formatter.indent(sb);
        sb.append("\"distinct\" : ").append(theIsDistinct);
        sb.append(",\n");
        theInput.display(sb, formatter);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy