提交 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; ...@@ -196,12 +196,13 @@ import org.h2.util.StringUtils;
import org.h2.util.Utils; import org.h2.util.Utils;
import org.h2.value.CompareMode; import org.h2.value.CompareMode;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.ExtTypeInfo;
import org.h2.value.ExtTypeInfoEnum;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueBoolean; import org.h2.value.ValueBoolean;
import org.h2.value.ValueBytes; import org.h2.value.ValueBytes;
import org.h2.value.ValueDate; import org.h2.value.ValueDate;
import org.h2.value.ValueDecimal; import org.h2.value.ValueDecimal;
import org.h2.value.ValueEnum;
import org.h2.value.ValueInt; import org.h2.value.ValueInt;
import org.h2.value.ValueInterval; import org.h2.value.ValueInterval;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
...@@ -4862,7 +4863,7 @@ public class Parser { ...@@ -4862,7 +4863,7 @@ public class Parser {
} }
long precision = -1; long precision = -1;
int displaySize = -1; int displaySize = -1;
String[] enumerators = null; ExtTypeInfo extTypeInfo = null;
int scale = -1; int scale = -1;
String comment = null; String comment = null;
Column templateColumn = null; Column templateColumn = null;
...@@ -4879,7 +4880,7 @@ public class Parser { ...@@ -4879,7 +4880,7 @@ public class Parser {
precision = templateColumn.getPrecision(); precision = templateColumn.getPrecision();
displaySize = templateColumn.getDisplaySize(); displaySize = templateColumn.getDisplaySize();
scale = templateColumn.getScale(); scale = templateColumn.getScale();
enumerators = templateColumn.getEnumerators(); extTypeInfo = templateColumn.getExtTypeInfo();
} else { } else {
Mode mode = database.getMode(); Mode mode = database.getMode();
dataType = DataType.getTypeByName(original, mode); dataType = DataType.getTypeByName(original, mode);
...@@ -5007,25 +5008,24 @@ public class Parser { ...@@ -5007,25 +5008,24 @@ public class Parser {
original = original + '(' + p + ')'; original = original + '(' + p + ')';
} }
} else if (dataType.type == Value.ENUM) { } else if (dataType.type == Value.ENUM) {
if (readIf(OPEN_PAREN)) { if (extTypeInfo == null) {
java.util.List<String> enumeratorList = new ArrayList<>(); String[] enumerators = null;
original += '('; if (readIf(OPEN_PAREN)) {
String enumerator0 = readString(); java.util.List<String> enumeratorList = new ArrayList<>();
enumeratorList.add(enumerator0); String enumerator0 = readString();
original += "'" + enumerator0 + "'"; enumeratorList.add(enumerator0);
while (readIfMore(true)) { while (readIfMore(true)) {
original += ','; String enumeratorN = readString();
String enumeratorN = readString(); enumeratorList.add(enumeratorN);
original += "'" + enumeratorN + "'"; }
enumeratorList.add(enumeratorN); enumerators = enumeratorList.toArray(new String[0]);
} }
original += ')'; try {
enumerators = enumeratorList.toArray(new String[0]); extTypeInfo = new ExtTypeInfoEnum(enumerators);
} } catch (DbException e) {
try { throw e.addSQL(original);
ValueEnum.check(enumerators); }
} catch (DbException e) { original += extTypeInfo.toString();
throw e.addSQL(original);
} }
} else if (readIf(OPEN_PAREN)) { } else if (readIf(OPEN_PAREN)) {
// Support for MySQL: INT(11), MEDIUMINT(8) and so on. // Support for MySQL: INT(11), MEDIUMINT(8) and so on.
...@@ -5049,7 +5049,7 @@ public class Parser { ...@@ -5049,7 +5049,7 @@ public class Parser {
} }
Column column = new Column(columnName, type, precision, scale, Column column = new Column(columnName, type, precision, scale,
displaySize, enumerators); displaySize, extTypeInfo);
if (templateColumn != null) { if (templateColumn != null) {
column.setNullable(templateColumn.isNullable()); column.setNullable(templateColumn.isNullable());
column.setDefaultExpression(session, column.setDefaultExpression(session,
......
...@@ -23,6 +23,7 @@ import org.h2.table.Column; ...@@ -23,6 +23,7 @@ import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.util.ColumnNamer; import org.h2.util.ColumnNamer;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
...@@ -197,18 +198,18 @@ public class CreateTable extends CommandWithColumns { ...@@ -197,18 +198,18 @@ public class CreateTable extends CommandWithColumns {
if (scale > precision) { if (scale > precision) {
precision = scale; precision = scale;
} }
String[] enumerators = null; ExtTypeInfo extTypeInfo = null;
if (dt.type == Value.ENUM) { if (dt.type == Value.ENUM) {
/** /**
* Only columns of tables may be enumerated. * Only columns of tables may be enumerated.
*/ */
if(!(expr instanceof ExpressionColumn)) { if (!(expr instanceof ExpressionColumn)) {
throw DbException.get(ErrorCode.GENERAL_ERROR_1, throw DbException.get(ErrorCode.GENERAL_ERROR_1,
"Unable to resolve enumerators of expression"); "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); addColumn(col);
} }
} }
......
...@@ -210,7 +210,7 @@ public class Comparison extends Condition { ...@@ -210,7 +210,7 @@ public class Comparison extends Condition {
Column column = ((ExpressionColumn) left).getColumn(); Column column = ((ExpressionColumn) left).getColumn();
right = ValueExpression.get(r.convertTo(resType, right = ValueExpression.get(r.convertTo(resType,
MathUtils.convertLongToInt(left.getPrecision()), MathUtils.convertLongToInt(left.getPrecision()),
session.getDatabase().getMode(), column, column.getEnumerators())); session.getDatabase().getMode(), column, column.getExtTypeInfo()));
} }
} else if (right instanceof Parameter) { } else if (right instanceof Parameter) {
((Parameter) right).setColumn( ((Parameter) right).setColumn(
......
...@@ -16,6 +16,7 @@ import org.h2.message.DbException; ...@@ -16,6 +16,7 @@ import org.h2.message.DbException;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueBoolean; import org.h2.value.ValueBoolean;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
...@@ -34,7 +35,7 @@ public class ConditionInConstantSet extends Condition { ...@@ -34,7 +35,7 @@ public class ConditionInConstantSet extends Condition {
private final ArrayList<Expression> valueList; private final ArrayList<Expression> valueList;
private final TreeSet<Value> valueSet; private final TreeSet<Value> valueSet;
private final int type; private final int type;
private String[] enumerators; private ExtTypeInfo extTypeInfo;
/** /**
* Create a new IN(..) condition. * Create a new IN(..) condition.
...@@ -54,9 +55,9 @@ public class ConditionInConstantSet extends Condition { ...@@ -54,9 +55,9 @@ public class ConditionInConstantSet extends Condition {
type = left.getType(); type = left.getType();
Mode mode = database.getMode(); Mode mode = database.getMode();
if (type == Value.ENUM) { if (type == Value.ENUM) {
enumerators = ((ExpressionColumn) left).getColumn().getEnumerators(); extTypeInfo = ((ExpressionColumn) left).getColumn().getExtTypeInfo();
for (Expression expression : valueList) { for (Expression expression : valueList) {
valueSet.add(expression.getValue(session).convertToEnum(enumerators)); valueSet.add(extTypeInfo.cast(expression.getValue(session)));
} }
} else { } else {
for (Expression expression : valueList) { for (Expression expression : valueList) {
...@@ -170,7 +171,7 @@ public class ConditionInConstantSet extends Condition { ...@@ -170,7 +171,7 @@ public class ConditionInConstantSet extends Condition {
if (add.isConstant()) { if (add.isConstant()) {
valueList.add(add); valueList.add(add);
if (type == Value.ENUM) { if (type == Value.ENUM) {
valueSet.add(add.getValue(session).convertToEnum(enumerators)); valueSet.add(add.getValue(session).convertToEnum(extTypeInfo));
} else { } else {
valueSet.add(add.getValue(session).convertTo(type, session.getDatabase().getMode())); valueSet.add(add.getValue(session).convertTo(type, session.getDatabase().getMode()));
} }
......
...@@ -19,9 +19,9 @@ import org.h2.table.Column; ...@@ -19,9 +19,9 @@ import org.h2.table.Column;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueBoolean; import org.h2.value.ValueBoolean;
import org.h2.value.ValueEnum;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
/** /**
...@@ -191,8 +191,11 @@ public class ExpressionColumn extends Expression { ...@@ -191,8 +191,11 @@ public class ExpressionColumn extends Expression {
throw DbException.get(ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL()); throw DbException.get(ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL());
} }
} }
if (column.getEnumerators() != null && value != ValueNull.INSTANCE) { if (value != ValueNull.INSTANCE) {
return ValueEnum.get(column.getEnumerators(), value.getInt()); ExtTypeInfo extTypeInfo = column.getExtTypeInfo();
if (extTypeInfo != null) {
return extTypeInfo.cast(value);
}
} }
return value; return value;
} }
......
...@@ -56,6 +56,7 @@ import org.h2.util.ToChar; ...@@ -56,6 +56,7 @@ import org.h2.util.ToChar;
import org.h2.util.ToDateParser; import org.h2.util.ToDateParser;
import org.h2.util.Utils; import org.h2.util.Utils;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray; import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean; import org.h2.value.ValueBoolean;
...@@ -162,7 +163,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -162,7 +163,7 @@ public class Function extends Expression implements FunctionCall {
protected int scale; protected int scale;
protected long precision = PRECISION_UNKNOWN; protected long precision = PRECISION_UNKNOWN;
protected int displaySize; protected int displaySize;
protected String[] enumerators; protected ExtTypeInfo extTypeInfo;
private final Database database; private final Database database;
...@@ -894,7 +895,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -894,7 +895,7 @@ public class Function extends Expression implements FunctionCall {
case CAST: case CAST:
case CONVERT: { case CONVERT: {
Mode mode = database.getMode(); 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.convertScale(mode.convertOnlyToSmallerScale, scale);
v0 = v0.convertPrecision(getPrecision(), false); v0 = v0.convertPrecision(getPrecision(), false);
result = v0; result = v0;
...@@ -2200,7 +2201,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -2200,7 +2201,7 @@ public class Function extends Expression implements FunctionCall {
precision = col.getPrecision(); precision = col.getPrecision();
displaySize = col.getDisplaySize(); displaySize = col.getDisplaySize();
scale = col.getScale(); scale = col.getScale();
enumerators = col.getEnumerators(); extTypeInfo = col.getExtTypeInfo();
} }
@Override @Override
...@@ -2601,7 +2602,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -2601,7 +2602,7 @@ public class Function extends Expression implements FunctionCall {
case CAST: { case CAST: {
buff.append(args[0].getSQL()).append(" AS "). buff.append(args[0].getSQL()).append(" AS ").
append(new Column(null, dataType, precision, append(new Column(null, dataType, precision,
scale, displaySize, enumerators).getCreateSQL()); scale, displaySize, extTypeInfo).getCreateSQL());
break; break;
} }
case CONVERT: { case CONVERT: {
......
...@@ -288,7 +288,7 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -288,7 +288,7 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex {
int idx = c.getColumnId(); int idx = c.getColumnId();
Value v = r.getValue(idx); Value v = r.getValue(idx);
if (v != null) { 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()); array[keyColumns - 1] = key != null ? key : ValueLong.get(r.getKey());
......
...@@ -6,7 +6,8 @@ ...@@ -6,7 +6,8 @@
package org.h2.table; package org.h2.table;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.util.Arrays; import java.util.Objects;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Parser; import org.h2.command.Parser;
import org.h2.engine.Constants; import org.h2.engine.Constants;
...@@ -25,8 +26,8 @@ import org.h2.schema.Sequence; ...@@ -25,8 +26,8 @@ import org.h2.schema.Sequence;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueEnum;
import org.h2.value.ValueInt; import org.h2.value.ValueInt;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
...@@ -65,7 +66,7 @@ public class Column { ...@@ -65,7 +66,7 @@ public class Column {
private final int type; private final int type;
private long precision; private long precision;
private int scale; private int scale;
private String[] enumerators; private ExtTypeInfo extTypeInfo;
private int displaySize; private int displaySize;
private Table table; private Table table;
private String name; private String name;
...@@ -99,8 +100,7 @@ public class Column { ...@@ -99,8 +100,7 @@ public class Column {
this(name, type, precision, scale, displaySize, null); this(name, type, precision, scale, displaySize, null);
} }
public Column(String name, int type, long precision, int scale, public Column(String name, int type, long precision, int scale, int displaySize, ExtTypeInfo extTypeInfo) {
int displaySize, String[] enumerators) {
this.name = name; this.name = name;
this.type = type; this.type = type;
if (precision == -1 && scale == -1 && displaySize == -1 && type != Value.UNKNOWN) { if (precision == -1 && scale == -1 && displaySize == -1 && type != Value.UNKNOWN) {
...@@ -112,7 +112,7 @@ public class Column { ...@@ -112,7 +112,7 @@ public class Column {
this.precision = precision; this.precision = precision;
this.scale = scale; this.scale = scale;
this.displaySize = displaySize; this.displaySize = displaySize;
this.enumerators = enumerators; this.extTypeInfo = extTypeInfo;
} }
@Override @Override
...@@ -141,12 +141,8 @@ public class Column { ...@@ -141,12 +141,8 @@ public class Column {
return table.getId() ^ name.hashCode(); return table.getId() ^ name.hashCode();
} }
public boolean isEnumerated() {
return type == Value.ENUM;
}
public Column getClone() { 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); newColumn.copy(this);
return newColumn; return newColumn;
} }
...@@ -172,7 +168,7 @@ public class Column { ...@@ -172,7 +168,7 @@ public class Column {
*/ */
public Value convert(Value v, Mode mode) { public Value convert(Value v, Mode mode) {
try { try {
return v.convertTo(type, MathUtils.convertLongToInt(precision), mode, this, getEnumerators()); return v.convertTo(type, MathUtils.convertLongToInt(precision), mode, this, extTypeInfo);
} catch (DbException e) { } catch (DbException e) {
if (e.getErrorCode() == ErrorCode.DATA_CONVERSION_ERROR_1) { if (e.getErrorCode() == ErrorCode.DATA_CONVERSION_ERROR_1) {
String target = (table == null ? "" : table.getName() + ": ") + String target = (table == null ? "" : table.getName() + ": ") +
...@@ -300,12 +296,12 @@ public class Column { ...@@ -300,12 +296,12 @@ public class Column {
nullable = b; nullable = b;
} }
public String[] getEnumerators() { public ExtTypeInfo getExtTypeInfo() {
return enumerators; return extTypeInfo;
} }
public void setEnumerators(String[] enumerators) { public void setExtTypeInfo(ExtTypeInfo extTypeInfo) {
this.enumerators = enumerators; this.extTypeInfo = extTypeInfo;
} }
public boolean getVisible() { public boolean getVisible() {
...@@ -406,17 +402,8 @@ public class Column { ...@@ -406,17 +402,8 @@ public class Column {
getCreateSQL(), s + " (" + value.getPrecision() + ")"); getCreateSQL(), s + " (" + value.getPrecision() + ")");
} }
} }
if (isEnumerated() && value != ValueNull.INSTANCE) { if (type == Value.ENUM && value != ValueNull.INSTANCE) {
if (!ValueEnum.isValid(enumerators, value)) { value = extTypeInfo.cast(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());
} }
updateSequenceIfRequired(session, value); updateSequenceIfRequired(session, value);
return value; return value;
...@@ -523,14 +510,7 @@ public class Column { ...@@ -523,14 +510,7 @@ public class Column {
buff.append('(').append(precision).append(", ").append(scale).append(')'); buff.append('(').append(precision).append(", ").append(scale).append(')');
break; break;
case Value.ENUM: case Value.ENUM:
buff.append('('); buff.append(extTypeInfo.toString());
for (int i = 0; i < enumerators.length; i++) {
buff.append('\'').append(enumerators[i]).append('\'');
if(i < enumerators.length - 1) {
buff.append(',');
}
}
buff.append(')');
break; break;
case Value.BYTES: case Value.BYTES:
case Value.STRING: case Value.STRING:
...@@ -862,6 +842,9 @@ public class Column { ...@@ -862,6 +842,9 @@ public class Column {
if (onUpdateExpression != null || newColumn.onUpdateExpression != null) { if (onUpdateExpression != null || newColumn.onUpdateExpression != null) {
return false; return false;
} }
if (!Objects.equals(extTypeInfo, newColumn.extTypeInfo)) {
return false;
}
return true; return true;
} }
...@@ -876,8 +859,7 @@ public class Column { ...@@ -876,8 +859,7 @@ public class Column {
displaySize = source.displaySize; displaySize = source.displaySize;
name = source.name; name = source.name;
precision = source.precision; precision = source.precision;
enumerators = source.enumerators == null ? null : extTypeInfo = source.extTypeInfo;
Arrays.copyOf(source.enumerators, source.enumerators.length);
scale = source.scale; scale = source.scale;
// table is not set // table is not set
// columnId is not set // columnId is not set
......
...@@ -38,6 +38,7 @@ import org.h2.util.ColumnNamer; ...@@ -38,6 +38,7 @@ import org.h2.util.ColumnNamer;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.util.Utils; import org.h2.util.Utils;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
...@@ -194,13 +195,13 @@ public class TableView extends Table { ...@@ -194,13 +195,13 @@ public class TableView extends Table {
long precision = expr.getPrecision(); long precision = expr.getPrecision();
int scale = expr.getScale(); int scale = expr.getScale();
int displaySize = expr.getDisplaySize(); int displaySize = expr.getDisplaySize();
String[] enumerators = null; ExtTypeInfo extTypeInfo = null;
if (type == Value.ENUM) { if (type == Value.ENUM) {
if (expr instanceof ExpressionColumn) { 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); col.setTable(this, i);
// Fetch check constraint from view column source // Fetch check constraint from view column source
ExpressionColumn fromColumn = null; 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 { ...@@ -677,10 +677,10 @@ public abstract class Value {
/** /**
* Convert value to ENUM 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 * @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 // Use -1 to indicate "default behaviour" where value conversion should not
// depend on any datatype precision. // depend on any datatype precision.
return convertTo(ENUM, -1, null, null, enumerators); return convertTo(ENUM, -1, null, null, enumerators);
...@@ -706,11 +706,10 @@ public abstract class Value { ...@@ -706,11 +706,10 @@ public abstract class Value {
* the precision plays no role when converting the value * the precision plays no role when converting the value
* @param mode the conversion mode * @param mode the conversion mode
* @param column the column (if any), used for to improve the error message if conversion fails * @param column the column (if any), used for to improve the error message if conversion fails
* @param enumerators the ENUM datatype enumerators (if any), * @param extTypeInfo the extended data type information, or null
* for dealing with ENUM conversions
* @return the converted value * @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 NULL is done in ValueNull
// converting BLOB to CLOB and vice versa is done in ValueLob // converting BLOB to CLOB and vice versa is done in ValueLob
if (getType() == targetType) { if (getType() == targetType) {
...@@ -755,7 +754,7 @@ public abstract class Value { ...@@ -755,7 +754,7 @@ public abstract class Value {
case JAVA_OBJECT: case JAVA_OBJECT:
return convertToJavaObject(); return convertToJavaObject();
case ENUM: case ENUM:
return convertToEnumInternal(enumerators); return convertToEnumInternal((ExtTypeInfoEnum) extTypeInfo);
case BLOB: case BLOB:
return convertToBlob(); return convertToBlob();
case CLOB: case CLOB:
...@@ -1158,24 +1157,24 @@ public abstract class Value { ...@@ -1158,24 +1157,24 @@ public abstract class Value {
return ValueJavaObject.getNoCopy(null, StringUtils.convertHexToBytes(getString().trim()), getDataHandler()); return ValueJavaObject.getNoCopy(null, StringUtils.convertHexToBytes(getString().trim()), getDataHandler());
} }
private ValueEnum convertToEnumInternal(String[] enumerators) { private ValueEnum convertToEnumInternal(ExtTypeInfoEnum extTypeInfo) {
switch (getType()) { switch (getType()) {
case BYTE: case BYTE:
case SHORT: case SHORT:
case INT: case INT:
case LONG: case LONG:
case DECIMAL: case DECIMAL:
return ValueEnum.get(enumerators, getInt()); return extTypeInfo.getValue(getInt());
case STRING: case STRING:
case STRING_IGNORECASE: case STRING_IGNORECASE:
case STRING_FIXED: case STRING_FIXED:
return ValueEnum.get(enumerators, getString()); return extTypeInfo.getValue(getString());
case JAVA_OBJECT: case JAVA_OBJECT:
Object object = JdbcUtils.deserialize(getBytesNoCopy(), getDataHandler()); Object object = JdbcUtils.deserialize(getBytesNoCopy(), getDataHandler());
if (object instanceof String) { if (object instanceof String) {
return ValueEnum.get(enumerators, (String) object); return extTypeInfo.getValue((String) object);
} else if (object instanceof Integer) { } else if (object instanceof Integer) {
return ValueEnum.get(enumerators, (int) object); return extTypeInfo.getValue((int) object);
} }
//$FALL-THROUGH$ //$FALL-THROUGH$
} }
...@@ -1337,7 +1336,7 @@ public abstract class Value { ...@@ -1337,7 +1336,7 @@ public abstract class Value {
if (leftType != rightType || leftType == Value.ENUM) { if (leftType != rightType || leftType == Value.ENUM) {
int dataType = Value.getHigherOrder(leftType, rightType); int dataType = Value.getHigherOrder(leftType, rightType);
if (dataType == Value.ENUM) { if (dataType == Value.ENUM) {
String[] enumerators = ValueEnum.getEnumeratorsForBinaryOperation(l, v); ExtTypeInfoEnum enumerators = ExtTypeInfoEnum.getEnumeratorsForBinaryOperation(l, v);
l = l.convertToEnum(enumerators); l = l.convertToEnum(enumerators);
v = v.convertToEnum(enumerators); v = v.convertToEnum(enumerators);
} else { } else {
......
...@@ -5,196 +5,17 @@ ...@@ -5,196 +5,17 @@
*/ */
package org.h2.value; package org.h2.value;
import java.util.Locale;
import org.h2.api.ErrorCode;
import org.h2.message.DbException;
public class ValueEnum extends ValueEnumBase { 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) { ValueEnum(ExtTypeInfoEnum enumerators, String label, int ordinal) {
super(enumerators[ordinal], ordinal); super(label, ordinal);
this.enumerators = enumerators; this.enumerators = enumerators;
} }
/** public ExtTypeInfoEnum getEnumerators() {
* 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() {
return enumerators; 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; ...@@ -8,6 +8,8 @@ package org.h2.value;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.engine.Mode;
/** /**
* Base implementation of the ENUM data type. * Base implementation of the ENUM data type.
* *
...@@ -137,4 +139,13 @@ public class ValueEnumBase extends Value { ...@@ -137,4 +139,13 @@ public class ValueEnumBase extends Value {
final Value iv = v.convertTo(Value.INT); final Value iv = v.convertTo(Value.INT);
return convertTo(Value.INT).subtract(iv); 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 { ...@@ -318,7 +318,7 @@ public class ValueGeometry extends Value {
} }
@Override @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) { if (targetType == Value.JAVA_OBJECT) {
return this; return this;
} }
......
...@@ -371,12 +371,11 @@ public class ValueLob extends Value { ...@@ -371,12 +371,11 @@ public class ValueLob extends Value {
* the precision plays no role when converting the value * the precision plays no role when converting the value
* @param mode the database mode * @param mode the database mode
* @param column the column (if any), used for to improve the error message if conversion fails * @param column the column (if any), used for to improve the error message if conversion fails
* @param enumerators the ENUM datatype enumerators (if any), * @param extTypeInfo the extended data type information, or null
* for dealing with ENUM conversions
* @return the converted value * @return the converted value
*/ */
@Override @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) { if (t == valueType) {
return this; return this;
} else if (t == Value.CLOB) { } else if (t == Value.CLOB) {
......
...@@ -206,12 +206,11 @@ public class ValueLobDb extends Value { ...@@ -206,12 +206,11 @@ public class ValueLobDb extends Value {
* @param precision the precision * @param precision the precision
* @param mode the mode * @param mode the mode
* @param column the column (if any), used for to improve the error message if conversion fails * @param column the column (if any), used for to improve the error message if conversion fails
* @param enumerators the ENUM datatype enumerators (if any), * @param extTypeInfo the extended data type information, or null
* for dealing with ENUM conversions
* @return the converted value * @return the converted value
*/ */
@Override @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) { if (t == valueType) {
return this; return this;
} else if (t == Value.CLOB) { } else if (t == Value.CLOB) {
......
...@@ -134,7 +134,7 @@ public class ValueNull extends Value { ...@@ -134,7 +134,7 @@ public class ValueNull extends Value {
} }
@Override @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; return this;
} }
......
...@@ -25,6 +25,7 @@ import org.h2.util.JdbcUtils; ...@@ -25,6 +25,7 @@ import org.h2.util.JdbcUtils;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.CompareMode; import org.h2.value.CompareMode;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueBytes; import org.h2.value.ValueBytes;
import org.h2.value.ValueDouble; import org.h2.value.ValueDouble;
...@@ -394,7 +395,7 @@ public class TestCustomDataTypesHandler extends TestDb { ...@@ -394,7 +395,7 @@ public class TestCustomDataTypesHandler extends TestDb {
} }
@Override @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) { if (getType() == targetType) {
return this; return this;
} }
......
...@@ -26,6 +26,12 @@ select * from card; ...@@ -26,6 +26,12 @@ select * from card;
> 4 null > 4 null
> rows: 3 > 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; select * from card order by suit;
> RANK SUIT > RANK SUIT
> ---- ------ > ---- ------
...@@ -50,7 +56,10 @@ select rank from card where suit = 'diamonds'; ...@@ -50,7 +56,10 @@ select rank from card where suit = 'diamonds';
>> 8 >> 8
select column_type from information_schema.columns where COLUMN_NAME = 'SUIT'; 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 --- ENUM integer-based operations
...@@ -242,13 +251,13 @@ SELECT * FROM V3; ...@@ -242,13 +251,13 @@ SELECT * FROM V3;
>> -1 >> -1
SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 'E' ORDER BY TABLE_NAME; 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 > 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 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 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 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 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 > 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
> rows (ordered): 5 > rows (ordered): 5
DROP VIEW V; DROP VIEW V;
......
...@@ -36,12 +36,12 @@ DROP DOMAIN E_NN CASCADE; ...@@ -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; SELECT COLUMN_NAME, NULLABLE, COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TEST' ORDER BY ORDINAL_POSITION;
> COLUMN_NAME NULLABLE COLUMN_TYPE > COLUMN_NAME NULLABLE COLUMN_TYPE
> ----------- -------- ---------------------- > ----------- -------- -----------------------
> I 0 INT NOT NULL > I 0 INT NOT NULL
> E1 1 ENUM('A','B') > E1 1 ENUM('A', 'B')
> E2 0 ENUM('A','B') NOT NULL > E2 0 ENUM('A', 'B') NOT NULL
> E3 0 ENUM('A','B') NOT NULL > E3 0 ENUM('A', 'B') NOT NULL
> E4 1 ENUM('A','B') > E4 1 ENUM('A', 'B')
> rows (ordered): 5 > rows (ordered): 5
DROP TABLE TEST; DROP TABLE TEST;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论