提交 11c11898 authored 作者: Thomas Mueller Graf's avatar Thomas Mueller Graf

Formatting and Javadocs

上级 54552660
...@@ -140,7 +140,8 @@ public class Mode { ...@@ -140,7 +140,8 @@ public class Mode {
public boolean onDuplicateKeyUpdate; public boolean onDuplicateKeyUpdate;
/** /**
* Pattern describing the keys the java.sql.Connection.setClientInfo() method accepts. * Pattern describing the keys the java.sql.Connection.setClientInfo()
* method accepts.
*/ */
public Pattern supportedClientInfoPropertiesRegEx; public Pattern supportedClientInfoPropertiesRegEx;
...@@ -161,9 +162,12 @@ public class Mode { ...@@ -161,9 +162,12 @@ public class Mode {
mode.supportOffsetFetch = true; mode.supportOffsetFetch = true;
mode.sysDummy1 = true; mode.sysDummy1 = true;
mode.isolationLevelInSelectOrInsertStatement = true; mode.isolationLevelInSelectOrInsertStatement = true;
// See https://www.ibm.com/support/knowledgecenter/SSEPEK_11.0.0/com.ibm.db2z11.doc.java/src/tpc/imjcc_r0052001.dita // See
// https://www.ibm.com/support/knowledgecenter/SSEPEK_11.0.0/
// com.ibm.db2z11.doc.java/src/tpc/imjcc_r0052001.dita
mode.supportedClientInfoPropertiesRegEx = mode.supportedClientInfoPropertiesRegEx =
Pattern.compile("ApplicationName|ClientAccountingInformation|ClientUser|ClientCorrelationToken"); Pattern.compile("ApplicationName|ClientAccountingInformation|" +
"ClientUser|ClientCorrelationToken");
add(mode); add(mode);
mode = new Mode("Derby"); mode = new Mode("Derby");
...@@ -183,7 +187,9 @@ public class Mode { ...@@ -183,7 +187,9 @@ public class Mode {
mode.uniqueIndexSingleNull = true; mode.uniqueIndexSingleNull = true;
mode.allowPlusForStringConcat = true; mode.allowPlusForStringConcat = true;
// HSQLDB does not support client info properties. See // HSQLDB does not support client info properties. See
// http://hsqldb.org/doc/apidocs/org/hsqldb/jdbc/JDBCConnection.html#setClientInfo%28java.lang.String,%20java.lang.String%29 // http://hsqldb.org/doc/apidocs/
// org/hsqldb/jdbc/JDBCConnection.html#
// setClientInfo%28java.lang.String,%20java.lang.String%29
mode.supportedClientInfoPropertiesRegEx = null; mode.supportedClientInfoPropertiesRegEx = null;
add(mode); add(mode);
...@@ -205,8 +211,11 @@ public class Mode { ...@@ -205,8 +211,11 @@ public class Mode {
mode.lowerCaseIdentifiers = true; mode.lowerCaseIdentifiers = true;
mode.onDuplicateKeyUpdate = true; mode.onDuplicateKeyUpdate = true;
// MySQL allows to use any key for client info entries. See // MySQL allows to use any key for client info entries. See
// http://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.24/com/mysql/jdbc/JDBC4CommentClientInfoProvider.java // http://grepcode.com/file/repo1.maven.org/maven2/mysql/
mode.supportedClientInfoPropertiesRegEx = Pattern.compile(".*"); // mysql-connector-java/5.1.24/com/mysql/jdbc/
// JDBC4CommentClientInfoProvider.java
mode.supportedClientInfoPropertiesRegEx =
Pattern.compile(".*");
add(mode); add(mode);
mode = new Mode("Oracle"); mode = new Mode("Oracle");
...@@ -217,7 +226,8 @@ public class Mode { ...@@ -217,7 +226,8 @@ public class Mode {
mode.supportPoundSymbolForColumnNames = true; mode.supportPoundSymbolForColumnNames = true;
// Oracle accepts keys of the form <namespace>.*. See // Oracle accepts keys of the form <namespace>.*. See
// https://docs.oracle.com/database/121/JJDBC/jdbcvers.htm#JJDBC29006 // https://docs.oracle.com/database/121/JJDBC/jdbcvers.htm#JJDBC29006
mode.supportedClientInfoPropertiesRegEx = Pattern.compile(".*\\..*"); mode.supportedClientInfoPropertiesRegEx =
Pattern.compile(".*\\..*");
add(mode); add(mode);
mode = new Mode("PostgreSQL"); mode = new Mode("PostgreSQL");
...@@ -228,8 +238,10 @@ public class Mode { ...@@ -228,8 +238,10 @@ public class Mode {
mode.logIsLogBase10 = true; mode.logIsLogBase10 = true;
mode.serialColumnIsNotPK = true; mode.serialColumnIsNotPK = true;
// PostgreSQL only supports the ApplicationName property. See // PostgreSQL only supports the ApplicationName property. See
// https://github.com/hhru/postgres-jdbc/blob/master/postgresql-jdbc-9.2-1002.src/org/postgresql/jdbc4/AbstractJdbc4Connection.java // https://github.com/hhru/postgres-jdbc/blob/master/postgresql-jdbc-9.2-1002.src/
mode.supportedClientInfoPropertiesRegEx = Pattern.compile("ApplicationName"); // org/postgresql/jdbc4/AbstractJdbc4Connection.java
mode.supportedClientInfoPropertiesRegEx =
Pattern.compile("ApplicationName");
add(mode); add(mode);
} }
......
...@@ -937,13 +937,13 @@ public class Session extends SessionWithState { ...@@ -937,13 +937,13 @@ public class Session extends SessionWithState {
private void cleanTempTables(boolean closeSession) { private void cleanTempTables(boolean closeSession) {
if (localTempTables != null && localTempTables.size() > 0) { if (localTempTables != null && localTempTables.size() > 0) {
synchronized (database) { synchronized (database) {
Iterator<Table> itr = localTempTables.values().iterator(); Iterator<Table> it = localTempTables.values().iterator();
while (itr.hasNext()) { while (it.hasNext()) {
Table table = itr.next(); Table table = it.next();
if (closeSession || table.getOnCommitDrop()) { if (closeSession || table.getOnCommitDrop()) {
modificationId++; modificationId++;
table.setModified(); table.setModified();
itr.remove(); it.remove();
table.removeChildrenAndResources(this); table.removeChildrenAndResources(this);
if (closeSession) { if (closeSession) {
// need to commit, otherwise recovery might // need to commit, otherwise recovery might
...@@ -954,7 +954,8 @@ public class Session extends SessionWithState { ...@@ -954,7 +954,8 @@ public class Session extends SessionWithState {
table.truncate(this); table.truncate(this);
} }
} }
// sometimes Table#removeChildrenAndResources will take the meta lock // sometimes Table#removeChildrenAndResources
// will take the meta lock
if (closeSession) { if (closeSession) {
database.unlockMeta(this); database.unlockMeta(this);
} }
......
...@@ -288,12 +288,18 @@ public class ExpressionVisitor { ...@@ -288,12 +288,18 @@ public class ExpressionVisitor {
return type; return type;
} }
/**
* Get the set of columns of all tables.
*
* @param filters the filters
* @return the set of columns
*/
public static HashSet<Column> allColumnsForTableFilters(TableFilter[] filters) { public static HashSet<Column> allColumnsForTableFilters(TableFilter[] filters) {
HashSet<Column> allColumnsSet = New.hashSet(); HashSet<Column> allColumnsSet = New.hashSet();
for (int i = 0; i < filters.length; i++) { for (int i = 0; i < filters.length; i++) {
if (filters[i].getSelect() != null) { if (filters[i].getSelect() != null) {
filters[i].getSelect().isEverything(ExpressionVisitor.getColumnsVisitor(allColumnsSet)); filters[i].getSelect().isEverything(
ExpressionVisitor.getColumnsVisitor(allColumnsSet));
} }
} }
return allColumnsSet; return allColumnsSet;
......
...@@ -156,6 +156,7 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -156,6 +156,7 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
* @param filter the current table filter index * @param filter the current table filter index
* @param sortOrder the sort order * @param sortOrder the sort order
* @param isScanIndex whether this is a "table scan" index * @param isScanIndex whether this is a "table scan" index
* @param allColumnsSet the set of all columns
* @return the estimated cost * @return the estimated cost
*/ */
protected final long getCostRangeIndex(int[] masks, long rowCount, protected final long getCostRangeIndex(int[] masks, long rowCount,
...@@ -240,8 +241,8 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -240,8 +241,8 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
} }
} }
// If we have two indexes with the same cost, and one of the indexes can // If we have two indexes with the same cost, and one of the indexes can
// satisfy the query without needing to read from the primary table (scan index), // satisfy the query without needing to read from the primary table
// make that one slightly lower cost. // (scan index), make that one slightly lower cost.
boolean needsToReadFromScanIndex = true; boolean needsToReadFromScanIndex = true;
if (!isScanIndex && allColumnsSet != null && !allColumnsSet.isEmpty()) { if (!isScanIndex && allColumnsSet != null && !allColumnsSet.isEmpty()) {
boolean foundAllColumnsWeNeed = true; boolean foundAllColumnsWeNeed = true;
......
...@@ -85,6 +85,7 @@ public interface Index extends SchemaObject { ...@@ -85,6 +85,7 @@ public interface Index extends SchemaObject {
* @param filters all joined table filters * @param filters all joined table filters
* @param filter the current table filter index * @param filter the current table filter index
* @param sortOrder the sort order * @param sortOrder the sort order
* @param allColumnsSet the set of all columns
* @return the estimated cost * @return the estimated cost
*/ */
double getCost(Session session, int[] masks, TableFilter[] filters, int filter, double getCost(Session session, int[] masks, TableFilter[] filters, int filter,
......
...@@ -20,10 +20,13 @@ public interface SpatialIndex extends Index { ...@@ -20,10 +20,13 @@ public interface SpatialIndex extends Index {
* *
* @param filter the table filter (which possibly knows about additional * @param filter the table filter (which possibly knows about additional
* conditions) * conditions)
* @param first the lower bound
* @param last the upper bound
* @param intersection the geometry which values should intersect with, or * @param intersection the geometry which values should intersect with, or
* null for anything * null for anything
* @return the cursor to iterate over the results * @return the cursor to iterate over the results
*/ */
Cursor findByGeometry(TableFilter filter, SearchRow first, SearchRow last, SearchRow intersection); Cursor findByGeometry(TableFilter filter, SearchRow first, SearchRow last,
SearchRow intersection);
} }
...@@ -168,7 +168,8 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex { ...@@ -168,7 +168,8 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex {
} }
@Override @Override
public Cursor findByGeometry(TableFilter filter, SearchRow first, SearchRow last, SearchRow intersection) { public Cursor findByGeometry(TableFilter filter, SearchRow first,
SearchRow last, SearchRow intersection) {
if (intersection == null) { if (intersection == null) {
return find(filter.getSession(), first, last); return find(filter.getSession(), first, last);
} }
......
...@@ -160,7 +160,8 @@ public class ViewIndex extends BaseIndex implements SpatialIndex { ...@@ -160,7 +160,8 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
} }
@Override @Override
public Cursor findByGeometry(TableFilter filter, SearchRow first, SearchRow last, SearchRow intersection) { public Cursor findByGeometry(TableFilter filter, SearchRow first,
SearchRow last, SearchRow intersection) {
return find(filter.getSession(), first, last, intersection); return find(filter.getSession(), first, last, intersection);
} }
......
...@@ -1675,16 +1675,21 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1675,16 +1675,21 @@ public class JdbcConnection extends TraceObject implements Connection {
} }
/** /**
* Set a client property. * Set a client property. This method always throws a SQLClientInfoException
* This method always throws a SQLClientInfoException in standard mode. * in standard mode. In compatibility mode the following properties are
* In compatibility mode the following properties are supported: * supported:
* <p><ul> * <ul>
* <li>DB2: The properties: ApplicationName, ClientAccountingInformation, ClientUser and ClientCorrelationToken * <li>DB2: The properties: ApplicationName, ClientAccountingInformation,
* are supported. * ClientUser and ClientCorrelationToken are supported.
* </li>
* <li>MySQL: All property names are supported. * <li>MySQL: All property names are supported.
* <li>Oracle: All properties in the form <namespace>.<key name> are supported. * </li>
* <li>Oracle: All properties in the form &lt;namespace&gt;.&lt;key name&gt;
* are supported.
* </li>
* <li>PostgreSQL: The ApplicationName property is supported. * <li>PostgreSQL: The ApplicationName property is supported.
* </ul><p> * </li>
* </ul>
* *
* For unsupported properties a SQLClientInfoException is thrown. * For unsupported properties a SQLClientInfoException is thrown.
* *
...@@ -1703,11 +1708,13 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1703,11 +1708,13 @@ public class JdbcConnection extends TraceObject implements Connection {
checkClosed(); checkClosed();
if (isInternalProperty(name)) { if (isInternalProperty(name)) {
throw new SQLClientInfoException("Property name '" + name + " is used internally by H2.", throw new SQLClientInfoException("Property name '" + name +
Collections.<String, ClientInfoStatus> emptyMap()); " is used internally by H2.",
Collections.<String, ClientInfoStatus> emptyMap());
} }
Pattern clientInfoNameRegEx = Mode.getInstance(getMode()).supportedClientInfoPropertiesRegEx; Pattern clientInfoNameRegEx =
Mode.getInstance(getMode()).supportedClientInfoPropertiesRegEx;
if (clientInfoNameRegEx != null && clientInfoNameRegEx.matcher(name).matches()) { if (clientInfoNameRegEx != null && clientInfoNameRegEx.matcher(name).matches()) {
if (clientInfo == null) { if (clientInfo == null) {
...@@ -1739,8 +1746,9 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1739,8 +1746,9 @@ public class JdbcConnection extends TraceObject implements Connection {
/** /**
* Set the client properties. This replaces all existing properties. * Set the client properties. This replaces all existing properties.
* *
* This method always throws a SQLClientInfoException in standard mode. In compatibility mode * This method always throws a SQLClientInfoException in standard mode. In
* some properties may be supported (see setProperty(String, String) for details). * compatibility mode some properties may be supported (see
* setProperty(String, String) for details).
* *
* @param properties the properties (ignored) * @param properties the properties (ignored)
*/ */
...@@ -1801,7 +1809,8 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1801,7 +1809,8 @@ public class JdbcConnection extends TraceObject implements Connection {
* Get a client property. * Get a client property.
* *
* @param name the client info name * @param name the client info name
* @return the property value or null if the property is not found or not supported. * @return the property value or null if the property is not found or not
* supported.
*/ */
@Override @Override
public String getClientInfo(String name) throws SQLException { public String getClientInfo(String name) throws SQLException {
......
...@@ -197,7 +197,8 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex { ...@@ -197,7 +197,8 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
} }
@Override @Override
public Cursor findByGeometry(TableFilter filter, SearchRow first, SearchRow last, SearchRow intersection) { public Cursor findByGeometry(TableFilter filter, SearchRow first,
SearchRow last, SearchRow intersection) {
Session session = filter.getSession(); Session session = filter.getSession();
if (intersection == null) { if (intersection == null) {
return find(session, first, last); return find(session, first, last);
......
...@@ -52,18 +52,20 @@ public class CipherFactory { ...@@ -52,18 +52,20 @@ public class CipherFactory {
*/ */
public static final String KEYSTORE_PASSWORD = public static final String KEYSTORE_PASSWORD =
"h2pass"; "h2pass";
/** /**
* The security property which can prevent anonymous TLS connections. * The security property which can prevent anonymous TLS connections.
* Introduced into Java 6,7,8 in updates from July 2015. * Introduced into Java 6, 7, 8 in updates from July 2015.
*/ */
public static final String LEGACY_ALGORITHMS_SECURITY_KEY = public static final String LEGACY_ALGORITHMS_SECURITY_KEY =
"jdk.tls.legacyAlgorithms"; "jdk.tls.legacyAlgorithms";
/** /**
* The value of {@value #LEGACY_ALGORITHMS_SECURITY_KEY} security * The value of {@value #LEGACY_ALGORITHMS_SECURITY_KEY} security
* property at the time of class initialization. * property at the time of class initialization.
* Null if it is not set. * Null if it is not set.
*/ */
public static final String DEFAULT_LEGACY_ALGORITHMS = getLegacyAlgoritmsSilently(); public static final String DEFAULT_LEGACY_ALGORITHMS = getLegacyAlgorithmsSilently();
private static final String KEYSTORE = private static final String KEYSTORE =
"~/.h2.keystore"; "~/.h2.keystore";
...@@ -201,7 +203,7 @@ public class CipherFactory { ...@@ -201,7 +203,7 @@ public class CipherFactory {
* behavior. * behavior.
*/ */
public static synchronized void removeAnonFromLegacyAlgorithms() { public static synchronized void removeAnonFromLegacyAlgorithms() {
String legacyAlgosOrig = getLegacyAlgoritmsSilently(); String legacyAlgosOrig = getLegacyAlgorithmsSilently();
if (legacyAlgosOrig == null) { if (legacyAlgosOrig == null) {
return; return;
} }
...@@ -227,10 +229,11 @@ public class CipherFactory { ...@@ -227,10 +229,11 @@ public class CipherFactory {
/** /**
* Returns the security property {@value #LEGACY_ALGORITHMS_SECURITY_KEY}. * Returns the security property {@value #LEGACY_ALGORITHMS_SECURITY_KEY}.
* Ignores security exceptions. * Ignores security exceptions.
*
* @return the value of the security property, or null if not set * @return the value of the security property, or null if not set
* or not accessible * or not accessible
*/ */
public static String getLegacyAlgoritmsSilently() { public static String getLegacyAlgorithmsSilently() {
String defaultLegacyAlgorithms = null; String defaultLegacyAlgorithms = null;
try { try {
defaultLegacyAlgorithms = Security.getProperty(LEGACY_ALGORITHMS_SECURITY_KEY); defaultLegacyAlgorithms = Security.getProperty(LEGACY_ALGORITHMS_SECURITY_KEY);
......
...@@ -298,7 +298,8 @@ public class Column { ...@@ -298,7 +298,8 @@ public class Column {
} else if (dt.type == Value.TIMESTAMP_UTC) { } else if (dt.type == Value.TIMESTAMP_UTC) {
value = ValueTimestampUtc.fromMillis(session.getTransactionStart()); value = ValueTimestampUtc.fromMillis(session.getTransactionStart());
} else if (dt.type == Value.TIMESTAMP_TZ) { } else if (dt.type == Value.TIMESTAMP_TZ) {
value = ValueTimestampTimeZone.fromMillis(session.getTransactionStart(), (short) 0); value = ValueTimestampTimeZone.fromMillis(
session.getTransactionStart(), (short) 0);
} else if (dt.type == Value.TIME) { } else if (dt.type == Value.TIME) {
value = ValueTime.fromNanos(0); value = ValueTime.fromNanos(0);
} else if (dt.type == Value.DATE) { } else if (dt.type == Value.DATE) {
......
...@@ -113,7 +113,8 @@ public class Plan { ...@@ -113,7 +113,8 @@ public class Plan {
} }
double cost = 1; double cost = 1;
boolean invalidPlan = false; boolean invalidPlan = false;
final HashSet<Column> allColumnsSet = ExpressionVisitor.allColumnsForTableFilters(allFilters); final HashSet<Column> allColumnsSet = ExpressionVisitor
.allColumnsForTableFilters(allFilters);
for (int i = 0; i < allFilters.length; i++) { for (int i = 0; i < allFilters.length; i++) {
TableFilter tableFilter = allFilters[i]; TableFilter tableFilter = allFilters[i];
if (t.isDebugEnabled()) { if (t.isDebugEnabled()) {
......
...@@ -703,6 +703,7 @@ public abstract class Table extends SchemaObjectBase { ...@@ -703,6 +703,7 @@ public abstract class Table extends SchemaObjectBase {
* @param filters all joined table filters * @param filters all joined table filters
* @param filter the current table filter index * @param filter the current table filter index
* @param sortOrder the sort order * @param sortOrder the sort order
* @param allColumnsSet the set of all columns
* @return the plan item * @return the plan item
*/ */
public PlanItem getBestPlanItem(Session session, int[] masks, public PlanItem getBestPlanItem(Session session, int[] masks,
...@@ -720,7 +721,8 @@ public abstract class Table extends SchemaObjectBase { ...@@ -720,7 +721,8 @@ public abstract class Table extends SchemaObjectBase {
if (indexes != null && masks != null) { if (indexes != null && masks != null) {
for (int i = 1, size = indexes.size(); i < size; i++) { for (int i = 1, size = indexes.size(); i < size; i++) {
Index index = indexes.get(i); Index index = indexes.get(i);
double cost = index.getCost(session, masks, filters, filter, sortOrder, allColumnsSet); double cost = index.getCost(session, masks, filters, filter,
sortOrder, allColumnsSet);
if (t.isDebugEnabled()) { if (t.isDebugEnabled()) {
t.debug("Table : potential plan item cost {0} index {1}", t.debug("Table : potential plan item cost {0} index {1}",
cost, index.getPlanSQL()); cost, index.getPlanSQL());
......
...@@ -184,6 +184,7 @@ public class TableFilter implements ColumnResolver { ...@@ -184,6 +184,7 @@ public class TableFilter implements ColumnResolver {
* @param s the session * @param s the session
* @param filters all joined table filters * @param filters all joined table filters
* @param filter the current table filter index * @param filter the current table filter index
* @param allColumnsSet the set of all columns
* @return the best plan item * @return the best plan item
*/ */
public PlanItem getBestPlanItem(Session s, TableFilter[] filters, int filter, public PlanItem getBestPlanItem(Session s, TableFilter[] filters, int filter,
...@@ -195,8 +196,10 @@ public class TableFilter implements ColumnResolver { ...@@ -195,8 +196,10 @@ public class TableFilter implements ColumnResolver {
} }
if (indexConditions.size() == 0) { if (indexConditions.size() == 0) {
item1 = new PlanItem(); item1 = new PlanItem();
item1.setIndex(table.getScanIndex(s, null, filters, filter, sortOrder, allColumnsSet)); item1.setIndex(table.getScanIndex(s, null, filters, filter,
item1.cost = item1.getIndex().getCost(s, null, filters, filter, sortOrder, allColumnsSet); sortOrder, allColumnsSet));
item1.cost = item1.getIndex().getCost(s, null, filters, filter,
sortOrder, allColumnsSet);
} }
int len = table.getColumns().length; int len = table.getColumns().length;
int[] masks = new int[len]; int[] masks = new int[len];
......
...@@ -557,6 +557,12 @@ public class TableView extends Table { ...@@ -557,6 +557,12 @@ public class TableView extends Table {
return 0; return 0;
} }
/**
* Get the index of the first parameter.
*
* @param additionalParameters additional parameters
* @return the index of the first parameter
*/
public int getParameterOffset(ArrayList<Parameter> additionalParameters) { public int getParameterOffset(ArrayList<Parameter> additionalParameters) {
int result = topQuery == null ? -1 : getMaxParameterIndex(topQuery.getParameters()); int result = topQuery == null ? -1 : getMaxParameterIndex(topQuery.getParameters());
if (additionalParameters != null) { if (additionalParameters != null) {
......
...@@ -314,7 +314,8 @@ public class DateTimeUtils { ...@@ -314,7 +314,8 @@ public class DateTimeUtils {
} }
/** /**
* Parse a time string. The format is: [-]hour:minute:second[.nanos] or alternatively [-]hour.minute.second[.nanos]. * Parse a time string. The format is: [-]hour:minute:second[.nanos] or
* alternatively [-]hour.minute.second[.nanos].
* *
* @param s the string to parse * @param s the string to parse
* @param start the parse index start * @param start the parse index start
...@@ -332,7 +333,8 @@ public class DateTimeUtils { ...@@ -332,7 +333,8 @@ public class DateTimeUtils {
int s2 = s.indexOf(':', s1 + 1); int s2 = s.indexOf(':', s1 + 1);
int s3 = s.indexOf('.', s2 + 1); int s3 = s.indexOf('.', s2 + 1);
if (s1 <= 0 || s2 <= s1) { if (s1 <= 0 || s2 <= s1) {
// if first try fails try to use IBM DB2 time format [-]hour.minute.second[.nanos] // if first try fails try to use IBM DB2 time format
// [-]hour.minute.second[.nanos]
s1 = s.indexOf('.', start); s1 = s.indexOf('.', start);
s2 = s.indexOf('.', s1 + 1); s2 = s.indexOf('.', s1 + 1);
s3 = s.indexOf('.', s2 + 1); s3 = s.indexOf('.', s2 + 1);
......
...@@ -589,7 +589,8 @@ public class Transfer { ...@@ -589,7 +589,8 @@ public class Transfer {
return ValueTimestampUtc.fromNanos(readLong()); return ValueTimestampUtc.fromNanos(readLong());
} }
case Value.TIMESTAMP_TZ: { case Value.TIMESTAMP_TZ: {
return ValueTimestampTimeZone.fromDateValueAndNanos(readLong(), readLong(), (short) readInt()); return ValueTimestampTimeZone.fromDateValueAndNanos(readLong(),
readLong(), (short) readInt());
} }
case Value.DECIMAL: case Value.DECIMAL:
return ValueDecimal.get(new BigDecimal(readString())); return ValueDecimal.get(new BigDecimal(readString()));
......
...@@ -20,7 +20,8 @@ import org.h2.util.StringUtils; ...@@ -20,7 +20,8 @@ import org.h2.util.StringUtils;
/** /**
* Implementation of the TIMESTAMP WITH TIMEZONE data type. * Implementation of the TIMESTAMP WITH TIMEZONE data type.
* *
* @see <a href="https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators">ISO 8601 Time zone designators</a> * @see <a href="https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators">
* ISO 8601 Time zone designators</a>
*/ */
public class ValueTimestampTimeZone extends Value { public class ValueTimestampTimeZone extends Value {
...@@ -54,12 +55,15 @@ public class ValueTimestampTimeZone extends Value { ...@@ -54,12 +55,15 @@ public class ValueTimestampTimeZone extends Value {
*/ */
private final short timeZoneOffsetMins; private final short timeZoneOffsetMins;
private ValueTimestampTimeZone(long dateValue, long timeNanos, short timeZoneOffsetMins) { private ValueTimestampTimeZone(long dateValue, long timeNanos,
short timeZoneOffsetMins) {
if (timeNanos < 0 || timeNanos >= 24L * 60 * 60 * 1000 * 1000 * 1000) { if (timeNanos < 0 || timeNanos >= 24L * 60 * 60 * 1000 * 1000 * 1000) {
throw new IllegalArgumentException("timeNanos out of range " + timeNanos); throw new IllegalArgumentException("timeNanos out of range " +
timeNanos);
} }
if (timeZoneOffsetMins < (-12 * 60) || timeZoneOffsetMins >= (12 * 60)) { if (timeZoneOffsetMins < (-12 * 60) || timeZoneOffsetMins >= (12 * 60)) {
throw new IllegalArgumentException("timeZoneOffsetMins out of range " + timeZoneOffsetMins); throw new IllegalArgumentException(
"timeZoneOffsetMins out of range " + timeZoneOffsetMins);
} }
this.dateValue = dateValue; this.dateValue = dateValue;
this.timeNanos = timeNanos; this.timeNanos = timeNanos;
...@@ -72,10 +76,13 @@ public class ValueTimestampTimeZone extends Value { ...@@ -72,10 +76,13 @@ public class ValueTimestampTimeZone extends Value {
* @param dateValue the date value, a bit field with bits for the year, * @param dateValue the date value, a bit field with bits for the year,
* month, and day * month, and day
* @param timeNanos the nanoseconds since midnight * @param timeNanos the nanoseconds since midnight
* @param timeZoneOffsetMins the timezone offset in minutes
* @return the value * @return the value
*/ */
public static ValueTimestampTimeZone fromDateValueAndNanos(long dateValue, long timeNanos, short timeZoneOffsetMins) { public static ValueTimestampTimeZone fromDateValueAndNanos(long dateValue,
return (ValueTimestampTimeZone) Value.cache(new ValueTimestampTimeZone(dateValue, timeNanos, timeZoneOffsetMins)); long timeNanos, short timeZoneOffsetMins) {
return (ValueTimestampTimeZone) Value.cache(new ValueTimestampTimeZone(
dateValue, timeNanos, timeZoneOffsetMins));
} }
/** /**
...@@ -89,7 +96,8 @@ public class ValueTimestampTimeZone extends Value { ...@@ -89,7 +96,8 @@ public class ValueTimestampTimeZone extends Value {
long nanos = timestamp.getNanos() % 1000000; long nanos = timestamp.getNanos() % 1000000;
long dateValue = DateTimeUtils.dateValueFromDate(ms); long dateValue = DateTimeUtils.dateValueFromDate(ms);
nanos += DateTimeUtils.nanosFromDate(ms); nanos += DateTimeUtils.nanosFromDate(ms);
return fromDateValueAndNanos(dateValue, nanos, timestamp.getTimeZoneOffsetMins()); return fromDateValueAndNanos(dateValue, nanos,
timestamp.getTimeZoneOffsetMins());
} }
/** /**
...@@ -97,9 +105,11 @@ public class ValueTimestampTimeZone extends Value { ...@@ -97,9 +105,11 @@ public class ValueTimestampTimeZone extends Value {
* *
* @param ms the milliseconds * @param ms the milliseconds
* @param nanos the nanoseconds * @param nanos the nanoseconds
* @param timeZoneOffsetMins the timezone offset in minutes
* @return the value * @return the value
*/ */
public static ValueTimestampTimeZone fromMillisNanos(long ms, int nanos, short timeZoneOffsetMins) { public static ValueTimestampTimeZone fromMillisNanos(long ms, int nanos,
short timeZoneOffsetMins) {
long dateValue = DateTimeUtils.dateValueFromDate(ms); long dateValue = DateTimeUtils.dateValueFromDate(ms);
long timeNanos = nanos + DateTimeUtils.nanosFromDate(ms); long timeNanos = nanos + DateTimeUtils.nanosFromDate(ms);
return fromDateValueAndNanos(dateValue, timeNanos, timeZoneOffsetMins); return fromDateValueAndNanos(dateValue, timeNanos, timeZoneOffsetMins);
...@@ -109,9 +119,11 @@ public class ValueTimestampTimeZone extends Value { ...@@ -109,9 +119,11 @@ public class ValueTimestampTimeZone extends Value {
* Get or create a timestamp value for the given date/time in millis. * Get or create a timestamp value for the given date/time in millis.
* *
* @param ms the milliseconds * @param ms the milliseconds
* @param timeZoneOffsetMins the timezone offset in minutes
* @return the value * @return the value
*/ */
public static ValueTimestampTimeZone fromMillis(long ms, short timeZoneOffsetMins) { public static ValueTimestampTimeZone fromMillis(long ms,
short timeZoneOffsetMins) {
long dateValue = DateTimeUtils.dateValueFromDate(ms); long dateValue = DateTimeUtils.dateValueFromDate(ms);
long nanos = DateTimeUtils.nanosFromDate(ms); long nanos = DateTimeUtils.nanosFromDate(ms);
return fromDateValueAndNanos(dateValue, nanos, timeZoneOffsetMins); return fromDateValueAndNanos(dateValue, nanos, timeZoneOffsetMins);
...@@ -188,7 +200,8 @@ public class ValueTimestampTimeZone extends Value { ...@@ -188,7 +200,8 @@ public class ValueTimestampTimeZone extends Value {
} }
nanos = DateTimeUtils.parseTimeNanos(s, dateEnd + 1, timeEnd, true); nanos = DateTimeUtils.parseTimeNanos(s, dateEnd + 1, timeEnd, true);
} }
return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, nanos, tzMinutes); return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, nanos,
tzMinutes);
} }
/** /**
...@@ -221,8 +234,10 @@ public class ValueTimestampTimeZone extends Value { ...@@ -221,8 +234,10 @@ public class ValueTimestampTimeZone extends Value {
@Override @Override
public Timestamp getTimestamp() { public Timestamp getTimestamp() {
Timestamp ts = DateTimeUtils.convertDateValueToTimestamp(dateValue, timeNanos); Timestamp ts = DateTimeUtils.convertDateValueToTimestamp(dateValue,
return new TimestampWithTimeZone(ts.getTime(), ts.getNanos(), getTimeZoneOffsetMins()); timeNanos);
return new TimestampWithTimeZone(ts.getTime(), ts.getNanos(),
getTimeZoneOffsetMins());
} }
@Override @Override
...@@ -324,12 +339,14 @@ public class ValueTimestampTimeZone extends Value { ...@@ -324,12 +339,14 @@ public class ValueTimestampTimeZone extends Value {
return false; return false;
} }
ValueTimestampTimeZone x = (ValueTimestampTimeZone) other; ValueTimestampTimeZone x = (ValueTimestampTimeZone) other;
return dateValue == x.dateValue && timeNanos == x.timeNanos && timeZoneOffsetMins == x.timeZoneOffsetMins; return dateValue == x.dateValue && timeNanos == x.timeNanos &&
timeZoneOffsetMins == x.timeZoneOffsetMins;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return (int) (dateValue ^ (dateValue >>> 32) ^ timeNanos ^ (timeNanos >>> 32) ^ timeZoneOffsetMins); return (int) (dateValue ^ (dateValue >>> 32) ^ timeNanos ^
(timeNanos >>> 32) ^ timeZoneOffsetMins);
} }
@Override @Override
...@@ -345,12 +362,16 @@ public class ValueTimestampTimeZone extends Value { ...@@ -345,12 +362,16 @@ public class ValueTimestampTimeZone extends Value {
@Override @Override
public Value add(Value v) { public Value add(Value v) {
throw DbException.getUnsupportedException("manipulating TIMESTAMP WITH TIMEZONE values is unsupported"); throw DbException
.getUnsupportedException(
"manipulating TIMESTAMP WITH TIMEZONE values is unsupported");
} }
@Override @Override
public Value subtract(Value v) { public Value subtract(Value v) {
throw DbException.getUnsupportedException("manipulating TIMESTAMP WITH TIMEZONE values is unsupported"); throw DbException
.getUnsupportedException(
"manipulating TIMESTAMP WITH TIMEZONE values is unsupported");
} }
} }
...@@ -147,18 +147,24 @@ public class TestCompatibilityOracle extends TestBase { ...@@ -147,18 +147,24 @@ public class TestCompatibilityOracle extends TestBase {
Connection conn = getConnection("oracle;MODE=Oracle"); Connection conn = getConnection("oracle;MODE=Oracle");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("CREATE TABLE DATETABLE (ID NUMBER PRIMARY KEY, TESTVAL TIMESTAMP)"); stat.execute("CREATE TABLE DATE_TABLE (ID NUMBER PRIMARY KEY, TEST_VAL TIMESTAMP)");
stat.execute("INSERT INTO DATETABLE VALUES (1, to_date('31-DEC-9999 23:59:59','DD-MON-RRRR HH24:MI:SS'))"); stat.execute("INSERT INTO DATE_TABLE VALUES (1, " +
stat.execute("INSERT INTO DATETABLE VALUES (2, to_date('01-JAN-0001 00:00:00','DD-MON-RRRR HH24:MI:SS'))"); "to_date('31-DEC-9999 23:59:59','DD-MON-RRRR HH24:MI:SS'))");
stat.execute("INSERT INTO DATE_TABLE VALUES (2, " +
"to_date('01-JAN-0001 00:00:00','DD-MON-RRRR HH24:MI:SS'))");
assertResultDate("9999-12-31T23:59:59", stat, "SELECT TESTVAL FROM DATETABLE WHERE ID=1"); assertResultDate("9999-12-31T23:59:59", stat,
assertResultDate("0001-01-01T00:00:00", stat, "SELECT TESTVAL FROM DATETABLE WHERE ID=2"); "SELECT TEST_VAL FROM DATE_TABLE WHERE ID=1");
assertResultDate("0001-01-01T00:00:00", stat,
"SELECT TEST_VAL FROM DATE_TABLE WHERE ID=2");
conn.close(); conn.close();
} }
private void assertResultDate(String expected, Statement stat, String sql) throws SQLException { private void assertResultDate(String expected, Statement stat, String sql)
SimpleDateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); throws SQLException {
SimpleDateFormat iso8601 = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss");
ResultSet rs = stat.executeQuery(sql); ResultSet rs = stat.executeQuery(sql);
if (rs.next()) { if (rs.next()) {
assertEquals(expected, iso8601.format(rs.getTimestamp(1))); assertEquals(expected, iso8601.format(rs.getTimestamp(1)));
......
...@@ -1407,10 +1407,12 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -1407,10 +1407,12 @@ public class TestFunctions extends TestBase implements AggregateFunction {
date = new SimpleDateFormat("yyyy-MM-dd").parse("2013-01-29"); date = new SimpleDateFormat("yyyy-MM-dd").parse("2013-01-29");
assertEquals(date, ToDateParser.toDate("113029", "J")); assertEquals(date, ToDateParser.toDate("113029", "J"));
date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse("9999-12-31T23:59:59"); date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
assertEquals(date, ToDateParser.toDate("31-DEC-9999 23:59:59","DD-MON-YYYY HH24:MI:SS")); .parse("9999-12-31T23:59:59");
assertEquals(date, ToDateParser.toDate("31-DEC-9999 23:59:59","DD-MON-RRRR HH24:MI:SS")); assertEquals(date, ToDateParser.toDate("31-DEC-9999 23:59:59",
"DD-MON-YYYY HH24:MI:SS"));
assertEquals(date, ToDateParser.toDate("31-DEC-9999 23:59:59",
"DD-MON-RRRR HH24:MI:SS"));
SimpleDateFormat ymd = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat ymd = new SimpleDateFormat("yyyy-MM-dd");
assertEquals(ymd.parse("0001-03-01"), ToDateParser.toDate("1-MAR-0001", "DD-MON-RRRR")); assertEquals(ymd.parse("0001-03-01"), ToDateParser.toDate("1-MAR-0001", "DD-MON-RRRR"));
...@@ -1661,7 +1663,8 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -1661,7 +1663,8 @@ public class TestFunctions extends TestBase implements AggregateFunction {
} }
private void testIfNull() throws SQLException { private void testIfNull() throws SQLException {
Connection conn = getConnection("functions"); Connection conn = getConnection("functions");
Statement stat = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); Statement stat = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
stat.execute("CREATE TABLE T(f1 double)"); stat.execute("CREATE TABLE T(f1 double)");
stat.executeUpdate("INSERT INTO T VALUES( 1.2 )"); stat.executeUpdate("INSERT INTO T VALUES( 1.2 )");
stat.executeUpdate("INSERT INTO T VALUES( null )"); stat.executeUpdate("INSERT INTO T VALUES( null )");
......
...@@ -148,7 +148,8 @@ public class TestRecursiveQueries extends TestBase { ...@@ -148,7 +148,8 @@ public class TestRecursiveQueries extends TestBase {
null, null); null, null);
rs = stat.executeQuery("select x from system_range(1,5) " rs = stat.executeQuery("select x from system_range(1,5) "
+ "where x not in (with w(x) as (select 1 union all select x+1 from w where x<3) select x from w)"); + "where x not in (with w(x) as (select 1 union all select x+1 from w where x<3) "
+ "select x from w)");
assertResultSetOrdered(rs, new String[][]{{"4"}, {"5"}}); assertResultSetOrdered(rs, new String[][]{{"4"}, {"5"}});
conn.close(); conn.close();
......
...@@ -1512,9 +1512,11 @@ public class TestTableEngines extends TestBase { ...@@ -1512,9 +1512,11 @@ public class TestTableEngines extends TestBase {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder, HashSet<Column> allColumnsSet) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
doTests(session); doTests(session);
return getCostRangeIndex(masks, set.size(), filters, filter, sortOrder, false, allColumnsSet); return getCostRangeIndex(masks, set.size(), filters, filter,
sortOrder, false, allColumnsSet);
} }
@Override @Override
......
...@@ -57,7 +57,7 @@ public class BuildBase { ...@@ -57,7 +57,7 @@ public class BuildBase {
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
@Documented @Documented
public static @interface Description { public static @interface Description {
String summary() default ""; String summary() default "";
} }
/** /**
...@@ -317,7 +317,8 @@ public class BuildBase { ...@@ -317,7 +317,8 @@ public class BuildBase {
if (!Modifier.isStatic(mod) && Modifier.isPublic(mod) if (!Modifier.isStatic(mod) && Modifier.isPublic(mod)
&& m.getParameterTypes().length == 0) { && m.getParameterTypes().length == 0) {
if (m.isAnnotationPresent(Description.class)) { if (m.isAnnotationPresent(Description.class)) {
description = String.format("%1$-20s %2$s", m.getName(), m.getAnnotation(Description.class).summary()); description = String.format("%1$-20s %2$s",
m.getName(), m.getAnnotation(Description.class).summary());
} else { } else {
description = m.getName(); description = m.getName();
} }
...@@ -355,7 +356,8 @@ public class BuildBase { ...@@ -355,7 +356,8 @@ public class BuildBase {
} }
/** /**
* Execute java in a separate process, but using the java executable of the current JRE. * Execute java in a separate process, but using the java executable of the
* current JRE.
* *
* @param args the command line parameters for the java command * @param args the command line parameters for the java command
* @return the exit value * @return the exit value
......
...@@ -538,10 +538,13 @@ public class ArchiveTool { ...@@ -538,10 +538,13 @@ public class ArchiveTool {
long inPos = 0; long inPos = 0;
int bufferTotal = 64 * 1024 * 1024; int bufferTotal = 64 * 1024 * 1024;
int bufferPerStream = bufferTotal / segmentStart.size(); int bufferPerStream = bufferTotal / segmentStart.size();
// FileChannel fc = new RandomAccessFile(tempFileName, "r").getChannel(); // FileChannel fc = new RandomAccessFile(tempFileName, "r").
// getChannel();
for (int i = 0; i < segmentStart.size(); i++) { for (int i = 0; i < segmentStart.size(); i++) {
// long end = i < segmentStart.size() - 1 ? segmentStart.get(i+1) : fc.size(); // long end = i < segmentStart.size() - 1 ?
// InputStream in = new SharedInputStream(fc, segmentStart.get(i), end); // segmentStart.get(i+1) : fc.size();
// InputStream in =
// new SharedInputStream(fc, segmentStart.get(i), end);
InputStream in = new FileInputStream(tempFileName); InputStream in = new FileInputStream(tempFileName);
in.skip(segmentStart.get(i)); in.skip(segmentStart.get(i));
ChunkStream s = new ChunkStream(i); ChunkStream s = new ChunkStream(i);
...@@ -1062,6 +1065,9 @@ public class ArchiveTool { ...@@ -1062,6 +1065,9 @@ public class ArchiveTool {
return x; return x;
} }
/**
* An input stream that uses a shared file channel.
*/
static class SharedInputStream extends InputStream { static class SharedInputStream extends InputStream {
private final FileChannel channel; private final FileChannel channel;
private final long endPosition; private final long endPosition;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论