提交 079785dc authored 作者: thomasmueller's avatar thomasmueller

Merge branch 'master' of https://github.com/h2database/h2database

......@@ -21,6 +21,12 @@ Change Log
<h2>Next Version (unreleased)</h2>
<ul>
<li>Fix bug in LinkSchema tool when object exists with same name in different schemas
</li>
<li>Issue #675: Fix date operations on Locales with non-Gregorian calendars
</li>
<li>Fix removal of LOB when rolling back transaction on a table containing more than one LOB column.
</li>
<li>Issue #654: List ENUM type values in INFORMATION_SCHEMA.COLUMNS
</li>
<li>Issue #650: Simple nested SELECT causes error for table with TIMESTAMP WITH TIMEZONE column
......
......@@ -21,7 +21,7 @@ public class DbColumn {
private final String dataType;
private int position;
private final int position;
private DbColumn(DbContents contents, ResultSet rs, boolean procedureColumn)
throws SQLException {
......
......@@ -5,12 +5,11 @@
*/
package org.h2.bnf.context;
import org.h2.util.New;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import org.h2.util.New;
/**
* Contains meta data information about a procedure.
......@@ -21,7 +20,7 @@ public class DbProcedure {
private final DbSchema schema;
private final String name;
private final String quotedName;
private boolean returnsResult;
private final boolean returnsResult;
private DbColumn[] parameters;
public DbProcedure(DbSchema schema, ResultSet rs) throws SQLException {
......
......@@ -6143,6 +6143,7 @@ public class Parser {
} else if (readIf("MODIFY")) {
// MySQL compatibility
readIf("COLUMN"); // optional
boolean hasOpeningBracket = readIf("("); // Oracle specifies (but will not require) an opening parenthesis
String columnName = readColumnIdentifier();
AlterTableAlterColumn command = null;
NullConstraintType nullConstraint = parseNotNullConstraint();
......@@ -6167,6 +6168,9 @@ public class Parser {
throw DbException.get(ErrorCode.UNKNOWN_MODE_1,
"Internal Error - unhandled case: " + nullConstraint.name());
}
if(hasOpeningBracket) {
read(")");
}
return command;
} else if (readIf("ALTER")) {
readIf("COLUMN");
......
......@@ -50,7 +50,7 @@ public class AlterTableAddConstraint extends SchemaCommand {
private boolean primaryKeyHash;
private boolean ifTableExists;
private final boolean ifNotExists;
private ArrayList<Index> createdIndexes = New.arrayList();
private final ArrayList<Index> createdIndexes = New.arrayList();
public AlterTableAddConstraint(Session session, Schema schema,
boolean ifNotExists) {
......
......@@ -114,7 +114,7 @@ public class MergeUsing extends Prepared {
private int countUpdatedRows = 0;
private Column[] sourceKeys;
private Select targetMatchQuery;
private HashMap<Value, Integer> targetRowidsRemembered = new HashMap<>();
private final HashMap<Value, Integer> targetRowidsRemembered = new HashMap<>();
private int sourceQueryRowNumber = 0;
public MergeUsing(Merge merge) {
......
......@@ -5,10 +5,6 @@
*/
package org.h2.command.dml;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import org.h2.api.ErrorCode;
import org.h2.api.Trigger;
import org.h2.command.CommandInterface;
......@@ -16,40 +12,23 @@ import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.engine.SysProperties;
import org.h2.expression.Alias;
import org.h2.expression.Comparison;
import org.h2.expression.ConditionAndOr;
import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn;
import org.h2.expression.ExpressionVisitor;
import org.h2.expression.Parameter;
import org.h2.expression.*;
import org.h2.index.Cursor;
import org.h2.index.Index;
import org.h2.index.IndexType;
import org.h2.message.DbException;
import org.h2.result.LazyResult;
import org.h2.result.LocalResult;
import org.h2.result.ResultInterface;
import org.h2.result.ResultTarget;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.result.SortOrder;
import org.h2.table.Column;
import org.h2.table.ColumnResolver;
import org.h2.table.IndexColumn;
import org.h2.table.JoinBatch;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.table.TableView;
import org.h2.util.ColumnNamer;
import org.h2.util.New;
import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils;
import org.h2.util.ValueHashMap;
import org.h2.result.*;
import org.h2.table.*;
import org.h2.util.*;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
/**
* This class represents a simple SELECT statement.
*
......@@ -409,13 +388,13 @@ public class Select extends Query {
sortColumns.add(exprCol.getColumn());
}
Column[] sortCols = sortColumns.toArray(new Column[sortColumns.size()]);
int[] sortTypes = sort.getSortTypes();
if (sortCols.length == 0) {
// sort just on constants - can use scan index
return topTableFilter.getTable().getScanIndex(session);
}
ArrayList<Index> list = topTableFilter.getTable().getIndexes();
if (list != null) {
int[] sortTypes = sort.getSortTypesWithNullPosition();
for (int i = 0, size = list.size(); i < size; i++) {
Index index = list.get(i);
if (index.getCreateSQL() == null) {
......@@ -439,9 +418,7 @@ public class Select extends Query {
ok = false;
break;
}
if (idxCol.sortType != sortTypes[j]) {
// NULL FIRST for ascending and NULLS LAST
// for descending would actually match the default
if (SortOrder.addExplicitNullPosition(idxCol.sortType) != sortTypes[j]) {
ok = false;
break;
}
......
......@@ -78,7 +78,7 @@ public class DbSettings extends SettingsBase {
* performance reasons. Please note the Oracle JDBC driver will try to
* resolve this database URL if it is loaded before the H2 driver.
*/
public boolean defaultConnection = get("DEFAULT_CONNECTION", false);
public final boolean defaultConnection = get("DEFAULT_CONNECTION", false);
/**
* Database setting <code>DEFAULT_ESCAPE</code> (default: \).<br />
......@@ -162,7 +162,7 @@ public class DbSettings extends SettingsBase {
* no limit. Please note the actual query timeout may be set to a lower
* value.
*/
public int maxQueryTimeout = get("MAX_QUERY_TIMEOUT", 0);
public final int maxQueryTimeout = get("MAX_QUERY_TIMEOUT", 0);
/**
* Database setting <code>NESTED_JOINS</code> (default: true).<br />
......
......@@ -22,11 +22,6 @@ public class Mode {
REGULAR, DB2, Derby, MSSQLServer, HSQLDB, MySQL, Oracle, PostgreSQL, Ignite,
}
/**
* The name of the default mode.
*/
static final String REGULAR = ModeEnum.REGULAR.name();
private static final HashMap<String, Mode> MODES = New.hashMap();
// Modes are also documented in the features section
......@@ -317,10 +312,6 @@ public class Mode {
return MODES.get(StringUtils.toUpperEnglish(name));
}
public static Mode getMySQL() {
return getInstance(ModeEnum.MySQL.name());
}
public static Mode getOracle() {
return getInstance(ModeEnum.Oracle.name());
}
......
......@@ -1312,8 +1312,8 @@ public class Session extends SessionWithState {
}
if (removeLobMap == null) {
removeLobMap = New.hashMap();
removeLobMap.put(v.toString(), v);
}
removeLobMap.put(v.toString(), v);
}
/**
......
......@@ -92,7 +92,7 @@ public class SessionRemote extends SessionWithState implements DataHandler {
private JavaObjectSerializer javaObjectSerializer;
private volatile boolean javaObjectSerializerInitialized;
private CompareMode compareMode = CompareMode.getInstance(null, 0);
private final CompareMode compareMode = CompareMode.getInstance(null, 0);
public SessionRemote(ConnectionInfo ci) {
this.connectionInfo = ci;
......
......@@ -64,6 +64,10 @@ public class SettingsBase {
* @return the setting
*/
protected String get(String key, String defaultValue) {
String v = settings.get(key);
if (v != null) {
return v;
}
StringBuilder buff = new StringBuilder("h2.");
boolean nextUpper = false;
for (char c : key.toCharArray()) {
......@@ -76,11 +80,8 @@ public class SettingsBase {
}
}
String sysProperty = buff.toString();
String v = settings.get(key);
if (v == null) {
v = Utils.getProperty(sysProperty, defaultValue);
settings.put(key, v);
}
v = Utils.getProperty(sysProperty, defaultValue);
settings.put(key, v);
return v;
}
......
......@@ -85,17 +85,6 @@ public class SysProperties {
public static final String ALLOWED_CLASSES =
Utils.getProperty("h2.allowedClasses", "*");
/**
* System property <code>h2.browser</code> (default: null).<br />
* The preferred browser to use. If not set, the default browser is used.
* For Windows, to use the Internet Explorer, set this property to
* 'explorer'. For Mac OS, if the default browser is not Safari and you want
* to use Safari, use:
* <code>java -Dh2.browser="open,-a,Safari,%url" ...</code>.
*/
public static final String BROWSER =
Utils.getProperty(H2_BROWSER, null);
/**
* System property <code>h2.enableAnonymousTLS</code> (default: true).<br />
* When using TLS connection, the anonymous cipher suites should be enabled.
......
......@@ -422,6 +422,11 @@ public class CompareLike extends Condition {
}
patternString = new String(patternChars, 0, patternLength);
// Clear optimizations
shortcutToStartsWith = false;
shortcutToEndsWith = false;
shortcutToContains = false;
// optimizes the common case of LIKE 'foo%'
if (compareMode.getName().equals(CompareMode.OFF) && patternLength > 1) {
int maxMatch = 0;
......
......@@ -44,7 +44,6 @@ import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.tools.CompressTool;
import org.h2.tools.Csv;
import org.h2.util.AutoCloseInputStream;
import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
......@@ -1252,7 +1251,7 @@ public class Function extends Expression implements FunctionCall {
case TRUNCATE: {
if (v0.getType() == Value.TIMESTAMP) {
java.sql.Timestamp d = v0.getTimestamp();
Calendar c = Calendar.getInstance();
Calendar c = DateTimeUtils.createGregorianCalendar();
c.setTime(d);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
......@@ -1261,7 +1260,7 @@ public class Function extends Expression implements FunctionCall {
result = ValueTimestamp.fromMillis(c.getTimeInMillis());
} else if (v0.getType() == Value.DATE) {
ValueDate vd = (ValueDate) v0;
Calendar c = Calendar.getInstance();
Calendar c = DateTimeUtils.createGregorianCalendar();
c.setTime(vd.getDate());
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
......@@ -1270,7 +1269,7 @@ public class Function extends Expression implements FunctionCall {
result = ValueTimestamp.fromMillis(c.getTimeInMillis());
} else if (v0.getType() == Value.STRING) {
ValueString vd = (ValueString) v0;
Calendar c = Calendar.getInstance();
Calendar c = DateTimeUtils.createGregorianCalendar();
c.setTime(ValueTimestamp.parse(vd.getString(), session.getDatabase().getMode()).getDate());
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
......@@ -1637,18 +1636,21 @@ public class Function extends Expression implements FunctionCall {
boolean blob = args.length == 1;
try {
long fileLength = FileUtils.size(fileName);
InputStream in = new AutoCloseInputStream(
FileUtils.newInputStream(fileName));
if (blob) {
result = database.getLobStorage().createBlob(in, fileLength);
} else {
Reader reader;
if (v1 == ValueNull.INSTANCE) {
reader = new InputStreamReader(in);
final InputStream in = FileUtils.newInputStream(fileName);
try {
if (blob) {
result = database.getLobStorage().createBlob(in, fileLength);
} else {
reader = new InputStreamReader(in, v1.getString());
Reader reader;
if (v1 == ValueNull.INSTANCE) {
reader = new InputStreamReader(in);
} else {
reader = new InputStreamReader(in, v1.getString());
}
result = database.getLobStorage().createClob(reader, fileLength);
}
result = database.getLobStorage().createClob(reader, fileLength);
} finally {
IOUtils.closeSilently(in);
}
session.addTemporaryLob(result);
} catch (IOException e) {
......@@ -1822,7 +1824,7 @@ public class Function extends Expression implements FunctionCall {
if (count > Integer.MAX_VALUE) {
throw DbException.getInvalidValueException("DATEADD count", count);
}
Calendar calendar = Calendar.getInstance();
Calendar calendar = DateTimeUtils.createGregorianCalendar();
int nanos = d.getNanos() % 1000000;
calendar.setTime(d);
calendar.add(field, (int) count);
......@@ -1846,7 +1848,7 @@ public class Function extends Expression implements FunctionCall {
*/
private static long datediff(String part, Timestamp d1, Timestamp d2) {
int field = getDatePart(part);
Calendar calendar = Calendar.getInstance();
Calendar calendar = DateTimeUtils.createGregorianCalendar();
long t1 = d1.getTime(), t2 = d2.getTime();
// need to convert to UTC, otherwise we get inconsistent results with
// certain time zones (those that are 30 minutes off)
......@@ -1896,7 +1898,7 @@ public class Function extends Expression implements FunctionCall {
default:
break;
}
calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calendar = DateTimeUtils.createGregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.setTimeInMillis(t1);
int year1 = calendar.get(Calendar.YEAR);
int month1 = calendar.get(Calendar.MONTH);
......
......@@ -17,7 +17,7 @@ import org.h2.value.Value;
*/
public class FunctionCursor implements Cursor {
private Session session;
private final Session session;
private final ResultInterface result;
private Value[] values;
private Row row;
......
......@@ -17,7 +17,7 @@ import org.h2.value.ValueLong;
*/
class RangeCursor implements Cursor {
private Session session;
private final Session session;
private boolean beforeFirst;
private long current;
private Row currentRow;
......
......@@ -3799,7 +3799,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
} else if (type == java.util.Date.class) {
return type.cast(new java.util.Date(value.getTimestamp().getTime()));
} else if (type == Calendar.class) {
Calendar calendar = Calendar.getInstance();
Calendar calendar = DateTimeUtils.createGregorianCalendar();
calendar.setTime(value.getTimestamp());
return type.cast(calendar);
} else if (type == UUID.class) {
......
......@@ -56,7 +56,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
private final DataType keyType;
private final DataType valueType;
private ConcurrentArrayList<Page> oldRoots =
private final ConcurrentArrayList<Page> oldRoots =
new ConcurrentArrayList<>();
......
......@@ -277,7 +277,7 @@ public final class MVStore {
private int autoCompactFillRate;
private long autoCompactLastFileOpCount;
private Object compactSync = new Object();
private final Object compactSync = new Object();
private IllegalStateException panicException;
......
......@@ -1192,7 +1192,7 @@ public class CacheLongKeyLIRS<V> {
* The number of entries in the non-resident queue, as a factor of the
* number of all other entries in the map.
*/
public int nonResidentQueueSize = 3;
public final int nonResidentQueueSize = 3;
}
......
......@@ -49,7 +49,7 @@ public class MVPrimaryIndex extends BaseIndex {
private final MVTable mvTable;
private final String mapName;
private TransactionMap<Value, Value> dataMap;
private final TransactionMap<Value, Value> dataMap;
private final AtomicLong lastKey = new AtomicLong(0);
private int mainIndexColumn = -1;
......
......@@ -52,8 +52,8 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
final MVTable mvTable;
private final String mapName;
private TransactionMap<SpatialKey, Value> dataMap;
private MVRTreeMap<VersionedValue> spatialMap;
private final TransactionMap<SpatialKey, Value> dataMap;
private final MVRTreeMap<VersionedValue> spatialMap;
/**
* Constructor.
......
......@@ -59,7 +59,7 @@ public class TransactionStore {
/**
* The map of maps.
*/
private HashMap<Integer, MVMap<Object, VersionedValue>> maps =
private final HashMap<Integer, MVMap<Object, VersionedValue>> maps =
New.hashMap();
private final DataType dataType;
......@@ -896,7 +896,7 @@ public class TransactionStore {
*/
final MVMap<K, VersionedValue> map;
private Transaction transaction;
private final Transaction transaction;
TransactionMap(Transaction transaction, MVMap<K, VersionedValue> map,
int mapId) {
......
......@@ -17,7 +17,7 @@ import org.h2.value.Value;
*/
public abstract class LazyResult implements ResultInterface {
private Expression[] expressions;
private final Expression[] expressions;
private int rowId = -1;
private Value[] currentRow;
private Value[] nextRow;
......
......@@ -5,10 +5,6 @@
*/
package org.h2.result;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import org.h2.command.dml.SelectOrderBy;
import org.h2.engine.Database;
import org.h2.engine.SysProperties;
......@@ -22,6 +18,10 @@ import org.h2.util.Utils;
import org.h2.value.Value;
import org.h2.value.ValueNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/**
* A sort order represents an ORDER BY clause in a query.
*/
......@@ -55,6 +55,16 @@ public class SortOrder implements Comparator<Value[]> {
private static final int DEFAULT_NULL_SORT =
SysProperties.SORT_NULLS_HIGH ? 1 : -1;
/**
* The default sort order bit for NULLs last.
*/
private static final int DEFAULT_NULLS_LAST = SysProperties.SORT_NULLS_HIGH ? NULLS_LAST : NULLS_FIRST;
/**
* The default sort order bit for NULLs first.
*/
private static final int DEFAULT_NULLS_FIRST = SysProperties.SORT_NULLS_HIGH ? NULLS_FIRST : NULLS_LAST;
private final Database database;
/**
......@@ -261,4 +271,32 @@ public class SortOrder implements Comparator<Value[]> {
return sortTypes;
}
/**
* Returns sort order bit masks with {@link #NULLS_FIRST} or {@link #NULLS_LAST}
* explicitly set, depending on {@link SysProperties#SORT_NULLS_HIGH}.
*
* @return bit masks with either {@link #NULLS_FIRST} or {@link #NULLS_LAST} explicitly set.
*/
public int[] getSortTypesWithNullPosition() {
final int[] sortTypes = this.sortTypes.clone();
for (int i=0, length = sortTypes.length; i<length; i++) {
sortTypes[i] = addExplicitNullPosition(sortTypes[i]);
}
return sortTypes;
}
/**
* Returns a sort type bit mask with {@link #NULLS_FIRST} or {@link #NULLS_LAST}
* explicitly set, depending on {@link SysProperties#SORT_NULLS_HIGH}.
*
* @param sortType sort type bit mask
* @return bit mask with either {@link #NULLS_FIRST} or {@link #NULLS_LAST} explicitly set.
*/
public static int addExplicitNullPosition(final int sortType) {
if ((sortType & NULLS_FIRST) != NULLS_FIRST && (sortType & NULLS_LAST) != NULLS_LAST) {
return sortType | ((sortType & DESCENDING) == ASCENDING ? DEFAULT_NULLS_LAST : DEFAULT_NULLS_FIRST);
} else {
return sortType;
}
}
}
......@@ -49,11 +49,6 @@ public class PgServer implements Service {
*/
public static final int PG_TYPE_VARCHAR = 1043;
/**
* The integer array type (for the column pg_index.indkey).
*/
public static final int PG_TYPE_INT2VECTOR = 22;
public static final int PG_TYPE_BOOL = 16;
public static final int PG_TYPE_BYTEA = 17;
public static final int PG_TYPE_BPCHAR = 1042;
......
......@@ -62,7 +62,7 @@ public class PgServerThread implements Runnable {
private String userName;
private String databaseName;
private int processId;
private int secret;
private final int secret;
private JdbcStatement activeRequest;
private String clientEncoding = SysProperties.PG_DEFAULT_CLIENT_ENCODING;
private String dateStyle = "ISO";
......
......@@ -24,7 +24,6 @@ import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import org.h2.engine.Constants;
import org.h2.engine.SysProperties;
import org.h2.message.DbException;
......@@ -189,22 +188,6 @@ public class WebServer implements Service {
return data;
}
/**
* Check if this is a simple name (only contains '.', '-', '_', letters, or
* digits).
*
* @param s the string
* @return true if it's a simple name
*/
static boolean isSimpleName(String s) {
for (char c : s.toCharArray()) {
if (c != '.' && c != '_' && c != '-' && !Character.isLetterOrDigit(c)) {
return false;
}
}
return true;
}
/**
* Remove this web thread from the set of running threads.
*
......
......@@ -7,7 +7,7 @@ a.remoteConnectionsDisabled=Verbindungen von anderen Rechnern sind nicht freigeg
a.title=H2 Console
a.tools=Tools
a.user=Benutzername
admin.executing=Aktiv
admin.executing=Aktive Ausführung
admin.ip=IP
admin.lastAccess=Letzter Zugriff
admin.lastQuery=Letzter Befehl
......@@ -16,28 +16,28 @@ admin.notConnected=nicht verbunden
admin.url=URL
admin.yes=Ja
adminAllow=Zugelassene Verbindungen
adminConnection=Verbindungs-Sicherheit
adminHttp=Unverschlüsselte HTTP Verbindungen
adminHttps=Verschlüsselte HTTPS Verbindungen
adminConnection=Verbindungssicherheit
adminHttp=Unverschlüsselte HTTP Verbindungen verwenden
adminHttps=Verschlüsselte HTTPS Verbindungen verwenden
adminLocal=Nur lokale Verbindungen erlauben
adminLogin=Administration Login
adminLoginCancel=Abbrechen
adminLoginOk=OK
adminLogout=Beenden
adminOthers=Verbindungen von anderen Computern erlauben
adminPort=Port
adminPort=Admin Port
adminPortWeb=Web-Server Port
adminRestart=Änderungen werden nach einem Neustart des Servers aktiv.
adminSave=Speichern
adminSessions=Aktive Verbindungen
adminShutdown=Shutdown
adminShutdown=Herunterfahren
adminTitle=H2 Console Optionen
adminTranslateHelp=Die H2 Console übersetzen oder die Übersetzung verbessern.
adminTranslateStart=Übersetzen
helpAction=Aktion
helpAddAnotherRow=Fügt einen weiteren Datensatz hinzu
helpAddDrivers=Datenbank Treiber hinzufügen
helpAddDriversText=Es ist möglich zusätzliche Datenbank-Treiber zu laden, indem die Pfade der Treiber-Dateien in den Umgebungsvariablen H2DRIVERS oder CLASSPATH eingetragen werden. Beispiel (Windows): Um den Datenbank-Treiber mit dem Jar-File C:/Programs/hsqldb/lib/hsqldb.jar hinzuzufügen, setzen Sie den die Umgebungvariable H2DRIVERS auf C:/Programs/hsqldb/lib/hsqldb.jar.
helpAddDriversText=Es ist möglich, zusätzliche Datenbank-Treiber zu laden, indem die Pfade der Treiber-Dateien in den Umgebungsvariablen H2DRIVERS oder CLASSPATH eingetragen werden. Beispiel (Windows): Um den Datenbank-Treiber mit dem Jar-File C:/Programs/hsqldb/lib/hsqldb.jar hinzuzufügen, setzen Sie die Umgebungvariable H2DRIVERS auf C:/Programs/hsqldb/lib/hsqldb.jar.
helpAddRow=Fügt einen Datensatz hinzu
helpCommandHistory=Zeigt die Befehls-Chronik
helpCreateTable=Erzeugt eine neue Tabelle
......@@ -113,13 +113,13 @@ toolbar.run=Ausführen
toolbar.runSelected=Ausgewähltes Ausführen
toolbar.sqlStatement=SQL Befehl
tools.backup=Backup
tools.backup.help=Erzeugt eine Sichheitskopie eine Datenbank.
tools.backup.help=Erzeugt eine Sicherheitskopie einer Datenbank.
tools.changeFileEncryption=ChangeFileEncryption
tools.changeFileEncryption.help=Erlaubt, Datei Verschlüsselungs-Passwort und -Algorithmus einer Datenbank zu ändern.
tools.cipher=Verschlüsselung (AES oder XTEA)
tools.commandLine=Kommandozeile
tools.convertTraceFile=ConvertTraceFile
tools.convertTraceFile.help=Konvertiert eine .trace.db Datei in eine Java Applikation und ein SQL Script.
tools.convertTraceFile.help=Konvertiert eine .trace.db Datei in eine Java Applikation und ein SQL Skript.
tools.createCluster=CreateCluster
tools.createCluster.help=Generiert ein Cluster aus einer autonomen Datenbank.
tools.databaseName=Datenbankname
......@@ -130,27 +130,27 @@ tools.directory=Verzeichnis
tools.encryptionPassword=Verschlüsselungs-Passwort
tools.javaDirectoryClassName=Java Verzeichnis- und Klassen-Name
tools.recover=Recover
tools.recover.help=Hilft bei der Reparatur eine beschädigten Datenbank.
tools.recover.help=Hilft bei der Reparatur einer beschädigten Datenbank.
tools.restore=Restore
tools.restore.help=Stellt eine Datenbank aus einem Backup her.
tools.result=Ergebnis
tools.run=Start
tools.runScript=RunScript
tools.runScript.help=Führt ein SQL Script aus.
tools.runScript.help=Führt ein SQL Skript aus.
tools.script=Script
tools.script.help=Generiert eine SQL Script einer Datenbank für Backup- und Migrationszwecke.
tools.scriptFileName=Script Dateiname
tools.serverList=Server List
tools.script.help=Generiert ein SQL Skript einer Datenbank für Backup- und Migrationszwecke.
tools.scriptFileName=Skript Dateiname
tools.serverList=Server Liste
tools.sourceDatabaseName=Quell-Datenbankname
tools.sourceDatabaseURL=Quell-Datenbank URL
tools.sourceDirectory=Quell-Verzeichnis
tools.sourceFileName=Quell-Dateiname
tools.sourceScriptFileName=Dateiname des Scripts (Quelle)
tools.sourceScriptFileName=Dateiname des Skripts (Quelle)
tools.targetDatabaseName=Ziel-Datenbankname
tools.targetDatabaseURL=Ziel-Datenbank URL
tools.targetDirectory=Ziel-Verzeichnis
tools.targetFileName=Ziel-Dateiname
tools.targetScriptFileName=Dateiname des Scripts (Ziel)
tools.targetScriptFileName=Dateiname des Skripts (Ziel)
tools.traceFileName=Name der Trace Datei
tree.admin=Administrator
tree.current=Aktueller Wert
......
......@@ -594,28 +594,6 @@ public class LobStorageBackend implements LobStorageInterface {
return lob;
}
@Override
public void setTable(ValueLobDb lob, int table) {
long lobId = lob.getLobId();
assertNotHolds(conn.getSession());
// see locking discussion at the top
synchronized (database) {
synchronized (conn.getSession()) {
try {
init();
String sql = "UPDATE " + LOBS + " SET TABLE = ? WHERE ID = ?";
PreparedStatement prep = prepare(sql);
prep.setInt(1, table);
prep.setLong(2, lobId);
prep.executeUpdate();
reuse(sql, prep);
} catch (SQLException e) {
throw DbException.convert(e);
}
}
}
}
private static void assertNotHolds(Object lock) {
if (Thread.holdsLock(lock)) {
throw DbException.throwInternalError(lock.toString());
......
......@@ -72,11 +72,6 @@ public class LobStorageFrontend implements LobStorageInterface {
throw new UnsupportedOperationException();
}
@Override
public void setTable(ValueLobDb lob, int tableIdSessionVariable) {
throw new UnsupportedOperationException();
}
@Override
public void removeAllForTable(int tableId) {
throw new UnsupportedOperationException();
......
......@@ -55,14 +55,6 @@ public interface LobStorageInterface {
InputStream getInputStream(ValueLobDb lob, byte[] hmac, long byteCount)
throws IOException;
/**
* Set the table reference of this lob.
*
* @param lob the lob
* @param table the table
*/
void setTable(ValueLobDb lob, int table);
/**
* Delete a LOB (from the database, if it is stored there).
*
......
......@@ -37,7 +37,7 @@ public class LobStorageMap implements LobStorageInterface {
private boolean init;
private Object nextLobIdSync = new Object();
private final Object nextLobIdSync = new Object();
private long nextLobId;
/**
......@@ -289,19 +289,6 @@ public class LobStorageMap implements LobStorageInterface {
return streamStore.get(streamStoreId);
}
@Override
public void setTable(ValueLobDb lob, int tableId) {
init();
long lobId = lob.getLobId();
Object[] value = lobMap.remove(lobId);
if (TRACE) {
trace("move " + lob.getTableId() + "/" + lob.getLobId() +
" > " + tableId + "/" + lobId);
}
value[1] = tableId;
lobMap.put(lobId, value);
}
@Override
public void removeAllForTable(int tableId) {
init();
......
......@@ -299,13 +299,15 @@ public class FilePathDisk extends FilePath {
// file name with a colon
if (name.startsWith(CLASSPATH_PREFIX)) {
String fileName = name.substring(CLASSPATH_PREFIX.length());
// Force absolute resolution in Class.getResourceAsStream
if (!fileName.startsWith("/")) {
fileName = "/" + fileName;
}
InputStream in = getClass().getResourceAsStream(fileName);
if (in == null) {
// ClassLoader.getResourceAsStream doesn't need leading "/"
in = Thread.currentThread().getContextClassLoader().
getResourceAsStream(fileName);
getResourceAsStream(fileName.substring(1));
}
if (in == null) {
throw new FileNotFoundException("resource " + fileName);
......
......@@ -95,10 +95,6 @@ public class Column {
this(name, type, -1, -1, -1, null);
}
public Column(String name, int type, String[] enumerators) {
this(name, type, -1, -1, -1, enumerators);
}
public Column(String name, int type, long precision, int scale,
int displaySize) {
this(name, type, precision, scale, displaySize, null);
......
......@@ -87,7 +87,7 @@ public final class JoinBatch {
/**
* The filters.
*/
JoinFilter[] filters;
final JoinFilter[] filters;
/**
* Whether this is a batched subquery.
......
......@@ -10,7 +10,6 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import org.h2.message.DbException;
import org.h2.tools.SimpleResultSet;
import org.h2.util.JdbcUtils;
......@@ -81,6 +80,8 @@ public class LinkSchema {
append(", ").
append(StringUtils.quoteStringSQL(password)).
append(", ").
append(StringUtils.quoteStringSQL(sourceSchema)).
append(", ").
append(StringUtils.quoteStringSQL(table)).
append(')');
stat.execute(buff.toString());
......
......@@ -15,11 +15,11 @@ import org.h2.result.SortOrder;
*/
public class SubQueryInfo {
private int[] masks;
private TableFilter[] filters;
private int filter;
private SortOrder sortOrder;
private SubQueryInfo upper;
private final int[] masks;
private final TableFilter[] filters;
private final int filter;
private final SortOrder sortOrder;
private final SubQueryInfo upper;
/**
* @param upper upper level sub-query if any
......
......@@ -8,10 +8,10 @@ package org.h2.table;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Objects;
import org.h2.message.DbException;
import org.h2.util.JdbcUtils;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
/**
* A connection for a linked table. The same connection may be used for multiple
......@@ -95,10 +95,10 @@ public class TableLinkConnection {
@Override
public int hashCode() {
return Utils.hashCode(driver)
^ Utils.hashCode(url)
^ Utils.hashCode(user)
^ Utils.hashCode(password);
return Objects.hashCode(driver)
^ Objects.hashCode(url)
^ Objects.hashCode(user)
^ Objects.hashCode(password);
}
@Override
......
......@@ -12,7 +12,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.StringTokenizer;
import org.h2.message.DbException;
import org.h2.store.fs.FileUtils;
import org.h2.util.IOUtils;
......
......@@ -23,7 +23,7 @@ import java.util.WeakHashMap;
*/
public class AbbaLockingDetector implements Runnable {
private int tickIntervalMs = 2;
private final int tickIntervalMs = 2;
private volatile boolean stop;
private final ThreadMXBean threadMXBean =
......
/*
* Copyright 2004-2014 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.util;
import java.io.IOException;
import java.io.InputStream;
/**
* This input stream wrapper closes the base input stream when fully read.
*/
public class AutoCloseInputStream extends InputStream {
private final InputStream in;
private boolean closed;
/**
* Create a new input stream.
*
* @param in the input stream
*/
public AutoCloseInputStream(InputStream in) {
this.in = in;
}
private int autoClose(int x) throws IOException {
if (x < 0) {
close();
}
return x;
}
@Override
public void close() throws IOException {
if (!closed) {
in.close();
closed = true;
}
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return closed ? -1 : autoClose(in.read(b, off, len));
}
@Override
public int read(byte[] b) throws IOException {
return closed ? -1 : autoClose(in.read(b));
}
@Override
public int read() throws IOException {
return closed ? -1 : autoClose(in.read());
}
}
......@@ -17,8 +17,8 @@ public class ColumnNamer {
private static final String DEFAULT_COLUMN_NAME = "DEFAULT";
private ColumnNamerConfiguration configuration;
private Session session;
private final ColumnNamerConfiguration configuration;
private final Session session;
private final Set<String> existingColumnNames = new HashSet<>();
public ColumnNamer(Session session) {
......@@ -35,15 +35,6 @@ public class ColumnNamer {
}
}
/**
* Create a standardized column name that isn't null and doesn't have a CR/LF in it.
* @param expr the column expression
* @param indexOfColumn index of column in below array
*/
public String getColumnName(Expression expr, int indexOfColumn) {
return getColumnName(expr, indexOfColumn, (String) null);
}
/**
* Create a standardized column name that isn't null and doesn't have a CR/LF in it.
* @param columnExp the column expression
......
......@@ -73,7 +73,7 @@ public class DateTimeUtils {
* use a fixed value throughout the duration of the JVM's life, rather than
* have this offset change, possibly midway through a long-running query.
*/
private static int zoneOffsetMillis = Calendar.getInstance()
private static int zoneOffsetMillis = DateTimeUtils.createGregorianCalendar()
.get(Calendar.ZONE_OFFSET);
private DateTimeUtils() {
......@@ -86,7 +86,7 @@ public class DateTimeUtils {
*/
public static void resetCalendar() {
CACHED_CALENDAR.remove();
zoneOffsetMillis = Calendar.getInstance().get(Calendar.ZONE_OFFSET);
zoneOffsetMillis = DateTimeUtils.createGregorianCalendar().get(Calendar.ZONE_OFFSET);
}
/**
......@@ -97,7 +97,7 @@ public class DateTimeUtils {
private static Calendar getCalendar() {
Calendar c = CACHED_CALENDAR.get();
if (c == null) {
c = Calendar.getInstance();
c = DateTimeUtils.createGregorianCalendar();
CACHED_CALENDAR.set(c);
}
c.clear();
......@@ -113,13 +113,40 @@ public class DateTimeUtils {
private static Calendar getCalendar(TimeZone tz) {
Calendar c = CACHED_CALENDAR_NON_DEFAULT_TIMEZONE.get();
if (c == null || !c.getTimeZone().equals(tz)) {
c = Calendar.getInstance(tz);
c = DateTimeUtils.createGregorianCalendar(tz);
CACHED_CALENDAR_NON_DEFAULT_TIMEZONE.set(c);
}
c.clear();
return c;
}
/**
* Creates a Gregorian calendar for the default timezone using the default
* locale. Dates in H2 are represented in a Gregorian calendar. So this
* method should be used instead of Calendar.getInstance() to ensure that
* the Gregorian calendar is used for all date processing instead of a
* default locale calendar that can be non-Gregorian in some locales.
*
* @return a new calendar instance.
*/
public static Calendar createGregorianCalendar() {
return new GregorianCalendar();
}
/**
* Creates a Gregorian calendar for the given timezone using the default
* locale. Dates in H2 are represented in a Gregorian calendar. So this
* method should be used instead of Calendar.getInstance() to ensure that
* the Gregorian calendar is used for all date processing instead of a
* default locale calendar that can be non-Gregorian in some locales.
*
* @param tz timezone for the calendar, is never null
* @return a new calendar instance.
*/
public static Calendar createGregorianCalendar(TimeZone tz) {
return new GregorianCalendar(tz);
}
/**
* Convert the date to the specified time zone.
*
......@@ -253,11 +280,9 @@ public class DateTimeUtils {
throw DbException.getInvalidValueException("calendar", null);
}
target = (Calendar) target.clone();
Calendar local = Calendar.getInstance();
synchronized (local) {
local.setTime(x);
convertTime(local, target);
}
Calendar local = DateTimeUtils.createGregorianCalendar();
local.setTime(x);
convertTime(local, target);
return target.getTime().getTime();
}
......@@ -531,7 +556,7 @@ public class DateTimeUtils {
* @return the day of the week, Monday as 1 to Sunday as 7
*/
public static int getIsoDayOfWeek(java.util.Date date) {
Calendar cal = Calendar.getInstance();
Calendar cal = DateTimeUtils.createGregorianCalendar();
cal.setTimeInMillis(date.getTime());
int val = cal.get(Calendar.DAY_OF_WEEK) - 1;
return val == 0 ? 7 : val;
......@@ -552,7 +577,7 @@ public class DateTimeUtils {
* @return the week of the year
*/
public static int getIsoWeek(java.util.Date date) {
Calendar c = Calendar.getInstance();
Calendar c = DateTimeUtils.createGregorianCalendar();
c.setTimeInMillis(date.getTime());
c.setFirstDayOfWeek(Calendar.MONDAY);
c.setMinimalDaysInFirstWeek(4);
......@@ -567,7 +592,7 @@ public class DateTimeUtils {
* @return the year
*/
public static int getIsoYear(java.util.Date date) {
Calendar cal = Calendar.getInstance();
Calendar cal = DateTimeUtils.createGregorianCalendar();
cal.setTimeInMillis(date.getTime());
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
......@@ -942,7 +967,7 @@ public class DateTimeUtils {
* @return the new timestamp
*/
public static Timestamp addMonths(Timestamp refDate, int nrOfMonthsToAdd) {
Calendar calendar = Calendar.getInstance();
Calendar calendar = DateTimeUtils.createGregorianCalendar();
calendar.setTime(refDate);
calendar.add(Calendar.MONTH, nrOfMonthsToAdd);
......
......@@ -11,11 +11,7 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Properties;
......@@ -294,7 +290,13 @@ public class JdbcUtils {
} else {
Class<?> d = loadUserClass(driver);
if (java.sql.Driver.class.isAssignableFrom(d)) {
return DriverManager.getConnection(url, prop);
try {
Driver driverInstance = (Driver) d.newInstance();
return driverInstance.connect(url, prop); /*fix issue #695 with drivers with the same
jdbc subprotocol in classpath of jdbc drivers (as example redshift and postgresql drivers)*/
} catch (Exception e) {
throw DbException.toSQLException(e);
}
} else if (javax.naming.Context.class.isAssignableFrom(d)) {
// JNDI context
try {
......
......@@ -8,11 +8,9 @@ package org.h2.util;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import org.h2.engine.Constants;
import org.h2.jdbcx.JdbcDataSource;
import org.osgi.framework.BundleContext;
......@@ -38,7 +36,7 @@ import org.osgi.service.jdbc.DataSourceFactory;
* @author Per Otterstrom
*/
public class OsgiDataSourceFactory implements DataSourceFactory {
private org.h2.Driver driver;
private final org.h2.Driver driver;
public OsgiDataSourceFactory(org.h2.Driver driver) {
this.driver = driver;
......
......@@ -13,7 +13,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public abstract class Task implements Runnable {
private static AtomicInteger counter = new AtomicInteger();
private final static AtomicInteger counter = new AtomicInteger();
/**
* A flag indicating the get() method has been called.
......@@ -94,16 +94,6 @@ public abstract class Task implements Runnable {
return finished;
}
/**
* Interrupt the thread.
*/
public void interruptThread() {
if (thread == null) {
throw new IllegalStateException("Thread not started");
}
thread.interrupt();
}
/**
* Get the exception that was thrown in the call (if any).
*
......
......@@ -21,7 +21,7 @@ public class ToDateParser {
private final ConfigParam functionName;
private String inputStr;
private String formatStr;
private final Calendar resultCalendar = (Calendar) Calendar.getInstance().clone();
private final Calendar resultCalendar = DateTimeUtils.createGregorianCalendar();
private Integer nanos;
/**
......@@ -33,7 +33,7 @@ public class ToDateParser {
private ToDateParser(ConfigParam functionName, String input, String format) {
// reset calendar - default oracle behaviour
resultCalendar.set(Calendar.YEAR, 1970);
resultCalendar.set(Calendar.MONTH, Calendar.getInstance().get(Calendar.MONTH));
resultCalendar.set(Calendar.MONTH, DateTimeUtils.createGregorianCalendar().get(Calendar.MONTH));
resultCalendar.clear(Calendar.DAY_OF_YEAR);
resultCalendar.clear(Calendar.DAY_OF_WEEK);
resultCalendar.clear(Calendar.DAY_OF_WEEK_IN_MONTH);
......
......@@ -194,7 +194,7 @@ class ToDateTokenizer {
result.set(Calendar.YEAR, dateNr);
break;
case RR:
Calendar calendar = Calendar.getInstance();
Calendar calendar = DateTimeUtils.createGregorianCalendar();
int cc = calendar.get(Calendar.YEAR) / 100;
inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS,
params, formatTokenEnum);
......
......@@ -270,16 +270,6 @@ public class Utils {
return copy;
}
/**
* Calculate the hash code of the given object. The object may be null.
*
* @param o the object
* @return the hash code, or 0 if the object is null
*/
public static int hashCode(Object o) {
return o == null ? 0 : o.hashCode();
}
/**
* Get the used memory in KB.
* This method possibly calls System.gc().
......
......@@ -54,7 +54,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
private final String fileName;
private final FileStore tempFile;
private int tableId;
private final int tableId;
private int hash;
//Arbonaut: 13.07.2016
......@@ -84,6 +84,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
this.handler = null;
this.fileName = null;
this.tempFile = null;
this.tableId = 0;
}
/**
......@@ -115,6 +116,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
}
}
this.precision = tmpPrecision;
this.tableId = 0;
}
/**
......@@ -151,6 +153,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
out.close();
}
this.precision = tmpPrecision;
this.tableId = 0;
}
private static String createTempLobFileName(DataHandler handler)
......
......@@ -10,7 +10,6 @@ import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.TimeZone;
import org.h2.api.ErrorCode;
import org.h2.engine.Mode;
......@@ -217,7 +216,7 @@ public class ValueTimestamp extends Value {
tz, year, month, day, hour, minute, (int) second, (int) ms);
ms = DateTimeUtils.convertToLocal(
new Date(millis),
Calendar.getInstance(TimeZone.getTimeZone("UTC")));
DateTimeUtils.createGregorianCalendar(TimeZone.getTimeZone("UTC")));
long md = DateTimeUtils.MILLIS_PER_DAY;
long absoluteDay = (ms >= 0 ? ms : ms - md + 1) / md;
dateValue = DateTimeUtils.dateValueFromAbsoluteDay(absoluteDay);
......
......@@ -52,6 +52,7 @@ public class TestAlter extends TestBase {
testAlterTableAddMultipleColumnsAfter();
testAlterTableModifyColumn();
testAlterTableModifyColumnSetNull();
testAlterTableModifyColumnNotNullOracle();
conn.close();
deleteDb(getTestName());
}
......@@ -317,4 +318,16 @@ public class TestAlter extends TestBase {
stat.execute("insert into T values(null)"); // <- Fixed in v1.4.196 - NULL is allowed
stat.execute("drop table T");
}
private void testAlterTableModifyColumnNotNullOracle() throws SQLException {
stat.execute("create table foo (bar varchar(255))");
stat.execute("alter table foo modify (bar varchar(255) not null)");
try {
stat.execute("insert into foo values(null)");
fail("Null should not be allowed after modification.");
}
catch(SQLException e) {
// This is what we expect, fails to insert null.
}
}
}
......@@ -58,6 +58,7 @@ public class TestCases extends TestBase {
testSortedSelect();
testMaxMemoryRows();
testDeleteTop();
testLikeExpressions();
testUnicode();
testOuterJoin();
testCommentOnColumnWithSchemaEqualDatabase();
......@@ -1841,4 +1842,15 @@ public class TestCases extends TestBase {
conn.close();
}
/** Tests fix for bug #682: Queries with 'like' expressions may filter rows incorrectly */
private void testLikeExpressions() throws SQLException {
Connection conn = getConnection("cases");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("select * from (select 'fo%' a union all select '%oo') where 'foo' like a");
assertTrue(rs.next());
assertEquals("fo%", rs.getString(1));
assertTrue(rs.next());
assertEquals("%oo", rs.getString(1));
conn.close();
}
}
......@@ -1199,7 +1199,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
"SELECT CURRENT_TIMESTAMP(), " +
"TRUNCATE(CURRENT_TIMESTAMP()) FROM dual");
rs.next();
Calendar c = Calendar.getInstance();
Calendar c = DateTimeUtils.createGregorianCalendar();
c.setTime(rs.getTimestamp(1));
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
......@@ -1305,7 +1305,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
}
private void testToDate() throws ParseException {
final int month = Calendar.getInstance().get(Calendar.MONTH);
final int month = DateTimeUtils.createGregorianCalendar().get(Calendar.MONTH);
Date date = null;
date = new SimpleDateFormat("yyyy-MM-dd").parse("1979-11-12");
......@@ -1434,7 +1434,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
}
private static void setMonth(Date date, int month) {
Calendar c = Calendar.getInstance();
Calendar c = DateTimeUtils.createGregorianCalendar();
c.setTime(date);
c.set(Calendar.MONTH, month);
date.setTime(c.getTimeInMillis());
......
......@@ -5,18 +5,6 @@
*/
package org.h2.test.db;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import org.h2.api.ErrorCode;
import org.h2.test.TestBase;
import org.h2.tools.SimpleResultSet;
......@@ -24,6 +12,13 @@ import org.h2.util.New;
import org.h2.util.StringUtils;
import org.h2.util.Task;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
/**
* Test various optimizations (query cache, optimization for MIN(..), and
* MAX(..)).
......@@ -81,6 +76,7 @@ public class TestOptimizations extends TestBase {
testMinMaxCountOptimization(true);
testMinMaxCountOptimization(false);
testOrderedIndexes();
testIndexUseDespiteNullsFirst();
testConvertOrToIn();
deleteDb("optimizations");
}
......@@ -1034,6 +1030,85 @@ public class TestOptimizations extends TestBase {
conn.close();
}
private void testIndexUseDespiteNullsFirst() throws SQLException {
deleteDb("optimizations");
Connection conn = getConnection("optimizations");
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE my_table(K1 INT)");
stat.execute("CREATE INDEX my_index ON my_table(K1)");
stat.execute("INSERT INTO my_table VALUES (NULL)");
stat.execute("INSERT INTO my_table VALUES (1)");
stat.execute("INSERT INTO my_table VALUES (2)");
ResultSet rs;
String result;
rs = stat.executeQuery(
"EXPLAIN PLAN FOR SELECT * FROM my_table " +
"ORDER BY K1 ASC NULLS FIRST");
rs.next();
result = rs.getString(1);
assertContains(result, "/* index sorted */");
rs = stat.executeQuery(
"SELECT * FROM my_table " +
"ORDER BY K1 ASC NULLS FIRST");
rs.next();
assertNull(rs.getObject(1));
rs.next();
assertEquals(1, rs.getInt(1));
rs.next();
assertEquals(2, rs.getInt(1));
// ===
rs = stat.executeQuery(
"EXPLAIN PLAN FOR SELECT * FROM my_table " +
"ORDER BY K1 DESC NULLS FIRST");
rs.next();
result = rs.getString(1);
if (result.contains("/* index sorted */")) {
fail(result + " does not contain: /* index sorted */");
}
rs = stat.executeQuery(
"SELECT * FROM my_table " +
"ORDER BY K1 DESC NULLS FIRST");
rs.next();
assertNull(rs.getObject(1));
rs.next();
assertEquals(2, rs.getInt(1));
rs.next();
assertEquals(1, rs.getInt(1));
// ===
rs = stat.executeQuery(
"EXPLAIN PLAN FOR SELECT * FROM my_table " +
"ORDER BY K1 ASC NULLS LAST");
rs.next();
result = rs.getString(1);
if (result.contains("/* index sorted */")) {
fail(result + " does not contain: /* index sorted */");
}
rs = stat.executeQuery(
"SELECT * FROM my_table " +
"ORDER BY K1 ASC NULLS LAST");
rs.next();
assertEquals(1, rs.getInt(1));
rs.next();
assertEquals(2, rs.getInt(1));
rs.next();
assertNull(rs.getObject(1));
// TODO: Test "EXPLAIN PLAN FOR SELECT * FROM my_table ORDER BY K1 DESC NULLS FIRST"
// Currently fails, as using the index when sorting DESC is currently not supported.
stat.execute("DROP TABLE my_table");
conn.close();
}
private void testConvertOrToIn() throws SQLException {
deleteDb("optimizations");
Connection conn = getConnection("optimizations");
......
......@@ -37,6 +37,7 @@ import java.util.TimeZone;
import org.h2.api.ErrorCode;
import org.h2.test.TestBase;
import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils;
import org.h2.util.LocalDateTimeUtils;
......@@ -1408,7 +1409,7 @@ public class TestResultSet extends TestBase {
"D DATE, T TIME, TS TIMESTAMP)");
PreparedStatement prep = conn.prepareStatement(
"INSERT INTO TEST VALUES(?, ?, ?, ?)");
Calendar regular = Calendar.getInstance();
Calendar regular = DateTimeUtils.createGregorianCalendar();
Calendar other = null;
// search a locale that has a _different_ raw offset
long testTime = java.sql.Date.valueOf("2001-02-03").getTime();
......@@ -1421,7 +1422,7 @@ public class TestResultSet extends TestBase {
if (rawOffsetDiff != 0 && rawOffsetDiff != 1000 * 60 * 60 * 24) {
if (regular.getTimeZone().getOffset(testTime) !=
zone.getOffset(testTime)) {
other = Calendar.getInstance(zone);
other = DateTimeUtils.createGregorianCalendar(zone);
break;
}
}
......
......@@ -42,6 +42,7 @@ import org.h2.test.synth.sql.RandomGen;
import org.h2.tools.Backup;
import org.h2.tools.DeleteDbFiles;
import org.h2.tools.Restore;
import org.h2.util.DateTimeUtils;
import org.h2.util.MathUtils;
import org.h2.util.New;
......@@ -485,7 +486,7 @@ public class TestCrashAPI extends TestBase implements Runnable {
// TODO should use generated savepoints
return null;
} else if (type == Calendar.class) {
return Calendar.getInstance();
return DateTimeUtils.createGregorianCalendar();
} else if (type == java.net.URL.class) {
return null;
} else if (type == java.math.BigDecimal.class) {
......
......@@ -352,7 +352,7 @@ public class TestDate extends TestBase {
}
private void testValidDate() {
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Calendar c = DateTimeUtils.createGregorianCalendar(TimeZone.getTimeZone("UTC"));
c.setLenient(false);
for (int y = -2000; y < 3000; y++) {
for (int m = -3; m <= 14; m++) {
......@@ -467,9 +467,9 @@ public class TestDate extends TestBase {
assertEquals("19999-08-07", d2.getString());
assertEquals("13:14:15.16", t2.getString());
ValueTimestamp ts1a = DateTimeUtils.convertTimestamp(
ts1.getTimestamp(), Calendar.getInstance());
ts1.getTimestamp(), DateTimeUtils.createGregorianCalendar());
ValueTimestamp ts2a = DateTimeUtils.convertTimestamp(
ts2.getTimestamp(), Calendar.getInstance());
ts2.getTimestamp(), DateTimeUtils.createGregorianCalendar());
assertEquals("-999-08-07 13:14:15.16", ts1a.getString());
assertEquals("19999-08-07 13:14:15.16", ts2a.getString());
......
......@@ -29,6 +29,7 @@ public class TestLocale extends TestBase {
@Override
public void test() throws SQLException {
testSpecialLocale();
testDatesInJapanLocale();
}
private void testSpecialLocale() throws SQLException {
......@@ -55,4 +56,32 @@ public class TestLocale extends TestBase {
conn.close();
}
private void testDatesInJapanLocale() throws SQLException {
deleteDb(getTestName());
Connection conn = getConnection(getTestName());
Statement stat = conn.createStatement();
Locale old = Locale.getDefault();
try {
// when using Japanese as the default locale, the default calendar is
// the imperial japanese calendar
Locale.setDefault(new Locale("ja", "JP", "JP"));
stat.execute("CREATE TABLE test(d TIMESTAMP, dz TIMESTAMP WITH TIME ZONE) " +
"as select '2017-12-03T00:00:00Z', '2017-12-03T00:00:00Z'");
ResultSet rs = stat.executeQuery("select YEAR(d) y, YEAR(dz) yz from test");
rs.next();
assertEquals(2017, rs.getInt("y"));
assertEquals(2017, rs.getInt("yz"));
stat.execute("drop table test");
rs = stat.executeQuery(
"CALL FORMATDATETIME(TIMESTAMP '2001-02-03 04:05:06', 'yyyy-MM-dd HH:mm:ss', 'en')");
rs.next();
assertEquals("2001-02-03 04:05:06", rs.getString(1));
} finally {
Locale.setDefault(old);
}
conn.close();
}
}
......@@ -26,13 +26,12 @@ public class TestColumnNamer extends TestBase {
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String[] args) {
new TestColumnNamer().test();
}
@Override
public void test() {
ColumnNamer columnNamer = new ColumnNamer(null);
columnNamer.getConfiguration().configure("MAX_IDENTIFIER_LENGTH = 30");
......
......@@ -178,13 +178,13 @@ public class BuildBase {
/**
* The full path to the executable of the current JRE.
*/
protected String javaExecutable = System.getProperty("java.home") +
protected final String javaExecutable = System.getProperty("java.home") +
File.separator + "bin" + File.separator + "java";
/**
* The full path to the tools jar of the current JDK.
*/
protected String javaToolsJar = System.getProperty("java.home") + File.separator + ".." +
protected final String javaToolsJar = System.getProperty("java.home") + File.separator + ".." +
File.separator + "lib" + File.separator + "tools.jar";
/**
......
......@@ -394,21 +394,6 @@ public class XMLParser {
return eventType;
}
/**
* Read the next start, end, or character tag. This method skips comments,
* DTDs, and processing instructions.
*
* @return the event type of the next tag
*/
public int nextTag() {
while (true) {
int type = next();
if (type != COMMENT && type != DTD && type != PROCESSING_INSTRUCTION) {
return type;
}
}
}
/**
* Get the event type of the current token.
*
......@@ -465,46 +450,6 @@ public class XMLParser {
return attributeValues[index * 3 + 1];
}
/**
* Get the full name of the attribute. If there is no prefix, only the local
* name is returned, otherwise the prefix, ':', and the local name.
*
* @param index the index of the attribute (starting with 0)
* @return the full name
*/
public String getAttributeName(int index) {
String pre = getAttributePrefix(index);
String name = getAttributeLocalName(index);
return pre == null || pre.length() == 0 ? name : pre + ":" + name;
}
/**
* Get the value of this attribute.
*
* @param index the index of the attribute (starting with 0)
* @return the value
*/
public String getAttributeValue(int index) {
return attributeValues[index * 3 + 2];
}
/**
* Get the value of this attribute.
*
* @param namespaceURI the namespace URI (currently ignored)
* @param name the local name of the attribute
* @return the value or null
*/
public String getAttributeValue(@SuppressWarnings("unused") String namespaceURI, String name) {
int len = getAttributeCount();
for (int i = 0; i < len; i++) {
if (getAttributeLocalName(i).equals(name)) {
return getAttributeValue(i);
}
}
return null;
}
/**
* Get the full name of the current start or end element. If there is no
* prefix, only the local name is returned, otherwise the prefix, ':', and
......
......@@ -933,7 +933,7 @@ public class ArchiveTool {
static class Chunk implements Comparable<Chunk> {
ArrayList<Long> idList;
final byte[] value;
private int[] sortKey;
private final int[] sortKey;
Chunk(ArrayList<Long> idList, int[] sortKey, byte[] value) {
this.idList = idList;
......
......@@ -71,7 +71,7 @@ public class ThreadDumpCleaner {
};
private ArrayList<Pattern> patterns = new ArrayList<>();
private final ArrayList<Pattern> patterns = new ArrayList<>();
{
for (String s : PATTERN) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论