提交 fb7e94c8 authored 作者: Noel Grandin's avatar Noel Grandin

Merge remote-tracking branch 'upstream/master' into testing_pagestore

...@@ -95,15 +95,6 @@ To run the build tool in shell mode, use the command line option <code>-</code>: ...@@ -95,15 +95,6 @@ To run the build tool in shell mode, use the command line option <code>-</code>:
./build.sh - ./build.sh -
</pre> </pre>
<h3>Switching the Source Code</h3>
<p>
The source code uses Java 7 features.
To switch the source code to the installed version of Java, run:
</p>
<pre>
build switchSource
</pre>
<h2 id="build_targets">Build Targets</h2> <h2 id="build_targets">Build Targets</h2>
<p> <p>
The build system can generate smaller jar files as well. The following targets are currently supported: The build system can generate smaller jar files as well. The following targets are currently supported:
......
...@@ -21,23 +21,39 @@ Change Log ...@@ -21,23 +21,39 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Issue #1106: Get rid of SwitchSource
</li>
<li>PR #1105: Assorted minor changes
</li>
<li>Issue #1102: CREATE SYNONYM rejects valid definition
</li>
<li>Issue #1048: 1.4.197 regression. org.h2.jdbc.JdbcSQLException: Timeout trying to lock table "SYS"
</li>
<li>PR #1101: Move some tests in better place and add an additional test for 2PC
</li>
<li>PR #1100: Fix Insert.prepareUpdateCondition() for PageStore
</li>
<li>PR #1098: Fix some issues with NULLS FIRST / LAST
</li>
<li>Issue #1089: Parser does not quote words INTERSECTS, DUAL, TOP <li>Issue #1089: Parser does not quote words INTERSECTS, DUAL, TOP
</li> </li>
<li>Issue #230: Renaming a column does not update foreign key constraint <li>Issue #230: Renaming a column does not update foreign key constraint
</li>
<li>Issue #1091 Get rid if the New class
</li> </li>
<li>PR #1087: improve performance of planning large queries <li>PR #1087: improve performance of planning large queries
</li> </li>
<li>Issue #394: Recover tool places COLLATION and BINARY_COLLATION after temporary tables <li>Issue #394: Recover tool places COLLATION and BINARY_COLLATION after temporary tables
</li> </li>
<li>Improve the script-based unit testing to check the error code of the exception thrown. <li>Improve the script-based unit testing to check the error code of the exception thrown.
</li> </li>
<li>Issue #1041: Support OR syntax while creating trigger <li>Issue #1041: Support OR syntax while creating trigger
</li> </li>
<li>Issue #1023: MVCC and existing page store file <li>Issue #1023: MVCC and existing page store file
</li> </li>
<li>Issue #1003: Decrypting database with incorrect password renders the database corrupt <li>Issue #1003: Decrypting database with incorrect password renders the database corrupt
</li> </li>
<li>Issue #873: No error when `=` in equal condition when column is not of array type <li>Issue #873: No error when `=` in equal condition when column is not of array type
</li> </li>
<li>Issue #1069: Failed to add DATETIME(3) column since 1.4.197 <li>Issue #1069: Failed to add DATETIME(3) column since 1.4.197
</li> </li>
......
...@@ -35,7 +35,7 @@ public class Driver implements java.sql.Driver, JdbcDriverBackwardsCompat { ...@@ -35,7 +35,7 @@ public class Driver implements java.sql.Driver, JdbcDriverBackwardsCompat {
private static final ThreadLocal<Connection> DEFAULT_CONNECTION = private static final ThreadLocal<Connection> DEFAULT_CONNECTION =
new ThreadLocal<>(); new ThreadLocal<>();
private static volatile boolean registered; private static boolean registered;
static { static {
load(); load();
......
...@@ -4465,11 +4465,12 @@ public class Parser { ...@@ -4465,11 +4465,12 @@ public class Parser {
precision = displaySize = ValueTimestampTimeZone.getDisplaySize(originalScale); precision = displaySize = ValueTimestampTimeZone.getDisplaySize(originalScale);
break; break;
} }
} else if (original.equals("DATETIME")) { } else if (original.equals("DATETIME") || original.equals("DATETIME2")) {
if (readIf("(")) { if (readIf("(")) {
originalScale = readPositiveInt(); originalScale = readPositiveInt();
if (originalScale > ValueTime.MAXIMUM_SCALE) { if (originalScale > ValueTime.MAXIMUM_SCALE) {
throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION, Integer.toString(originalScale)); throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION,
Integer.toString(originalScale));
} }
read(")"); read(")");
scale = originalScale; scale = originalScale;
......
...@@ -56,7 +56,7 @@ public class CreateSynonym extends SchemaCommand { ...@@ -56,7 +56,7 @@ public class CreateSynonym extends SchemaCommand {
data.session = session; data.session = session;
db.lockMeta(session); db.lockMeta(session);
if (data.synonymForSchema.findTableOrView(session, data.synonymName) != null) { if (getSchema().findTableOrView(session, data.synonymName) != null) {
throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1, data.synonymName); throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1, data.synonymName);
} }
......
...@@ -24,6 +24,7 @@ import org.h2.expression.ExpressionColumn; ...@@ -24,6 +24,7 @@ import org.h2.expression.ExpressionColumn;
import org.h2.expression.Parameter; import org.h2.expression.Parameter;
import org.h2.expression.SequenceValue; import org.h2.expression.SequenceValue;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.index.PageDataIndex;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.mvstore.db.MVPrimaryIndex; import org.h2.mvstore.db.MVPrimaryIndex;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
...@@ -423,11 +424,18 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -423,11 +424,18 @@ public class Insert extends Prepared implements ResultTarget {
// It returns all of the columns in the table when we call // It returns all of the columns in the table when we call
// getIndexColumns() or getColumns(). // getIndexColumns() or getColumns().
// Don't have time right now to fix that, so just special-case it. // Don't have time right now to fix that, so just special-case it.
// PageDataIndex has the same problem.
final Column[] indexedColumns; final Column[] indexedColumns;
if (foundIndex instanceof MVPrimaryIndex) { if (foundIndex instanceof MVPrimaryIndex) {
MVPrimaryIndex foundMV = (MVPrimaryIndex) foundIndex; MVPrimaryIndex foundMV = (MVPrimaryIndex) foundIndex;
indexedColumns = new Column[] { foundMV.getIndexColumns()[foundMV indexedColumns = new Column[] { foundMV.getIndexColumns()[foundMV
.getMainIndexColumn()].column }; .getMainIndexColumn()].column };
} else if (foundIndex instanceof PageDataIndex) {
PageDataIndex foundPD = (PageDataIndex) foundIndex;
int mainIndexColumn = foundPD.getMainIndexColumn();
indexedColumns = mainIndexColumn >= 0
? new Column[] { foundPD.getIndexColumns()[mainIndexColumn].column }
: foundIndex.getColumns();
} else { } else {
indexedColumns = foundIndex.getColumns(); indexedColumns = foundIndex.getColumns();
} }
......
...@@ -33,9 +33,7 @@ class DatabaseCloser extends Thread { ...@@ -33,9 +33,7 @@ class DatabaseCloser extends Thread {
* database has been closed, or after a session has been created. * database has been closed, or after a session has been created.
*/ */
void reset() { void reset() {
synchronized (this) { databaseRef = null;
databaseRef = null;
}
} }
@Override @Override
...@@ -53,10 +51,9 @@ class DatabaseCloser extends Thread { ...@@ -53,10 +51,9 @@ class DatabaseCloser extends Thread {
} }
} }
Database database = null; Database database = null;
synchronized (this) { WeakReference<Database> ref = this.databaseRef;
if (databaseRef != null) { if (ref != null) {
database = databaseRef.get(); database = ref.get();
}
} }
if (database != null) { if (database != null) {
try { try {
......
...@@ -329,10 +329,10 @@ public class DbSettings extends SettingsBase { ...@@ -329,10 +329,10 @@ public class DbSettings extends SettingsBase {
/** /**
* Database setting <code>MV_STORE</code> * Database setting <code>MV_STORE</code>
* (default: false for version 1.3, true for version 1.4).<br /> * (default: true).<br />
* Use the MVStore storage engine. * Use the MVStore storage engine.
*/ */
public boolean mvStore = get("MV_STORE", Constants.VERSION_MINOR >= 4); public boolean mvStore = get("MV_STORE", true);
/** /**
* Database setting <code>COMPRESS</code> * Database setting <code>COMPRESS</code>
......
...@@ -200,14 +200,14 @@ public class Mode { ...@@ -200,14 +200,14 @@ public class Mode {
private final String name; private final String name;
private ModeEnum modeEnum; private final ModeEnum modeEnum;
static { static {
Mode mode = new Mode(ModeEnum.REGULAR.name()); Mode mode = new Mode(ModeEnum.REGULAR);
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
add(mode); add(mode);
mode = new Mode(ModeEnum.DB2.name()); mode = new Mode(ModeEnum.DB2);
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.sysDummy1 = true; mode.sysDummy1 = true;
mode.isolationLevelInSelectOrInsertStatement = true; mode.isolationLevelInSelectOrInsertStatement = true;
...@@ -221,7 +221,7 @@ public class Mode { ...@@ -221,7 +221,7 @@ public class Mode {
mode.allowDB2TimestampFormat = true; mode.allowDB2TimestampFormat = true;
add(mode); add(mode);
mode = new Mode(ModeEnum.Derby.name()); mode = new Mode(ModeEnum.Derby);
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.uniqueIndexNullsHandling = UniqueIndexNullsHandling.FORBID_ANY_DUPLICATES; mode.uniqueIndexNullsHandling = UniqueIndexNullsHandling.FORBID_ANY_DUPLICATES;
mode.sysDummy1 = true; mode.sysDummy1 = true;
...@@ -230,7 +230,7 @@ public class Mode { ...@@ -230,7 +230,7 @@ public class Mode {
mode.supportedClientInfoPropertiesRegEx = null; mode.supportedClientInfoPropertiesRegEx = null;
add(mode); add(mode);
mode = new Mode(ModeEnum.HSQLDB.name()); mode = new Mode(ModeEnum.HSQLDB);
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.convertOnlyToSmallerScale = true; mode.convertOnlyToSmallerScale = true;
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
...@@ -243,7 +243,7 @@ public class Mode { ...@@ -243,7 +243,7 @@ public class Mode {
mode.supportedClientInfoPropertiesRegEx = null; mode.supportedClientInfoPropertiesRegEx = null;
add(mode); add(mode);
mode = new Mode(ModeEnum.MSSQLServer.name()); mode = new Mode(ModeEnum.MSSQLServer);
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.squareBracketQuotedNames = true; mode.squareBracketQuotedNames = true;
mode.uniqueIndexNullsHandling = UniqueIndexNullsHandling.FORBID_ANY_DUPLICATES; mode.uniqueIndexNullsHandling = UniqueIndexNullsHandling.FORBID_ANY_DUPLICATES;
...@@ -255,7 +255,7 @@ public class Mode { ...@@ -255,7 +255,7 @@ public class Mode {
mode.supportedClientInfoPropertiesRegEx = null; mode.supportedClientInfoPropertiesRegEx = null;
add(mode); add(mode);
mode = new Mode(ModeEnum.MySQL.name()); mode = new Mode(ModeEnum.MySQL);
mode.convertInsertNullToZero = true; mode.convertInsertNullToZero = true;
mode.indexDefinitionInCreateTable = true; mode.indexDefinitionInCreateTable = true;
mode.lowerCaseIdentifiers = true; mode.lowerCaseIdentifiers = true;
...@@ -271,7 +271,7 @@ public class Mode { ...@@ -271,7 +271,7 @@ public class Mode {
mode.prohibitEmptyInPredicate = true; mode.prohibitEmptyInPredicate = true;
add(mode); add(mode);
mode = new Mode(ModeEnum.Oracle.name()); mode = new Mode(ModeEnum.Oracle);
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.convertOnlyToSmallerScale = true; mode.convertOnlyToSmallerScale = true;
mode.uniqueIndexNullsHandling = UniqueIndexNullsHandling.ALLOW_DUPLICATES_WITH_ALL_NULLS; mode.uniqueIndexNullsHandling = UniqueIndexNullsHandling.ALLOW_DUPLICATES_WITH_ALL_NULLS;
...@@ -286,7 +286,7 @@ public class Mode { ...@@ -286,7 +286,7 @@ public class Mode {
mode.typeByNameMap.put("DATE", DataType.getDataType(Value.TIMESTAMP)); mode.typeByNameMap.put("DATE", DataType.getDataType(Value.TIMESTAMP));
add(mode); add(mode);
mode = new Mode(ModeEnum.PostgreSQL.name()); mode = new Mode(ModeEnum.PostgreSQL);
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
mode.systemColumns = true; mode.systemColumns = true;
...@@ -309,16 +309,16 @@ public class Mode { ...@@ -309,16 +309,16 @@ public class Mode {
mode.disallowedTypes = disallowedTypes; mode.disallowedTypes = disallowedTypes;
add(mode); add(mode);
mode = new Mode(ModeEnum.Ignite.name()); mode = new Mode(ModeEnum.Ignite);
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
mode.allowAffinityKey = true; mode.allowAffinityKey = true;
mode.indexDefinitionInCreateTable = true; mode.indexDefinitionInCreateTable = true;
add(mode); add(mode);
} }
private Mode(String name) { private Mode(ModeEnum modeEnum) {
this.name = name; this.name = modeEnum.name();
this.modeEnum = ModeEnum.valueOf(name); this.modeEnum = modeEnum;
} }
private static void add(Mode mode) { private static void add(Mode mode) {
......
...@@ -406,11 +406,17 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -406,11 +406,17 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
public void removeLocalTempTable(Table table) { public void removeLocalTempTable(Table table) {
// Exception thrown in org.h2.engine.Database.removeMeta if line below // Exception thrown in org.h2.engine.Database.removeMeta if line below
// is missing with TestGeneralCommonTableQueries // is missing with TestGeneralCommonTableQueries
database.lockMeta(this); boolean wasLocked = database.lockMeta(this);
modificationId++; try {
localTempTables.remove(table.getName()); modificationId++;
synchronized (database) { localTempTables.remove(table.getName());
table.removeChildrenAndResources(this); synchronized (database) {
table.removeChildrenAndResources(this);
}
} finally {
if (!wasLocked) {
database.unlockMeta(this);
}
} }
} }
......
...@@ -93,26 +93,19 @@ public class SysProperties { ...@@ -93,26 +93,19 @@ public class SysProperties {
Utils.getProperty("h2.bindAddress", null); Utils.getProperty("h2.bindAddress", null);
/** /**
* System property <code>h2.check</code> (default: true).<br /> * System property <code>h2.check</code>
* (default: true for JDK/JRE, false for Android).<br />
* Assertions in the database engine. * Assertions in the database engine.
*/ */
//## CHECK ##
public static final boolean CHECK = public static final boolean CHECK =
Utils.getProperty("h2.check", true); Utils.getProperty("h2.check", !"0.9".equals(Utils.getProperty("java.specification.version", null)));
/*/
public static final boolean CHECK = false;
//*/
/** /**
* System property <code>h2.check2</code> (default: false).<br /> * System property <code>h2.check2</code> (default: false).<br />
* Additional assertions in the database engine. * Additional assertions in the database engine.
*/ */
//## CHECK ##
public static final boolean CHECK2 = public static final boolean CHECK2 =
Utils.getProperty("h2.check2", false); Utils.getProperty("h2.check2", false);
/*/
public static final boolean CHECK2 = false;
//*/
/** /**
* System property <code>h2.clientTraceDirectory</code> (default: * System property <code>h2.clientTraceDirectory</code> (default:
...@@ -332,12 +325,11 @@ public class SysProperties { ...@@ -332,12 +325,11 @@ public class SysProperties {
/** /**
* System property <code>h2.oldStyleOuterJoin</code> * System property <code>h2.oldStyleOuterJoin</code>
* (default: true for version 1.3, false for version 1.4).<br /> * (default: false).<br />
* Limited support for the old-style Oracle outer join with "(+)". * Limited support for the old-style Oracle outer join with "(+)".
*/ */
public static final boolean OLD_STYLE_OUTER_JOIN = public static final boolean OLD_STYLE_OUTER_JOIN =
Utils.getProperty("h2.oldStyleOuterJoin", Utils.getProperty("h2.oldStyleOuterJoin", false);
Constants.VERSION_MINOR < 4);
/** /**
* System property {@code h2.oldResultSetGetObject}, {@code true} by default. * System property {@code h2.oldResultSetGetObject}, {@code true} by default.
...@@ -439,13 +431,12 @@ public class SysProperties { ...@@ -439,13 +431,12 @@ public class SysProperties {
/** /**
* System property <code>h2.sortBinaryUnsigned</code> * System property <code>h2.sortBinaryUnsigned</code>
* (default: false with version 1.3, true with version 1.4).<br /> * (default: true).<br />
* Whether binary data should be sorted in unsigned mode * Whether binary data should be sorted in unsigned mode
* (0xff is larger than 0x00). * (0xff is larger than 0x00).
*/ */
public static final boolean SORT_BINARY_UNSIGNED = public static final boolean SORT_BINARY_UNSIGNED =
Utils.getProperty("h2.sortBinaryUnsigned", Utils.getProperty("h2.sortBinaryUnsigned", true);
Constants.VERSION_MINOR >= 4);
/** /**
* System property <code>h2.sortNullsHigh</code> (default: false).<br /> * System property <code>h2.sortNullsHigh</code> (default: false).<br />
...@@ -493,13 +484,12 @@ public class SysProperties { ...@@ -493,13 +484,12 @@ public class SysProperties {
/** /**
* System property <code>h2.implicitRelativePath</code> * System property <code>h2.implicitRelativePath</code>
* (default: true for version 1.3, false for version 1.4).<br /> * (default: false).<br />
* If disabled, relative paths in database URLs need to be written as * If disabled, relative paths in database URLs need to be written as
* jdbc:h2:./test instead of jdbc:h2:test. * jdbc:h2:./test instead of jdbc:h2:test.
*/ */
public static final boolean IMPLICIT_RELATIVE_PATH = public static final boolean IMPLICIT_RELATIVE_PATH =
Utils.getProperty("h2.implicitRelativePath", Utils.getProperty("h2.implicitRelativePath", false);
Constants.VERSION_MINOR < 4);
/** /**
* System property <code>h2.urlMap</code> (default: null).<br /> * System property <code>h2.urlMap</code> (default: null).<br />
......
...@@ -88,7 +88,7 @@ public abstract class Page implements Cloneable ...@@ -88,7 +88,7 @@ public abstract class Page implements Cloneable
MEMORY_POINTER + // children MEMORY_POINTER + // children
MEMORY_ARRAY + // Object[] children MEMORY_ARRAY + // Object[] children
8; // totalCount 8; // totalCount
/** /**
* The estimated number of bytes used per empty leaf page. * The estimated number of bytes used per empty leaf page.
*/ */
......
...@@ -288,7 +288,7 @@ public class ObjectDataType implements DataType { ...@@ -288,7 +288,7 @@ public class ObjectDataType implements DataType {
* @return true if yes * @return true if yes
*/ */
static boolean isBigInteger(Object obj) { static boolean isBigInteger(Object obj) {
return obj instanceof BigInteger && obj.getClass() == BigInteger.class; return obj != null && obj.getClass() == BigInteger.class;
} }
/** /**
...@@ -298,7 +298,7 @@ public class ObjectDataType implements DataType { ...@@ -298,7 +298,7 @@ public class ObjectDataType implements DataType {
* @return true if yes * @return true if yes
*/ */
static boolean isBigDecimal(Object obj) { static boolean isBigDecimal(Object obj) {
return obj instanceof BigDecimal && obj.getClass() == BigDecimal.class; return obj != null && obj.getClass() == BigDecimal.class;
} }
/** /**
...@@ -308,7 +308,7 @@ public class ObjectDataType implements DataType { ...@@ -308,7 +308,7 @@ public class ObjectDataType implements DataType {
* @return true if yes * @return true if yes
*/ */
static boolean isDate(Object obj) { static boolean isDate(Object obj) {
return obj instanceof Date && obj.getClass() == Date.class; return obj != null && obj.getClass() == Date.class;
} }
/** /**
...@@ -1247,21 +1247,13 @@ public class ObjectDataType implements DataType { ...@@ -1247,21 +1247,13 @@ public class ObjectDataType implements DataType {
Class<?> type = obj.getClass().getComponentType(); Class<?> type = obj.getClass().getComponentType();
if (type.isPrimitive()) { if (type.isPrimitive()) {
int len = Array.getLength(obj); int len = Array.getLength(obj);
if (type == boolean.class) { if (type == boolean.class || type == byte.class) {
size += len; size += len;
} else if (type == byte.class) { } else if (type == char.class || type == short.class) {
size += len;
} else if (type == char.class) {
size += len * 2;
} else if (type == short.class) {
size += len * 2; size += len * 2;
} else if (type == int.class) { } else if (type == int.class || type == float.class) {
size += len * 4; size += len * 4;
} else if (type == float.class) { } else if (type == double.class || type == long.class) {
size += len * 4;
} else if (type == double.class) {
size += len * 8;
} else if (type == long.class) {
size += len * 8; size += len * 8;
} }
} else { } else {
......
...@@ -1420,7 +1420,8 @@ public class WebApp { ...@@ -1420,7 +1420,8 @@ public class WebApp {
} }
private static boolean isBuiltIn(String sql, String builtIn) { private static boolean isBuiltIn(String sql, String builtIn) {
return StringUtils.startsWithIgnoreCase(sql, builtIn); int len = builtIn.length();
return sql.length() >= len && sql.regionMatches(true, 0, builtIn, 0, len);
} }
private String executeLoop(Connection conn, int count, String sql) private String executeLoop(Connection conn, int count, String sql)
......
差异被折叠。
...@@ -649,8 +649,8 @@ public class Recover extends Tool implements DataHandler { ...@@ -649,8 +649,8 @@ public class Recover extends Tool implements DataHandler {
} }
} }
} }
// Have to do these before the tables because settings like COLLATION may affect some of them, // Have to do these before the tables because settings like COLLATION may affect
// and we can't change settings after we have created user tables // some of them, and we can't change settings after we have created user tables
writeSchemaSET(writer); writeSchemaSET(writer);
writer.println("---- Table Data ----"); writer.println("---- Table Data ----");
for (String mapName : mv.getMapNames()) { for (String mapName : mv.getMapNames()) {
......
...@@ -110,20 +110,6 @@ public class StringUtils { ...@@ -110,20 +110,6 @@ public class StringUtils {
return s.toLowerCase(Locale.ENGLISH); return s.toLowerCase(Locale.ENGLISH);
} }
/**
* Check is a string starts with another string, ignoring the case.
*
* @param s the string to check (must be longer than start)
* @param start the prefix of s
* @return true if start is a prefix of s
*/
public static boolean startsWithIgnoreCase(String s, String start) {
if (s.length() < start.length()) {
return false;
}
return s.substring(0, start.length()).equalsIgnoreCase(start);
}
/** /**
* Convert a string to a SQL literal. Null is converted to NULL. The text is * Convert a string to a SQL literal. Null is converted to NULL. The text is
* enclosed in single quotes. If there are any special characters, the * enclosed in single quotes. If there are any special characters, the
......
...@@ -57,7 +57,7 @@ public class ValueDecimal extends Value { ...@@ -57,7 +57,7 @@ public class ValueDecimal extends Value {
private ValueDecimal(BigDecimal value) { private ValueDecimal(BigDecimal value) {
if (value == null) { if (value == null) {
throw new IllegalArgumentException("null"); throw new IllegalArgumentException("null");
} else if (!value.getClass().equals(BigDecimal.class)) { } else if (value.getClass() != BigDecimal.class) {
throw DbException.get(ErrorCode.INVALID_CLASS_2, throw DbException.get(ErrorCode.INVALID_CLASS_2,
BigDecimal.class.getName(), value.getClass().getName()); BigDecimal.class.getName(), value.getClass().getName());
} }
......
...@@ -10,6 +10,7 @@ import java.sql.SQLException; ...@@ -10,6 +10,7 @@ import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
import org.h2.engine.Mode; import org.h2.engine.Mode;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.util.Bits;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.util.Utils; import org.h2.util.Utils;
import org.locationtech.jts.geom.CoordinateSequence; import org.locationtech.jts.geom.CoordinateSequence;
...@@ -71,7 +72,11 @@ public class ValueGeometry extends Value { ...@@ -71,7 +72,11 @@ public class ValueGeometry extends Value {
* @return the value * @return the value
*/ */
public static ValueGeometry getFromGeometry(Object o) { public static ValueGeometry getFromGeometry(Object o) {
return get((Geometry) o); /*
* Do not pass untrusted source geometry object to a cache, use only its WKB
* representation. Geometries are not fully immutable.
*/
return get(convertToWKB((Geometry) o));
} }
private static ValueGeometry get(Geometry g) { private static ValueGeometry get(Geometry g) {
...@@ -143,24 +148,37 @@ public class ValueGeometry extends Value { ...@@ -143,24 +148,37 @@ public class ValueGeometry extends Value {
public Geometry getGeometry() { public Geometry getGeometry() {
Geometry geometry = getGeometryNoCopy(); Geometry geometry = getGeometryNoCopy();
Geometry copy = geometry.copy(); Geometry copy = geometry.copy();
/*
* Geometry factory is not preserved in WKB format, but SRID is preserved.
*
* We use a new factory to read geometries from WKB with default SRID value of
* 0.
*
* Geometry.copy() copies the geometry factory and copied value has SRID form
* the factory instead of original SRID value. So we need to copy SRID here with
* non-recommended (but not deprecated) setSRID() method.
*/
copy.setSRID(geometry.getSRID());
return copy; return copy;
} }
public Geometry getGeometryNoCopy() { public Geometry getGeometryNoCopy() {
if (geometry == null) { if (geometry == null) {
try { try {
geometry = new WKBReader().read(bytes); int srid = 0;
getSRID: if (bytes.length >= 9) {
boolean bigEndian;
switch (bytes[0]) {
case 0:
bigEndian = true;
break;
case 1:
bigEndian = false;
break;
default:
break getSRID;
}
if ((bytes[bigEndian ? 1 : 4] & 0x20) != 0) {
srid = Bits.readInt(bytes, 5);
if (!bigEndian) {
srid = Integer.reverseBytes(srid);
}
}
}
/*
* No-arg WKBReader() constructor instantiates a new GeometryFactory and a new
* PrecisionModel anyway, so special case for srid == 0 is not needed.
*/
geometry = new WKBReader(new GeometryFactory(new PrecisionModel(), srid)).read(bytes);
} catch (ParseException ex) { } catch (ParseException ex) {
throw DbException.convert(ex); throw DbException.convert(ex);
} }
......
...@@ -286,7 +286,7 @@ java org.h2.test.TestAll timer ...@@ -286,7 +286,7 @@ java org.h2.test.TestAll timer
/** /**
* Whether the MVStore storage is used. * Whether the MVStore storage is used.
*/ */
public boolean mvStore = Constants.VERSION_MINOR >= 4; public boolean mvStore = true;
/** /**
* If the test should run with many rows. * If the test should run with many rows.
......
...@@ -20,7 +20,7 @@ import java.util.List; ...@@ -20,7 +20,7 @@ import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.Constants; import org.h2.engine.SysProperties;
import org.h2.store.fs.FileUtils; import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase; import org.h2.test.TestBase;
...@@ -1265,23 +1265,21 @@ public class TestCases extends TestBase { ...@@ -1265,23 +1265,21 @@ public class TestCases extends TestBase {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
ResultSet rs; ResultSet rs;
// test the default (SIGNED) // test the SIGNED mode
if (Constants.VERSION_MINOR < 4) { stat.execute("SET BINARY_COLLATION SIGNED");
stat.execute("create table bin( x binary(1) );"); stat.execute("create table bin( x binary(1) );");
stat.execute("insert into bin(x) values (x'09'),(x'0a'),(x'99'),(x'aa');"); stat.execute("insert into bin(x) values (x'09'),(x'0a'),(x'99'),(x'aa');");
rs = stat.executeQuery("select * from bin order by x;"); rs = stat.executeQuery("select * from bin order by x;");
rs.next(); rs.next();
assertEquals("99", rs.getString(1)); assertEquals("99", rs.getString(1));
rs.next(); rs.next();
assertEquals("aa", rs.getString(1)); assertEquals("aa", rs.getString(1));
rs.next(); rs.next();
assertEquals("09", rs.getString(1)); assertEquals("09", rs.getString(1));
rs.next(); rs.next();
assertEquals("0a", rs.getString(1)); assertEquals("0a", rs.getString(1));
stat.execute("drop table bin"); stat.execute("drop table bin");
} // test UNSIGNED mode (default)
// test UNSIGNED mode
stat.execute("SET BINARY_COLLATION UNSIGNED"); stat.execute("SET BINARY_COLLATION UNSIGNED");
stat.execute("create table bin( x binary(1) );"); stat.execute("create table bin( x binary(1) );");
stat.execute("insert into bin(x) values (x'09'),(x'0a'),(x'99'),(x'aa');"); stat.execute("insert into bin(x) values (x'09'),(x'0a'),(x'99'),(x'aa');");
...@@ -1294,6 +1292,9 @@ public class TestCases extends TestBase { ...@@ -1294,6 +1292,9 @@ public class TestCases extends TestBase {
assertEquals("99", rs.getString(1)); assertEquals("99", rs.getString(1));
rs.next(); rs.next();
assertEquals("aa", rs.getString(1)); assertEquals("aa", rs.getString(1));
stat.execute("drop table bin");
stat.execute("SET BINARY_COLLATION "
+ (SysProperties.SORT_BINARY_UNSIGNED ? "UNSIGNED" : "SIGNED"));
conn.close(); conn.close();
} }
......
...@@ -35,7 +35,6 @@ public class TestCompatibility extends TestBase { ...@@ -35,7 +35,6 @@ public class TestCompatibility extends TestBase {
public void test() throws SQLException { public void test() throws SQLException {
deleteDb("compatibility"); deleteDb("compatibility");
testOnDuplicateKey();
testCaseSensitiveIdentifiers(); testCaseSensitiveIdentifiers();
testKeyAsColumnInMySQLMode(); testKeyAsColumnInMySQLMode();
...@@ -56,42 +55,6 @@ public class TestCompatibility extends TestBase { ...@@ -56,42 +55,6 @@ public class TestCompatibility extends TestBase {
deleteDb("compatibility"); deleteDb("compatibility");
} }
private void testOnDuplicateKey() throws SQLException {
Connection c = getConnection("compatibility;MODE=MYSQL");
Statement stat = c.createStatement();
stat.execute("set mode mysql");
stat.execute("create schema s2");
stat.execute("create table s2.test(id int primary key, name varchar(255))");
stat.execute("insert into s2.test(id, name) values(1, 'a')");
assertEquals(2, stat.executeUpdate("insert into s2.test(id, name) values(1, 'b') " +
"on duplicate key update name = values(name)"));
assertEquals(0, stat.executeUpdate("insert into s2.test(id, name) values(1, 'b') " +
"on duplicate key update name = values(name)"));
assertEquals(1, stat.executeUpdate("insert into s2.test(id, name) values(2, 'c') " +
"on duplicate key update name = values(name)"));
ResultSet rs = stat.executeQuery("select id, name from s2.test order by id");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertEquals("b", rs.getString(2));
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertEquals("c", rs.getString(2));
assertFalse(rs.next());
// Check qualified names in ON UPDATE case
assertEquals(2, stat.executeUpdate("insert into s2.test(id, name) values(2, 'd') " +
"on duplicate key update test.name = values(name)"));
assertThrows(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, stat)
.executeUpdate("insert into s2.test(id, name) values(2, 'd') " +
"on duplicate key update test2.name = values(name)");
assertEquals(2, stat.executeUpdate("insert into s2.test(id, name) values(2, 'e') " +
"on duplicate key update s2.test.name = values(name)"));
assertThrows(ErrorCode.SCHEMA_NAME_MUST_MATCH, stat)
.executeUpdate("insert into s2.test(id, name) values(2, 'd') " +
"on duplicate key update s3.test.name = values(name)");
stat.execute("drop schema s2 cascade");
c.close();
}
private void testKeyAsColumnInMySQLMode() throws SQLException { private void testKeyAsColumnInMySQLMode() throws SQLException {
Connection c = getConnection("compatibility;MODE=MYSQL"); Connection c = getConnection("compatibility;MODE=MYSQL");
Statement stat = c.createStatement(); Statement stat = c.createStatement();
......
...@@ -10,6 +10,8 @@ import java.sql.PreparedStatement; ...@@ -10,6 +10,8 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import org.h2.api.ErrorCode;
import org.h2.test.TestBase; import org.h2.test.TestBase;
/** /**
...@@ -37,6 +39,7 @@ public class TestDuplicateKeyUpdate extends TestBase { ...@@ -37,6 +39,7 @@ public class TestDuplicateKeyUpdate extends TestBase {
testOnDuplicateKeyInsertBatch(conn); testOnDuplicateKeyInsertBatch(conn);
testOnDuplicateKeyInsertMultiValue(conn); testOnDuplicateKeyInsertMultiValue(conn);
testPrimaryKeyAndUniqueKey(conn); testPrimaryKeyAndUniqueKey(conn);
testUpdateCountAndQualifiedNames(conn);
conn.close(); conn.close();
deleteDb("duplicateKeyUpdate"); deleteDb("duplicateKeyUpdate");
} }
...@@ -262,4 +265,39 @@ public class TestDuplicateKeyUpdate extends TestBase { ...@@ -262,4 +265,39 @@ public class TestDuplicateKeyUpdate extends TestBase {
stat.execute("drop table test"); stat.execute("drop table test");
} }
private void testUpdateCountAndQualifiedNames(Connection conn) throws SQLException {
Statement stat = conn.createStatement();
stat.execute("set mode mysql");
stat.execute("create schema s2");
stat.execute("create table s2.test(id int primary key, name varchar(255))");
stat.execute("insert into s2.test(id, name) values(1, 'a')");
assertEquals(2, stat.executeUpdate("insert into s2.test(id, name) values(1, 'b') " +
"on duplicate key update name = values(name)"));
assertEquals(0, stat.executeUpdate("insert into s2.test(id, name) values(1, 'b') " +
"on duplicate key update name = values(name)"));
assertEquals(1, stat.executeUpdate("insert into s2.test(id, name) values(2, 'c') " +
"on duplicate key update name = values(name)"));
ResultSet rs = stat.executeQuery("select id, name from s2.test order by id");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertEquals("b", rs.getString(2));
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertEquals("c", rs.getString(2));
assertFalse(rs.next());
// Check qualified names in ON UPDATE case
assertEquals(2, stat.executeUpdate("insert into s2.test(id, name) values(2, 'd') " +
"on duplicate key update test.name = values(name)"));
assertThrows(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, stat)
.executeUpdate("insert into s2.test(id, name) values(2, 'd') " +
"on duplicate key update test2.name = values(name)");
assertEquals(2, stat.executeUpdate("insert into s2.test(id, name) values(2, 'e') " +
"on duplicate key update s2.test.name = values(name)"));
assertThrows(ErrorCode.SCHEMA_NAME_MUST_MATCH, stat)
.executeUpdate("insert into s2.test(id, name) values(2, 'd') " +
"on duplicate key update s3.test.name = values(name)");
stat.execute("drop schema s2 cascade");
}
} }
...@@ -26,7 +26,9 @@ import org.locationtech.jts.geom.GeometryFactory; ...@@ -26,7 +26,9 @@ import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon; import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.util.AffineTransformation; import org.locationtech.jts.geom.util.AffineTransformation;
import org.locationtech.jts.io.ByteOrderValues;
import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBWriter;
import org.locationtech.jts.io.WKTReader; import org.locationtech.jts.io.WKTReader;
/** /**
...@@ -604,6 +606,26 @@ public class TestSpatial extends TestBase { ...@@ -604,6 +606,26 @@ public class TestSpatial extends TestBase {
// Test SRID // Test SRID
copy = ValueGeometry.get(geom3d.getBytes()); copy = ValueGeometry.get(geom3d.getBytes());
assertEquals(27572, copy.getGeometry().getSRID()); assertEquals(27572, copy.getGeometry().getSRID());
Point point = new GeometryFactory().createPoint((new Coordinate(1.1d, 1.2d)));
// SRID 0
checkSRID(ValueGeometry.getFromGeometry(point).getBytes(), 0);
checkSRID(new WKBWriter(2, ByteOrderValues.BIG_ENDIAN, false).write(point), 0);
checkSRID(new WKBWriter(2, ByteOrderValues.BIG_ENDIAN, true).write(point), 0);
checkSRID(new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN, false).write(point), 0);
checkSRID(new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN, true).write(point), 0);
// SRID 1,000,000,000
point.setSRID(1_000_000_000);
checkSRID(ValueGeometry.getFromGeometry(point).getBytes(), 1_000_000_000);
checkSRID(new WKBWriter(2, ByteOrderValues.BIG_ENDIAN, true).write(point), 1_000_000_000);
checkSRID(new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN, true).write(point), 1_000_000_000);
}
private void checkSRID(byte[] bytes, int srid) {
Point point = (Point) ValueGeometry.get(bytes).getGeometry();
assertEquals(1.1, point.getX());
assertEquals(1.2, point.getY());
assertEquals(srid, point.getSRID());
assertEquals(srid, point.getFactory().getSRID());
} }
/** /**
......
...@@ -48,7 +48,6 @@ public class TestTransaction extends TestBase { ...@@ -48,7 +48,6 @@ public class TestTransaction extends TestBase {
testReferential(); testReferential();
testSavepoint(); testSavepoint();
testIsolation(); testIsolation();
testTwoPhaseCommit();
deleteDb("transaction"); deleteDb("transaction");
} }
...@@ -544,42 +543,4 @@ public class TestTransaction extends TestBase { ...@@ -544,42 +543,4 @@ public class TestTransaction extends TestBase {
stat.execute(sql); stat.execute(sql);
} }
private void testTwoPhaseCommit() throws SQLException {
if (config.memory) {
return;
}
deleteDb("transaction2pc");
Connection conn = getConnection("transaction2pc");
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID INT PRIMARY KEY)");
conn.setAutoCommit(false);
stat.execute("INSERT INTO TEST VALUES (1)");
stat.execute("PREPARE COMMIT \"#1\"");
conn.commit();
stat.execute("SHUTDOWN IMMEDIATELY");
conn = getConnection("transaction2pc");
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT TRANSACTION, STATE FROM INFORMATION_SCHEMA.IN_DOUBT");
assertFalse(rs.next());
rs = stat.executeQuery("SELECT ID FROM TEST");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertFalse(rs.next());
conn.setAutoCommit(false);
stat.execute("INSERT INTO TEST VALUES (2)");
stat.execute("PREPARE COMMIT \"#2\"");
conn.rollback();
stat.execute("SHUTDOWN IMMEDIATELY");
conn = getConnection("transaction2pc");
stat = conn.createStatement();
rs = stat.executeQuery("SELECT TRANSACTION, STATE FROM INFORMATION_SCHEMA.IN_DOUBT");
assertFalse(rs.next());
rs = stat.executeQuery("SELECT ID FROM TEST");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertFalse(rs.next());
conn.close();
deleteDb("transaction2pc");
}
} }
...@@ -43,6 +43,8 @@ public class TestTwoPhaseCommit extends TestBase { ...@@ -43,6 +43,8 @@ public class TestTwoPhaseCommit extends TestBase {
openWith(false); openWith(false);
test(false); test(false);
testInDoubtAfterShutdown();
if (!config.mvStore) { if (!config.mvStore) {
testLargeTransactionName(); testLargeTransactionName();
} }
...@@ -115,4 +117,57 @@ public class TestTwoPhaseCommit extends TestBase { ...@@ -115,4 +117,57 @@ public class TestTwoPhaseCommit extends TestBase {
stat.execute("PREPARE COMMIT XID_TEST_TRANSACTION_WITH_LONG_NAME"); stat.execute("PREPARE COMMIT XID_TEST_TRANSACTION_WITH_LONG_NAME");
crash(conn); crash(conn);
} }
private void testInDoubtAfterShutdown() throws SQLException {
if (config.memory) {
return;
}
deleteDb("twoPhaseCommit");
Connection conn = getConnection("twoPhaseCommit");
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID INT PRIMARY KEY)");
conn.setAutoCommit(false);
stat.execute("INSERT INTO TEST VALUES (1)");
stat.execute("PREPARE COMMIT \"#1\"");
conn.commit();
stat.execute("SHUTDOWN IMMEDIATELY");
conn = getConnection("twoPhaseCommit");
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT TRANSACTION, STATE FROM INFORMATION_SCHEMA.IN_DOUBT");
assertFalse(rs.next());
rs = stat.executeQuery("SELECT ID FROM TEST");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertFalse(rs.next());
conn.setAutoCommit(false);
stat.execute("INSERT INTO TEST VALUES (2)");
stat.execute("PREPARE COMMIT \"#2\"");
conn.rollback();
stat.execute("SHUTDOWN IMMEDIATELY");
conn = getConnection("twoPhaseCommit");
stat = conn.createStatement();
rs = stat.executeQuery("SELECT TRANSACTION, STATE FROM INFORMATION_SCHEMA.IN_DOUBT");
assertFalse(rs.next());
rs = stat.executeQuery("SELECT ID FROM TEST");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertFalse(rs.next());
conn.setAutoCommit(false);
stat.execute("INSERT INTO TEST VALUES (3)");
stat.execute("PREPARE COMMIT \"#3\"");
stat.execute("SHUTDOWN IMMEDIATELY");
conn = getConnection("twoPhaseCommit");
stat = conn.createStatement();
rs = stat.executeQuery("SELECT TRANSACTION, STATE FROM INFORMATION_SCHEMA.IN_DOUBT");
assertTrue(rs.next());
assertEquals("#3", rs.getString("TRANSACTION"));
assertEquals("IN_DOUBT", rs.getString("STATE"));
rs = stat.executeQuery("SELECT ID FROM TEST");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertFalse(rs.next());
conn.close();
deleteDb("twoPhaseCommit");
}
} }
...@@ -85,6 +85,7 @@ public class TestScript extends TestBase { ...@@ -85,6 +85,7 @@ public class TestScript extends TestBase {
reconnectOften = !config.memory && config.big; reconnectOften = !config.memory && config.big;
testScript("testScript.sql"); testScript("testScript.sql");
testScript("comments.sql");
testScript("derived-column-names.sql"); testScript("derived-column-names.sql");
testScript("dual.sql"); testScript("dual.sql");
testScript("indexes.sql"); testScript("indexes.sql");
...@@ -113,7 +114,7 @@ public class TestScript extends TestBase { ...@@ -113,7 +114,7 @@ public class TestScript extends TestBase {
testScript("datatypes/" + s + ".sql"); testScript("datatypes/" + s + ".sql");
} }
for (String s : new String[] { "alterTableAdd", "alterTableDropColumn", for (String s : new String[] { "alterTableAdd", "alterTableDropColumn",
"createAlias", "createView", "createTable", "createTrigger", "createAlias", "createSynonym", "createView", "createTable", "createTrigger",
"dropSchema" }) { "dropSchema" }) {
testScript("ddl/" + s + ".sql"); testScript("ddl/" + s + ".sql");
} }
...@@ -207,7 +208,37 @@ public class TestScript extends TestBase { ...@@ -207,7 +208,37 @@ public class TestScript extends TestBase {
while (true) { while (true) {
String s = in.readLine(); String s = in.readLine();
if (s == null) { if (s == null) {
return s; return null;
}
if (s.startsWith("#")) {
int end = s.indexOf('#', 1);
if (end < 3) {
fail("Bad line \"" + s + '\"');
}
boolean val;
switch (s.charAt(1)) {
case '+':
val = true;
break;
case '-':
val = false;
break;
default:
fail("Bad line \"" + s + '\"');
return null;
}
String flag = s.substring(2, end);
s = s.substring(end + 1);
switch (flag) {
case "mvStore":
if (config.mvStore == val) {
break;
} else {
continue;
}
default:
fail("Unknown flag \"" + flag + '\"');
}
} }
s = s.trim(); s = s.trim();
if (s.length() > 0) { if (s.length() > 0) {
...@@ -494,10 +525,7 @@ public class TestScript extends TestBase { ...@@ -494,10 +525,7 @@ public class TestScript extends TestBase {
if (reconnectOften && sql.toUpperCase().startsWith("EXPLAIN")) { if (reconnectOften && sql.toUpperCase().startsWith("EXPLAIN")) {
return; return;
} }
errors.append(fileName).append('\n'); addWriteResultError(compare, s);
errors.append("line: ").append(in.getLineNumber()).append('\n');
errors.append("exp: ").append(compare).append('\n');
errors.append("got: ").append(s).append('\n');
if (ex != null) { if (ex != null) {
TestBase.logError("script", ex); TestBase.logError("script", ex);
} }
...@@ -508,11 +536,20 @@ public class TestScript extends TestBase { ...@@ -508,11 +536,20 @@ public class TestScript extends TestBase {
} }
} }
} else { } else {
addWriteResultError("<nothing>", s);
TestBase.logErrorMessage(errors.toString());
putBack = compare; putBack = compare;
} }
write(s); write(s);
} }
private void addWriteResultError(String expected, String got) {
errors.append(fileName).append('\n');
errors.append("line: ").append(in.getLineNumber()).append('\n');
errors.append("exp: ").append(expected).append('\n');
errors.append("got: ").append(got).append('\n');
}
private void write(String s) { private void write(String s) {
out.println(s); out.println(s);
} }
......
-- 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
--
CALL 1 /* comment */ ;;
> 1
> -
> 1
> rows: 1
CALL 1 /* comment */ ;
> 1
> -
> 1
> rows: 1
call /* remark * / * /* ** // end */ 1;
> 1
> -
> 1
> rows: 1
--- remarks/comments/syntax ----------------------------------------------------------------------------------------------
CREATE TABLE TEST(
ID INT PRIMARY KEY, -- this is the primary key, type {integer}
NAME VARCHAR(255) -- this is a string
);
> ok
INSERT INTO TEST VALUES(
1 /* ID */,
'Hello' // NAME
);
> update count: 1
SELECT * FROM TEST;
> ID NAME
> -- -----
> 1 Hello
> rows: 1
DROP_ TABLE_ TEST_T;
> exception SYNTAX_ERROR_2
DROP TABLE TEST /*;
> exception SYNTAX_ERROR_1
DROP TABLE TEST;
> ok
...@@ -24,6 +24,7 @@ select * from card; ...@@ -24,6 +24,7 @@ select * from card;
> 0 clubs > 0 clubs
> 3 hearts > 3 hearts
> 4 null > 4 null
> rows: 3
select * from card order by suit; select * from card order by suit;
> RANK SUIT > RANK SUIT
...@@ -31,6 +32,7 @@ select * from card order by suit; ...@@ -31,6 +32,7 @@ select * from card order by suit;
> 4 null > 4 null
> 3 hearts > 3 hearts
> 0 clubs > 0 clubs
> rows (ordered): 3
insert into card (rank, suit) values (8, 'diamonds'), (10, 'clubs'), (7, 'hearts'); insert into card (rank, suit) values (8, 'diamonds'), (10, 'clubs'), (7, 'hearts');
> update count: 3 > update count: 3
...@@ -42,17 +44,13 @@ select suit, count(rank) from card group by suit order by suit, count(rank); ...@@ -42,17 +44,13 @@ select suit, count(rank) from card group by suit order by suit, count(rank);
> hearts 2 > hearts 2
> clubs 2 > clubs 2
> diamonds 1 > diamonds 1
> rows (ordered): 4
select rank from card where suit = 'diamonds'; select rank from card where suit = 'diamonds';
> RANK >> 8
> ----
> 8
select column_type from information_schema.columns where COLUMN_NAME = 'SUIT'; select column_type from information_schema.columns where COLUMN_NAME = 'SUIT';
> COLUMN_TYPE >> ENUM('hearts','clubs','spades','diamonds')
> ------------------------------------------
> ENUM('hearts','clubs','spades','diamonds')
> rows: 1
--- ENUM integer-based operations --- ENUM integer-based operations
...@@ -61,6 +59,7 @@ select rank from card where suit = 1; ...@@ -61,6 +59,7 @@ select rank from card where suit = 1;
> ---- > ----
> 0 > 0
> 10 > 10
> rows: 2
insert into card (rank, suit) values(5, 2); insert into card (rank, suit) values(5, 2);
> update count: 1 > update count: 1
...@@ -69,6 +68,7 @@ select * from card where rank = 5; ...@@ -69,6 +68,7 @@ select * from card where rank = 5;
> RANK SUIT > RANK SUIT
> ---- ------ > ---- ------
> 5 spades > 5 spades
> rows: 1
--- ENUM edge cases --- ENUM edge cases
...@@ -100,6 +100,7 @@ select * from card; ...@@ -100,6 +100,7 @@ select * from card;
> ---- ------ > ---- ------
> 0 clubs > 0 clubs
> 3 hearts > 3 hearts
> rows: 2
drop table card; drop table card;
> ok > ok
...@@ -125,6 +126,7 @@ select rank from card where suit = 'clubs'; ...@@ -125,6 +126,7 @@ select rank from card where suit = 'clubs';
> ---- > ----
> 0 > 0
> 1 > 1
> rows: 2
drop table card; drop table card;
> ok > ok
...@@ -143,18 +145,21 @@ insert into card (rank, suit) values (0, 'clubs'), (3, 'hearts'), (1, 'clubs'); ...@@ -143,18 +145,21 @@ insert into card (rank, suit) values (0, 'clubs'), (3, 'hearts'), (1, 'clubs');
> update count: 3 > update count: 3
create index idx_card_suite on card(`suit`); create index idx_card_suite on card(`suit`);
> ok
select rank from card where suit = 'clubs'; select rank from card where suit = 'clubs';
> RANK > RANK
> ---- > ----
> 0 > 0
> 1 > 1
> rows: 2
select rank from card where suit in ('clubs'); select rank from card where suit in ('clubs');
> RANK > RANK
> ---- > ----
> 0 > 0
> 1 > 1
> rows: 2
drop table card; drop table card;
> ok > ok
...@@ -196,37 +201,25 @@ CREATE VIEW V AS SELECT * FROM TEST; ...@@ -196,37 +201,25 @@ CREATE VIEW V AS SELECT * FROM TEST;
> ok > ok
SELECT * FROM V; SELECT * FROM V;
> E >> B
> -
> B
> rows: 1
CREATE VIEW V1 AS SELECT E + 2 AS E FROM TEST; CREATE VIEW V1 AS SELECT E + 2 AS E FROM TEST;
> ok > ok
SELECT * FROM V1; SELECT * FROM V1;
> E >> 3
> -
> 3
> rows: 1
CREATE VIEW V2 AS SELECT E + E AS E FROM TEST; CREATE VIEW V2 AS SELECT E + E AS E FROM TEST;
> ok > ok
SELECT * FROM V2; SELECT * FROM V2;
> E >> 2
> -
> 2
> rows: 1
CREATE VIEW V3 AS SELECT -E AS E FROM TEST; CREATE VIEW V3 AS SELECT -E AS E FROM TEST;
> ok > ok
SELECT * FROM V3; SELECT * FROM V3;
> E >> -1
> --
> -1
> rows: 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 CHARACTER_SET_NAME COLLATION_NAME TYPE_NAME NULLABLE IS_COMPUTED SELECTIVITY CHECK_CONSTRAINT SEQUENCE_NAME REMARKS SOURCE_DATA_TYPE COLUMN_TYPE COLUMN_ON_UPDATE > 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 CHARACTER_SET_NAME COLLATION_NAME TYPE_NAME NULLABLE IS_COMPUTED SELECTIVITY CHECK_CONSTRAINT SEQUENCE_NAME REMARKS SOURCE_DATA_TYPE COLUMN_TYPE COLUMN_ON_UPDATE
......
...@@ -50,10 +50,7 @@ INSERT INTO TEST VALUES (TIME '08:00:00'); ...@@ -50,10 +50,7 @@ INSERT INTO TEST VALUES (TIME '08:00:00');
> update count: 1 > update count: 1
SELECT TIME FROM TEST; SELECT TIME FROM TEST;
> TIME >> 08:00:00
> --------
> 08:00:00
> rows: 1
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
......
...@@ -10,9 +10,7 @@ INSERT INTO tab_with_timezone(x) VALUES ('2017-01-01'); ...@@ -10,9 +10,7 @@ INSERT INTO tab_with_timezone(x) VALUES ('2017-01-01');
> update count: 1 > update count: 1
SELECT "Query".* FROM (select * from tab_with_timezone where x > '2016-01-01') AS "Query"; SELECT "Query".* FROM (select * from tab_with_timezone where x > '2016-01-01') AS "Query";
> X >> 2017-01-01 00:00:00+00
> ----------------------
> 2017-01-01 00:00:00+00
DELETE FROM tab_with_timezone; DELETE FROM tab_with_timezone;
> update count: 1 > update count: 1
......
...@@ -16,7 +16,9 @@ SELECT T1, T2, T1 = T2 FROM TEST; ...@@ -16,7 +16,9 @@ SELECT T1, T2, T1 = T2 FROM TEST;
> rows: 1 > rows: 1
ALTER TABLE TEST ADD (T3 TIMESTAMP(0), T4 TIMESTAMP(9) WITHOUT TIME ZONE, ALTER TABLE TEST ADD (T3 TIMESTAMP(0), T4 TIMESTAMP(9) WITHOUT TIME ZONE,
DT1 DATETIME, DT2 DATETIME(0), DT3 DATETIME(9), SDT1 SMALLDATETIME); DT1 DATETIME, DT2 DATETIME(0), DT3 DATETIME(9),
DT2_1 DATETIME2, DT2_2 DATETIME2(0), DT2_3 DATETIME2(7),
SDT1 SMALLDATETIME);
> ok > ok
SELECT COLUMN_NAME, DATA_TYPE, TYPE_NAME, COLUMN_TYPE, NUMERIC_SCALE FROM INFORMATION_SCHEMA.COLUMNS SELECT COLUMN_NAME, DATA_TYPE, TYPE_NAME, COLUMN_TYPE, NUMERIC_SCALE FROM INFORMATION_SCHEMA.COLUMNS
...@@ -30,8 +32,11 @@ SELECT COLUMN_NAME, DATA_TYPE, TYPE_NAME, COLUMN_TYPE, NUMERIC_SCALE FROM INFORM ...@@ -30,8 +32,11 @@ SELECT COLUMN_NAME, DATA_TYPE, TYPE_NAME, COLUMN_TYPE, NUMERIC_SCALE FROM INFORM
> DT1 93 TIMESTAMP DATETIME 6 > DT1 93 TIMESTAMP DATETIME 6
> DT2 93 TIMESTAMP DATETIME(0) 0 > DT2 93 TIMESTAMP DATETIME(0) 0
> DT3 93 TIMESTAMP DATETIME(9) 9 > DT3 93 TIMESTAMP DATETIME(9) 9
> DT2_1 93 TIMESTAMP DATETIME2 6
> DT2_2 93 TIMESTAMP DATETIME2(0) 0
> DT2_3 93 TIMESTAMP DATETIME2(7) 7
> SDT1 93 TIMESTAMP SMALLDATETIME 0 > SDT1 93 TIMESTAMP SMALLDATETIME 0
> rows (ordered): 8 > rows (ordered): 11
ALTER TABLE TEST ADD T5 TIMESTAMP(10); ALTER TABLE TEST ADD T5 TIMESTAMP(10);
> exception INVALID_VALUE_SCALE_PRECISION > exception INVALID_VALUE_SCALE_PRECISION
...@@ -39,6 +44,9 @@ ALTER TABLE TEST ADD T5 TIMESTAMP(10); ...@@ -39,6 +44,9 @@ ALTER TABLE TEST ADD T5 TIMESTAMP(10);
ALTER TABLE TEST ADD DT4 DATETIME(10); ALTER TABLE TEST ADD DT4 DATETIME(10);
> exception INVALID_VALUE_SCALE_PRECISION > exception INVALID_VALUE_SCALE_PRECISION
ALTER TABLE TEST ADD DT2_4 DATETIME2(10);
> exception INVALID_VALUE_SCALE_PRECISION
ALTER TABLE TEST ADD STD2 SMALLDATETIME(1); ALTER TABLE TEST ADD STD2 SMALLDATETIME(1);
> exception SYNTAX_ERROR_1 > exception SYNTAX_ERROR_1
......
-- 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
--
CREATE SCHEMA SCHEMA1;
> ok
CREATE SCHEMA SCHEMA2;
> ok
CREATE TABLE SCHEMA1.T1(K BIGINT PRIMARY KEY, V VARCHAR);
> ok
CREATE SYNONYM SCHEMA1.T1 FOR SCHEMA1.T1;
> exception TABLE_OR_VIEW_ALREADY_EXISTS_1
CREATE SYNONYM SCHEMA2.T1 FOR SCHEMA1.T1;
> ok
DROP SYNONYM SCHEMA2.T1;
> ok
SET SCHEMA SCHEMA2;
> ok
CREATE SYNONYM T1 FOR SCHEMA1.T1;
> ok
DROP SYNONYM T1;
> ok
SET SCHEMA SCHEMA1;
> ok
CREATE SYNONYM T1 FOR T1;
> exception TABLE_OR_VIEW_ALREADY_EXISTS_1
CREATE SYNONYM SCHEMA2.T1 FOR T1;
> ok
DROP SYNONYM SCHEMA2.T1;
> ok
SET SCHEMA PUBLIC;
> ok
DROP SCHEMA SCHEMA2 CASCADE;
> ok
DROP SCHEMA SCHEMA1 CASCADE;
> ok
...@@ -19,6 +19,7 @@ SELECT * FROM PARENT; ...@@ -19,6 +19,7 @@ SELECT * FROM PARENT;
> -- ----- > -- -----
> 1 Coco1 > 1 Coco1
> 2 Coco2 > 2 Coco2
> rows: 2
EXPLAIN PLAN EXPLAIN PLAN
MERGE INTO PARENT AS P MERGE INTO PARENT AS P
...@@ -28,9 +29,7 @@ EXPLAIN PLAN ...@@ -28,9 +29,7 @@ EXPLAIN PLAN
UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT
MATCHED THEN MATCHED THEN
INSERT (ID, NAME) VALUES (S.ID, S.NAME); INSERT (ID, NAME) VALUES (S.ID, S.NAME);
> PLAN >> MERGE INTO PUBLIC.PARENT(ID, NAME) KEY(ID) SELECT X AS ID, ('Coco' || X) AS NAME FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX */
> ---------------------------------------------------------------------------------------------------------------------------------
> MERGE INTO PUBLIC.PARENT(ID, NAME) KEY(ID) SELECT X AS ID, ('Coco' || X) AS NAME FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX */
DROP TABLE PARENT; DROP TABLE PARENT;
> ok > ok
......
...@@ -6,10 +6,7 @@ explain with recursive r(n) as ( ...@@ -6,10 +6,7 @@ explain with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3) (select 1) union all (select n+1 from r where n < 3)
) )
select n from r; select n from r;
> PLAN >> WITH RECURSIVE R(N) AS ( (SELECT 1 FROM SYSTEM_RANGE(1, 1) /* PUBLIC.RANGE_INDEX */) UNION ALL (SELECT (N + 1) FROM PUBLIC.R /* PUBLIC.R.tableScan */ WHERE N < 3) ) SELECT N FROM R R /* null */
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> WITH RECURSIVE R(N) AS ( (SELECT 1 FROM SYSTEM_RANGE(1, 1) /* PUBLIC.RANGE_INDEX */) UNION ALL (SELECT (N + 1) FROM PUBLIC.R /* PUBLIC.R.tableScan */ WHERE N < 3) ) SELECT N FROM R R /* null */
> rows: 1
select sum(n) from ( select sum(n) from (
with recursive r(n) as ( with recursive r(n) as (
...@@ -17,10 +14,7 @@ select sum(n) from ( ...@@ -17,10 +14,7 @@ select sum(n) from (
) )
select n from r select n from r
); );
> SUM(N) >> 6
> ------
> 6
> rows: 1
select sum(n) from (select 0) join ( select sum(n) from (select 0) join (
with recursive r(n) as ( with recursive r(n) as (
...@@ -28,10 +22,7 @@ select sum(n) from (select 0) join ( ...@@ -28,10 +22,7 @@ select sum(n) from (select 0) join (
) )
select n from r select n from r
) on 1=1; ) on 1=1;
> SUM(N) >> 6
> ------
> 6
> rows: 1
select 0 from ( select 0 from (
select 0 where 0 in ( select 0 where 0 in (
......
...@@ -20,6 +20,7 @@ select array_agg(v order by v asc), ...@@ -20,6 +20,7 @@ select array_agg(v order by v asc),
> rows (ordered): 1 > rows (ordered): 1
create index test_idx on test(v); create index test_idx on test(v);
> ok
select ARRAY_AGG(v order by v asc), select ARRAY_AGG(v order by v asc),
ARRAY_AGG(v order by v desc) filter (where v >= '4') ARRAY_AGG(v order by v desc) filter (where v >= '4')
......
...@@ -18,6 +18,7 @@ select avg(v), avg(v) filter (where v >= 40) from test where v <= 100; ...@@ -18,6 +18,7 @@ select avg(v), avg(v) filter (where v >= 40) from test where v <= 100;
> rows: 1 > rows: 1
create index test_idx on test(v); create index test_idx on test(v);
> ok
select avg(v), avg(v) filter (where v >= 40) from test where v <= 100; select avg(v), avg(v) filter (where v >= 40) from test where v <= 100;
> AVG(V) AVG(V) FILTER (WHERE (V >= 40)) > AVG(V) AVG(V) FILTER (WHERE (V >= 40))
......
...@@ -21,6 +21,7 @@ select bit_and(v), bit_and(v) filter (where v <= 0xffffffff0fff) from test where ...@@ -21,6 +21,7 @@ select bit_and(v), bit_and(v) filter (where v <= 0xffffffff0fff) from test where
> rows: 1 > rows: 1
create index test_idx on test(v); create index test_idx on test(v);
> ok
select bit_and(v), bit_and(v) filter (where v <= 0xffffffff0fff) from test where v >= 0xff0fffffffff; select bit_and(v), bit_and(v) filter (where v <= 0xffffffff0fff) from test where v >= 0xff0fffffffff;
> BIT_AND(V) BIT_AND(V) FILTER (WHERE (V <= 281474976649215)) > BIT_AND(V) BIT_AND(V) FILTER (WHERE (V <= 281474976649215))
......
...@@ -20,6 +20,7 @@ select bit_or(v), bit_or(v) filter (where v >= 8) from test where v <= 512; ...@@ -20,6 +20,7 @@ select bit_or(v), bit_or(v) filter (where v >= 8) from test where v <= 512;
> rows: 1 > rows: 1
create index test_idx on test(v); create index test_idx on test(v);
> ok
select bit_or(v), bit_or(v) filter (where v >= 8) from test where v <= 512; select bit_or(v), bit_or(v) filter (where v >= 8) from test where v <= 512;
> BIT_OR(V) BIT_OR(V) FILTER (WHERE (V >= 8)) > BIT_OR(V) BIT_OR(V) FILTER (WHERE (V >= 8))
......
...@@ -18,6 +18,7 @@ select count(v), count(v) filter (where v >= 4) from test where v <= 10; ...@@ -18,6 +18,7 @@ select count(v), count(v) filter (where v >= 4) from test where v <= 10;
> rows: 1 > rows: 1
create index test_idx on test(v); create index test_idx on test(v);
> ok
select count(v), count(v) filter (where v >= 4) from test where v <= 10; select count(v), count(v) filter (where v >= 4) from test where v <= 10;
> COUNT(V) COUNT(V) FILTER (WHERE (V >= 4)) > COUNT(V) COUNT(V) FILTER (WHERE (V >= 4))
......
...@@ -20,6 +20,7 @@ select group_concat(v order by v asc separator '-'), ...@@ -20,6 +20,7 @@ select group_concat(v order by v asc separator '-'),
> rows (ordered): 1 > rows (ordered): 1
create index test_idx on test(v); create index test_idx on test(v);
> ok
select group_concat(v order by v asc separator '-'), select group_concat(v order by v asc separator '-'),
group_concat(v order by v desc separator '-') filter (where v >= '4') group_concat(v order by v desc separator '-') filter (where v >= '4')
......
...@@ -18,6 +18,7 @@ select max(v), max(v) filter (where v <= 8) from test where v <= 10; ...@@ -18,6 +18,7 @@ select max(v), max(v) filter (where v <= 8) from test where v <= 10;
> rows: 1 > rows: 1
create index test_idx on test(v); create index test_idx on test(v);
> ok
select max(v), max(v) filter (where v <= 8) from test where v <= 10; select max(v), max(v) filter (where v <= 8) from test where v <= 10;
> MAX(V) MAX(V) FILTER (WHERE (V <= 8)) > MAX(V) MAX(V) FILTER (WHERE (V <= 8))
......
...@@ -598,6 +598,7 @@ select median(v), median(v) filter (where v >= 40) from test where v <= 100; ...@@ -598,6 +598,7 @@ select median(v), median(v) filter (where v >= 40) from test where v <= 100;
> rows: 1 > rows: 1
create index test_idx on test(v); create index test_idx on test(v);
> ok
select median(v), median(v) filter (where v >= 40) from test where v <= 100; select median(v), median(v) filter (where v >= 40) from test where v <= 100;
> MEDIAN(V) MEDIAN(V) FILTER (WHERE (V >= 40)) > MEDIAN(V) MEDIAN(V) FILTER (WHERE (V >= 40))
...@@ -623,6 +624,7 @@ insert into test values ...@@ -623,6 +624,7 @@ insert into test values
('First', 10), ('First', 10), ('First', 20), ('First', 30), ('First', 30), ('First', 10), ('First', 10), ('First', 20), ('First', 30), ('First', 30),
('Second', 5), ('Second', 4), ('Second', 20), ('Second', 22), ('Second', 300), ('Second', 5), ('Second', 4), ('Second', 20), ('Second', 22), ('Second', 300),
('Third', 3), ('Third', 100), ('Third', 150), ('Third', 170), ('Third', 400); ('Third', 3), ('Third', 100), ('Third', 150), ('Third', 170), ('Third', 400);
> update count: 15
select dept, median(amount) from test group by dept order by dept; select dept, median(amount) from test group by dept order by dept;
> DEPT MEDIAN(AMOUNT) > DEPT MEDIAN(AMOUNT)
......
...@@ -18,6 +18,7 @@ select min(v), min(v) filter (where v >= 4) from test where v >= 2; ...@@ -18,6 +18,7 @@ select min(v), min(v) filter (where v >= 4) from test where v >= 2;
> rows: 1 > rows: 1
create index test_idx on test(v); create index test_idx on test(v);
> ok
select min(v), min(v) filter (where v >= 4) from test where v >= 2; select min(v), min(v) filter (where v >= 4) from test where v >= 2;
> MIN(V) MIN(V) FILTER (WHERE (V >= 4)) > MIN(V) MIN(V) FILTER (WHERE (V >= 4))
......
...@@ -18,6 +18,7 @@ select sum(v), sum(v) filter (where v >= 4) from test where v <= 10; ...@@ -18,6 +18,7 @@ select sum(v), sum(v) filter (where v >= 4) from test where v <= 10;
> rows: 1 > rows: 1
create index test_idx on test(v); create index test_idx on test(v);
> ok
select sum(v), sum(v) filter (where v >= 4) from test where v <= 10; select sum(v), sum(v) filter (where v >= 4) from test where v <= 10;
> SUM(V) SUM(V) FILTER (WHERE (V >= 4)) > SUM(V) SUM(V) FILTER (WHERE (V >= 4))
......
...@@ -7,10 +7,10 @@ create memory table test(id int primary key, name varchar(255)); ...@@ -7,10 +7,10 @@ create memory table test(id int primary key, name varchar(255));
> ok > ok
insert into test values(1, 'Hello'); insert into test values(1, 'Hello');
> update count: 1
select char(null) en, char(65) ea from test; select char(null) en, char(65) ea from test;
> EN EA > EN EA
> ---- -- > ---- --
> null A > null A
> rows: 1 > rows: 1
...@@ -6,6 +6,7 @@ create memory table test(id int primary key, name varchar(255)); ...@@ -6,6 +6,7 @@ create memory table test(id int primary key, name varchar(255));
> ok > ok
insert into test values(1, 'Hello'); insert into test values(1, 'Hello');
> update count: 1
select concat(null, null) en, concat(null, 'a') ea, concat('b', null) eb, concat('ab', 'c') abc from test; select concat(null, null) en, concat(null, 'a') ea, concat('b', null) eb, concat('ab', 'c') abc from test;
> EN EA EB ABC > EN EA EB ABC
......
...@@ -7,6 +7,7 @@ create memory table test(id int primary key, name varchar(255)); ...@@ -7,6 +7,7 @@ create memory table test(id int primary key, name varchar(255));
> ok > ok
insert into test values(1, 'Hello'); insert into test values(1, 'Hello');
> update count: 1
select difference(null, null) en, difference('a', null) en1, difference(null, 'a') en2 from test; select difference(null, null) en, difference('a', null) en1, difference(null, 'a') en2 from test;
> EN EN1 EN2 > EN EN1 EN2
...@@ -19,5 +20,3 @@ select difference('abc', 'abc') e0, difference('Thomas', 'Tom') e1 from test; ...@@ -19,5 +20,3 @@ select difference('abc', 'abc') e0, difference('Thomas', 'Tom') e1 from test;
> -- -- > -- --
> 4 3 > 4 3
> rows: 1 > rows: 1
...@@ -13,6 +13,7 @@ select regexp_replace('Sylvain', 'S..', 'TOTO', 'mni'); ...@@ -13,6 +13,7 @@ select regexp_replace('Sylvain', 'S..', 'TOTO', 'mni');
>> TOTOvain >> TOTOvain
set mode oracle; set mode oracle;
> ok
select regexp_replace('first last', '(\w+) (\w+)', '\2 \1'); select regexp_replace('first last', '(\w+) (\w+)', '\2 \1');
>> last first >> last first
...@@ -27,6 +28,7 @@ select regexp_replace('first last', '(\w+) (\w+)', '$2 $1'); ...@@ -27,6 +28,7 @@ select regexp_replace('first last', '(\w+) (\w+)', '$2 $1');
>> $2 $1 >> $2 $1
set mode regular; set mode regular;
> ok
select regexp_replace('first last', '(\w+) (\w+)', '\2 \1'); select regexp_replace('first last', '(\w+) (\w+)', '\2 \1');
>> 2 1 >> 2 1
......
...@@ -7,6 +7,7 @@ create memory table test(id int primary key, name varchar(255)); ...@@ -7,6 +7,7 @@ create memory table test(id int primary key, name varchar(255));
> ok > ok
insert into test values(1, 'Hello'); insert into test values(1, 'Hello');
> update count: 1
select soundex(null) en, soundex('tom') et from test; select soundex(null) en, soundex('tom') et from test;
> EN ET > EN ET
...@@ -23,4 +24,3 @@ soundex('VanDeusen') V532, soundex('Ashcraft') A261 from test; ...@@ -23,4 +24,3 @@ soundex('VanDeusen') V532, soundex('Ashcraft') A261 from test;
> ---- ---- ---- ---- ---- ---- ---- ---- > ---- ---- ---- ---- ---- ---- ---- ----
> W252 L000 G362 P236 J250 T522 V532 A261 > W252 L000 G362 P236 J250 T522 V532 A261
> rows: 1 > rows: 1
...@@ -11,7 +11,7 @@ select row_number() over () as rnum, str from test where str = 'A'; ...@@ -11,7 +11,7 @@ select row_number() over () as rnum, str from test where str = 'A';
> RNUM STR > RNUM STR
> ---- --- > ---- ---
> 1 A > 1 A
> rows: 1
drop table test; drop table test;
> ok > ok
...@@ -24,6 +24,7 @@ SELECT 1 AS VERY_VERY_VERY_LONG_ID_VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _12345678 ...@@ -24,6 +24,7 @@ SELECT 1 AS VERY_VERY_VERY_LONG_ID_VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _12345678
> VERY_VERY_VERY_LONG_ID_VERY_VE _123456789012345 SUMX1 SUMX147 x noName6 noName7 > VERY_VERY_VERY_LONG_ID_VERY_VE _123456789012345 SUMX1 SUMX147 x noName6 noName7
> ------------------------------ ---------------- ----- ------- - ------- ------- > ------------------------------ ---------------- ----- ------- - ------- -------
> 1 4 4 51 x !!! !!!! > 1 4 4 51 x !!! !!!!
> rows: 1
SET COLUMN_NAME_RULES=EMULATE='Oracle'; SET COLUMN_NAME_RULES=EMULATE='Oracle';
> ok > ok
...@@ -33,6 +34,7 @@ SELECT 1 AS VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _123456789012345, SUM(X)+1 , SUM ...@@ -33,6 +34,7 @@ SELECT 1 AS VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _123456789012345, SUM(X)+1 , SUM
> VERY_VERY_VERY_LONG_ID _123456789012345 SUMX1 SUMX147 x _UNNAMED_6 _UNNAMED_7 > VERY_VERY_VERY_LONG_ID _123456789012345 SUMX1 SUMX147 x _UNNAMED_6 _UNNAMED_7
> ---------------------- ---------------- ----- ------- - ---------- ---------- > ---------------------- ---------------- ----- ------- - ---------- ----------
> 1 4 4 51 x !!! !!!! > 1 4 4 51 x !!! !!!!
> rows: 1
SET COLUMN_NAME_RULES=EMULATE='Oracle'; SET COLUMN_NAME_RULES=EMULATE='Oracle';
> ok > ok
...@@ -42,6 +44,7 @@ SELECT 1 AS VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _123456789012345, SUM(X)+1 , SUM ...@@ -42,6 +44,7 @@ SELECT 1 AS VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _123456789012345, SUM(X)+1 , SUM
> VERY_VERY_VERY_LONG_ID _123456789012345 SUMX1 SUMX147 x _UNNAMED_6 _UNNAMED_7 _23456789012345678901234567890XXX > VERY_VERY_VERY_LONG_ID _123456789012345 SUMX1 SUMX147 x _UNNAMED_6 _UNNAMED_7 _23456789012345678901234567890XXX
> ---------------------- ---------------- ----- ------- - ---------- ---------- --------------------------------- > ---------------------- ---------------- ----- ------- - ---------- ---------- ---------------------------------
> 1 4 4 51 x !!! !!!! Very Long > 1 4 4 51 x !!! !!!! Very Long
> rows: 1
SET COLUMN_NAME_RULES=EMULATE='PostgreSQL'; SET COLUMN_NAME_RULES=EMULATE='PostgreSQL';
> ok > ok
...@@ -51,6 +54,7 @@ SELECT 1 AS VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _123456789012345, SUM(X)+1 , SUM ...@@ -51,6 +54,7 @@ SELECT 1 AS VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _123456789012345, SUM(X)+1 , SUM
> VERY_VERY_VERY_LONG_ID _123456789012345 SUMX1 SUMX147 x _UNNAMED_6 _UNNAMED_7 QuotedColumnId > VERY_VERY_VERY_LONG_ID _123456789012345 SUMX1 SUMX147 x _UNNAMED_6 _UNNAMED_7 QuotedColumnId
> ---------------------- ---------------- ----- ------- - ---------- ---------- -------------- > ---------------------- ---------------- ----- ------- - ---------- ---------- --------------
> 1 4 4 51 x !!! !!!! 999 > 1 4 4 51 x !!! !!!! 999
> rows: 1
SET COLUMN_NAME_RULES=DEFAULT; SET COLUMN_NAME_RULES=DEFAULT;
> ok > ok
......
...@@ -32,10 +32,7 @@ drop table test; ...@@ -32,10 +32,7 @@ drop table test;
> ok > ok
explain select * from table(id int = (1, 2), name varchar=('Hello', 'World')); explain select * from table(id int = (1, 2), name varchar=('Hello', 'World'));
> PLAN >> SELECT TABLE.ID, TABLE.NAME FROM TABLE(ID INT=(1, 2), NAME VARCHAR=('Hello', 'World')) /* function */
> -----------------------------------------------------------------------------------------------------
> SELECT TABLE.ID, TABLE.NAME FROM TABLE(ID INT=(1, 2), NAME VARCHAR=('Hello', 'World')) /* function */
> rows: 1
select * from table(id int=(1, 2), name varchar=('Hello', 'World')) x order by id; select * from table(id int=(1, 2), name varchar=('Hello', 'World')) x order by id;
> ID NAME > ID NAME
......
...@@ -16,7 +16,4 @@ insert into person select convert(x,varchar) as firstname, (convert(x,varchar) | ...@@ -16,7 +16,4 @@ insert into person select convert(x,varchar) as firstname, (convert(x,varchar) |
-- can directly use the index. -- can directly use the index.
-- --
explain analyze SELECT * FROM person WHERE firstname IN ('FirstName1', 'FirstName2') AND lastname='LastName1'; explain analyze SELECT * FROM person WHERE firstname IN ('FirstName1', 'FirstName2') AND lastname='LastName1';
> PLAN >> SELECT PERSON.FIRSTNAME, PERSON.LASTNAME FROM PUBLIC.PERSON /* PUBLIC.PERSON_1: FIRSTNAME IN('FirstName1', 'FirstName2') AND LASTNAME = 'LastName1' */ /* scanCount: 1 */ WHERE (FIRSTNAME IN('FirstName1', 'FirstName2')) AND (LASTNAME = 'LastName1')
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> SELECT PERSON.FIRSTNAME, PERSON.LASTNAME FROM PUBLIC.PERSON /* PUBLIC.PERSON_1: FIRSTNAME IN('FirstName1', 'FirstName2') AND LASTNAME = 'LastName1' */ /* scanCount: 1 */ WHERE (FIRSTNAME IN('FirstName1', 'FirstName2')) AND (LASTNAME = 'LastName1')
> rows: 1
...@@ -4,22 +4,13 @@ ...@@ -4,22 +4,13 @@
-- --
explain select * from system_range(1, 2) where x=x+1 and x=1; explain select * from system_range(1, 2) where x=x+1 and x=1;
> PLAN >> SELECT SYSTEM_RANGE.X FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX: X = 1 */ WHERE ((X = 1) AND (X = (X + 1))) AND (1 = (X + 1))
> ---------------------------------------------------------------------------------------------------------------------------------
> SELECT SYSTEM_RANGE.X FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX: X = 1 */ WHERE ((X = 1) AND (X = (X + 1))) AND (1 = (X + 1))
> rows: 1
explain select * from system_range(1, 2) where not (x = 1 and x*2 = 2); explain select * from system_range(1, 2) where not (x = 1 and x*2 = 2);
> PLAN >> SELECT SYSTEM_RANGE.X FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX */ WHERE (X <> 1) OR ((X * 2) <> 2)
> -------------------------------------------------------------------------------------------------------
> SELECT SYSTEM_RANGE.X FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX */ WHERE (X <> 1) OR ((X * 2) <> 2)
> rows: 1
explain select * from system_range(1, 10) where (NOT x >= 5); explain select * from system_range(1, 10) where (NOT x >= 5);
> PLAN >> SELECT SYSTEM_RANGE.X FROM SYSTEM_RANGE(1, 10) /* PUBLIC.RANGE_INDEX: X < 5 */ WHERE X < 5
> ------------------------------------------------------------------------------------------
> SELECT SYSTEM_RANGE.X FROM SYSTEM_RANGE(1, 10) /* PUBLIC.RANGE_INDEX: X < 5 */ WHERE X < 5
> rows: 1
select (select t1.x from system_range(1,1) t2) from system_range(1,1) t1; select (select t1.x from system_range(1,1) t2) from system_range(1,1) t1;
> SELECT T1.X FROM SYSTEM_RANGE(1, 1) T2 /* PUBLIC.RANGE_INDEX */ /* scanCount: 2 */ > SELECT T1.X FROM SYSTEM_RANGE(1, 1) T2 /* PUBLIC.RANGE_INDEX */ /* scanCount: 2 */
...@@ -28,23 +19,14 @@ select (select t1.x from system_range(1,1) t2) from system_range(1,1) t1; ...@@ -28,23 +19,14 @@ select (select t1.x from system_range(1,1) t2) from system_range(1,1) t1;
> rows: 1 > rows: 1
EXPLAIN PLAN FOR SELECT * FROM SYSTEM_RANGE(1, 20); EXPLAIN PLAN FOR SELECT * FROM SYSTEM_RANGE(1, 20);
> PLAN >> SELECT SYSTEM_RANGE.X FROM SYSTEM_RANGE(1, 20) /* PUBLIC.RANGE_INDEX */
> -----------------------------------------------------------------------
> SELECT SYSTEM_RANGE.X FROM SYSTEM_RANGE(1, 20) /* PUBLIC.RANGE_INDEX */
> rows: 1
select sum(x) from system_range(2, 1000) r where select sum(x) from system_range(2, 1000) r where
not exists(select * from system_range(2, 32) r2 where r.x>r2.x and mod(r.x, r2.x)=0); not exists(select * from system_range(2, 32) r2 where r.x>r2.x and mod(r.x, r2.x)=0);
> SUM(X) >> 76127
> ------
> 76127
> rows: 1
SELECT COUNT(*) FROM SYSTEM_RANGE(0, 2111222333); SELECT COUNT(*) FROM SYSTEM_RANGE(0, 2111222333);
> COUNT(*) >> 2111222334
> ----------
> 2111222334
> rows: 1
select * from system_range(2, 100) r where select * from system_range(2, 100) r where
not exists(select * from system_range(2, 11) r2 where r.x>r2.x and mod(r.x, r2.x)=0); not exists(select * from system_range(2, 11) r2 where r.x>r2.x and mod(r.x, r2.x)=0);
...@@ -148,19 +130,13 @@ SELECT COUNT(*) FROM SYSTEM_RANGE(10, 2, -2); ...@@ -148,19 +130,13 @@ SELECT COUNT(*) FROM SYSTEM_RANGE(10, 2, -2);
>> 5 >> 5
SELECT * FROM SYSTEM_RANGE(1, 1); SELECT * FROM SYSTEM_RANGE(1, 1);
> X >> 1
> -
> 1
> rows: 1
SELECT COUNT(*) FROM SYSTEM_RANGE(1, 1); SELECT COUNT(*) FROM SYSTEM_RANGE(1, 1);
>> 1 >> 1
SELECT * FROM SYSTEM_RANGE(1, 1, -1); SELECT * FROM SYSTEM_RANGE(1, 1, -1);
> X >> 1
> -
> 1
> rows: 1
SELECT COUNT(*) FROM SYSTEM_RANGE(1, 1, -1); SELECT COUNT(*) FROM SYSTEM_RANGE(1, 1, -1);
>> 1 >> 1
......
...@@ -50,6 +50,7 @@ import org.h2.tools.ChangeFileEncryption; ...@@ -50,6 +50,7 @@ import org.h2.tools.ChangeFileEncryption;
import org.h2.tools.Console; import org.h2.tools.Console;
import org.h2.tools.ConvertTraceFile; import org.h2.tools.ConvertTraceFile;
import org.h2.tools.DeleteDbFiles; import org.h2.tools.DeleteDbFiles;
import org.h2.tools.GUIConsole;
import org.h2.tools.Recover; import org.h2.tools.Recover;
import org.h2.tools.Restore; import org.h2.tools.Restore;
import org.h2.tools.RunScript; import org.h2.tools.RunScript;
...@@ -127,7 +128,7 @@ public class TestTools extends TestBase { ...@@ -127,7 +128,7 @@ public class TestTools extends TestBase {
private void testConsole() throws Exception { private void testConsole() throws Exception {
String old = System.getProperty(SysProperties.H2_BROWSER); String old = System.getProperty(SysProperties.H2_BROWSER);
Console c = new Console(); GUIConsole c = new GUIConsole();
c.setOut(new PrintStream(new ByteArrayOutputStream())); c.setOut(new PrintStream(new ByteArrayOutputStream()));
try { try {
......
...@@ -23,7 +23,6 @@ import java.util.concurrent.TimeUnit; ...@@ -23,7 +23,6 @@ import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import org.h2.build.code.SwitchSource;
import org.h2.build.doc.XMLParser; import org.h2.build.doc.XMLParser;
/** /**
...@@ -231,34 +230,11 @@ public class Build extends BuildBase { ...@@ -231,34 +230,11 @@ public class Build extends BuildBase {
m.invoke(d, new File("coverage/report/index.html")); m.invoke(d, new File("coverage/report/index.html"));
} }
/**
* Switch the source code to the current JDK.
*/
@Description(summary = "Switch the source code to match the current JDK.")
public void switchSource() {
switchSource(true);
}
private static String getTargetJavaVersion() { private static String getTargetJavaVersion() {
return System.getProperty("version"); return System.getProperty("version");
} }
private static void switchSource(boolean enableCheck) {
try {
String version = getTargetJavaVersion();
String check = enableCheck ? "+CHECK" : "-CHECK";
if (version == null) {
SwitchSource.main("-dir", "src", "-auto", check);
} else {
SwitchSource.main("-dir", "src", "-version", version, check);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void compileMVStore(boolean debugInfo) { private void compileMVStore(boolean debugInfo) {
switchSource(debugInfo);
clean(); clean();
mkdir("temp"); mkdir("temp");
String classpath = "temp"; String classpath = "temp";
...@@ -282,7 +258,6 @@ public class Build extends BuildBase { ...@@ -282,7 +258,6 @@ public class Build extends BuildBase {
private void compile(boolean debugInfo, boolean clientOnly, private void compile(boolean debugInfo, boolean clientOnly,
boolean basicResourcesOnly) { boolean basicResourcesOnly) {
switchSource(debugInfo);
clean(); clean();
mkdir("temp"); mkdir("temp");
download(); download();
......
/*
* 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.build.code;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
/**
* Switched source code to a specific Java version, automatically to the current
* version, or enable / disable other blocks of source code in Java files.
*/
public class SwitchSource {
private final ArrayList<String> enable = new ArrayList<>();
private final ArrayList<String> disable = new ArrayList<>();
/**
* This method is called when executing this application from the command
* line.
*
* @param args the command line parameters
*/
public static void main(String... args) throws IOException {
new SwitchSource().run(args);
}
private void run(String... args) throws IOException {
String dir = null;
String version = null;
for (int i = 0; i < args.length; i++) {
String a = args[i];
if ("-dir".equals(a)) {
dir = args[++i];
} else if ("-auto".equals(a)) {
enable.add("AWT");
version = System.getProperty("java.specification.version");
} else if ("-version".equals(a)) {
version = args[++i];
} else if (a.startsWith("-")) {
String x = a.substring(1);
disable.add(x);
enable.remove(x);
} else if (a.startsWith("+")) {
String x = a.substring(1);
enable.add(x);
disable.remove(x);
} else {
showUsage();
return;
}
}
if (version == null) {
// ok
} else if ("1.5".equals(version)) {
disable.add("Java 1.6");
disable.add("Java 1.7");
} else if ("1.6".equals(version)) {
enable.add("Java 1.6");
disable.add("Java 1.7");
} else if (version.compareTo("1.7") >= 0) {
enable.add("Java 1.6");
enable.add("Java 1.7");
} else {
throw new IllegalArgumentException("version: " + version);
}
if (dir == null) {
showUsage();
} else {
process(new File(dir));
}
}
private void showUsage() {
System.out.println("Switched source code to a specific Java version.");
System.out.println("java "+getClass().getName() + "\n" +
" -dir <dir> The target directory\n" +
" [-version] Use the specified Java version (1.4 or newer)\n" +
" [-auto] Auto-detect Java version (1.4 or newer)\n" +
" [+MODE] Enable code labeled MODE\n" +
" [-MODE] Disable code labeled MODE");
}
private void process(File f) throws IOException {
String name = f.getName();
if (name.startsWith(".svn")) {
return;
} else if (name.endsWith(".java")) {
processFile(f);
} else if (f.isDirectory()) {
for (File file : f.listFiles()) {
process(file);
}
}
}
private void processFile(File f) throws IOException {
byte[] buffer;
try (RandomAccessFile read = new RandomAccessFile(f, "r")) {
long len = read.length();
if (len >= Integer.MAX_VALUE) {
throw new IOException("Files bigger than Integer.MAX_VALUE are not supported");
}
buffer = new byte[(int) len];
read.readFully(buffer);
}
boolean found = false;
// check for ## without creating a string
for (int i = 0; i < buffer.length - 1; i++) {
if (buffer[i] == '#' && buffer[i + 1] == '#') {
found = true;
break;
}
}
if (!found) {
return;
}
String source = new String(buffer);
String target = source;
for (String x : enable) {
target = replaceAll(target, "/*## " + x + " ##", "//## " + x + " ##");
}
for (String x : disable) {
target = replaceAll(target, "//## " + x + " ##", "/*## " + x + " ##");
}
if (!source.equals(target)) {
String name = f.getPath();
File fileNew = new File(name + ".new");
FileWriter write = new FileWriter(fileNew);
write.write(target);
write.close();
File fileBack = new File(name + ".bak");
fileBack.delete();
f.renameTo(fileBack);
File fileCopy = new File(name);
if (!fileNew.renameTo(fileCopy)) {
throw new IOException("Could not rename "
+ fileNew.getAbsolutePath() + " to " + name);
}
if (!fileBack.delete()) {
throw new IOException("Could not delete " + fileBack.getAbsolutePath());
}
// System.out.println(name);
}
}
private static String replaceAll(String s, String before, String after) {
int index = 0;
while (true) {
int next = s.indexOf(before, index);
if (next < 0) {
return s;
}
s = s.substring(0, next) + after + s.substring(next + before.length());
index = next + after.length();
}
}
}
...@@ -773,3 +773,5 @@ opti excessively ...@@ -773,3 +773,5 @@ opti excessively
iterators tech enums incompatibilities loses reimplement readme reorganize milli subdirectory linkplain inspections iterators tech enums incompatibilities loses reimplement readme reorganize milli subdirectory linkplain inspections
geometries sourceschema destschema generatedcolumn alphanumerically usages geometries sourceschema destschema generatedcolumn alphanumerically usages
sizable instantiates renders sdt txcommit unhelpful optimiser treats rejects referring untrusted computes vacate inverted
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论