package com.tesora.dve.db;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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/>.
* #L%
*/
import java.io.Serializable;
import java.sql.DatabaseMetaData;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import com.tesora.dve.exceptions.PEException;
public abstract class NativeType implements Serializable {
private static final long serialVersionUID = 1L;
// simple type name, i.e. varchar, varbinary, enum, set, float
private String typeName;
private int nativeTypeId;
private int dataType;
private boolean jdbcType;
private long precision = 0;
private String literalPrefix = "";
private String literalSuffix = "";
private String createParams = ""; // TODO haven't really figured out how to use this yet
private boolean supportsPrecision = false;
private boolean supportsScale = false;
private short nullability = DatabaseMetaData.typeNullableUnknown;
private boolean caseSensitive = false;
private int searchable = DatabaseMetaData.typeSearchable;
private boolean unsignedAttribute = false;
private boolean autoIncrement = false;
private int minimumScale = 0;
private int maximumScale = 0;
private int numPrecRadix = 10;
protected List<NativeTypeAlias> aliases;
private boolean comparable = true; // recognizing that most types are comparable
private boolean usedInCreate = true; // can this type be used in CREATE stmts
private long maxPrecision = 0; // we are using precision in some cases as "default precision". We need to store a max (PE-1232)
@SuppressWarnings("unused")
private NativeType() {
}
public NativeType(String typeName, int nativeTypeId, int dataType, boolean jdbcType) {
this(typeName, nativeTypeId, dataType, jdbcType, null);
}
public NativeType(String typeName, int nativeTypeId, int dataType, boolean jdbcType, NativeTypeAlias[] aliases) {
setTypeName(typeName);
setNativeTypeId(nativeTypeId);
setDataType(dataType);
this.jdbcType = jdbcType;
setAliases(aliases);
}
/**
* Make sure the type name is always the same. Sets the name to lower case with spaces instead of '_'
*
* Does the 'opposite' of fixNameForEnum.
*
* @param name
* @return
*/
public static String fixName(String name) {
return fixName(name, false);
}
/**
* Make sure the type name is always the same. Sets the name to lower case with spaces instead of '_'
*
* Does the 'opposite' of fixNameForEnum.
*
* @param name
* @return
*/
public static String fixName(String name, boolean stripEnum) {
final String[] matches = new String[] { "enum", "set" };
final String[] replacements = new String[] { "enum", "set" };
for(int i = 0; i < matches.length; i++) {
if (StringUtils.startsWith(StringUtils.lowerCase(name, Locale.ENGLISH), matches[i])) {
if (stripEnum) {
return replacements[i];
}
return matches[i] + name.substring(matches[i].length());
}
}
return name == null ? null : StringUtils.lowerCase(name.replaceAll("_", " "),Locale.ENGLISH);
}
/**
* This method is to make sure that when mapping a string to a type (through, say, enum.valueOf), the format is always
* the same. Inherited classes should use this to set up their own enum's of valid types.
*
* Does the 'opposite' of fixName.
*
* @param name
* @return
*/
public static String fixNameForType(String name) {
if (StringUtils.startsWith(StringUtils.lowerCase(name, Locale.ENGLISH), "enum")) {
return "ENUM";
}
return name == null ? null : StringUtils.replace(name.toUpperCase(Locale.ENGLISH)," ", "_");
}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = fixName(typeName);
}
@SuppressWarnings("hiding")
public NativeType withTypeName(String typeName) {
setTypeName(typeName);
return this;
}
public boolean requiresQuotes() {
return (!this.literalPrefix.isEmpty() && !this.literalSuffix.isEmpty());
}
public void setQuoteCharacter(String quote) {
this.literalPrefix = quote;
this.literalSuffix = quote;
}
public NativeType withQuoteCharacter(String quote) {
setQuoteCharacter(quote);
return this;
}
public int getDataType() {
return this.dataType;
}
public void setDataType(int dataType) {
this.dataType = dataType;
}
public int getNativeTypeId() {
return nativeTypeId;
}
public void setNativeTypeId(int nativeTypeId) {
this.nativeTypeId = nativeTypeId;
}
public boolean isJdbcType() {
return jdbcType;
}
@SuppressWarnings("hiding")
public NativeType withDataType(int dataType) {
setDataType(dataType);
return this;
}
public long getPrecision() {
return precision;
}
public void setPrecision(long precision) {
this.precision = precision;
}
@SuppressWarnings("hiding")
public NativeType withPrecision(long precision) {
setPrecision(precision);
setMaxPrecision(precision);
return this;
}
public long getMaxPrecision() {
return maxPrecision;
}
public void setMaxPrecision(long maxPrecision) {
this.maxPrecision = maxPrecision;
}
@SuppressWarnings("hiding")
public NativeType withMaxPrecision(long maxPrecision) {
setMaxPrecision(maxPrecision);
return this;
}
public String getLiteralPrefix() {
return literalPrefix;
}
public void setLiteralPrefix(String literalPrefix) {
this.literalPrefix = literalPrefix;
}
@SuppressWarnings("hiding")
public NativeType withLiteralPrefix(String literalPrefix) {
setLiteralPrefix(literalPrefix);
return this;
}
public String getLiteralSuffix() {
return literalSuffix;
}
public void setLiteralSuffix(String literalSuffix) {
this.literalSuffix = literalSuffix;
}
@SuppressWarnings("hiding")
public NativeType withLiteralSuffix(String literalSuffix) {
setLiteralSuffix(literalSuffix);
return this;
}
public String getCreateParams() {
return createParams;
}
public void setCreateParams(String createParams) {
this.createParams = createParams;
}
@SuppressWarnings("hiding")
public NativeType withCreateParams(String createParams) {
setCreateParams(createParams);
return this;
}
public short getNullability() {
return nullability;
}
public boolean isNullable() {
return (nullability == DatabaseMetaData.typeNullable ? true : false);
}
public NativeType isNullable(boolean nullable) {
setNullability((short) (nullable ? DatabaseMetaData.typeNullable
: DatabaseMetaData.typeNoNulls));
return this;
}
public void setNullability(short nullability) {
this.nullability = nullability;
}
@SuppressWarnings("hiding")
public NativeType withNullability(short nullability) {
setNullability(nullability);
return this;
}
public boolean isCaseSensitive() {
return caseSensitive;
}
public void setCaseSensitive(boolean caseSensitive) {
this.caseSensitive = caseSensitive;
}
@SuppressWarnings("hiding")
public NativeType withCaseSensitive(boolean caseSensitive) {
setCaseSensitive(caseSensitive);
return this;
}
public int getSearchable() {
return searchable;
}
public void setSearchable(int searchable) {
this.searchable = searchable;
}
@SuppressWarnings("hiding")
public NativeType withSearchable(int searchable) {
setSearchable(searchable);
return this;
}
public boolean isUnsignedAttribute() {
return unsignedAttribute;
}
public void setUnsignedAttribute(boolean unsignedAttribute) {
this.unsignedAttribute = unsignedAttribute;
}
@SuppressWarnings("hiding")
public NativeType withUnsignedAttribute(boolean unsignedAttribute) {
setUnsignedAttribute(unsignedAttribute);
return this;
}
public boolean isAutoIncrement() {
return autoIncrement;
}
public void setAutoIncrement(boolean autoIncrement) {
this.autoIncrement = autoIncrement;
}
@SuppressWarnings("hiding")
public NativeType withAutoIncrement(boolean autoIncrement) {
setAutoIncrement(autoIncrement);
return this;
}
public int getMinimumScale() {
return minimumScale;
}
public void setMinimumScale(int minimumScale) {
this.minimumScale = minimumScale;
}
@SuppressWarnings("hiding")
public NativeType withMinimumScale(int minimumScale) {
setMinimumScale(minimumScale);
return this;
}
public int getMaximumScale() {
return maximumScale;
}
public void setMaximumScale(int maximumScale) {
this.maximumScale = maximumScale;
}
@SuppressWarnings("hiding")
public NativeType withMaximumScale(int maximumScale) {
setMaximumScale(maximumScale);
return this;
}
public int getNumPrecRadix() {
return numPrecRadix;
}
public void setNumPrecRadix(int numPrecRadix) {
this.numPrecRadix = numPrecRadix;
}
@SuppressWarnings("hiding")
public NativeType withNumPrecRadix(int numPrecRadix) {
setNumPrecRadix(numPrecRadix);
return this;
}
public List<NativeTypeAlias> getAliases() {
return aliases;
}
public void setAliases(List<NativeTypeAlias> aliases) {
this.aliases = aliases;
}
public void setAliases(NativeTypeAlias[] aliases) {
if ( aliases != null ) {
this.aliases = new ArrayList<NativeTypeAlias>(Arrays.asList(aliases));
} else
this.aliases = new ArrayList<NativeTypeAlias>();
}
public Set<String> getNames() {
Set<String> names = new HashSet<String>();
names.add(getTypeName());
for (NativeTypeAlias alias : aliases) {
names.add(fixName(alias.getAliasName()));
}
return names;
}
public boolean getSupportsPrecision() {
return supportsPrecision;
}
public void setSupportsPrecision(boolean supportsPrecision) {
this.supportsPrecision = supportsPrecision;
}
@SuppressWarnings("hiding")
public NativeType withSupportsPrecision(boolean supportsPrecision) {
setSupportsPrecision(supportsPrecision);
return this;
}
public boolean getSupportsScale() {
return supportsScale;
}
public void setSupportsScale(boolean supportsScale) {
this.supportsScale = supportsScale;
}
@SuppressWarnings("hiding")
public NativeType withSupportsScale(boolean supportsScale) {
setSupportsScale(supportsScale);
return this;
}
public boolean isComparable() {
return comparable;
}
public void setComparable(boolean comparable) {
this.comparable = comparable;
}
@SuppressWarnings("hiding")
public NativeType withComparable(boolean comparable) {
setComparable(comparable);
return this;
}
public boolean isUsedInCreate() {
return usedInCreate;
}
public void setUsedInCreate(boolean usedInCreate) {
this.usedInCreate = usedInCreate;
}
@SuppressWarnings("hiding")
public NativeType withUsedInCreate(boolean usedInCreate) {
setUsedInCreate(usedInCreate);
return this;
}
public boolean isBinaryType() {
return dataType == Types.LONGVARBINARY || dataType == Types.BLOB ||
dataType == Types.BINARY || dataType == Types.VARBINARY;
}
public boolean isStringType() {
return dataType == Types.VARCHAR || dataType == Types.LONGVARCHAR ||
dataType == Types.CHAR || dataType == Types.CLOB ||
dataType == Types.LONGNVARCHAR;
}
public boolean supportsDefaultValue() {
return true;
}
public boolean isFloatType() {
return dataType == Types.FLOAT || dataType == Types.REAL || dataType == Types.DOUBLE;
}
public boolean isNumericType() {
return dataType == Types.BIGINT || dataType == Types.DECIMAL || dataType == Types.DOUBLE
|| dataType == Types.FLOAT || dataType == Types.INTEGER || dataType == Types.NUMERIC
|| dataType == Types.REAL || dataType == Types.TINYINT || dataType == Types.SMALLINT;
}
public boolean isDecimalType() {
return dataType == Types.DECIMAL || dataType == Types.NUMERIC;
}
public boolean isTimestampType() {
return dataType == Types.TIMESTAMP;
}
public boolean isIntegralType() {
return dataType == Types.BIGINT || dataType == Types.INTEGER || dataType == Types.TINYINT || dataType == Types.SMALLINT;
}
public boolean asKeyRequiresPrefix() {
return false;
}
// not always correct, but presumably the subtypes will do the right thing
public Object getZeroValue() throws PEException {
return "";
}
public int getDefaultColumnAttrFlags() {
return 0;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (autoIncrement ? 1231 : 1237);
result = prime * result + (caseSensitive ? 1231 : 1237);
result = prime * result + (comparable ? 1231 : 1237);
result = prime * result + ((createParams == null) ? 0 : createParams.hashCode());
result = prime * result + dataType;
result = prime * result + (jdbcType ? 1231 : 1237);
result = prime * result + ((literalPrefix == null) ? 0 : literalPrefix.hashCode());
result = prime * result + ((literalSuffix == null) ? 0 : literalSuffix.hashCode());
result = prime * result + maximumScale;
result = prime * result + minimumScale;
result = prime * result + nullability;
result = prime * result + numPrecRadix;
result = prime * result + (int) (precision ^ (precision >>> 32));
result = prime * result + searchable;
result = prime * result + (supportsPrecision ? 1231 : 1237);
result = prime * result + (supportsScale ? 1231 : 1237);
result = prime * result + ((typeName == null) ? 0 : typeName.hashCode());
result = prime * result + (unsignedAttribute ? 1231 : 1237);
result = prime * result + (usedInCreate ? 1231 : 1237);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NativeType other = (NativeType) obj;
if (autoIncrement != other.autoIncrement)
return false;
if (caseSensitive != other.caseSensitive)
return false;
if (comparable != other.comparable)
return false;
if (createParams == null) {
if (other.createParams != null)
return false;
} else if (!createParams.equals(other.createParams))
return false;
if (dataType != other.dataType)
return false;
if (jdbcType != other.jdbcType)
return false;
if (literalPrefix == null) {
if (other.literalPrefix != null)
return false;
} else if (!literalPrefix.equals(other.literalPrefix))
return false;
if (literalSuffix == null) {
if (other.literalSuffix != null)
return false;
} else if (!literalSuffix.equals(other.literalSuffix))
return false;
if (maximumScale != other.maximumScale)
return false;
if (minimumScale != other.minimumScale)
return false;
if (nullability != other.nullability)
return false;
if (numPrecRadix != other.numPrecRadix)
return false;
if (precision != other.precision)
return false;
if (searchable != other.searchable)
return false;
if (supportsPrecision != other.supportsPrecision)
return false;
if (supportsScale != other.supportsScale)
return false;
if (typeName == null) {
if (other.typeName != null)
return false;
} else if (!typeName.equals(other.typeName))
return false;
if (unsignedAttribute != other.unsignedAttribute)
return false;
if (usedInCreate != other.usedInCreate)
return false;
return true;
}
}