提交 eb396945 authored 作者: Max Englander's avatar Max Englander

enum-support: handle enum comparisons with ints and strings

上级 d0fe846b
......@@ -4200,13 +4200,13 @@ public class Parser {
if (readIf("(")) {
original += '(';
String enumerator0 = readString();
enumerators.add(enumerator0);
enumerators.add(enumerator0.toLowerCase().trim());
original += "'" + enumerator0 + "'";
while(readIf(",")) {
original += ',';
String enumeratorN = readString();
original += "'" + enumeratorN + "'";
enumerators.add(enumeratorN);
enumerators.add(enumeratorN.toLowerCase().trim());
}
read(")");
original += ')';
......@@ -4232,7 +4232,7 @@ public class Parser {
Integer.toString(scale), Long.toString(precision));
}
Column column = new Column(columnName, type, precision, scale,
displaySize, enumerators);
displaySize, enumerators.toArray(new String[enumerators.size()]));
if (templateColumn != null) {
column.setNullable(templateColumn.isNullable());
column.setDefaultExpression(session,
......
......@@ -189,9 +189,7 @@ public class ExpressionColumn extends Expression {
throw DbException.get(ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL());
}
if (column.getEnumerators() != null) {
final int ordinal = value.getInt();
return new ValueEnum(column.getEnumerators()
.toArray(new String[column.getEnumerators().size()]), ordinal);
return ValueEnum.get(column.getEnumerators(), value);
}
return value;
}
......
......@@ -199,6 +199,7 @@ public class ValueDataType implements DataType {
case Value.SHORT:
buff.put((byte) type).putShort(v.getShort());
break;
case Value.ENUM:
case Value.INT: {
int x = v.getInt();
if (x < 0) {
......
......@@ -7,7 +7,6 @@ package org.h2.table;
import java.sql.ResultSetMetaData;
import java.util.Iterator;
import java.util.List;
import org.h2.api.ErrorCode;
import org.h2.command.Parser;
import org.h2.engine.Constants;
......@@ -28,6 +27,7 @@ import org.h2.util.StringUtils;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueDate;
import org.h2.value.ValueEnum;
import org.h2.value.ValueInt;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
......@@ -68,7 +68,7 @@ public class Column {
private final int type;
private long precision;
private int scale;
private List<String> enumerators;
private String[] enumerators;
private int displaySize;
private Table table;
private String name;
......@@ -94,7 +94,7 @@ public class Column {
this(name, type, -1, -1, -1, null);
}
public Column(String name, int type, List<String> enumerators) {
public Column(String name, int type, String[] enumerators) {
this(name, type, -1, -1, -1, enumerators);
}
......@@ -104,7 +104,7 @@ public class Column {
}
public Column(String name, int type, long precision, int scale,
int displaySize, List<String> enumerators) {
int displaySize, String[] enumerators) {
this.name = name;
this.type = type;
if (precision == -1 && scale == -1 && displaySize == -1 && type != Value.UNKNOWN) {
......@@ -145,6 +145,10 @@ public class Column {
return table.getId() ^ name.hashCode();
}
public boolean isEnumerated() {
return enumerators != null && enumerators.length > 0;
}
public Column getClone() {
Column newColumn = new Column(name, type, precision, scale, displaySize, enumerators);
newColumn.copy(this);
......@@ -270,11 +274,11 @@ public class Column {
nullable = b;
}
public List<String> getEnumerators() {
public String[] getEnumerators() {
return enumerators;
}
public void setEnumerators(List<String> enumerators) {
public void setEnumerators(String[] enumerators) {
this.enumerators = enumerators;
}
......@@ -357,24 +361,17 @@ public class Column {
getCreateSQL(), s + " (" + value.getPrecision() + ")");
}
}
if (!enumerators.isEmpty()) {
int index;
if (DataType.isStringType(value.getType())) {
index = enumerators.indexOf(value.getString());
} else {
index = value.getInt() < enumerators.size() ? value.getInt() : -1;
}
if (index == -1) {
if (isEnumerated()) {
if (!ValueEnum.isValid(enumerators, value)) {
String s = value.getTraceSQL();
if (s.length() > 127) {
s = s.substring(0, 128) + "...";
}
throw DbException.get(ErrorCode.VALUE_NOT_PERMITTED,
getCreateSQL(), s + " (" + value.getString() + ")");
} else {
value = ValueInt.get(index);
}
value = ValueEnum.get(enumerators, value);
}
updateSequenceIfRequired(session, value);
return value;
......@@ -467,10 +464,9 @@ public class Column {
break;
case Value.ENUM:
buff.append('(');
Iterator<String> it = enumerators.iterator();
while(it.hasNext()) {
buff.append('\'').append(it.next()).append('\'');
if(it.hasNext()) {
for (int i = 0; i < enumerators.length; i++) {
buff.append('\'').append(enumerators[i]).append('\'');
if(i < enumerators.length - 1) {
buff.append(',');
}
}
......
......@@ -852,11 +852,13 @@ public abstract class Value {
}
break;
}
case ENUM:
case ENUM: {
switch (getType()) {
case INT:
case STRING:
return this;
}
}
case BLOB: {
switch (getType()) {
case BYTES:
......@@ -984,7 +986,7 @@ public abstract class Value {
}
} catch (NumberFormatException e) {
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, e, getString());
ErrorCode.DATA_CONVERSION_ERROR_1, e, getString() + " type=" + getType());
}
}
......
......@@ -3,36 +3,91 @@ package org.h2.value;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.h2.api.ErrorCode;
import org.h2.message.DbException;
import org.h2.util.MathUtils;
import org.h2.value.DataType;
public class ValueEnum extends Value {
public static final int PRECISION = 10;
public static final int DISPLAY_SIZE = 11;
private final String[] labels;
private static enum Validation {
DUPLICATE,
EMPTY,
INVALID,
VALID
}
private final String[] enumerators;
private final String label;
private final int ordinal;
public ValueEnum(final String[] labels, final int ordinal) {
this.label = labels[ordinal];
this.labels = labels;
private ValueEnum(final String[] enumerators, final int ordinal) {
this.label = enumerators[ordinal];
this.enumerators = enumerators;
this.ordinal = ordinal;
}
@Override
public Value add(final Value v) {
throw new UnsupportedOperationException("Not yet implemented");
private static final void check(final String[] enumerators) {
switch (validate(enumerators)) {
case VALID:
return;
case EMPTY:
throw DbException.get(ErrorCode.INVALID_VALUE_2,
"Empty enum is not allowed");
case DUPLICATE:
throw DbException.get(ErrorCode.INVALID_VALUE_2,
"Enum with duplicate enumerator is not allowed");
default:
throw DbException.get(ErrorCode.INVALID_VALUE_2,
"Invalid enumerator list for enum");
}
}
@Override
protected int compareSecure(final Value o, final CompareMode mode) {
final ValueEnum v = (ValueEnum) o;
return MathUtils.compareInt(ordinal(), v.ordinal());
private static final void check(final String[] enumerators, final String label) {
check(enumerators);
switch (validate(enumerators, label)) {
case VALID:
return;
case EMPTY:
throw DbException.get(ErrorCode.VALUE_NOT_PERMITTED,
"Enumerator label may not be empty");
default:
throw DbException.get(ErrorCode.VALUE_NOT_PERMITTED,
"Enumerator label is invalid");
}
}
private static final void check(final String[] enumerators, final int ordinal) {
check(enumerators);
switch (validate(enumerators, ordinal)) {
case VALID:
return;
default:
throw DbException.get(ErrorCode.VALUE_NOT_PERMITTED,
"Provided enumerator label does not match any member of enum");
}
}
private static final void check(final String[] enumerators, final Value value) {
check(enumerators);
switch (validate(enumerators, value)) {
case VALID:
return;
default:
throw DbException.get(ErrorCode.VALUE_NOT_PERMITTED,
"Provided value is does not match any enumerators");
}
}
@Override
public Value divide(final Value v) {
throw new UnsupportedOperationException("Not yet implemented");
protected int compareSecure(final Value o, final CompareMode mode) {
final ValueEnum v = ValueEnum.get(enumerators, o);
return MathUtils.compareInt(ordinal(), v.ordinal());
}
@Override
......@@ -41,6 +96,32 @@ public class ValueEnum extends Value {
ordinal() == ((ValueEnum) other).ordinal();
}
public static ValueEnum get(final String[] enumerators, final String label) {
check(enumerators, label);
for (int i = 0; i < enumerators.length; i++) {
if (label.equals(enumerators[i]))
return new ValueEnum(enumerators, i);
}
throw DbException.get(ErrorCode.GENERAL_ERROR_1, "Unexpected error");
}
public static ValueEnum get(final String[] enumerators, final int ordinal) {
check(enumerators, ordinal);
return new ValueEnum(enumerators, ordinal);
}
public static ValueEnum get(final String[] enumerators, final Value value) {
check(enumerators, value);
if (DataType.isStringType(value.getType())) {
return get(enumerators, value.getString());
} else {
return get(enumerators, value.getInt());
}
}
@Override
public int getDisplaySize() {
return DISPLAY_SIZE;
......@@ -83,27 +164,24 @@ public class ValueEnum extends Value {
@Override
public int hashCode() {
return ordinal;
return enumerators.hashCode() + ordinal;
}
@Override
public int getType() {
return Value.INT;
public static boolean isValid(final String enumerators[], final String label) {
return validate(enumerators, label).equals(Validation.VALID);
}
@Override
public Value modulus(final Value v) {
throw new UnsupportedOperationException("Not yet implemented");
public static boolean isValid(final String enumerators[], final int ordinal) {
return validate(enumerators, ordinal).equals(Validation.VALID);
}
@Override
public Value multiply(final Value v) {
throw new UnsupportedOperationException("Not yet implemented");
public static boolean isValid(final String enumerators[], final Value value) {
return validate(enumerators, value).equals(Validation.VALID);
}
@Override
public Value negate() {
throw new UnsupportedOperationException("Not yet implemented");
public int getType() {
return Value.ENUM;
}
protected int ordinal() {
......@@ -116,8 +194,55 @@ public class ValueEnum extends Value {
prep.setInt(parameterIndex, ordinal);
}
@Override
public Value subtract(final Value v) {
throw new UnsupportedOperationException("Not yet implemented");
private static Validation validate(final String[] enumerators, final String label) {
check(enumerators);
if (label == null || label.trim().length() == 0) {
return Validation.EMPTY;
}
for (int i = 0; i < enumerators.length; i++) {
if (label.equals(enumerators[i])) {
return Validation.VALID;
}
}
return Validation.INVALID;
}
private static Validation validate(final String[] enumerators) {
for (int i = 0; i < enumerators.length; i++) {
if (enumerators[i] == null || enumerators[i].equals("")) {
return Validation.EMPTY;
}
if (i < enumerators.length - 1) {
for (int j = i + 1; j < enumerators.length; j++) {
if (enumerators[i].equals(enumerators[j])) {
return Validation.DUPLICATE;
}
}
}
}
return Validation.VALID;
}
private static Validation validate(final String[] enumerators, final int ordinal) {
check(enumerators);
if (ordinal < 0 || ordinal >= enumerators.length) {
return Validation.INVALID;
}
return Validation.VALID;
}
private static Validation validate(final String[] enumerators, final Value value) {
if (DataType.isStringType(value.getType())) {
return validate(enumerators, value.getString());
} else {
return validate(enumerators, value.getInt());
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论