Package com.foundationdb.qp.row

Source Code of com.foundationdb.qp.row.ValuesHKey

/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.qp.row;

import java.util.Arrays;
import java.util.EnumMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.foundationdb.ais.model.HKeyColumn;
import com.foundationdb.ais.model.HKeySegment;
import com.foundationdb.ais.model.Table;
import com.foundationdb.qp.rowtype.HKeyRowType;
import com.foundationdb.server.store.PersistitKeyAppender;
import com.foundationdb.server.types.TClass;
import com.foundationdb.server.types.TInstance;
import com.foundationdb.server.types.TKeyComparable;
import com.foundationdb.server.types.service.TypesRegistryService;
import com.foundationdb.server.types.value.UnderlyingType;
import com.foundationdb.server.types.value.Value;
import com.foundationdb.server.types.value.ValueSource;
import com.foundationdb.server.types.value.ValueTargets;
import com.persistit.Key;

public class ValuesHKey extends AbstractValuesHolderRow implements HKey {

    // HKey interface - Object interface
    @Override
    public boolean equals(Object that)
    {
        return
            that == this ||
            (that != null &&
                that instanceof ValuesHKey &&
                this.compareTo((ValuesHKey)that) == 0);
    }

    @Override
    // TODO: This is overkill, but several tests rely upon the older PersistitHKey(key#toString()) behavior,
    // See ITBase#compareTwoRows(line 190ff).
    public String toString() {
        Key target = new Key (null, 2047);
        this.copyTo(target);
        return target.toString();
    }
   
   
    // HKey Interface  - Comparable interface
    @Override
    public int compareTo(HKey o) {
        assert o instanceof ValuesHKey : "Wrong HKey Type for compareTo";
        ValuesHKey that = (ValuesHKey)o;
        int columnIndex = 0;
        int cmp;
        for (int segment = 0; segment < hKeySegments; segment++) {
            cmp = this.ordinals[segment] - that.ordinals[segment];
            if (cmp != 0) {
                return cmp;
            }
            for (int i = 0; i < rowType().hKey().segments().get(segment).columns().size(); i++ ) {
                if (!that.values.get(columnIndex).hasAnyValue()) {
                    return 1;
                } else if (!this.values.get(columnIndex).hasAnyValue()) {
                    return -1;
                } else {
                    ValueSource left = this.values.get(columnIndex);
                    ValueSource right = that.values.get(columnIndex);
                    TKeyComparable compare = registry.getKeyComparable(this.values.get(columnIndex).getType().typeClass(),
                            that.values.get(columnIndex).getType().typeClass());
                    if (compare != null) {
                        cmp =  compare.getComparison().compare(left.getType(), left, right.getType(), right);
                    } else {
                        cmp = TClass.compare(left.getType(), left, right.getType(), right);
                    }
                    if (cmp != 0) {
                        return cmp;
                    }
                }
            }
            columnIndex++;
        }
        return 0;
    }

    // HKey interface implementation
    @Override
    public boolean prefixOf(HKey hKey) {
        assert hKey instanceof ValuesHKey : "Wrong HKey Type for prefixOf";
        ValuesHKey that = (ValuesHKey)hKey;

        if (this.rowType().table().getGroup() != that.rowType().table().getGroup())
            return false;
        if (this.hKeySegments <= that.hKeySegments) {
            int cmp = compareTo(that);
            if (cmp == 0) return true;
        }
        return false;
    }
   
    @Override
    public int segments() {
        return hKeySegments;
    }

    @Override
    public void useSegments(int segments) {
        assert segments > 0 && segments < ordinals.length : segments;
        hKeySegments = segments;
    }

    @Override
    public void copyTo(HKey target) {
        assert target instanceof ValuesHKey : "Wrong HKey Type for copyTo";
        ValuesHKey t = (ValuesHKey)target;

        int columnIndex = 0;
       
        for (int segment = 0; segment < hKeySegments; segment++) {
            if (segment >= t.hKeySegments) break;
            assert ordinals[segment] == t.ordinals[segment] : "Mismatched ordinals on segment " + segment +" for " + ordinals[segment] + " source vs " + t.ordinals[segment] + " target";
            for (int i = 0 ; i < keyDepth[segment]; i++) {
                copyValue (valueAt(columnIndex), t.valueAt(columnIndex));
                columnIndex++;
            }
        }
        if (t.hKeySegments > hKeySegments)
            t.useSegments(hKeySegments);
    }
   
    public void copyValueTo(ValueSource value, int columnIndex) {
        copyValue (value, valueAt(columnIndex));
    }
   
    @Override
    public void extendWithOrdinal(int ordinal) {
       
        // There are two cases where we want to extend this HKey
        // This (child hkey) was copied from parent, and now extended to match this child
        if (hKeySegments < ordinals.length-1 ) {

            //LOG.trace("Attempting to assign ordinal " + ordinal + " to position " + hKeySegments + " into " + Arrays.toString(ordinals));
           
            int finalSegment = 0;
            for (int segment = hKeySegments - 1; segment < ordinals.length-1; segment++) {
                if (ordinals[segment] == ordinal)
                    finalSegment = segment;
            }
            assert finalSegment != 0 : "Attempting to assign ordinal " + ordinal + " to position " + hKeySegments + " into " + Arrays.toString(ordinals);
           
            for (int segment = hKeySegments; segment < finalSegment; segment++) {
                hKeySegments++;
                extendWithNull();
            }
            hKeySegments++;
        } else {
            // This (parent hkey) is being extended to query a specific child
            ordinals[hKeySegments++] = ordinal;
        }
    }

   
    @Override
    public void extendWithNull() {
        int columnIndex = -1;
        int segment;
        for (segment = 0; segment < hKeySegments; segment++) {
            columnIndex += keyDepth[segment];
        }
        for (int i = 0; i < keyDepth[segment-1] && columnIndex < values.size() ; columnIndex++, i++) {
            valueAt(columnIndex).putNull();
        }
    }

    // HKey interface implementation - low level interface (to be removed at some point)
   
    @Override
    public void copyTo (Key target) {
        int columnIndex = 0;
        PersistitKeyAppender appender = PersistitKeyAppender.create(target, rowType().table().getName() );
        int maxSegments = Math.min(hKeySegments, rowType().hKey().segments().size());
        for (int segment = 0; segment < maxSegments; segment++) {
            appender.append(ordinals[segment]);
            for (HKeyColumn column : rowType().hKey().segments().get(segment).columns()) {
                if (this.values.get(columnIndex).hasAnyValue()) {
                    appender.append(this.values.get(columnIndex), column.column());
                }
                columnIndex++;
            }
        }
    }
   
    @Override
    public void copyFrom(Key source)
    {
        int sourceDepth = source.getDepth();
        assert sourceDepth >= 1 : "No data in source key";
        source.indexTo(0);
        int segment = 0;
        int columnsInSegment = 0;
       
        int ordinal = source.decodeInt();
        sourceDepth--;
        assert ordinal == ordinals[segment] : "Wrong ordinal for segment from key";
        for (int i = 0; i < values.size(); i++) {
            if (columnsInSegment == keyDepth[segment] ) {
                segment++;
                ordinal = source.decodeInt();
                assert ordinals[segment] == ordinal : "Mismatched ordinals " + ordinals[segment] + " source vs " + ordinal + " target";
                columnsInSegment = 0;
                sourceDepth--;
            }
            if (sourceDepth <= 0|| source.isNull(true)) {
                values.get(i).putNull();
            } else {
                sourceDepth--;
                Value valueTarget = values.get(i);
                UnderlyingType underlyingType = TInstance.underlyingType(valueTarget.getType());
                Class<?> expected = underlyingExpectedClasses.get(underlyingType);
                if (source.decodeType() == expected) {
                    switch (underlyingType) {
                        case BOOL:      valueTarget.putBool(source.decodeBoolean());        break;
                        case INT_8:     valueTarget.putInt8((byte)source.decodeLong());     break;
                        case INT_16:    valueTarget.putInt16((short)source.decodeLong());   break;
                        case UINT_16:   valueTarget.putUInt16((char)source.decodeLong());   break;
                        case INT_32:    valueTarget.putInt32((int)source.decodeLong());     break;
                        case INT_64:    valueTarget.putInt64(source.decodeLong());          break;
                        case FLOAT:     valueTarget.putFloat(source.decodeFloat());         break;
                        case DOUBLE:    valueTarget.putDouble(source.decodeDouble());       break;
                        case BYTES:     valueTarget.putBytes(source.decodeByteArray());     break;
                        case STRING:    valueTarget.putString(source.decodeString(), null); break;
                        default: throw new UnsupportedOperationException(valueTarget.getType() + " with " + underlyingType);
                    }
                }
                else {
                    valueTarget.putObject(source.decode());
                }
                // the following assumes that the TClass' readCollating expects the same UnderlyingType for in and out
                valueTarget.getType().readCollating(valueTarget, valueTarget);
            }
            columnsInSegment++;
        }       
    }
   

   
    // AbstractHoldersRow overrides
   
    @Override
    public HKey hKey() {
        return this;
    }

    public Value valueAt(int index) {
        return super.valueAt(index);
    }

    @Override
    public HKey ancestorHKey(Table table)
    {
        // TODO: This does the wrong thing for hkeys derived from group index rows!
        // TODO: See bug 997746.
        HKeyRowType rowType = this.rowType().schema().newHKeyRowType(table.hKey());
        HKey ancestorHKey = new ValuesHKey(rowType, this.registry);
        copyTo(ancestorHKey);
        ancestorHKey.useSegments(table.getDepth() + 1);
        return ancestorHKey;
    }

    // Constructors and private methods.
   
    public ValuesHKey (HKeyRowType rowType, TypesRegistryService registry)
    {
        super(rowType, true);
        this.registry = registry;
        this.hKeySegments = rowType().hKey().segments().size();
        setOrdinals();
    }

    private void setOrdinals() {
        this.ordinals = new int [hKeySegments+1];
        this.keyDepth = new int [hKeySegments];
        int ordinalIndex = 0;
        for (HKeySegment hKeySegment : rowType().hKey().segments()) {
            Table segmentTable = hKeySegment.table();
            ordinals[ordinalIndex] = segmentTable.getOrdinal();
            keyDepth[ordinalIndex] = hKeySegment.columns().size();
            ordinalIndex++;
        }
    }

    private void copyValue (ValueSource valueSource, Value valueTarget) {
        if (valueSource.hasAnyValue()) {
            TKeyComparable compare = registry.getKeyComparable(valueSource.getType().typeClass(), valueTarget.getType().typeClass());
            if (compare != null) {
                compare.getComparison().copyComparables(valueSource, valueTarget);
            } else {
                ValueTargets.copyFrom(valueSource, valueTarget);
            }
        }       
    }
    // For testing purposes
    protected int[] ordinals() { return ordinals; }
   
    private int[] ordinals;
    private int[] keyDepth;
    private int hKeySegments;
    private static final Logger LOG = LoggerFactory.getLogger(ValuesHKey.class);
    private final TypesRegistryService registry;

    private static final EnumMap<UnderlyingType, Class<?>> underlyingExpectedClasses = createPUnderlyingExpectedClasses();

    private static EnumMap<UnderlyingType, Class<?>> createPUnderlyingExpectedClasses() {
        EnumMap<UnderlyingType, Class<?>> result = new EnumMap<>(UnderlyingType.class);
        for (UnderlyingType underlyingType : UnderlyingType.values()) {
            final Class<?> expected;
            switch (underlyingType) {
            case BOOL:
                expected = Boolean.class;
                break;
            case INT_8:
            case INT_16:
            case UINT_16:
            case INT_32:
            case INT_64:
                expected = Long.class;
                break;
            case FLOAT:
                expected = Float.class;
                break;
            case DOUBLE:
                expected = Double.class;
                break;
            case BYTES:
                expected = byte[].class;
                break;
            case STRING:
                expected = String.class;
                break;
            default:
                throw new AssertionError("unrecognized UnderlyingType: " + underlyingType);
            }
            result.put(underlyingType, expected);
        }
        return result;
    }

}

TOP

Related Classes of com.foundationdb.qp.row.ValuesHKey

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.