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

oracle.kv.impl.query.runtime.InsertRowIter 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.runtime;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import oracle.kv.Durability;
import oracle.kv.Key;
import oracle.kv.ReturnValueVersion.Choice;
import oracle.kv.Value;
import oracle.kv.impl.api.KVStoreImpl;
import oracle.kv.impl.api.KeySerializer;
import oracle.kv.impl.api.Request;
import oracle.kv.impl.api.ops.Put;
import oracle.kv.impl.api.ops.PutIfAbsent;
import oracle.kv.impl.api.ops.Result.PutResult;
import oracle.kv.impl.api.table.FieldDefImpl;
import oracle.kv.impl.api.table.FieldDefSerialization;
import oracle.kv.impl.api.table.FieldValueImpl;
import oracle.kv.impl.api.table.FieldValueSerialization;
import oracle.kv.impl.api.table.IntegerValueImpl;
import oracle.kv.impl.api.table.RecordDefImpl;
import oracle.kv.impl.api.table.RecordValueImpl;
import oracle.kv.impl.api.table.RowImpl;
import oracle.kv.impl.api.table.TableImpl;
import oracle.kv.impl.api.table.TableMetadataHelper;
import oracle.kv.impl.api.table.TimestampDefImpl;
import oracle.kv.impl.query.QueryException.Location;
import oracle.kv.impl.query.compiler.Expr;
import oracle.kv.impl.query.compiler.ExprInsertRow;
import oracle.kv.impl.query.compiler.QueryFormatter;
import oracle.kv.impl.topo.PartitionId;
import oracle.kv.impl.util.SerializationUtil;
import oracle.kv.table.TimeToLive;

/**
 *
 */
public class InsertRowIter extends PlanIter {

    public static class InsertRowState extends PlanIterState {

        RowImpl theRTRow;

        public InsertRowState(RowImpl row) {
            theRTRow = row;
        }
    }

    static IntegerValueImpl one = FieldDefImpl.integerDef.createInteger(1);

    static IntegerValueImpl zero = FieldDefImpl.integerDef.createInteger(0);

    static KeySerializer keySerializer =
        KeySerializer.PROHIBIT_INTERNAL_KEYSPACE;

    final String theNamespace;

    final String theTableName;

    final RecordValueImpl theRow;

    final int[] theColPositions;

    final PlanIter[] theColIters;

    protected boolean theUpdateTTL;

    protected PlanIter theTTLIter;

    protected TimeUnit theTTLUnit;

    final boolean theIsUpsert;

    final boolean theHasReturningClause;

    public InsertRowIter(
        Expr e,
        int resultReg,
        TableImpl table,
        RecordValueImpl row,
        int[] pos,
        PlanIter[] ops,
        boolean updateTTL,
        PlanIter ttlIter,
        TimeUnit ttlUnit,
        boolean isUpsert,
        boolean hasReturningClause) {

        super(e, resultReg);
        theNamespace = table.getInternalNamespace();
        theTableName = table.getFullName();
        theRow = row;
        theColPositions = pos;
        theColIters = ops;
        theUpdateTTL = updateTTL;
        theTTLIter = ttlIter;
        theTTLUnit = ttlUnit;
        assert(theTTLIter == null || theUpdateTTL);
        theIsUpsert = isUpsert;
        theHasReturningClause = hasReturningClause;
    }

    public InsertRowIter(DataInput in, short serialVersion) throws IOException {

        super(in, serialVersion);
        theNamespace = SerializationUtil.readString(in, serialVersion);
        theTableName = SerializationUtil.readString(in, serialVersion);

        FieldDefImpl rowDef = FieldDefSerialization.readFieldDef(in,
                                                                 serialVersion);

        theRow = (RecordValueImpl)
            FieldValueSerialization.readNonNullFieldValue(rowDef,
                                                          null, // valKind
                                                          in,
                                                          serialVersion);

        theColPositions = deserializeIntArray(in, serialVersion);
        theColIters = deserializeIters(in, serialVersion);
        theUpdateTTL = in.readBoolean();
        if (theUpdateTTL) {
            theTTLIter = deserializeIter(in, serialVersion);
            if (theTTLIter != null) {
                theTTLUnit = TimeToLive.readTTLUnit(in, 1);
            }
        }
        theIsUpsert = in.readBoolean();
        theHasReturningClause = in.readBoolean();
    }

    @Override
    public void writeFastExternal(DataOutput out, short serialVersion)
        throws IOException {

        super.writeFastExternal(out, serialVersion);
        SerializationUtil.writeString(out, serialVersion, theNamespace);
        SerializationUtil.writeString(out, serialVersion, theTableName);

        FieldDefSerialization.writeFieldDef(theRow.getDefinition(),
                                            out,
                                            serialVersion);

        FieldValueSerialization.writeNonNullFieldValue(theRow,
                                                       false, // writeValDef
                                                       true, // writeValKind
                                                       out,
                                                       serialVersion);

        serializeIntArray(theColPositions, out, serialVersion);
        serializeIters(theColIters, out, serialVersion);
        out.writeBoolean(theUpdateTTL);
        if (theUpdateTTL) {
            serializeIter(theTTLIter, out, serialVersion);
            if (theTTLIter != null) {
                out.writeByte((byte) theTTLUnit.ordinal());
            }
        }
        out.writeBoolean(theIsUpsert);
        out.writeBoolean(theHasReturningClause);
    }

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

    @Override
    public void open(RuntimeControlBlock rcb) {

        for (PlanIter colIter : theColIters) {
            colIter.open(rcb);
        }

        if (theTTLIter != null) {
            theTTLIter.open(rcb);
        }

        RowImpl row;

        if (theRow instanceof RowImpl) {
            row = ((RowImpl)theRow).clone();

        } else {
            TableMetadataHelper md =  rcb.getMetadataHelper();
            TableImpl table = md.getTable(theNamespace, theTableName);

            row = table.createRow();

            int numCols = row.getNumFields();

            for (int i = 0; i < numCols; ++i) {

                FieldValueImpl val = theRow.get(i);
                if (val != null) {
                    row.putInternal(i, val);
                }
            }
        }

        rcb.setState(theStatePos, new InsertRowState(row));
    }

    @Override
    public void close(RuntimeControlBlock rcb) {

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

        for (PlanIter colIter : theColIters) {
            colIter.close(rcb);
        }

        if (theTTLIter != null) {
            theTTLIter.close(rcb);
        }

        state.close();
    }

    @Override
    public void reset(RuntimeControlBlock rcb) {

        for (PlanIter colIter : theColIters) {
            colIter.reset(rcb);
        }

        if (theTTLIter != null) {
            theTTLIter.reset(rcb);
        }

        PlanIterState state = rcb.getState(theStatePos);
        state.reset(this);
    }

    @Override
    public boolean next(RuntimeControlBlock rcb) {

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

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

        RowImpl row = state.theRTRow;

        for (int i = 0; i < theColIters.length; ++i) {

            PlanIter colIter = theColIters[i];

            if (colIter.next(rcb)) {
                FieldValueImpl val = rcb.getRegVal(colIter.getResultReg());
                row.put(theColPositions[i], val);
            } else {
                row.putNull(theColPositions[i]);
            }
        }

        KVStoreImpl store = rcb.getStore();
        TableImpl table = row.getTableImpl();
        int idCol = table.getIdentityColumn();

        if (table.hasIdentityColumn() &&
            (row.get(idCol) == null || row.get(idCol).isEMPTY() ||
            (table.isIdentityOnNull() && row.get(idCol).isNull()))) {
            /* must get the next generated value */
            RecordDefImpl rowDef = table.getRowDef();
            FieldValueImpl generatedValue =
                store.getIdentityNextValue(table, rowDef.getFieldDef(idCol), 0,
                    row.get(idCol), idCol);

            if (generatedValue != null) {
                row.putInternal(idCol, generatedValue, false);
            }
        }

        if (rcb.getTraceLevel() >= 1) {
            rcb.trace("Row to insert =\n" + row);
        }

        long tableId = table.getId();
        Value rowval = row.createValue();
        Key rowkey = row.getPrimaryKey(false/*allowPartial*/);
        byte[] keybytes = keySerializer.toByteArray(rowkey);

        TimeToLive ttlObj;
        Put put;

        if (theIsUpsert) {

            ttlObj = setRowExpTime(rcb, row, true, theTTLIter,
                                   theTTLUnit, theLocation);

            put = new Put(keybytes, rowval, Choice.NONE, tableId,
                          ttlObj, theUpdateTTL);
        } else {

            ttlObj = setRowExpTime(rcb, row, true, theTTLIter,
                                   theTTLUnit, theLocation);

            Choice choice = (!theHasReturningClause ?
                             Choice.NONE : Choice.ALL);

            put = new PutIfAbsent(keybytes, rowval, choice, tableId,
                                  ttlObj, true);
        }

        PartitionId pid = store.getDispatcher().getPartitionId(keybytes);

        Durability durability = rcb.getDurability();
        long timeout = rcb.getTimeout();
        TimeUnit timeUnit = rcb.getTimeUnit();

        Request req = store.makeWriteRequest(put, pid,  durability,
                                             timeout, timeUnit, null);

        PutResult res = (PutResult)store.executeRequest(req);

        boolean wasInsert =
            (theIsUpsert ? !res.getWasUpdate() : res.getSuccess());

        if (theHasReturningClause) {

            if (!theIsUpsert && !wasInsert) {

                row = row.getTable().
                    initRowFromByteValue(row,
                                         res.getPreviousValue().toByteArray(),
                                         res.getPreviousExpirationTime(),
                                         res.getPreviousVersion());

                if (row == null) {
                    state.done();
                    return false;
                }

            } else {
                row.setVersion(res.getNewVersion());
                row.setExpirationTime(res.getNewExpirationTime());
            }

            rcb.setRegVal(theResultReg, row);

        } else {
            RecordValueImpl retval =
                ExprInsertRow.theNumRowsInsertedType.createRecord();
            retval.put(0, (wasInsert ? one : zero));
            rcb.setRegVal(theResultReg, retval);
        }

        state.done();
        return true;
    }

    /*
     * Note: this method is used by ServerUpdateRowIter as well.
     */
    public static TimeToLive setRowExpTime(
        RuntimeControlBlock rcb,
        RowImpl row,
        boolean updateTTL,
        PlanIter ttlIter,
        TimeUnit ttlUnit,
        Location loc) {

        if (!updateTTL) {
            return null;
        }

        TimeToLive ttlObj = null;

        if (ttlIter != null) {

            if (ttlIter.next(rcb)) {
                FieldValueImpl ttlVal = rcb.getRegVal(ttlIter.getResultReg());

                ttlVal = CastIter.castValue(ttlVal,
                                            FieldDefImpl.integerDef,
                                            loc);
                int ttl = ((IntegerValueImpl)ttlVal).get();
                if (ttl < 0) {
                    ttl = 0;
                }

                if (ttlUnit == TimeUnit.HOURS) {
                    ttlObj = TimeToLive.ofHours(ttl);
                } else {
                    ttlObj = TimeToLive.ofDays(ttl);
                }
            } else {
                ttlObj = row.getTable().getDefaultTTL();
            }
        } else {
            ttlObj = row.getTable().getDefaultTTL();
        }

        /*
         * ttlObj will be null if there is ttlIter is null and the table has
         * no default TTL.
         */
        if (ttlObj != null) {
            TimeUnit unit = ttlObj.getUnit();
            long ttl = ttlObj.getValue();
            long expTime;

            if (ttl == 0) {
                expTime = 0;
            } else if (unit == TimeUnit.DAYS) {
                expTime = ((System.currentTimeMillis() +
                            TimestampDefImpl.MILLIS_PER_DAY - 1) /
                            TimestampDefImpl.MILLIS_PER_DAY);

                expTime = (expTime + ttl) * TimestampDefImpl.MILLIS_PER_DAY;
            } else {
                expTime = ((System.currentTimeMillis() +
                            TimestampDefImpl.MILLIS_PER_HOUR - 1) /
                            TimestampDefImpl.MILLIS_PER_HOUR);

                expTime = (expTime + ttl) * TimestampDefImpl.MILLIS_PER_HOUR;
            }

            if (rcb.getTraceLevel() > 3) {
                rcb.trace("ttl = " + ttl + " expiration time = " + expTime);
            }

            row.setExpirationTime(expTime);

        } else {
            row.setExpirationTime(0);
        }

        return ttlObj;
    }

    @Override
    void displayName(StringBuilder sb) {

        if (theIsUpsert) {
            sb.append("UPSERT_ROW");
        } else {
            sb.append("INSERT_ROW");
        }
    }

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

        for (int i = 0; i < theColIters.length; ++i) {
            theColIters[i].display(sb, formatter);
            sb.append(",\n");
        }

        if (theTTLIter != null) {
            theTTLIter.display(sb, formatter);
        }

        sb.append(theRow.toJsonString(true));
        sb.append("\n");
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy