Unverified 提交 fad4a812 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1685 from katzyn/value

Fix CHAR in PostgreSQL mode and refactor some code
...@@ -21,6 +21,8 @@ Change Log ...@@ -21,6 +21,8 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>PR #1685: Fix CHAR in PostgreSQL mode and refactor some code
</li>
<li>Issue #1681: IN () doesn't work with row values when data types are not exactly the same <li>Issue #1681: IN () doesn't work with row values when data types are not exactly the same
</li> </li>
<li>Issue #1320: OOME / GC overhead in IndexCursor.nextCursor() <li>Issue #1320: OOME / GC overhead in IndexCursor.nextCursor()
......
...@@ -18,6 +18,7 @@ import org.h2.message.DbException; ...@@ -18,6 +18,7 @@ import org.h2.message.DbException;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.result.ResultWithGeneratedKeys; import org.h2.result.ResultWithGeneratedKeys;
import org.h2.result.ResultWithPaddedStrings;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
/** /**
...@@ -200,6 +201,9 @@ public abstract class Command implements CommandInterface { ...@@ -200,6 +201,9 @@ public abstract class Command implements CommandInterface {
try { try {
ResultInterface result = query(maxrows); ResultInterface result = query(maxrows);
callStop = !result.isLazy(); callStop = !result.isLazy();
if (database.getMode().padFixedLengthStrings) {
return ResultWithPaddedStrings.get(result);
}
return result; return result;
} catch (DbException e) { } catch (DbException e) {
start = filterConcurrentUpdate(e, start); start = filterConcurrentUpdate(e, start);
......
...@@ -216,7 +216,6 @@ import org.h2.table.TableFilter; ...@@ -216,7 +216,6 @@ import org.h2.table.TableFilter;
import org.h2.table.TableFilter.TableFilterVisitor; import org.h2.table.TableFilter.TableFilterVisitor;
import org.h2.table.TableView; import org.h2.table.TableView;
import org.h2.util.IntervalUtils; import org.h2.util.IntervalUtils;
import org.h2.util.MathUtils;
import org.h2.util.ParserUtil; import org.h2.util.ParserUtil;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
...@@ -5351,7 +5350,6 @@ public class Parser { ...@@ -5351,7 +5350,6 @@ public class Parser {
regular = true; regular = true;
} }
long precision = -1; long precision = -1;
int displaySize = -1;
ExtTypeInfo extTypeInfo = null; ExtTypeInfo extTypeInfo = null;
int scale = -1; int scale = -1;
String comment = null; String comment = null;
...@@ -5368,7 +5366,6 @@ public class Parser { ...@@ -5368,7 +5366,6 @@ public class Parser {
comment = templateColumn.getComment(); comment = templateColumn.getComment();
original = forTable ? domain.getSQL() : templateColumn.getOriginalSQL(); original = forTable ? domain.getSQL() : templateColumn.getOriginalSQL();
precision = type.getPrecision(); precision = type.getPrecision();
displaySize = type.getDisplaySize();
scale = type.getScale(); scale = type.getScale();
extTypeInfo = type.getExtTypeInfo(); extTypeInfo = type.getExtTypeInfo();
} else { } else {
...@@ -5388,8 +5385,6 @@ public class Parser { ...@@ -5388,8 +5385,6 @@ public class Parser {
read(); read();
} }
precision = precision == -1 ? dataType.defaultPrecision : precision; precision = precision == -1 ? dataType.defaultPrecision : precision;
displaySize = displaySize == -1 ? dataType.defaultDisplaySize
: displaySize;
scale = scale == -1 ? dataType.defaultScale : scale; scale = scale == -1 ? dataType.defaultScale : scale;
if (dataType.supportsPrecision || dataType.supportsScale) { if (dataType.supportsPrecision || dataType.supportsScale) {
int t = dataType.type; int t = dataType.type;
...@@ -5403,7 +5398,6 @@ public class Parser { ...@@ -5403,7 +5398,6 @@ public class Parser {
} else { } else {
original = original + '(' + originalScale + ')'; original = original + '(' + originalScale + ')';
} }
precision = displaySize = ValueTime.getDisplaySize(originalScale);
break; break;
case Value.TIMESTAMP: case Value.TIMESTAMP:
if (original.equals("TIMESTAMP WITHOUT TIME ZONE")) { if (original.equals("TIMESTAMP WITHOUT TIME ZONE")) {
...@@ -5411,11 +5405,9 @@ public class Parser { ...@@ -5411,11 +5405,9 @@ public class Parser {
} else { } else {
original = original + '(' + originalScale + ')'; original = original + '(' + originalScale + ')';
} }
precision = displaySize = ValueTimestamp.getDisplaySize(originalScale);
break; break;
case Value.TIMESTAMP_TZ: case Value.TIMESTAMP_TZ:
original = "TIMESTAMP(" + originalScale + ") WITH TIME ZONE"; original = "TIMESTAMP(" + originalScale + ") WITH TIME ZONE";
precision = displaySize = ValueTimestampTimeZone.getDisplaySize(originalScale);
break; break;
} }
} else if (original.equals("DATETIME") || original.equals("DATETIME2")) { } else if (original.equals("DATETIME") || original.equals("DATETIME2")) {
...@@ -5428,11 +5420,9 @@ public class Parser { ...@@ -5428,11 +5420,9 @@ public class Parser {
read(CLOSE_PAREN); read(CLOSE_PAREN);
scale = originalScale; scale = originalScale;
original = original + '(' + originalScale + ')'; original = original + '(' + originalScale + ')';
precision = displaySize = ValueTimestamp.getDisplaySize(originalScale);
} }
} else if (original.equals("SMALLDATETIME")) { } else if (original.equals("SMALLDATETIME")) {
scale = 0; scale = 0;
precision = displaySize = ValueTimestamp.getDisplaySize(0);
} }
} else if (DataType.isIntervalType(t)) { } else if (DataType.isIntervalType(t)) {
if (originalPrecision >= 0 || originalScale >= 0) { if (originalPrecision >= 0 || originalScale >= 0) {
...@@ -5466,7 +5456,6 @@ public class Parser { ...@@ -5466,7 +5456,6 @@ public class Parser {
} }
} }
precision = p; precision = p;
displaySize = MathUtils.convertLongToInt(precision);
original += ")"; original += ")";
} }
read(CLOSE_PAREN); read(CLOSE_PAREN);
...@@ -5547,13 +5536,13 @@ public class Parser { ...@@ -5547,13 +5536,13 @@ public class Parser {
// MySQL compatibility // MySQL compatibility
readIf("UNSIGNED"); readIf("UNSIGNED");
int type = dataType.type; int type = dataType.type;
if (scale > precision && !DataType.isIntervalType(type)) { if (scale > precision && dataType.supportsPrecision && dataType.supportsScale
&& !DataType.isIntervalType(type)) {
throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION, throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION,
Integer.toString(scale), Long.toString(precision)); Integer.toString(scale), Long.toString(precision));
} }
Column column = new Column(columnName, type, precision, scale, Column column = new Column(columnName, TypeInfo.getTypeInfo(type, precision, scale, extTypeInfo));
displaySize, extTypeInfo);
if (templateColumn != null) { if (templateColumn != null) {
column.setNullable(templateColumn.isNullable()); column.setNullable(templateColumn.isNullable());
column.setDefaultExpression(session, column.setDefaultExpression(session,
...@@ -5883,7 +5872,7 @@ public class Parser { ...@@ -5883,7 +5872,7 @@ public class Parser {
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
Column c = columns.get(i); Column c = columns.get(i);
if (c.getType().getValueType() == Value.UNKNOWN) { if (c.getType().getValueType() == Value.UNKNOWN) {
c = new Column(c.getName(), Value.STRING, 0, 0, 0); c = new Column(c.getName(), Value.STRING);
columns.set(i, c); columns.set(i, c);
} }
Expression[] array = new Expression[rowCount]; Expression[] array = new Expression[rowCount];
......
...@@ -15,17 +15,12 @@ import org.h2.engine.Database; ...@@ -15,17 +15,12 @@ import org.h2.engine.Database;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.schema.Sequence; import org.h2.schema.Sequence;
import org.h2.table.Column; 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.ExtTypeInfo;
import org.h2.value.TypeInfo;
import org.h2.value.Value;
/** /**
* This class represents the statement * This class represents the statement
...@@ -181,39 +176,8 @@ public class CreateTable extends CommandWithColumns { ...@@ -181,39 +176,8 @@ public class CreateTable extends CommandWithColumns {
ColumnNamer columnNamer= new ColumnNamer(session); ColumnNamer columnNamer= new ColumnNamer(session);
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
Expression expr = expressions.get(i); Expression expr = expressions.get(i);
TypeInfo type = expr.getType(); String name = columnNamer.getColumnName(expr, i, expr.getAlias());
int valueType = type.getValueType(); Column col = new Column(name, expr.getType());
String name = columnNamer.getColumnName(expr,i,expr.getAlias());
long precision = type.getPrecision();
int displaySize = type.getDisplaySize();
DataType dt = DataType.getDataType(valueType);
if (precision > 0 && (dt.defaultPrecision == 0 ||
(dt.defaultPrecision > precision && dt.defaultPrecision < Byte.MAX_VALUE))) {
// dont' set precision to MAX_VALUE if this is the default
precision = dt.defaultPrecision;
}
int scale = type.getScale();
if (scale > 0 && (dt.defaultScale == 0 ||
(dt.defaultScale > scale && dt.defaultScale < precision))) {
scale = dt.defaultScale;
}
if (scale > precision) {
precision = scale;
}
ExtTypeInfo extTypeInfo = null;
int t = dt.type;
if (DataType.isExtInfoType(t)) {
if (expr instanceof ExpressionColumn) {
extTypeInfo = ((ExpressionColumn) expr).getColumn().getType().getExtTypeInfo();
} else if (t == Value.ENUM) {
/*
* Only columns of tables may be enumerated.
*/
throw DbException.get(ErrorCode.GENERAL_ERROR_1,
"Unable to resolve enumerators of expression");
}
}
Column col = new Column(name, valueType, precision, scale, displaySize, extTypeInfo);
addColumn(col); addColumn(col);
} }
} }
......
...@@ -18,6 +18,7 @@ import org.h2.table.Column; ...@@ -18,6 +18,7 @@ import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableType; import org.h2.table.TableType;
import org.h2.table.TableView; import org.h2.table.TableView;
import org.h2.value.TypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
...@@ -110,7 +111,7 @@ public class CreateView extends SchemaCommand { ...@@ -110,7 +111,7 @@ public class CreateView extends SchemaCommand {
columnTemplatesAsStrings = new Column[columnNames.length]; columnTemplatesAsStrings = new Column[columnNames.length];
for (int i = 0; i < columnNames.length; ++i) { for (int i = 0; i < columnNames.length; ++i) {
// non table expressions are fine to use unknown column type // non table expressions are fine to use unknown column type
columnTemplatesAsUnknowns[i] = new Column(columnNames[i], Value.UNKNOWN); columnTemplatesAsUnknowns[i] = new Column(columnNames[i], TypeInfo.TYPE_UNKNOWN);
// table expressions can't have unknown types - so we use string instead // table expressions can't have unknown types - so we use string instead
columnTemplatesAsStrings[i] = new Column(columnNames[i], Value.STRING); columnTemplatesAsStrings[i] = new Column(columnNames[i], Value.STRING);
} }
......
...@@ -45,12 +45,6 @@ public class Constants { ...@@ -45,12 +45,6 @@ public class Constants {
*/ */
public static final String BUILD_VENDOR_AND_VERSION = null; public static final String BUILD_VENDOR_AND_VERSION = null;
/**
* The TCP protocol version number 8.
* @since 1.2.143 (2010-09-18)
*/
public static final int TCP_PROTOCOL_VERSION_8 = 8;
/** /**
* The TCP protocol version number 9. * The TCP protocol version number 9.
* @since 1.3.158 (2011-07-17) * @since 1.3.158 (2011-07-17)
...@@ -114,7 +108,7 @@ public class Constants { ...@@ -114,7 +108,7 @@ public class Constants {
/** /**
* Minimum supported version of TCP protocol. * Minimum supported version of TCP protocol.
*/ */
public static final int TCP_PROTOCOL_VERSION_MIN_SUPPORTED = TCP_PROTOCOL_VERSION_8; public static final int TCP_PROTOCOL_VERSION_MIN_SUPPORTED = TCP_PROTOCOL_VERSION_9;
/** /**
* Maximum supported version of TCP protocol. * Maximum supported version of TCP protocol.
......
...@@ -99,11 +99,10 @@ public class BinaryOperation extends Expression { ...@@ -99,11 +99,10 @@ public class BinaryOperation extends Expression {
@Override @Override
public Value getValue(Session session) { public Value getValue(Session session) {
Mode mode = session.getDatabase().getMode(); Mode mode = session.getDatabase().getMode();
int dataType = type.getValueType(); Value l = left.getValue(session).convertTo(type, mode, null);
Value l = left.getValue(session).convertTo(dataType, mode);
Value r = right.getValue(session); Value r = right.getValue(session);
if (convertRight) { if (convertRight) {
r = r.convertTo(dataType, mode); r = r.convertTo(type, mode, null);
} }
switch (opType) { switch (opType) {
case CONCAT: { case CONCAT: {
......
...@@ -21,11 +21,9 @@ import org.h2.table.Column; ...@@ -21,11 +21,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.TypeInfo; import org.h2.value.TypeInfo;
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;
/** /**
* A expression that represents a column of a table or view. * A expression that represents a column of a table or view.
...@@ -216,12 +214,6 @@ public class ExpressionColumn extends Expression { ...@@ -216,12 +214,6 @@ 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 (value != ValueNull.INSTANCE) {
ExtTypeInfo extTypeInfo = column.getType().getExtTypeInfo();
if (extTypeInfo != null) {
return extTypeInfo.cast(value);
}
}
return value; return value;
} }
......
...@@ -34,7 +34,7 @@ public class UnaryOperation extends Expression { ...@@ -34,7 +34,7 @@ public class UnaryOperation extends Expression {
@Override @Override
public Value getValue(Session session) { public Value getValue(Session session) {
Value a = arg.getValue(session).convertTo(type.getValueType(), session.getDatabase().getMode()); Value a = arg.getValue(session).convertTo(type, session.getDatabase().getMode(), null);
return a == ValueNull.INSTANCE ? a : a.negate(); return a == ValueNull.INSTANCE ? a : a.negate();
} }
......
...@@ -21,7 +21,7 @@ import org.h2.message.DbException; ...@@ -21,7 +21,7 @@ import org.h2.message.DbException;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.util.MathUtils; import org.h2.value.TypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueBoolean; import org.h2.value.ValueBoolean;
import org.h2.value.ValueGeometry; import org.h2.value.ValueGeometry;
...@@ -225,17 +225,17 @@ public class Comparison extends Condition { ...@@ -225,17 +225,17 @@ public class Comparison extends Condition {
return ValueExpression.getNull(); return ValueExpression.getNull();
} }
} }
int colType = left.getType().getValueType(); TypeInfo colType = left.getType(), constType = r.getType();
int constType = r.getValueType(); int constValueType = constType.getValueType();
int resType = Value.getHigherOrder(colType, constType); if (constValueType != colType.getValueType()) {
// If not, the column values will need to be promoted TypeInfo resType = Value.getHigherType(colType, constType);
// to constant type, but vise versa, then let's do this here // If not, the column values will need to be promoted
// once. // to constant type, but vise versa, then let's do this here
if (constType != resType) { // once.
Column column = ((ExpressionColumn) left).getColumn(); if (constValueType != resType.getValueType()) {
right = ValueExpression.get(r.convertTo(resType, Column column = ((ExpressionColumn) left).getColumn();
MathUtils.convertLongToInt(left.getType().getPrecision()), right = ValueExpression.get(r.convertTo(resType, session.getDatabase().getMode(), column));
session.getDatabase().getMode(), column, column.getType().getExtTypeInfo())); }
} }
} else if (right instanceof Parameter) { } else if (right instanceof Parameter) {
((Parameter) right).setColumn( ((Parameter) right).setColumn(
......
...@@ -19,6 +19,7 @@ import org.h2.result.ResultInterface; ...@@ -19,6 +19,7 @@ import org.h2.result.ResultInterface;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.TypeInfo;
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;
...@@ -72,8 +73,8 @@ public class ConditionInSelect extends Condition { ...@@ -72,8 +73,8 @@ public class ConditionInSelect extends Condition {
return ValueBoolean.TRUE; return ValueBoolean.TRUE;
} }
} else { } else {
int dataType = rows.getColumnType(0).getValueType(); TypeInfo colType = rows.getColumnType(0);
if (dataType == Value.NULL) { if (colType.getValueType() == Value.NULL) {
return ValueBoolean.FALSE; return ValueBoolean.FALSE;
} }
if (l.getValueType() == Value.ROW) { if (l.getValueType() == Value.ROW) {
...@@ -83,7 +84,7 @@ public class ConditionInSelect extends Condition { ...@@ -83,7 +84,7 @@ public class ConditionInSelect extends Condition {
} }
l = leftList[0]; l = leftList[0];
} }
l = l.convertTo(dataType, database.getMode()); l = l.convertTo(colType, database.getMode(), null);
if (rows.containsDistinct(new Value[] { l })) { if (rows.containsDistinct(new Value[] { l })) {
return ValueBoolean.TRUE; return ValueBoolean.TRUE;
} }
......
...@@ -7,11 +7,10 @@ package org.h2.expression.function; ...@@ -7,11 +7,10 @@ package org.h2.expression.function;
import static java.lang.String.format; import static java.lang.String.format;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import org.h2.engine.Session;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeUtils;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone; import org.h2.value.ValueTimestampTimeZone;
...@@ -21,6 +20,8 @@ import org.h2.value.ValueTimestampTimeZone; ...@@ -21,6 +20,8 @@ import org.h2.value.ValueTimestampTimeZone;
* This class holds and handles the input data form the TO_DATE-method * This class holds and handles the input data form the TO_DATE-method
*/ */
public class ToDateParser { public class ToDateParser {
private final Session session;
private final String unmodifiedInputStr; private final String unmodifiedInputStr;
private final String unmodifiedFormatStr; private final String unmodifiedFormatStr;
private final ConfigParam functionName; private final ConfigParam functionName;
...@@ -52,12 +53,14 @@ public class ToDateParser { ...@@ -52,12 +53,14 @@ public class ToDateParser {
private int currentYear, currentMonth; private int currentYear, currentMonth;
/** /**
* @param input the input date with the date-time info * @param session the database session
* @param format the format of date-time info
* @param functionName one of [TO_DATE, TO_TIMESTAMP] (both share the same * @param functionName one of [TO_DATE, TO_TIMESTAMP] (both share the same
* code) * code)
* @param input the input date with the date-time info
* @param format the format of date-time info
*/ */
private ToDateParser(ConfigParam functionName, String input, String format) { private ToDateParser(Session session, ConfigParam functionName, String input, String format) {
this.session = session;
this.functionName = functionName; this.functionName = functionName;
inputStr = input.trim(); inputStr = input.trim();
// Keep a copy // Keep a copy
...@@ -72,8 +75,8 @@ public class ToDateParser { ...@@ -72,8 +75,8 @@ public class ToDateParser {
unmodifiedFormatStr = formatStr; unmodifiedFormatStr = formatStr;
} }
private static ToDateParser getTimestampParser(ConfigParam param, String input, String format) { private static ToDateParser getTimestampParser(Session session, ConfigParam param, String input, String format) {
ToDateParser result = new ToDateParser(param, input, format); ToDateParser result = new ToDateParser(session, param, input, format);
parse(result); parse(result);
return result; return result;
} }
...@@ -145,10 +148,10 @@ public class ToDateParser { ...@@ -145,10 +148,10 @@ public class ToDateParser {
} }
private void queryCurrentYearAndMonth() { private void queryCurrentYearAndMonth() {
GregorianCalendar gc = DateTimeUtils.getCalendar(); long dateValue = (session.getDatabase().getMode().dateTimeValueWithinTransaction
gc.setTimeInMillis(System.currentTimeMillis()); ? session.getTransactionStart() : session.getCurrentCommandStart()).getDateValue();
currentYear = gc.get(Calendar.YEAR); currentYear = DateTimeUtils.yearFromDateValue(dateValue);
currentMonth = gc.get(Calendar.MONTH) + 1; currentMonth = DateTimeUtils.monthFromDateValue(dateValue);
} }
int getCurrentYear() { int getCurrentYear() {
...@@ -319,36 +322,39 @@ public class ToDateParser { ...@@ -319,36 +322,39 @@ public class ToDateParser {
/** /**
* Parse a string as a timestamp with the given format. * Parse a string as a timestamp with the given format.
* *
* @param session the database session
* @param input the input * @param input the input
* @param format the format * @param format the format
* @return the timestamp * @return the timestamp
*/ */
public static ValueTimestamp toTimestamp(String input, String format) { public static ValueTimestamp toTimestamp(Session session, String input, String format) {
ToDateParser parser = getTimestampParser(ConfigParam.TO_TIMESTAMP, input, format); ToDateParser parser = getTimestampParser(session, ConfigParam.TO_TIMESTAMP, input, format);
return parser.getResultingValue(); return parser.getResultingValue();
} }
/** /**
* Parse a string as a timestamp with the given format. * Parse a string as a timestamp with the given format.
* *
* @param session the database session
* @param input the input * @param input the input
* @param format the format * @param format the format
* @return the timestamp * @return the timestamp
*/ */
public static ValueTimestampTimeZone toTimestampTz(String input, String format) { public static ValueTimestampTimeZone toTimestampTz(Session session, String input, String format) {
ToDateParser parser = getTimestampParser(ConfigParam.TO_TIMESTAMP_TZ, input, format); ToDateParser parser = getTimestampParser(session, ConfigParam.TO_TIMESTAMP_TZ, input, format);
return parser.getResultingValueWithTimeZone(); return parser.getResultingValueWithTimeZone();
} }
/** /**
* Parse a string as a date with the given format. * Parse a string as a date with the given format.
* *
* @param session the database session
* @param input the input * @param input the input
* @param format the format * @param format the format
* @return the date as a timestamp * @return the date as a timestamp
*/ */
public static ValueTimestamp toDate(String input, String format) { public static ValueTimestamp toDate(Session session, String input, String format) {
ToDateParser parser = getTimestampParser(ConfigParam.TO_DATE, input, format); ToDateParser parser = getTimestampParser(session, ConfigParam.TO_DATE, input, format);
return parser.getResultingValue(); return parser.getResultingValue();
} }
......
...@@ -97,10 +97,10 @@ public class HashIndex extends BaseIndex { ...@@ -97,10 +97,10 @@ public class HashIndex extends BaseIndex {
/* /*
* Sometimes the incoming search is a similar, but not the same type * Sometimes the incoming search is a similar, but not the same type
* e.g. the search value is INT, but the index column is LONG. In which * e.g. the search value is INT, but the index column is LONG. In which
* case we need to convert, otherwise the ValueHashMap will not find the * case we need to convert, otherwise the HashMap will not find the
* result. * result.
*/ */
v = v.convertTo(tableData.getColumn(indexColumn).getType().getValueType(), database.getMode()); v = v.convertTo(tableData.getColumn(indexColumn).getType(), database.getMode(), null);
Row result; Row result;
Long pos = rows.get(v); Long pos = rows.get(v);
if (pos == null) { if (pos == null) {
......
...@@ -105,10 +105,10 @@ public class NonUniqueHashIndex extends BaseIndex { ...@@ -105,10 +105,10 @@ public class NonUniqueHashIndex extends BaseIndex {
/* /*
* Sometimes the incoming search is a similar, but not the same type * Sometimes the incoming search is a similar, but not the same type
* e.g. the search value is INT, but the index column is LONG. In which * e.g. the search value is INT, but the index column is LONG. In which
* case we need to convert, otherwise the ValueHashMap will not find the * case we need to convert, otherwise the HashMap will not find the
* result. * result.
*/ */
v = v.convertTo(tableData.getColumn(indexColumn).getType().getValueType(), database.getMode()); v = v.convertTo(tableData.getColumn(indexColumn).getType(), database.getMode(), null);
ArrayList<Long> positions = rows.get(v); ArrayList<Long> positions = rows.get(v);
return new NonUniqueHashCursor(session, tableData, positions); return new NonUniqueHashCursor(session, tableData, positions);
} }
......
...@@ -1087,7 +1087,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS ...@@ -1087,7 +1087,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
public byte[] getBytes(String columnLabel) throws SQLException { public byte[] getBytes(String columnLabel) throws SQLException {
try { try {
debugCodeCall("getBytes", columnLabel); debugCodeCall("getBytes", columnLabel);
return get(columnLabel).getBytes(); return get(columnLabel).convertTo(Value.BYTES, conn.getMode()).getBytes();
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
......
...@@ -202,8 +202,7 @@ public class FunctionsMySQL extends FunctionsBase { ...@@ -202,8 +202,7 @@ public class FunctionsMySQL extends FunctionsBase {
if (allConst) { if (allConst) {
return ValueExpression.get(getValue(session)); return ValueExpression.get(getValue(session));
} }
dataType = info.returnDataType; type = TypeInfo.getTypeInfo(info.returnDataType);
type = TypeInfo.getTypeInfo(dataType);
return this; return this;
} }
......
...@@ -30,7 +30,6 @@ import org.h2.table.Column; ...@@ -30,7 +30,6 @@ import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.value.CompareMode; import org.h2.value.CompareMode;
import org.h2.value.TypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray; import org.h2.value.ValueArray;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
...@@ -289,8 +288,7 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -289,8 +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) {
TypeInfo type = c.getType(); array[i] = v.convertTo(c.getType(), database.getMode(), null);
array[i] = v.convertTo(type.getValueType(), -1, database.getMode(), null, type.getExtTypeInfo());
} }
} }
array[keyColumns - 1] = key != null ? key : ValueLong.get(r.getKey()); array[keyColumns - 1] = key != null ? key : ValueLong.get(r.getKey());
......
/*
* Copyright 2004-2019 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.result;
import java.util.Arrays;
import org.h2.engine.SessionInterface;
import org.h2.util.MathUtils;
import org.h2.value.TypeInfo;
import org.h2.value.Value;
import org.h2.value.ValueString;
/**
* Result with padded fixed length strings.
*/
public class ResultWithPaddedStrings implements ResultInterface {
private final ResultInterface source;
/**
* Returns wrapped result if necessary, or original result if it does not
* contain visible CHAR columns.
*
* @param source
* source result
* @return wrapped result or original result
*/
public static ResultInterface get(ResultInterface source) {
int count = source.getVisibleColumnCount();
for (int i = 0; i < count; i++) {
if (source.getColumnType(i).getValueType() == Value.STRING_FIXED) {
return new ResultWithPaddedStrings(source);
}
}
return source;
}
/**
* Creates new instance of result.
*
* @param source
* the source result
*/
private ResultWithPaddedStrings(ResultInterface source) {
this.source = source;
}
@Override
public void reset() {
source.reset();
}
@Override
public Value[] currentRow() {
int count = source.getVisibleColumnCount();
Value[] row = Arrays.copyOf(source.currentRow(), count);
for (int i = 0; i < count; i++) {
TypeInfo type = source.getColumnType(i);
if (type.getValueType() == Value.STRING_FIXED) {
long precision = type.getPrecision();
if (precision == Integer.MAX_VALUE) {
// CHAR is CHAR(1)
precision = 1;
}
String s = row[i].getString();
if (s != null && s.length() < precision) {
/*
* Use ValueString to avoid truncation of spaces. There is
* no difference between ValueStringFixed and ValueString
* for JDBC layer anyway.
*/
row[i] = ValueString.get(rightPadWithSpaces(s, MathUtils.convertLongToInt(precision)));
}
}
}
return row;
}
private static String rightPadWithSpaces(String s, int length) {
int used = s.length();
if (length <= used) {
return s;
}
char[] res = new char[length];
s.getChars(0, used, res, 0);
Arrays.fill(res, used, length, ' ');
return new String(res);
}
@Override
public boolean next() {
return source.next();
}
@Override
public int getRowId() {
return source.getRowId();
}
@Override
public boolean isAfterLast() {
return source.isAfterLast();
}
@Override
public int getVisibleColumnCount() {
return source.getVisibleColumnCount();
}
@Override
public int getRowCount() {
return source.getRowCount();
}
@Override
public boolean hasNext() {
return source.hasNext();
}
@Override
public boolean needToClose() {
return source.needToClose();
}
@Override
public void close() {
source.close();
}
@Override
public String getAlias(int i) {
return source.getAlias(i);
}
@Override
public String getSchemaName(int i) {
return source.getSchemaName(i);
}
@Override
public String getTableName(int i) {
return source.getTableName(i);
}
@Override
public String getColumnName(int i) {
return source.getColumnName(i);
}
@Override
public TypeInfo getColumnType(int i) {
return source.getColumnType(i);
}
@Override
public boolean isAutoIncrement(int i) {
return source.isAutoIncrement(i);
}
@Override
public int getNullable(int i) {
return source.getNullable(i);
}
@Override
public void setFetchSize(int fetchSize) {
source.setFetchSize(fetchSize);
}
@Override
public int getFetchSize() {
return source.getFetchSize();
}
@Override
public boolean isLazy() {
return source.isLazy();
}
@Override
public boolean isClosed() {
return source.isClosed();
}
@Override
public ResultInterface createShallowCopy(SessionInterface targetSession) {
ResultInterface copy = source.createShallowCopy(targetSession);
return copy != null ? new ResultWithPaddedStrings(copy) : null;
}
}
...@@ -27,7 +27,6 @@ import org.h2.schema.Sequence; ...@@ -27,7 +27,6 @@ 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.TypeInfo; import org.h2.value.TypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueInt; import org.h2.value.ValueInt;
...@@ -88,22 +87,7 @@ public class Column { ...@@ -88,22 +87,7 @@ public class Column {
private Domain domain; private Domain domain;
public Column(String name, int valueType) { public Column(String name, int valueType) {
this(name, valueType, -1, -1, -1, null); this(name, TypeInfo.getTypeInfo(valueType));
}
public Column(String name, int valueType, long precision, int scale, int displaySize) {
this(name, valueType, precision, scale, displaySize, null);
}
public Column(String name, int valueType, long precision, int scale, int displaySize, ExtTypeInfo extTypeInfo) {
this.name = name;
if (precision == -1 && scale == -1 && displaySize == -1 && valueType != Value.UNKNOWN) {
DataType dt = DataType.getDataType(valueType);
precision = dt.defaultPrecision;
scale = dt.defaultScale;
displaySize = dt.defaultDisplaySize;
}
this.type = new TypeInfo(valueType, precision, scale, displaySize, extTypeInfo);
} }
public Column(String name, TypeInfo type) { public Column(String name, TypeInfo type) {
...@@ -164,8 +148,7 @@ public class Column { ...@@ -164,8 +148,7 @@ public class Column {
*/ */
public Value convert(Value v, Mode mode) { public Value convert(Value v, Mode mode) {
try { try {
return v.convertTo(type.getValueType(), MathUtils.convertLongToInt(type.getPrecision()), mode, this, return v.convertTo(type, mode, this);
type.getExtTypeInfo());
} 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() + ": ") +
......
...@@ -28,11 +28,11 @@ import org.h2.message.DbException; ...@@ -28,11 +28,11 @@ import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.RowList; import org.h2.result.RowList;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.util.MathUtils;
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.DataType; import org.h2.value.DataType;
import org.h2.value.TypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueDate; import org.h2.value.ValueDate;
import org.h2.value.ValueTime; import org.h2.value.ValueTime;
...@@ -156,9 +156,8 @@ public class TableLink extends Table { ...@@ -156,9 +156,8 @@ public class TableLink extends Table {
precision = convertPrecision(sqlType, precision); precision = convertPrecision(sqlType, precision);
int scale = rs.getInt("DECIMAL_DIGITS"); int scale = rs.getInt("DECIMAL_DIGITS");
scale = convertScale(sqlType, scale); scale = convertScale(sqlType, scale);
int displaySize = MathUtils.convertLongToInt(precision);
int type = DataType.convertSQLTypeToValueType(sqlType, sqlTypeName); int type = DataType.convertSQLTypeToValueType(sqlType, sqlTypeName);
Column col = new Column(n, type, precision, scale, displaySize); Column col = new Column(n, TypeInfo.getTypeInfo(type, precision, scale, null));
col.setTable(this, i++); col.setTable(this, i++);
columnList.add(col); columnList.add(col);
columnMap.put(n, col); columnMap.put(n, col);
...@@ -185,9 +184,8 @@ public class TableLink extends Table { ...@@ -185,9 +184,8 @@ public class TableLink extends Table {
precision = convertPrecision(sqlType, precision); precision = convertPrecision(sqlType, precision);
int scale = rsMeta.getScale(i + 1); int scale = rsMeta.getScale(i + 1);
scale = convertScale(sqlType, scale); scale = convertScale(sqlType, scale);
int displaySize = rsMeta.getColumnDisplaySize(i + 1);
int type = DataType.getValueTypeFromResultSet(rsMeta, i + 1); int type = DataType.getValueTypeFromResultSet(rsMeta, i + 1);
Column col = new Column(n, type, precision, scale, displaySize); Column col = new Column(n, TypeInfo.getTypeInfo(type, precision, scale, null));
col.setTable(this, i++); col.setTable(this, i++);
columnList.add(col); columnList.add(col);
columnMap.put(n, col); columnMap.put(n, col);
......
...@@ -38,8 +38,6 @@ import org.h2.util.ColumnNamer; ...@@ -38,8 +38,6 @@ 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.DataType;
import org.h2.value.ExtTypeInfo;
import org.h2.value.TypeInfo; import org.h2.value.TypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -182,29 +180,19 @@ public class TableView extends Table { ...@@ -182,29 +180,19 @@ public class TableView extends Table {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
Expression expr = expressions.get(i); Expression expr = expressions.get(i);
String name = null; String name = null;
int valueType = Value.UNKNOWN; TypeInfo type = TypeInfo.TYPE_UNKNOWN;
if (columnTemplates != null && columnTemplates.length > i) { if (columnTemplates != null && columnTemplates.length > i) {
name = columnTemplates[i].getName(); name = columnTemplates[i].getName();
valueType = columnTemplates[i].getType().getValueType(); type = columnTemplates[i].getType();
} }
if (name == null) { if (name == null) {
name = expr.getAlias(); name = expr.getAlias();
} }
name = columnNamer.getColumnName(expr, i, name); name = columnNamer.getColumnName(expr, i, name);
if (valueType == Value.UNKNOWN) { if (type.getValueType() == Value.UNKNOWN) {
valueType = expr.getType().getValueType(); type = expr.getType();
} }
TypeInfo type = expr.getType(); Column col = new Column(name, type);
long precision = type.getPrecision();
int scale = type.getScale();
int displaySize = type.getDisplaySize();
ExtTypeInfo extTypeInfo = null;
if (DataType.isExtInfoType(valueType)) {
if (expr instanceof ExpressionColumn) {
extTypeInfo = ((ExpressionColumn) expr).getColumn().getType().getExtTypeInfo();
}
}
Column col = new Column(name, valueType, 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;
......
...@@ -109,12 +109,12 @@ public class DateTimeUtils { ...@@ -109,12 +109,12 @@ public class DateTimeUtils {
private static volatile TimeZone timeZone; private static volatile TimeZone timeZone;
/** /**
* Observed JVM behaviour is that if the timezone of the host computer is * Raw offset doesn't change during DST transitions, but changes during
* changed while the JVM is running, the zone offset does not change but * other transitions that some time zones have. H2 1.4.193 and later
* keeps the initial value. So it is correct to measure this once and use * versions use zone offset that is valid for startup time for performance
* this value throughout the JVM's lifecycle. In any case, it is safer to * reasons. This code is now used only by old PageStore engine and its
* use a fixed value throughout the duration of the JVM's life, rather than * datetime storage code has issues with all time zone transitions, so this
* have this offset change, possibly midway through a long-running query. * buggy logic is preserved as is too.
*/ */
private static int zoneOffsetMillis = createGregorianCalendar().get(Calendar.ZONE_OFFSET); private static int zoneOffsetMillis = createGregorianCalendar().get(Calendar.ZONE_OFFSET);
......
...@@ -14,7 +14,6 @@ import java.io.Reader; ...@@ -14,7 +14,6 @@ import java.io.Reader;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import java.sql.Timestamp;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.api.IntervalQualifier; import org.h2.api.IntervalQualifier;
import org.h2.engine.Constants; import org.h2.engine.Constants;
...@@ -26,7 +25,6 @@ import org.h2.security.SHA256; ...@@ -26,7 +25,6 @@ import org.h2.security.SHA256;
import org.h2.store.Data; import org.h2.store.Data;
import org.h2.store.DataReader; import org.h2.store.DataReader;
import org.h2.util.Bits; import org.h2.util.Bits;
import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils; import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils; import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
...@@ -348,31 +346,17 @@ public class Transfer { ...@@ -348,31 +346,17 @@ public class Transfer {
break; break;
case Value.TIME: case Value.TIME:
writeInt(Value.TIME); writeInt(Value.TIME);
if (version >= Constants.TCP_PROTOCOL_VERSION_9) { writeLong(((ValueTime) v).getNanos());
writeLong(((ValueTime) v).getNanos());
} else {
writeLong(DateTimeUtils.getTimeLocalWithoutDst(v.getTime()));
}
break; break;
case Value.DATE: case Value.DATE:
writeInt(Value.DATE); writeInt(Value.DATE);
if (version >= Constants.TCP_PROTOCOL_VERSION_9) { writeLong(((ValueDate) v).getDateValue());
writeLong(((ValueDate) v).getDateValue());
} else {
writeLong(DateTimeUtils.getTimeLocalWithoutDst(v.getDate()));
}
break; break;
case Value.TIMESTAMP: { case Value.TIMESTAMP: {
writeInt(Value.TIMESTAMP); writeInt(Value.TIMESTAMP);
if (version >= Constants.TCP_PROTOCOL_VERSION_9) { ValueTimestamp ts = (ValueTimestamp) v;
ValueTimestamp ts = (ValueTimestamp) v; writeLong(ts.getDateValue());
writeLong(ts.getDateValue()); writeLong(ts.getTimeNanos());
writeLong(ts.getTimeNanos());
} else {
Timestamp ts = v.getTimestamp();
writeLong(DateTimeUtils.getTimeLocalWithoutDst(ts));
writeInt(ts.getNanos() % 1_000_000);
}
break; break;
} }
case Value.TIMESTAMP_TZ: { case Value.TIMESTAMP_TZ: {
...@@ -608,30 +592,13 @@ public class Transfer { ...@@ -608,30 +592,13 @@ public class Transfer {
case Value.BYTE: case Value.BYTE:
return ValueByte.get(readByte()); return ValueByte.get(readByte());
case Value.DATE: case Value.DATE:
if (version >= Constants.TCP_PROTOCOL_VERSION_9) { return ValueDate.fromDateValue(readLong());
return ValueDate.fromDateValue(readLong());
} else {
return ValueDate.fromMillis(DateTimeUtils.getTimeUTCWithoutDst(readLong()));
}
case Value.TIME: case Value.TIME:
if (version >= Constants.TCP_PROTOCOL_VERSION_9) { return ValueTime.fromNanos(readLong());
return ValueTime.fromNanos(readLong()); case Value.TIMESTAMP:
} else { return ValueTimestamp.fromDateValueAndNanos(readLong(), readLong());
return ValueTime.fromMillis(DateTimeUtils.getTimeUTCWithoutDst(readLong()));
}
case Value.TIMESTAMP: {
if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
return ValueTimestamp.fromDateValueAndNanos(
readLong(), readLong());
} else {
return ValueTimestamp.fromMillisNanos(
DateTimeUtils.getTimeUTCWithoutDst(readLong()),
readInt() % 1_000_000);
}
}
case Value.TIMESTAMP_TZ: { case Value.TIMESTAMP_TZ: {
return ValueTimestampTimeZone.fromDateValueAndNanos(readLong(), return ValueTimestampTimeZone.fromDateValueAndNanos(readLong(), readLong(), (short) readInt());
readLong(), (short) readInt());
} }
case Value.DECIMAL: case Value.DECIMAL:
return ValueDecimal.get(new BigDecimal(readString())); return ValueDecimal.get(new BigDecimal(readString()));
...@@ -655,7 +622,7 @@ public class Transfer { ...@@ -655,7 +622,7 @@ public class Transfer {
case Value.STRING_IGNORECASE: case Value.STRING_IGNORECASE:
return ValueStringIgnoreCase.get(readString()); return ValueStringIgnoreCase.get(readString());
case Value.STRING_FIXED: case Value.STRING_FIXED:
return ValueStringFixed.get(readString(), ValueStringFixed.PRECISION_DO_NOT_TRIM, null); return ValueStringFixed.get(readString());
case Value.BLOB: { case Value.BLOB: {
long length = readLong(); long length = readLong();
if (version >= Constants.TCP_PROTOCOL_VERSION_11) { if (version >= Constants.TCP_PROTOCOL_VERSION_11) {
......
...@@ -257,29 +257,36 @@ public class TypeInfo { ...@@ -257,29 +257,36 @@ public class TypeInfo {
if (scale < 0) { if (scale < 0) {
scale = ValueDecimal.DEFAULT_SCALE; scale = ValueDecimal.DEFAULT_SCALE;
} }
if (precision < scale) {
precision = scale;
}
return new TypeInfo(Value.DECIMAL, precision, scale, MathUtils.convertLongToInt(precision + 2), null); return new TypeInfo(Value.DECIMAL, precision, scale, MathUtils.convertLongToInt(precision + 2), null);
case Value.TIME: case Value.TIME: {
if (scale < 0 || scale >= ValueTime.MAXIMUM_SCALE) { if (scale < 0 || scale >= ValueTime.MAXIMUM_SCALE) {
return TYPE_TIME; return TYPE_TIME;
} }
return new TypeInfo(Value.TIME, ValueTime.MAXIMUM_PRECISION, scale, ValueTime.DEFAULT_PRECISION, null); int d = scale == 0 ? 8 : 9 + scale;
case Value.TIMESTAMP: return new TypeInfo(Value.TIME, d, scale, d, null);
}
case Value.TIMESTAMP: {
if (scale < 0 || scale >= ValueTimestamp.MAXIMUM_SCALE) { if (scale < 0 || scale >= ValueTimestamp.MAXIMUM_SCALE) {
return TYPE_TIMESTAMP; return TYPE_TIMESTAMP;
} }
return new TypeInfo(Value.TIMESTAMP, ValueTimestamp.MAXIMUM_PRECISION, scale, int d = scale == 0 ? 19 : 20 + scale;
ValueTimestamp.MAXIMUM_PRECISION, null); return new TypeInfo(Value.TIMESTAMP, d, scale, d, null);
case Value.TIMESTAMP_TZ: }
case Value.TIMESTAMP_TZ: {
if (scale < 0 || scale >= ValueTimestampTimeZone.MAXIMUM_SCALE) { if (scale < 0 || scale >= ValueTimestampTimeZone.MAXIMUM_SCALE) {
return TYPE_TIMESTAMP_TZ; return TYPE_TIMESTAMP_TZ;
} }
return new TypeInfo(Value.TIMESTAMP_TZ, ValueTimestampTimeZone.MAXIMUM_PRECISION, scale, int d = scale == 0 ? 25 : 26 + scale;
ValueTimestampTimeZone.MAXIMUM_PRECISION, null); return new TypeInfo(Value.TIMESTAMP_TZ, d, scale, d, null);
}
case Value.BYTES: case Value.BYTES:
if (precision < 0) { if (precision < 0) {
precision = Integer.MAX_VALUE; precision = Integer.MAX_VALUE;
} }
return new TypeInfo(Value.BYTES, precision, scale, MathUtils.convertLongToInt(precision) * 2, null); return new TypeInfo(Value.BYTES, precision, 0, MathUtils.convertLongToInt(precision) * 2, null);
case Value.STRING: case Value.STRING:
if (precision < 0) { if (precision < 0) {
return TYPE_STRING_DEFAULT; return TYPE_STRING_DEFAULT;
...@@ -287,19 +294,28 @@ public class TypeInfo { ...@@ -287,19 +294,28 @@ public class TypeInfo {
//$FALL-THROUGH$ //$FALL-THROUGH$
case Value.STRING_FIXED: case Value.STRING_FIXED:
case Value.STRING_IGNORECASE: case Value.STRING_IGNORECASE:
if (precision < 0) {
precision = Integer.MAX_VALUE;
}
return new TypeInfo(type, precision, 0, MathUtils.convertLongToInt(precision), null);
case Value.BLOB: case Value.BLOB:
case Value.CLOB: case Value.CLOB:
if (precision < 0) {
precision = Long.MAX_VALUE;
}
return new TypeInfo(type, precision, 0, MathUtils.convertLongToInt(precision), null); return new TypeInfo(type, precision, 0, MathUtils.convertLongToInt(precision), null);
case Value.GEOMETRY: case Value.GEOMETRY:
if (extTypeInfo == null) { if (extTypeInfo instanceof ExtTypeInfoGeometry) {
return new TypeInfo(Value.GEOMETRY, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, extTypeInfo);
} else {
return TYPE_GEOMETRY; return TYPE_GEOMETRY;
} }
return new TypeInfo(Value.GEOMETRY, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, extTypeInfo);
case Value.ENUM: case Value.ENUM:
if (extTypeInfo == null) { if (extTypeInfo instanceof ExtTypeInfoEnum) {
return new TypeInfo(Value.ENUM, ValueEnum.PRECISION, 0, ValueEnum.DISPLAY_SIZE, extTypeInfo);
} else {
return TYPE_ENUM_UNDEFINED; return TYPE_ENUM_UNDEFINED;
} }
return new TypeInfo(Value.ENUM, ValueEnum.PRECISION, 0, ValueEnum.DISPLAY_SIZE, extTypeInfo);
case Value.INTERVAL_YEAR: case Value.INTERVAL_YEAR:
case Value.INTERVAL_MONTH: case Value.INTERVAL_MONTH:
case Value.INTERVAL_DAY: case Value.INTERVAL_DAY:
......
...@@ -696,9 +696,7 @@ public abstract class Value extends VersionedValue { ...@@ -696,9 +696,7 @@ public abstract class Value extends VersionedValue {
* @return the converted value * @return the converted value
*/ */
public final Value convertTo(int targetType) { public final Value convertTo(int targetType) {
// Use -1 to indicate "default behaviour" where value conversion should not return convertTo(targetType, null, null, null);
// depend on any datatype precision.
return convertTo(targetType, null);
} }
/** /**
...@@ -706,10 +704,8 @@ public abstract class Value extends VersionedValue { ...@@ -706,10 +704,8 @@ public abstract class Value extends VersionedValue {
* @param enumerators the extended type information for the ENUM data type * @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(ExtTypeInfo enumerators) { private Value convertToEnum(ExtTypeInfo enumerators) {
// Use -1 to indicate "default behaviour" where value conversion should not return convertTo(ENUM, null, null, enumerators);
// depend on any datatype precision.
return convertTo(ENUM, -1, null, null, enumerators);
} }
/** /**
...@@ -720,7 +716,7 @@ public abstract class Value extends VersionedValue { ...@@ -720,7 +716,7 @@ public abstract class Value extends VersionedValue {
* @return the converted value * @return the converted value
*/ */
public final Value convertTo(int targetType, Mode mode) { public final Value convertTo(int targetType, Mode mode) {
return convertTo(targetType, -1, mode, null, null); return convertTo(targetType, mode, null, null);
} }
/** /**
...@@ -731,23 +727,20 @@ public abstract class Value extends VersionedValue { ...@@ -731,23 +727,20 @@ public abstract class Value extends VersionedValue {
* @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
* @return the converted value * @return the converted value
*/ */
public Value convertTo(TypeInfo targetType, Mode mode, Object column) { public final Value convertTo(TypeInfo targetType, Mode mode, Object column) {
return convertTo(targetType.getValueType(), -1, mode, column, targetType.getExtTypeInfo()); return convertTo(targetType.getValueType(), mode, column, targetType.getExtTypeInfo());
} }
/** /**
* Convert a value to the specified type. * Convert a value to the specified type.
* *
* @param targetType the type of the returned value * @param targetType the type of the returned value
* @param precision the precision of the column to convert this value to.
* The special constant <code>-1</code> is used to indicate that
* 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 extTypeInfo the extended data type information, or null * @param extTypeInfo the extended data type information, or null
* @return the converted value * @return the converted value
*/ */
public Value convertTo(int targetType, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) { protected Value convertTo(int targetType, 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 (getValueType() == targetType) { if (getValueType() == targetType) {
...@@ -788,7 +781,7 @@ public abstract class Value extends VersionedValue { ...@@ -788,7 +781,7 @@ public abstract class Value extends VersionedValue {
case STRING_IGNORECASE: case STRING_IGNORECASE:
return convertToStringIgnoreCase(mode); return convertToStringIgnoreCase(mode);
case STRING_FIXED: case STRING_FIXED:
return convertToStringFixed(precision, mode); return convertToStringFixed(mode);
case JAVA_OBJECT: case JAVA_OBJECT:
return convertToJavaObject(); return convertToJavaObject();
case ENUM: case ENUM:
...@@ -1177,14 +1170,14 @@ public abstract class Value extends VersionedValue { ...@@ -1177,14 +1170,14 @@ public abstract class Value extends VersionedValue {
return ValueStringIgnoreCase.get(s); return ValueStringIgnoreCase.get(s);
} }
private ValueString convertToStringFixed(int precision, Mode mode) { private ValueString convertToStringFixed(Mode mode) {
String s; String s;
if (getValueType() == BYTES && mode != null && mode.charToBinaryInUtf8) { if (getValueType() == BYTES && mode != null && mode.charToBinaryInUtf8) {
s = new String(getBytesNoCopy(), StandardCharsets.UTF_8); s = new String(getBytesNoCopy(), StandardCharsets.UTF_8);
} else { } else {
s = getString(); s = getString();
} }
return ValueStringFixed.get(s, precision, mode); return ValueStringFixed.get(s);
} }
private ValueJavaObject convertToJavaObject() { private ValueJavaObject convertToJavaObject() {
......
...@@ -137,11 +137,11 @@ public class ValueEnumBase extends Value { ...@@ -137,11 +137,11 @@ public class ValueEnumBase extends Value {
} }
@Override @Override
public Value convertTo(int targetType, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) { protected Value convertTo(int targetType, Mode mode, Object column, ExtTypeInfo extTypeInfo) {
if (targetType == Value.ENUM) { if (targetType == Value.ENUM) {
return extTypeInfo.cast(this); return extTypeInfo.cast(this);
} }
return super.convertTo(targetType, precision, mode, column, extTypeInfo); return super.convertTo(targetType, mode, column, extTypeInfo);
} }
} }
...@@ -346,13 +346,13 @@ public class ValueGeometry extends Value { ...@@ -346,13 +346,13 @@ public class ValueGeometry extends Value {
} }
@Override @Override
public Value convertTo(int targetType, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) { protected Value convertTo(int targetType, Mode mode, Object column, ExtTypeInfo extTypeInfo) {
if (targetType == Value.GEOMETRY) { if (targetType == Value.GEOMETRY) {
return extTypeInfo != null ? extTypeInfo.cast(this) : this; return extTypeInfo != null ? extTypeInfo.cast(this) : this;
} else if (targetType == Value.JAVA_OBJECT) { } else if (targetType == Value.JAVA_OBJECT) {
return this; return this;
} }
return super.convertTo(targetType, precision, mode, column, null); return super.convertTo(targetType, mode, column, null);
} }
} }
...@@ -330,7 +330,7 @@ public class ValueInterval extends Value { ...@@ -330,7 +330,7 @@ public class ValueInterval extends Value {
if (leading == 0L && remaining == 0L) { if (leading == 0L && remaining == 0L) {
return this; return this;
} }
return from(getQualifier(), !negative, leading, remaining); return Value.cache(new ValueInterval(valueType, !negative, leading, remaining));
} }
} }
...@@ -367,16 +367,13 @@ public class ValueLob extends Value { ...@@ -367,16 +367,13 @@ public class ValueLob extends Value {
* except when converting to BLOB or CLOB. * except when converting to BLOB or CLOB.
* *
* @param t the new type * @param t the new type
* @param precision the precision of the column to convert this value to.
* The special constant <code>-1</code> is used to indicate that
* 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 extTypeInfo the extended data type information, or null * @param extTypeInfo the extended data type information, or null
* @return the converted value * @return the converted value
*/ */
@Override @Override
public Value convertTo(int t, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) { protected Value convertTo(int t, 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) {
...@@ -384,7 +381,7 @@ public class ValueLob extends Value { ...@@ -384,7 +381,7 @@ public class ValueLob extends Value {
} else if (t == Value.BLOB) { } else if (t == Value.BLOB) {
return ValueLobDb.createTempBlob(getInputStream(), -1, handler); return ValueLobDb.createTempBlob(getInputStream(), -1, handler);
} }
return super.convertTo(t, precision, mode, column, null); return super.convertTo(t, mode, column, null);
} }
@Override @Override
......
...@@ -205,14 +205,13 @@ public class ValueLobDb extends Value { ...@@ -205,14 +205,13 @@ public class ValueLobDb extends Value {
* except when converting to BLOB or CLOB. * except when converting to BLOB or CLOB.
* *
* @param t the new type * @param t the new type
* @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 extTypeInfo the extended data type information, or null * @param extTypeInfo the extended data type information, or null
* @return the converted value * @return the converted value
*/ */
@Override @Override
public Value convertTo(int t, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) { protected Value convertTo(int t, 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) {
...@@ -230,7 +229,7 @@ public class ValueLobDb extends Value { ...@@ -230,7 +229,7 @@ public class ValueLobDb extends Value {
return ValueLobDb.createSmallLob(t, small); return ValueLobDb.createSmallLob(t, small);
} }
} }
return super.convertTo(t, precision, mode, column, null); return super.convertTo(t, mode, column, null);
} }
@Override @Override
......
...@@ -139,7 +139,7 @@ public class ValueNull extends Value { ...@@ -139,7 +139,7 @@ public class ValueNull extends Value {
} }
@Override @Override
public Value convertTo(int type, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) { protected Value convertTo(int type, Mode mode, Object column, ExtTypeInfo extTypeInfo) {
return this; return this;
} }
......
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
*/ */
package org.h2.value; package org.h2.value;
import java.util.Arrays;
import org.h2.engine.Mode;
import org.h2.engine.SysProperties; import org.h2.engine.SysProperties;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
...@@ -15,18 +13,6 @@ import org.h2.util.StringUtils; ...@@ -15,18 +13,6 @@ import org.h2.util.StringUtils;
*/ */
public class ValueStringFixed extends ValueString { public class ValueStringFixed extends ValueString {
/**
* Special value for the precision in {@link #get(String, int, Mode)} to indicate that the value
* should <i>not</i> be trimmed.
*/
public static final int PRECISION_DO_NOT_TRIM = Integer.MIN_VALUE;
/**
* Special value for the precision in {@link #get(String, int, Mode)} to indicate
* that the default behaviour should of trimming the value should apply.
*/
public static final int PRECISION_TRIM = -1;
private static final ValueStringFixed EMPTY = new ValueStringFixed(""); private static final ValueStringFixed EMPTY = new ValueStringFixed("");
protected ValueStringFixed(String value) { protected ValueStringFixed(String value) {
...@@ -36,6 +22,7 @@ public class ValueStringFixed extends ValueString { ...@@ -36,6 +22,7 @@ public class ValueStringFixed extends ValueString {
private static String trimRight(String s) { private static String trimRight(String s) {
return trimRight(s, 0); return trimRight(s, 0);
} }
private static String trimRight(String s, int minLength) { private static String trimRight(String s, int minLength) {
int endIndex = s.length() - 1; int endIndex = s.length() - 1;
int i = endIndex; int i = endIndex;
...@@ -46,17 +33,6 @@ public class ValueStringFixed extends ValueString { ...@@ -46,17 +33,6 @@ public class ValueStringFixed extends ValueString {
return s; return s;
} }
private static String rightPadWithSpaces(String s, int length) {
int used = s.length();
if (length <= used) {
return s;
}
char[] res = new char[length];
s.getChars(0, used, res, 0);
Arrays.fill(res, used, length, ' ');
return new String(res);
}
@Override @Override
public int getValueType() { public int getValueType() {
return STRING_FIXED; return STRING_FIXED;
...@@ -70,45 +46,7 @@ public class ValueStringFixed extends ValueString { ...@@ -70,45 +46,7 @@ public class ValueStringFixed extends ValueString {
* @return the value * @return the value
*/ */
public static ValueStringFixed get(String s) { public static ValueStringFixed get(String s) {
// Use the special precision constant PRECISION_TRIM to indicate s = trimRight(s);
// default H2 behaviour of trimming the value.
return get(s, PRECISION_TRIM, null);
}
/**
* Get or create a fixed length string value for the given string.
* <p>
* This method will use a {@link Mode}-specific conversion when <code>mode</code> is not
* <code>null</code>.
* Otherwise it will use the default H2 behaviour of trimming the given string if
* <code>precision</code> is not {@link #PRECISION_DO_NOT_TRIM}.
*
* @param s the string
* @param precision if the {@link Mode#padFixedLengthStrings} indicates that strings should
* be padded, this defines the overall length of the (potentially padded) string.
* If the special constant {@link #PRECISION_DO_NOT_TRIM} is used the value will
* not be trimmed.
* @param mode the database mode
* @return the value
*/
public static ValueStringFixed get(String s, int precision, Mode mode) {
// Should fixed strings be padded?
if (mode != null && mode.padFixedLengthStrings) {
if (precision == Integer.MAX_VALUE) {
// CHAR without a length specification is identical to CHAR(1)
precision = 1;
}
if (s.length() < precision) {
// We have to pad
s = rightPadWithSpaces(s, precision);
} else {
// We should trim, because inserting 'A ' into a CHAR(1) is possible!
s = trimRight(s, precision);
}
} else if (precision != PRECISION_DO_NOT_TRIM) {
// Default behaviour of H2
s = trimRight(s);
}
int length = s.length(); int length = s.length();
if (length == 0) { if (length == 0) {
return EMPTY; return EMPTY;
......
...@@ -39,16 +39,6 @@ public class ValueTime extends Value { ...@@ -39,16 +39,6 @@ public class ValueTime extends Value {
*/ */
public static final int MAXIMUM_SCALE = 9; public static final int MAXIMUM_SCALE = 9;
/**
* Get display size for the specified scale.
*
* @param scale scale
* @return display size
*/
public static int getDisplaySize(int scale) {
return scale == 0 ? 8 : 9 + scale;
}
/** /**
* Nanoseconds since midnight * Nanoseconds since midnight
*/ */
......
...@@ -40,16 +40,6 @@ public class ValueTimestamp extends Value { ...@@ -40,16 +40,6 @@ public class ValueTimestamp extends Value {
*/ */
public static final int MAXIMUM_SCALE = 9; public static final int MAXIMUM_SCALE = 9;
/**
* Get display size for the specified scale.
*
* @param scale scale
* @return display size
*/
public static int getDisplaySize(int scale) {
return scale == 0 ? 19 : 20 + scale;
}
/** /**
* A bit field with bits for the year, month, and day (see DateTimeUtils for * A bit field with bits for the year, month, and day (see DateTimeUtils for
* encoding) * encoding)
......
...@@ -45,16 +45,6 @@ public class ValueTimestampTimeZone extends Value { ...@@ -45,16 +45,6 @@ public class ValueTimestampTimeZone extends Value {
*/ */
static final int MAXIMUM_SCALE = ValueTimestamp.MAXIMUM_SCALE; static final int MAXIMUM_SCALE = ValueTimestamp.MAXIMUM_SCALE;
/**
* Get display size for the specified scale.
*
* @param scale scale
* @return display size
*/
public static int getDisplaySize(int scale) {
return scale == 0 ? 25 : 26 + scale;
}
/** /**
* A bit field with bits for the year, month, and day (see DateTimeUtils for * A bit field with bits for the year, month, and day (see DateTimeUtils for
* encoding) * encoding)
......
...@@ -356,7 +356,7 @@ public class TestCases extends TestDb { ...@@ -356,7 +356,7 @@ public class TestCases extends TestDb {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("create table test as select cast(0 as dec(10, 2)) x"); stat.execute("create table test as select cast(0 as dec(10, 2)) x");
ResultSetMetaData meta = stat.executeQuery("select * from test").getMetaData(); ResultSetMetaData meta = stat.executeQuery("select * from test").getMetaData();
assertEquals(2, meta.getPrecision(1)); assertEquals(10, meta.getPrecision(1));
assertEquals(2, meta.getScale(1)); assertEquals(2, meta.getScale(1));
stat.execute("alter table test add column y int"); stat.execute("alter table test add column y int");
stat.execute("drop table test"); stat.execute("drop table test");
......
...@@ -337,6 +337,7 @@ public class TestCompatibility extends TestDb { ...@@ -337,6 +337,7 @@ public class TestCompatibility extends TestDb {
ResultSet rs = stat.executeQuery("SELECT B FROM TEST2"); ResultSet rs = stat.executeQuery("SELECT B FROM TEST2");
assertTrue(rs.next()); assertTrue(rs.next());
assertEquals(bytes, rs.getBytes(1)); assertEquals(bytes, rs.getBytes(1));
assertEquals(bytes, rs.getBytes("B"));
assertEquals(1, stat.executeUpdate("UPDATE TEST2 SET C = B")); assertEquals(1, stat.executeUpdate("UPDATE TEST2 SET C = B"));
testMySQLBytesCheck(stat, string, bytes); testMySQLBytesCheck(stat, string, bytes);
PreparedStatement prep = conn.prepareStatement("UPDATE TEST2 SET C = ?"); PreparedStatement prep = conn.prepareStatement("UPDATE TEST2 SET C = ?");
...@@ -452,6 +453,7 @@ public class TestCompatibility extends TestDb { ...@@ -452,6 +453,7 @@ public class TestCompatibility extends TestDb {
assertTrue(rs.next()); assertTrue(rs.next());
assertEquals(string, rs.getString(1)); assertEquals(string, rs.getString(1));
assertEquals(bytes, rs.getBytes(1)); assertEquals(bytes, rs.getBytes(1));
assertEquals(bytes, rs.getBytes("C"));
} }
private void testSybaseAndMSSQLServer() throws SQLException { private void testSybaseAndMSSQLServer() throws SQLException {
......
...@@ -391,7 +391,7 @@ public class TestCustomDataTypesHandler extends TestDb { ...@@ -391,7 +391,7 @@ public class TestCustomDataTypesHandler extends TestDb {
} }
@Override @Override
public Value convertTo(int targetType, int precision, Mode mode, Object column, ExtTypeInfo extTypeInfo) { protected Value convertTo(int targetType, Mode mode, Object column, ExtTypeInfo extTypeInfo) {
if (getValueType() == targetType) { if (getValueType() == targetType) {
return this; return this;
} }
......
...@@ -17,3 +17,59 @@ SELECT COLUMN_NAME, DATA_TYPE, TYPE_NAME, COLUMN_TYPE FROM INFORMATION_SCHEMA.CO ...@@ -17,3 +17,59 @@ SELECT COLUMN_NAME, DATA_TYPE, TYPE_NAME, COLUMN_TYPE FROM INFORMATION_SCHEMA.CO
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
CREATE TABLE TEST(C CHAR(2));
> ok
INSERT INTO TEST VALUES 'aa', 'b';
> update count: 2
SELECT * FROM TEST WHERE C = 'b';
>> b
SELECT * FROM TEST WHERE C = 'b ';
>> b
SELECT * FROM TEST WHERE C = 'b ';
>> b
SELECT C || 'x' V FROM TEST;
> V
> ---
> aax
> bx
> rows: 2
DROP TABLE TEST;
> ok
SET MODE PostgreSQL;
> ok
CREATE TABLE TEST(C CHAR(2));
> ok
INSERT INTO TEST VALUES 'aa', 'b';
> update count: 2
SELECT * FROM TEST WHERE C = 'b';
>> b
SELECT * FROM TEST WHERE C = 'b ';
>> b
SELECT * FROM TEST WHERE C = 'b ';
>> b
SELECT C || 'x' V FROM TEST;
> V
> ---
> aax
> bx
> rows: 2
DROP TABLE TEST;
> ok
SET MODE Regular;
> ok
...@@ -253,8 +253,8 @@ SELECT * FROM V3; ...@@ -253,8 +253,8 @@ SELECT * FROM V3;
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 DOMAIN_CATALOG DOMAIN_SCHEMA DOMAIN_NAME 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 DOMAIN_CATALOG DOMAIN_SCHEMA DOMAIN_NAME 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 null null 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 null null null YES 1111 10 10 10 10 0 null null null Unicode OFF ENUM 1 FALSE 50 null null ENUM('A', 'B') null TRUE
> SCRIPT PUBLIC V E 1 null null null 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 null null null YES 1111 10 10 10 10 0 null null null Unicode OFF ENUM 1 FALSE 50 null null ENUM('A', 'B') null TRUE
> SCRIPT PUBLIC V1 E 1 null null null null YES 4 10 10 10 10 0 null null null Unicode OFF INTEGER 1 FALSE 50 null null INTEGER null TRUE > SCRIPT PUBLIC V1 E 1 null null null null YES 4 10 10 10 10 0 null null null Unicode OFF INTEGER 1 FALSE 50 null null INTEGER null TRUE
> SCRIPT PUBLIC V2 E 1 null null null null YES 4 10 10 10 10 0 null null null Unicode OFF INTEGER 1 FALSE 50 null null INTEGER null TRUE > SCRIPT PUBLIC V2 E 1 null null null null YES 4 10 10 10 10 0 null null null Unicode OFF INTEGER 1 FALSE 50 null null INTEGER null TRUE
> SCRIPT PUBLIC V3 E 1 null null null null YES 4 10 10 10 10 0 null null null Unicode OFF INTEGER 1 FALSE 50 null null INTEGER null TRUE > SCRIPT PUBLIC V3 E 1 null null null null YES 4 10 10 10 10 0 null null null Unicode OFF INTEGER 1 FALSE 50 null null INTEGER null TRUE
......
...@@ -6084,18 +6084,18 @@ SELECT ID FROM TEST WHERE XVI LIKE 'abc%'; ...@@ -6084,18 +6084,18 @@ SELECT ID FROM TEST WHERE XVI LIKE 'abc%';
> 3 > 3
> rows: 1 > rows: 1
SELECT 'abc', 'Papa Joe''s', CAST(-1 AS SMALLINT), CAST(2 AS BIGINT), CAST(0 AS DOUBLE), CAST('0a0f' AS BINARY), CAST(125 AS TINYINT), TRUE, FALSE FROM TEST WHERE ID=1; SELECT 'abc', 'Papa Joe''s', CAST(-1 AS SMALLINT), CAST(2 AS BIGINT), CAST(0 AS DOUBLE), CAST('0a0f' AS BINARY) B, CAST(125 AS TINYINT), TRUE, FALSE FROM TEST WHERE ID=1;
> 'abc' 'Papa Joe''s' -1 2 0.0 X'0a0f' 125 TRUE FALSE > 'abc' 'Papa Joe''s' -1 2 0.0 B 125 TRUE FALSE
> ----- ------------- -- - --- ------- --- ---- ----- > ----- ------------- -- - --- ---- --- ---- -----
> abc Papa Joe's -1 2 0.0 0a0f 125 TRUE FALSE > abc Papa Joe's -1 2 0.0 0a0f 125 TRUE FALSE
> rows: 1 > rows: 1
-- ' This apostrophe is here to fix syntax highlighting in the text editors. -- ' This apostrophe is here to fix syntax highlighting in the text editors.
SELECT CAST('abcd' AS VARCHAR(255)), CAST('ef_gh' AS VARCHAR(3)); SELECT CAST('abcd' AS VARCHAR(255)) C1, CAST('ef_gh' AS VARCHAR(3)) C2;
> 'abcd' 'ef_' > C1 C2
> ------ ----- > ---- ---
> abcd ef_ > abcd ef_
> rows: 1 > rows: 1
DROP TABLE TEST; DROP TABLE TEST;
......
...@@ -414,7 +414,11 @@ public class TestValue extends TestDb { ...@@ -414,7 +414,11 @@ public class TestValue extends TestDb {
ValueJavaObject voString = ValueJavaObject.getNoCopy( ValueJavaObject voString = ValueJavaObject.getNoCopy(
new String("This is not a ValueUuid object"), null, null); new String("This is not a ValueUuid object"), null, null);
assertThrows(DbException.class, voString).convertTo(Value.UUID); try {
voString.convertTo(Value.UUID);
fail();
} catch (DbException expected) {
}
} }
private void testModulusDouble() { private void testModulusDouble() {
......
...@@ -806,4 +806,4 @@ econd irst bcef ordinality nord unnest ...@@ -806,4 +806,4 @@ econd irst bcef ordinality nord unnest
analyst occupation distributive josaph aor engineer sajeewa isuru randil kevin doctor businessman artist ashan analyst occupation distributive josaph aor engineer sajeewa isuru randil kevin doctor businessman artist ashan
corrupts splitted disruption unintentional octets preconditions predicates subq objectweb insn opcodes corrupts splitted disruption unintentional octets preconditions predicates subq objectweb insn opcodes
preserves masking holder unboxing avert iae transformed subtle reevaluate exclusions subclause ftbl rgr preserves masking holder unboxing avert iae transformed subtle reevaluate exclusions subclause ftbl rgr
presorted inclusion contexts presorted inclusion contexts aax
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论