提交 685f01b6 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add ExtTypeInfo as generic replacement for String[] enumerators

上级 c734f793
......@@ -196,12 +196,13 @@ import org.h2.util.StringUtils;
import org.h2.util.Utils;
import org.h2.value.CompareMode;
import org.h2.value.DataType;
import org.h2.value.ExtTypeInfo;
import org.h2.value.ExtTypeInfoEnum;
import org.h2.value.Value;
import org.h2.value.ValueBoolean;
import org.h2.value.ValueBytes;
import org.h2.value.ValueDate;
import org.h2.value.ValueDecimal;
import org.h2.value.ValueEnum;
import org.h2.value.ValueInt;
import org.h2.value.ValueInterval;
import org.h2.value.ValueLong;
......@@ -4862,7 +4863,7 @@ public class Parser {
}
long precision = -1;
int displaySize = -1;
String[] enumerators = null;
ExtTypeInfo extTypeInfo = null;
int scale = -1;
String comment = null;
Column templateColumn = null;
......@@ -4879,7 +4880,7 @@ public class Parser {
precision = templateColumn.getPrecision();
displaySize = templateColumn.getDisplaySize();
scale = templateColumn.getScale();
enumerators = templateColumn.getEnumerators();
extTypeInfo = templateColumn.getExtTypeInfo();
} else {
Mode mode = database.getMode();
dataType = DataType.getTypeByName(original, mode);
......@@ -5007,26 +5008,25 @@ public class Parser {
original = original + '(' + p + ')';
}
} else if (dataType.type == Value.ENUM) {
if (extTypeInfo == null) {
String[] enumerators = null;
if (readIf(OPEN_PAREN)) {
java.util.List<String> enumeratorList = new ArrayList<>();
original += '(';
String enumerator0 = readString();
enumeratorList.add(enumerator0);
original += "'" + enumerator0 + "'";
while (readIfMore(true)) {
original += ',';
String enumeratorN = readString();
original += "'" + enumeratorN + "'";
enumeratorList.add(enumeratorN);
}
original += ')';
enumerators = enumeratorList.toArray(new String[0]);
}
try {
ValueEnum.check(enumerators);
extTypeInfo = new ExtTypeInfoEnum(enumerators);
} catch (DbException e) {
throw e.addSQL(original);
}
original += extTypeInfo.toString();
}
} else if (readIf(OPEN_PAREN)) {
// Support for MySQL: INT(11), MEDIUMINT(8) and so on.
// Just ignore the precision.
......@@ -5049,7 +5049,7 @@ public class Parser {
}
Column column = new Column(columnName, type, precision, scale,
displaySize, enumerators);
displaySize, extTypeInfo);
if (templateColumn != null) {
column.setNullable(templateColumn.isNullable());
column.setDefaultExpression(session,
......
......@@ -23,6 +23,7 @@ import org.h2.table.Column;
import org.h2.table.Table;
import org.h2.util.ColumnNamer;
import org.h2.value.DataType;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value;
/**
......@@ -197,18 +198,18 @@ public class CreateTable extends CommandWithColumns {
if (scale > precision) {
precision = scale;
}
String[] enumerators = null;
ExtTypeInfo extTypeInfo = null;
if (dt.type == Value.ENUM) {
/**
* Only columns of tables may be enumerated.
*/
if(!(expr instanceof ExpressionColumn)) {
if (!(expr instanceof ExpressionColumn)) {
throw DbException.get(ErrorCode.GENERAL_ERROR_1,
"Unable to resolve enumerators of expression");
}
enumerators = ((ExpressionColumn)expr).getColumn().getEnumerators();
extTypeInfo = ((ExpressionColumn) expr).getColumn().getExtTypeInfo();
}
Column col = new Column(name, type, precision, scale, displaySize, enumerators);
Column col = new Column(name, type, precision, scale, displaySize, extTypeInfo);
addColumn(col);
}
}
......
......@@ -210,7 +210,7 @@ public class Comparison extends Condition {
Column column = ((ExpressionColumn) left).getColumn();
right = ValueExpression.get(r.convertTo(resType,
MathUtils.convertLongToInt(left.getPrecision()),
session.getDatabase().getMode(), column, column.getEnumerators()));
session.getDatabase().getMode(), column, column.getExtTypeInfo()));
}
} else if (right instanceof Parameter) {
((Parameter) right).setColumn(
......
......@@ -16,6 +16,7 @@ import org.h2.message.DbException;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value;
import org.h2.value.ValueBoolean;
import org.h2.value.ValueNull;
......@@ -34,7 +35,7 @@ public class ConditionInConstantSet extends Condition {
private final ArrayList<Expression> valueList;
private final TreeSet<Value> valueSet;
private final int type;
private String[] enumerators;
private ExtTypeInfo extTypeInfo;
/**
* Create a new IN(..) condition.
......@@ -54,9 +55,9 @@ public class ConditionInConstantSet extends Condition {
type = left.getType();
Mode mode = database.getMode();
if (type == Value.ENUM) {
enumerators = ((ExpressionColumn) left).getColumn().getEnumerators();
extTypeInfo = ((ExpressionColumn) left).getColumn().getExtTypeInfo();
for (Expression expression : valueList) {
valueSet.add(expression.getValue(session).convertToEnum(enumerators));
valueSet.add(extTypeInfo.cast(expression.getValue(session)));
}
} else {
for (Expression expression : valueList) {
......@@ -170,7 +171,7 @@ public class ConditionInConstantSet extends Condition {
if (add.isConstant()) {
valueList.add(add);
if (type == Value.ENUM) {
valueSet.add(add.getValue(session).convertToEnum(enumerators));
valueSet.add(add.getValue(session).convertToEnum(extTypeInfo));
} else {
valueSet.add(add.getValue(session).convertTo(type, session.getDatabase().getMode()));
}
......
......@@ -19,9 +19,9 @@ import org.h2.table.Column;
import org.h2.table.ColumnResolver;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value;
import org.h2.value.ValueBoolean;
import org.h2.value.ValueEnum;
import org.h2.value.ValueNull;
/**
......@@ -191,8 +191,11 @@ public class ExpressionColumn extends Expression {
throw DbException.get(ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL());
}
}
if (column.getEnumerators() != null && value != ValueNull.INSTANCE) {
return ValueEnum.get(column.getEnumerators(), value.getInt());
if (value != ValueNull.INSTANCE) {
ExtTypeInfo extTypeInfo = column.getExtTypeInfo();
if (extTypeInfo != null) {
return extTypeInfo.cast(value);
}
}
return value;
}
......
......@@ -56,6 +56,7 @@ import org.h2.util.ToChar;
import org.h2.util.ToDateParser;
import org.h2.util.Utils;
import org.h2.value.DataType;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean;
......@@ -162,7 +163,7 @@ public class Function extends Expression implements FunctionCall {
protected int scale;
protected long precision = PRECISION_UNKNOWN;
protected int displaySize;
protected String[] enumerators;
protected ExtTypeInfo extTypeInfo;
private final Database database;
......@@ -894,7 +895,7 @@ public class Function extends Expression implements FunctionCall {
case CAST:
case CONVERT: {
Mode mode = database.getMode();
v0 = v0.convertTo(dataType, MathUtils.convertLongToInt(precision), mode, null, enumerators);
v0 = v0.convertTo(dataType, MathUtils.convertLongToInt(precision), mode, null, extTypeInfo);
v0 = v0.convertScale(mode.convertOnlyToSmallerScale, scale);
v0 = v0.convertPrecision(getPrecision(), false);
result = v0;
......@@ -2200,7 +2201,7 @@ public class Function extends Expression implements FunctionCall {
precision = col.getPrecision();
displaySize = col.getDisplaySize();
scale = col.getScale();
enumerators = col.getEnumerators();
extTypeInfo = col.getExtTypeInfo();
}
@Override
......@@ -2601,7 +2602,7 @@ public class Function extends Expression implements FunctionCall {
case CAST: {
buff.append(args[0].getSQL()).append(" AS ").
append(new Column(null, dataType, precision,
scale, displaySize, enumerators).getCreateSQL());
scale, displaySize, extTypeInfo).getCreateSQL());
break;
}
case CONVERT: {
......
......@@ -288,7 +288,7 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex {
int idx = c.getColumnId();
Value v = r.getValue(idx);
if (v != null) {
array[i] = v.convertTo(c.getType(), -1, database.getMode(), null, c.getEnumerators());
array[i] = v.convertTo(c.getType(), -1, database.getMode(), null, c.getExtTypeInfo());
}
}
array[keyColumns - 1] = key != null ? key : ValueLong.get(r.getKey());
......
......@@ -6,7 +6,8 @@
package org.h2.table;
import java.sql.ResultSetMetaData;
import java.util.Arrays;
import java.util.Objects;
import org.h2.api.ErrorCode;
import org.h2.command.Parser;
import org.h2.engine.Constants;
......@@ -25,8 +26,8 @@ import org.h2.schema.Sequence;
import org.h2.util.MathUtils;
import org.h2.util.StringUtils;
import org.h2.value.DataType;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value;
import org.h2.value.ValueEnum;
import org.h2.value.ValueInt;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
......@@ -65,7 +66,7 @@ public class Column {
private final int type;
private long precision;
private int scale;
private String[] enumerators;
private ExtTypeInfo extTypeInfo;
private int displaySize;
private Table table;
private String name;
......@@ -99,8 +100,7 @@ public class Column {
this(name, type, precision, scale, displaySize, null);
}
public Column(String name, int type, long precision, int scale,
int displaySize, String[] enumerators) {
public Column(String name, int type, long precision, int scale, int displaySize, ExtTypeInfo extTypeInfo) {
this.name = name;
this.type = type;
if (precision == -1 && scale == -1 && displaySize == -1 && type != Value.UNKNOWN) {
......@@ -112,7 +112,7 @@ public class Column {
this.precision = precision;
this.scale = scale;
this.displaySize = displaySize;
this.enumerators = enumerators;
this.extTypeInfo = extTypeInfo;
}
@Override
......@@ -141,12 +141,8 @@ public class Column {
return table.getId() ^ name.hashCode();
}
public boolean isEnumerated() {
return type == Value.ENUM;
}
public Column getClone() {
Column newColumn = new Column(name, type, precision, scale, displaySize, enumerators);
Column newColumn = new Column(name, type, precision, scale, displaySize, extTypeInfo);
newColumn.copy(this);
return newColumn;
}
......@@ -172,7 +168,7 @@ public class Column {
*/
public Value convert(Value v, Mode mode) {
try {
return v.convertTo(type, MathUtils.convertLongToInt(precision), mode, this, getEnumerators());
return v.convertTo(type, MathUtils.convertLongToInt(precision), mode, this, extTypeInfo);
} catch (DbException e) {
if (e.getErrorCode() == ErrorCode.DATA_CONVERSION_ERROR_1) {
String target = (table == null ? "" : table.getName() + ": ") +
......@@ -300,12 +296,12 @@ public class Column {
nullable = b;
}
public String[] getEnumerators() {
return enumerators;
public ExtTypeInfo getExtTypeInfo() {
return extTypeInfo;
}
public void setEnumerators(String[] enumerators) {
this.enumerators = enumerators;
public void setExtTypeInfo(ExtTypeInfo extTypeInfo) {
this.extTypeInfo = extTypeInfo;
}
public boolean getVisible() {
......@@ -406,17 +402,8 @@ public class Column {
getCreateSQL(), s + " (" + value.getPrecision() + ")");
}
}
if (isEnumerated() && value != ValueNull.INSTANCE) {
if (!ValueEnum.isValid(enumerators, value)) {
String s = value.getTraceSQL();
if (s.length() > 127) {
s = s.substring(0, 128) + "...";
}
throw DbException.get(ErrorCode.ENUM_VALUE_NOT_PERMITTED,
getCreateSQL(), s);
}
value = ValueEnum.get(enumerators, value.getInt());
if (type == Value.ENUM && value != ValueNull.INSTANCE) {
value = extTypeInfo.cast(value);
}
updateSequenceIfRequired(session, value);
return value;
......@@ -523,14 +510,7 @@ public class Column {
buff.append('(').append(precision).append(", ").append(scale).append(')');
break;
case Value.ENUM:
buff.append('(');
for (int i = 0; i < enumerators.length; i++) {
buff.append('\'').append(enumerators[i]).append('\'');
if(i < enumerators.length - 1) {
buff.append(',');
}
}
buff.append(')');
buff.append(extTypeInfo.toString());
break;
case Value.BYTES:
case Value.STRING:
......@@ -862,6 +842,9 @@ public class Column {
if (onUpdateExpression != null || newColumn.onUpdateExpression != null) {
return false;
}
if (!Objects.equals(extTypeInfo, newColumn.extTypeInfo)) {
return false;
}
return true;
}
......@@ -876,8 +859,7 @@ public class Column {
displaySize = source.displaySize;
name = source.name;
precision = source.precision;
enumerators = source.enumerators == null ? null :
Arrays.copyOf(source.enumerators, source.enumerators.length);
extTypeInfo = source.extTypeInfo;
scale = source.scale;
// table is not set
// columnId is not set
......
......@@ -38,6 +38,7 @@ import org.h2.util.ColumnNamer;
import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value;
/**
......@@ -194,13 +195,13 @@ public class TableView extends Table {
long precision = expr.getPrecision();
int scale = expr.getScale();
int displaySize = expr.getDisplaySize();
String[] enumerators = null;
ExtTypeInfo extTypeInfo = null;
if (type == Value.ENUM) {
if (expr instanceof ExpressionColumn) {
enumerators = ((ExpressionColumn) expr).getColumn().getEnumerators();
extTypeInfo = ((ExpressionColumn) expr).getColumn().getExtTypeInfo();
}
}
Column col = new Column(name, type, precision, scale, displaySize, enumerators);
Column col = new Column(name, type, precision, scale, displaySize, extTypeInfo);
col.setTable(this, i);
// Fetch check constraint from view column source
ExpressionColumn fromColumn = null;
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.value;
/**
* Extended parameters of a data type.
*/
public abstract class ExtTypeInfo {
/**
* Casts a specified value to this data type.
*
* @param value
* value to cast
* @return casted value
*/
public abstract Value cast(Value value);
}
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.value;
import java.util.Arrays;
import java.util.Locale;
import org.h2.api.ErrorCode;
import org.h2.message.DbException;
/**
* Extended parameters of the ENUM data type.
*/
public final class ExtTypeInfoEnum extends ExtTypeInfo {
private final String[] enumerators, cleaned;
/**
* Returns enumerators for the two specified values for a binary operation.
*
* @param left
* left (first) operand
* @param right
* right (second) operand
* @return enumerators from the left or the right value, or an empty array
* if both values do not have enumerators
*/
public static ExtTypeInfoEnum getEnumeratorsForBinaryOperation(Value left, Value right) {
if (left.getType() == Value.ENUM) {
return ((ValueEnum) left).getEnumerators();
} else if (right.getType() == Value.ENUM) {
return ((ValueEnum) right).getEnumerators();
} else {
throw DbException.get(ErrorCode.UNKNOWN_DATA_TYPE_1,
"type1=" + left.getType() + ", type2=" + right.getType());
}
}
private static String sanitize(String label) {
return label == null ? null : label.trim().toUpperCase(Locale.ENGLISH);
}
private static String toString(String[] enumerators) {
StringBuilder result = new StringBuilder();
result.append('(');
for (int i = 0; i < enumerators.length; i++) {
if (i != 0) {
result.append(", ");
}
result.append('\'');
String s = enumerators[i];
for (int j = 0; j < s.length(); j++) {
char c = s.charAt(j);
if (c == '\'') {
result.append('\'');
}
result.append(c);
}
result.append('\'');
}
result.append(')');
return result.toString();
}
/**
* Creates new instance of extended parameters of the ENUM data type.
*
* @param enumerators
* the enumerators. May not be modified by caller or this class.
*/
public ExtTypeInfoEnum(String[] enumerators) {
if (enumerators == null || enumerators.length == 0) {
throw DbException.get(ErrorCode.ENUM_EMPTY);
}
final String[] cleaned = new String[enumerators.length];
for (int i = 0; i < enumerators.length; i++) {
String l = sanitize(enumerators[i]);
if (l == null || l.isEmpty()) {
throw DbException.get(ErrorCode.ENUM_EMPTY);
}
for (int j = 0; j < i; j++) {
if (l.equals(cleaned[j])) {
throw DbException.get(ErrorCode.ENUM_DUPLICATE, toString(enumerators));
}
}
cleaned[i] = l;
}
this.enumerators = enumerators;
this.cleaned = Arrays.equals(cleaned, enumerators) ? enumerators : cleaned;
}
@Override
public Value cast(Value value) {
switch (value.getType()) {
case Value.ENUM:
if (value instanceof ValueEnum && ((ValueEnum) value).getEnumerators().equals(this)) {
return value;
}
//$FALL-THROUGH$
case Value.STRING:
case Value.STRING_FIXED:
case Value.STRING_IGNORECASE:
ValueEnum v = getValueOrNull(value.getString());
if (v != null) {
return v;
}
break;
default:
int ordinal = value.getInt();
if (ordinal >= 0 && ordinal < enumerators.length) {
return new ValueEnum(this, enumerators[ordinal], ordinal);
}
}
String s = value.getTraceSQL();
if (s.length() > 127) {
s = s.substring(0, 128) + "...";
}
throw DbException.get(ErrorCode.ENUM_VALUE_NOT_PERMITTED, toString(), s);
}
/**
* Returns an enumerator with specified 0-based ordinal value.
*
* @param ordinal
* ordinal value of an enumerator
* @return the enumerator with specified ordinal value
*/
public String getEnumerator(int ordinal) {
return enumerators[ordinal];
}
public ValueEnum getValue(int ordinal) {
if (ordinal < 0 || ordinal >= enumerators.length) {
throw DbException.get(ErrorCode.ENUM_VALUE_NOT_PERMITTED, enumerators.toString(),
Integer.toString(ordinal));
}
return new ValueEnum(this, enumerators[ordinal], ordinal);
}
public ValueEnum getValue(String label) {
ValueEnum value = getValueOrNull(label);
if (value == null) {
throw DbException.get(ErrorCode.ENUM_VALUE_NOT_PERMITTED, toString(), label);
}
return value;
}
private ValueEnum getValueOrNull(String label) {
String l = sanitize(label);
if (l != null) {
for (int ordinal = 0; ordinal < cleaned.length; ordinal++) {
if (l.equals(cleaned[ordinal])) {
return new ValueEnum(this, enumerators[ordinal], ordinal);
}
}
}
return null;
}
@Override
public int hashCode() {
return Arrays.hashCode(cleaned) + 203_117;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || obj.getClass() != ExtTypeInfoEnum.class) {
return false;
}
return Arrays.equals(cleaned, ((ExtTypeInfoEnum) obj).cleaned);
}
@Override
public String toString() {
return toString(enumerators);
}
}
......@@ -677,10 +677,10 @@ public abstract class Value {
/**
* Convert value to ENUM value
* @param enumerators allowed values for the ENUM to which the value is converted
* @param enumerators the extended type information for the ENUM data type
* @return value represented as ENUM
*/
public final Value convertToEnum(String[] enumerators) {
public final Value convertToEnum(ExtTypeInfo enumerators) {
// Use -1 to indicate "default behaviour" where value conversion should not
// depend on any datatype precision.
return convertTo(ENUM, -1, null, null, enumerators);
......@@ -706,11 +706,10 @@ public abstract class Value {
* the precision plays no role when converting the value
* @param mode the conversion mode
* @param column the column (if any), used for to improve the error message if conversion fails
* @param enumerators the ENUM datatype enumerators (if any),
* for dealing with ENUM conversions
* @param extTypeInfo the extended data type information, or null
* @return the converted value
*/
public Value convertTo(int targetType, int precision, Mode mode, Object column, String[] enumerators) {
public Value convertTo(int targetType, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) {
// converting NULL is done in ValueNull
// converting BLOB to CLOB and vice versa is done in ValueLob
if (getType() == targetType) {
......@@ -755,7 +754,7 @@ public abstract class Value {
case JAVA_OBJECT:
return convertToJavaObject();
case ENUM:
return convertToEnumInternal(enumerators);
return convertToEnumInternal((ExtTypeInfoEnum) extTypeInfo);
case BLOB:
return convertToBlob();
case CLOB:
......@@ -1158,24 +1157,24 @@ public abstract class Value {
return ValueJavaObject.getNoCopy(null, StringUtils.convertHexToBytes(getString().trim()), getDataHandler());
}
private ValueEnum convertToEnumInternal(String[] enumerators) {
private ValueEnum convertToEnumInternal(ExtTypeInfoEnum extTypeInfo) {
switch (getType()) {
case BYTE:
case SHORT:
case INT:
case LONG:
case DECIMAL:
return ValueEnum.get(enumerators, getInt());
return extTypeInfo.getValue(getInt());
case STRING:
case STRING_IGNORECASE:
case STRING_FIXED:
return ValueEnum.get(enumerators, getString());
return extTypeInfo.getValue(getString());
case JAVA_OBJECT:
Object object = JdbcUtils.deserialize(getBytesNoCopy(), getDataHandler());
if (object instanceof String) {
return ValueEnum.get(enumerators, (String) object);
return extTypeInfo.getValue((String) object);
} else if (object instanceof Integer) {
return ValueEnum.get(enumerators, (int) object);
return extTypeInfo.getValue((int) object);
}
//$FALL-THROUGH$
}
......@@ -1337,7 +1336,7 @@ public abstract class Value {
if (leftType != rightType || leftType == Value.ENUM) {
int dataType = Value.getHigherOrder(leftType, rightType);
if (dataType == Value.ENUM) {
String[] enumerators = ValueEnum.getEnumeratorsForBinaryOperation(l, v);
ExtTypeInfoEnum enumerators = ExtTypeInfoEnum.getEnumeratorsForBinaryOperation(l, v);
l = l.convertToEnum(enumerators);
v = v.convertToEnum(enumerators);
} else {
......
......@@ -5,196 +5,17 @@
*/
package org.h2.value;
import java.util.Locale;
import org.h2.api.ErrorCode;
import org.h2.message.DbException;
public class ValueEnum extends ValueEnumBase {
private enum Validation {
DUPLICATE,
EMPTY,
INVALID,
VALID
}
private final String[] enumerators;
private final ExtTypeInfoEnum enumerators;
private ValueEnum(final String[] enumerators, final int ordinal) {
super(enumerators[ordinal], ordinal);
ValueEnum(ExtTypeInfoEnum enumerators, String label, int ordinal) {
super(label, ordinal);
this.enumerators = enumerators;
}
/**
* Check for any violations, such as empty
* values, duplicate values.
*
* @param enumerators the enumerators
*/
public static void check(final String[] enumerators) {
switch (validate(enumerators)) {
case VALID:
return;
case EMPTY:
throw DbException.get(ErrorCode.ENUM_EMPTY);
case DUPLICATE:
throw DbException.get(ErrorCode.ENUM_DUPLICATE,
toString(enumerators));
default:
throw DbException.get(ErrorCode.INVALID_VALUE_2,
toString(enumerators));
}
}
private static void check(final String[] enumerators, final Value value) {
check(enumerators);
if (validate(enumerators, value) != Validation.VALID) {
throw DbException.get(ErrorCode.ENUM_VALUE_NOT_PERMITTED,
toString(enumerators), value.toString());
}
}
/**
* Create an ENUM value from the provided enumerators
* and value.
*
* @param enumerators the enumerators
* @param value a value
* @return the ENUM value
*/
public static ValueEnum get(final String[] enumerators, int value) {
check(enumerators, ValueInt.get(value));
return new ValueEnum(enumerators, value);
}
public static ValueEnum get(final String[] enumerators, String value) {
check(enumerators, ValueString.get(value));
final String cleanLabel = sanitize(value);
for (int i = 0; i < enumerators.length; i++) {
if (cleanLabel.equals(sanitize(enumerators[i]))) {
return new ValueEnum(enumerators, i);
}
}
throw DbException.get(ErrorCode.GENERAL_ERROR_1, "Unexpected error");
}
/**
* Returns enumerators for the two specified values for a binary operation.
*
* @param left
* left (first) operand
* @param right
* right (second) operand
* @return enumerators from the left or the right value, or an empty array if
* both values do not have enumerators
*/
public static String[] getEnumeratorsForBinaryOperation(Value left, Value right) {
if (left.getType() == Value.ENUM) {
return ((ValueEnum) left).getEnumerators();
} else if (right.getType() == Value.ENUM) {
return ((ValueEnum) right).getEnumerators();
} else {
return new String[0];
}
}
public String[] getEnumerators() {
public ExtTypeInfoEnum getEnumerators() {
return enumerators;
}
/**
* Evaluates whether a valid ENUM can be constructed
* from the provided enumerators and value.
*
* @param enumerators the enumerators
* @param value the value
* @return whether a valid ENUM can be constructed from the provided values
*/
public static boolean isValid(final String enumerators[], final Value value) {
return validate(enumerators, value).equals(Validation.VALID);
}
private static String sanitize(final String label) {
return label == null ? null : label.trim().toUpperCase(Locale.ENGLISH);
}
private static String[] sanitize(final String[] enumerators) {
if (enumerators == null || enumerators.length == 0) {
return null;
}
final String[] clean = new String[enumerators.length];
for (int i = 0; i < enumerators.length; i++) {
clean[i] = sanitize(enumerators[i]);
}
return clean;
}
private static String toString(final String[] enumerators) {
String result = "(";
for (int i = 0; i < enumerators.length; i++) {
result += "'" + enumerators[i] + "'";
if (i < enumerators.length - 1) {
result += ", ";
}
}
result += ")";
return result;
}
private static Validation validate(final String[] enumerators) {
final String[] cleaned = sanitize(enumerators);
if (cleaned == null || cleaned.length == 0) {
return Validation.EMPTY;
}
for (int i = 0; i < cleaned.length; i++) {
if (cleaned[i] == null || cleaned[i].equals("")) {
return Validation.EMPTY;
}
if (i < cleaned.length - 1) {
for (int j = i + 1; j < cleaned.length; j++) {
if (cleaned[i].equals(cleaned[j])) {
return Validation.DUPLICATE;
}
}
}
}
return Validation.VALID;
}
private static Validation validate(final String[] enumerators, final Value value) {
final Validation validation = validate(enumerators);
if (!validation.equals(Validation.VALID)) {
return validation;
}
if (DataType.isStringType(value.getType())) {
final String cleanLabel = sanitize(value.getString());
for (String enumerator : enumerators) {
if (cleanLabel.equals(sanitize(enumerator))) {
return Validation.VALID;
}
}
return Validation.INVALID;
} else {
final int ordinal = value.getInt();
if (ordinal < 0 || ordinal >= enumerators.length) {
return Validation.INVALID;
}
return Validation.VALID;
}
}
}
......@@ -8,6 +8,8 @@ package org.h2.value;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.h2.engine.Mode;
/**
* Base implementation of the ENUM data type.
*
......@@ -137,4 +139,13 @@ public class ValueEnumBase extends Value {
final Value iv = v.convertTo(Value.INT);
return convertTo(Value.INT).subtract(iv);
}
@Override
public Value convertTo(int targetType, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) {
if (targetType == Value.ENUM) {
return extTypeInfo.cast(this);
}
return super.convertTo(targetType, precision, mode, column, extTypeInfo);
}
}
......@@ -318,7 +318,7 @@ public class ValueGeometry extends Value {
}
@Override
public Value convertTo(int targetType, int precision, Mode mode, Object column, String[] enumerators) {
public Value convertTo(int targetType, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) {
if (targetType == Value.JAVA_OBJECT) {
return this;
}
......
......@@ -371,12 +371,11 @@ public class ValueLob extends Value {
* the precision plays no role when converting the value
* @param mode the database mode
* @param column the column (if any), used for to improve the error message if conversion fails
* @param enumerators the ENUM datatype enumerators (if any),
* for dealing with ENUM conversions
* @param extTypeInfo the extended data type information, or null
* @return the converted value
*/
@Override
public Value convertTo(int t, int precision, Mode mode, Object column, String[] enumerators) {
public Value convertTo(int t, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) {
if (t == valueType) {
return this;
} else if (t == Value.CLOB) {
......
......@@ -206,12 +206,11 @@ public class ValueLobDb extends Value {
* @param precision the precision
* @param mode the mode
* @param column the column (if any), used for to improve the error message if conversion fails
* @param enumerators the ENUM datatype enumerators (if any),
* for dealing with ENUM conversions
* @param extTypeInfo the extended data type information, or null
* @return the converted value
*/
@Override
public Value convertTo(int t, int precision, Mode mode, Object column, String[] enumerators) {
public Value convertTo(int t, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) {
if (t == valueType) {
return this;
} else if (t == Value.CLOB) {
......
......@@ -134,7 +134,7 @@ public class ValueNull extends Value {
}
@Override
public Value convertTo(int type, int precision, Mode mode, Object column, String[] enumerators) {
public Value convertTo(int type, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) {
return this;
}
......
......@@ -25,6 +25,7 @@ import org.h2.util.JdbcUtils;
import org.h2.util.StringUtils;
import org.h2.value.CompareMode;
import org.h2.value.DataType;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value;
import org.h2.value.ValueBytes;
import org.h2.value.ValueDouble;
......@@ -394,7 +395,7 @@ public class TestCustomDataTypesHandler extends TestDb {
}
@Override
public Value convertTo(int targetType, int precision, Mode mode, Object column, String[] enumerators) {
public Value convertTo(int targetType, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) {
if (getType() == targetType) {
return this;
}
......
......@@ -26,6 +26,12 @@ select * from card;
> 4 null
> rows: 3
alter table card alter column suit enum('a', 'b', 'c', 'd');
> exception ENUM_VALUE_NOT_PERMITTED
alter table card alter column suit enum('''none''', 'hearts', 'clubs', 'spades', 'diamonds');
> ok
select * from card order by suit;
> RANK SUIT
> ---- ------
......@@ -50,7 +56,10 @@ select rank from card where suit = 'diamonds';
>> 8
select column_type from information_schema.columns where COLUMN_NAME = 'SUIT';
>> ENUM('hearts','clubs','spades','diamonds')
>> ENUM('''none''', 'hearts', 'clubs', 'spades', 'diamonds')
alter table card alter column suit enum('hearts', 'clubs', 'spades', 'diamonds');
> ok
--- ENUM integer-based operations
......@@ -243,9 +252,9 @@ SELECT * FROM V3;
SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 'E' ORDER BY TABLE_NAME;
> TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_PRECISION_RADIX NUMERIC_SCALE DATETIME_PRECISION INTERVAL_TYPE INTERVAL_PRECISION CHARACTER_SET_NAME COLLATION_NAME TYPE_NAME NULLABLE IS_COMPUTED SELECTIVITY CHECK_CONSTRAINT SEQUENCE_NAME REMARKS SOURCE_DATA_TYPE COLUMN_TYPE COLUMN_ON_UPDATE IS_VISIBLE
> ------------- ------------ ---------- ----------- ---------------- -------------- ----------- --------- ------------------------ ---------------------- ----------------- ----------------------- ------------- ------------------ ------------- ------------------ ------------------ -------------- --------- -------- ----------- ----------- ---------------- ------------- ------- ---------------- ------------- ---------------- ----------
> SCRIPT PUBLIC TEST E 1 null YES 1111 2147483647 2147483647 2147483647 10 0 null null null Unicode OFF ENUM 1 FALSE 50 null null ENUM('A','B') null TRUE
> SCRIPT PUBLIC V E 1 null YES 1111 2147483647 2147483647 2147483647 10 0 null null null Unicode OFF ENUM 1 FALSE 50 null null ENUM('A','B') null TRUE
> ------------- ------------ ---------- ----------- ---------------- -------------- ----------- --------- ------------------------ ---------------------- ----------------- ----------------------- ------------- ------------------ ------------- ------------------ ------------------ -------------- --------- -------- ----------- ----------- ---------------- ------------- ------- ---------------- -------------- ---------------- ----------
> SCRIPT PUBLIC TEST E 1 null YES 1111 2147483647 2147483647 2147483647 10 0 null null null Unicode OFF ENUM 1 FALSE 50 null null ENUM('A', 'B') null TRUE
> SCRIPT PUBLIC V E 1 null YES 1111 2147483647 2147483647 2147483647 10 0 null null null Unicode OFF ENUM 1 FALSE 50 null null ENUM('A', 'B') null TRUE
> SCRIPT PUBLIC V1 E 1 null YES 4 2147483647 2147483647 2147483647 10 0 null null null Unicode OFF INTEGER 1 FALSE 50 null null INTEGER null TRUE
> SCRIPT PUBLIC V2 E 1 null YES 4 2147483647 2147483647 2147483647 10 0 null null null Unicode OFF INTEGER 1 FALSE 50 null null INTEGER null TRUE
> SCRIPT PUBLIC V3 E 1 null YES 4 2147483647 2147483647 2147483647 10 0 null null null Unicode OFF INTEGER 1 FALSE 50 null null INTEGER null TRUE
......
......@@ -36,12 +36,12 @@ DROP DOMAIN E_NN CASCADE;
SELECT COLUMN_NAME, NULLABLE, COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TEST' ORDER BY ORDINAL_POSITION;
> COLUMN_NAME NULLABLE COLUMN_TYPE
> ----------- -------- ----------------------
> ----------- -------- -----------------------
> I 0 INT NOT NULL
> E1 1 ENUM('A','B')
> E2 0 ENUM('A','B') NOT NULL
> E3 0 ENUM('A','B') NOT NULL
> E4 1 ENUM('A','B')
> E1 1 ENUM('A', 'B')
> E2 0 ENUM('A', 'B') NOT NULL
> E3 0 ENUM('A', 'B') NOT NULL
> E4 1 ENUM('A', 'B')
> rows (ordered): 5
DROP TABLE TEST;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论