Package com.foundationdb.ais.model

Source Code of com.foundationdb.ais.model.Column

/**
* 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.ais.model;

import com.foundationdb.ais.model.validation.AISInvariants;
import com.foundationdb.server.collation.AkCollator;
import com.foundationdb.server.rowdata.FieldDef;
import com.foundationdb.server.types.TClass;
import com.foundationdb.server.types.TInstance;
import com.foundationdb.server.types.common.types.DecimalAttribute;
import com.foundationdb.server.types.common.types.StringAttribute;
import com.foundationdb.server.types.common.types.StringFactory;
import com.foundationdb.server.types.common.types.TBinary;
import com.foundationdb.server.types.common.types.TString;

import java.util.UUID;

public class Column implements ColumnContainer, Visitable
{
    public static Column create(Columnar table, String name, Integer position, TInstance type) {
        return create(table, name, position, type, null, null, null);
    }

    public static Column create(Columnar table, String name, Integer position, TInstance type, Long initialAutoIncValue)
    {
        return create(table, name, position, type, initialAutoIncValue,
                      null, null);
    }

    public static Column create(Columnar table, String name, Integer position, TInstance type, Long initialAutoIncValue,
                                Long maxStorageSize, Integer prefixSize)
    {
        table.checkMutability();
        AISInvariants.checkNullName(name, "column", "column name");
        AISInvariants.checkDuplicateColumnsInTable(table, name);
        AISInvariants.checkDuplicateColumnPositions(table, position);
        Column column = new Column(table, name, position, type, initialAutoIncValue,
                                   maxStorageSize, prefixSize);
        table.addColumn(column);
        return column;
    }

    /**
     * Create an independent copy of an existing Column.
     * @param columnar Destination Columnar.
     * @param column Column to copy.
     * @param position Position of the new column, or <code>null</code> to copy from the given column.
     * @return Copy of the Column.
     * */
    public static Column create(Columnar columnar, Column column, String name, Integer position) {
        Integer finalPosition = (position != null) ? position : column.position;
        String finalName = (name != null) ? name :  column.getName();
        Column out = create(columnar, finalName, finalPosition, column.type, column.initialAutoIncrementValue,
                            column.maxStorageSize, column.prefixSize);
        if(column.identityGenerator != null) {
            Sequence newGenerator = columnar.getAIS().getSequence(column.identityGenerator.getSequenceName());
            if(newGenerator != null) {
                out.setDefaultIdentity(column.defaultIdentity);
                out.setIdentityGenerator(newGenerator);
            }
        }
        out.setDefaultValue(column.getDefaultValue());
        out.setDefaultFunction(column.getDefaultFunction());
        out.setUuid(column.getUuid());
        return out;
    }

    @Override
    public Column getColumn() {
        return this;
    }

    @Override
    public String toString()
    {
        return columnar.getName().getTableName() + "." + columnName;
    }

    public void finishCreating() {
    }

    public void setAutoIncrement(Boolean autoIncrement)
    {
        this.initialAutoIncrementValue = autoIncrement ? 1L /* mysql default */ : null;
        columnar.markColumnsStale();
    }

    public final void setDefaultIdentity(Boolean defaultIdentity) {
        this.defaultIdentity = defaultIdentity;
        columnar.markColumnsStale();
    }

    public final void setIdentityGenerator(Sequence identityGenerator) {
        this.identityGenerator = identityGenerator;
        columnar.markColumnsStale();
    }

    public String getDescription()
    {
        StringBuilder buffer = new StringBuilder();
        buffer.append(columnar.getName().getSchemaName());
        buffer.append(".");
        buffer.append(columnar.getName().getTableName());
        buffer.append(".");
        buffer.append(getName());
        return buffer.toString();
    }

    public String getName()
    {
        return columnName;
    }

    public Integer getPosition()
    {
        return position;
    }

    public Columnar getColumnar()
    {
        return columnar;
    }

    public Table getTable()
    {
        return (Table)columnar;
    }

    /**
     * The initial auto-increment value used in the MySQL
     * generated table identity columns.
     */
    public Long getInitialAutoIncrementValue()
    {
        return initialAutoIncrementValue;
    }

    public void setInitialAutoIncrementValue(Long initialAutoIncrementValue)
    {
        this.initialAutoIncrementValue = initialAutoIncrementValue;
        columnar.markColumnsStale();
    }

    /**
     * <p>
     * This is a three state boolean:
     * <ul>
     *   <li><b>True</b>: column created with GENERATED BY DEFAULT AS IDENTITY</li>
     *   <li><b>False</b>: Column created with GENERATED ALWAYS AS IDENTITY</li>
     *   <li><b>null</b>: Not generated by identity column</li>
     * </ul>
     * </p>
     * <p>
     * <b>NOTE</b>: It is possible for the GetInitialAutoIncrement to be
     * not null and this to be null, as MySQL generated tables use
     *  auto-increment value, where as the SQL Layer uses identity generators.
     * </p>
     */
    public final Boolean getDefaultIdentity() {
        return defaultIdentity;
    }

    /**
     * The identity generator sequence for this column.
     * Will be null if not a IDENTITY Column.
     * The null/not-null state matches the getDefaultIdentity
     */
    public final Sequence getIdentityGenerator() {
        return identityGenerator;
     }

    public TInstance getType() {
        return type;
    }

    public void setType(TInstance type) {
        columnar.checkMutability();
        this.type = type;
        clearMaxAndPrefixSize();
        columnar.markColumnsStale();
    }

    public String getTypeName() {
        return type.typeClass().name().unqualifiedName();
    }

    public UUID getTypeBundleUUID() {
        return type.typeClass().name().bundleId().uuid();
    }

    public int getTypeVersion() {
        return type.typeClass().serializationVersion();
    }

    public String getTypeDescription()
    {
        return type.toStringConcise(true);
    }

    public Boolean getNullable()
    {
        return type.nullability();
    }

    public Long getTypeParameter1()
    {
        return getTypeParameter1(type);
    }

    public Long getTypeParameter2()
    {
        return getTypeParameter2(type);
    }

    public static Long getTypeParameter1(TInstance type)
    {
        if (type.hasAttributes(StringAttribute.class)) {
            return (long) type.attribute(StringAttribute.MAX_LENGTH);
        }
        else if (type.hasAttributes(TBinary.Attrs.class)) {
            return (long) type.attribute(TBinary.Attrs.LENGTH);
        }
        else if (type.hasAttributes(DecimalAttribute.class)) {
            return (long) type.attribute(DecimalAttribute.PRECISION);
        }
        else {
            return null;
        }
    }

    public static Long getTypeParameter2(TInstance type)
    {
        if (type.hasAttributes(DecimalAttribute.class)) {
            return (long) type.attribute(DecimalAttribute.SCALE);
        }
        else {
            return null;
        }
    }

    public boolean hasCharsetAndCollation() {
        return hasCharsetAndCollation(type);
    }

    public static boolean hasCharsetAndCollation(TInstance type) {
        return type.hasAttributes(StringAttribute.class);
    }

    public String getCharsetName() {
        if (hasCharsetAndCollation()) {
            return StringAttribute.charsetName(type);
        }
        else {
            return null;
        }
    }

    public int getCharsetId() {
        if (hasCharsetAndCollation()) {
            return type.attribute(StringAttribute.CHARSET);
        }
        else {
            return StringFactory.NULL_CHARSET_ID;
        }
    }

    public String getCollationName() {
        AkCollator collator = getCollator();
        if (collator != null) {
            return collator.getScheme();
        }
        else {
            return null;
        }
    }

    public int getCollationId() {
        if (hasCharsetAndCollation()) {
            return type.attribute(StringAttribute.COLLATION);
        }
        else {
            return StringFactory.NULL_COLLATION_ID;
        }
    }

    public AkCollator getCollator() {
        if (hasCharsetAndCollation()) {
            return TString.getCollator(type);
        }
        else {
            return null;
        }
    }

    public Long getMaxStorageSize() {
        return getMaxStorageSize(true);
    }

    public Long getMaxStorageSizeWithoutComputing() {
        return getMaxStorageSize(false);
    }

    private Long getMaxStorageSize(boolean compute) {
        if(maxStorageSize == null && compute) {
            synchronized(this) {
                if(maxStorageSize == null) {
                    maxStorageSize = computeStorageSize(false);
                }
            }
        }
        return maxStorageSize;
    }

    public long getAverageStorageSize()
    {
        return computeStorageSize(true);
    }

    public Integer getPrefixSize() {
        return getPrefixSize(true);
    }

    public Integer getPrefixSizeWithoutComputing() {
        return getPrefixSize(false);
    }

    private Integer getPrefixSize(boolean compute) {
        if((prefixSize == null) && compute) {
            synchronized(this) {
                if(prefixSize == null) {
                    prefixSize = computePrefixSize();
                }
            }
        }
        return prefixSize;
    }

    public void clearMaxAndPrefixSize() {
        maxStorageSize = null;
        prefixSize = null;
    }

    public boolean fixedSize() {
        TClass tclass = TInstance.tClass(type);
        return tclass.hasFixedSerializationSize(type);
    }

    // TODO -
    // This is the largest BLOB size that will fit in a message.  Increase or
    // remove this when we are no longer limited by the message size.
    // Note that the Type objects for the BLOB types carry their MySQL-defined
    // values so that the prefix size will be computed correctly.  The
    // cap is imposed by the constructor of a Column object.
    //
    public final static int MAX_STORAGE_SIZE_CAP = 1024 * 1024 - 1024;

    public long computeStorageSize(boolean average) {
        TClass tclass = TInstance.tClass(type);
        if (tclass.hasFixedSerializationSize(type)) {
            return tclass.fixedSerializationSize(type);
        }
        else {
            long maxBytes = tclass.variableSerializationSize(type, average);
            return Math.min(MAX_STORAGE_SIZE_CAP, maxBytes) + prefixSize(maxBytes);
        }
    }

    public int computePrefixSize() {
        TClass tclass = TInstance.tClass(type);
        if (tclass.hasFixedSerializationSize(type)) {
            return 0;
        }
        else {
            long maxBytes = tclass.variableSerializationSize(type, false);
            return prefixSize(maxBytes);
        }
    }

    private int prefixSize(final long byteCount)
    {
        return
            byteCount < 256 ? 1 :
            byteCount < 65536 ? 2 :
            byteCount < 16777216 ? 3 : 4;
    }

    public UUID getUuid() {
        return uuid;
    }

    public void setUuid(UUID uuid) {
        this.uuid = uuid;
    }

    public Boolean isInternalColumn()
    {
        // right now this just calls through, but this way the language is consistent between
        // getColumnsIncludingInternal() and this method
        return isAkibanPKColumn();
    }

    public Boolean isAkibanPKColumn()
    {
        return columnName.equals(ROW_ID_NAME);
    }

    public void setDefaultValue(String defaultValue) {
        this.defaultValue = defaultValue;
        columnar.markColumnsStale();
    }

    public String getDefaultValue() {
        return defaultValue;
    }

    public void setDefaultFunction(String defaultFunction) {
        this.defaultFunction = defaultFunction;
        columnar.markColumnsStale();
    }

    public String getDefaultFunction() {
        return defaultFunction;
    }

    public void setFieldDef(FieldDef fieldDef)
    {
        this.fieldDef = fieldDef;
    }

    public FieldDef getFieldDef()
    {
        return fieldDef;
    }

    private Column(Columnar columnar,
                   String columnName,
                   Integer position,
                   TInstance type,
                   Long initialAutoIncValue,
                   Long maxStorageSize,
                   Integer prefixSize)
    {
        this.columnar = columnar;
        this.columnName = columnName;
        this.position = position;
        this.type = type;
        this.initialAutoIncrementValue = initialAutoIncValue;
        this.maxStorageSize = maxStorageSize;
        this.prefixSize = prefixSize;
    }

    // Visitable

    /** {@link Visitor#visit(Column)} this instance. */
    @Override
    public void visit(Visitor visitor) {
        visitor.visit(this);
    }

    // State

    public static final String ROW_ID_NAME = "__row_id";

    public static boolean isInternalName(String columnName) {
        return ROW_ID_NAME.equals(columnName);
    }

    private final String columnName;
    private final Columnar columnar;
    private final Integer position;
    private TInstance type;
    private UUID uuid;
    private Long initialAutoIncrementValue;

    // TODO: Should be final, but the multi-part construction of a valid Column needs to be cleaned up
    private volatile Long maxStorageSize;
    private volatile Integer prefixSize;

    private FieldDef fieldDef;
    private Boolean defaultIdentity;
    private Sequence identityGenerator;
    private String defaultValue;
    private String defaultFunction;
}
TOP

Related Classes of com.foundationdb.ais.model.Column

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.