提交 2a239e30 authored 作者: tledkov's avatar tledkov

Merge branch 'master' into pre-release-cleanup

...@@ -1248,8 +1248,7 @@ SET CLUSTER '' ...@@ -1248,8 +1248,7 @@ SET CLUSTER ''
" "
"Commands (Other)","SET BINARY_COLLATION"," "Commands (Other)","SET BINARY_COLLATION","
SET BINARY_COLLATION SET BINARY_COLLATION { UNSIGNED | SIGNED }
{ UNSIGNED | SIGNED } ] }
"," ","
Sets the collation used for comparing BINARY columns, the default is SIGNED Sets the collation used for comparing BINARY columns, the default is SIGNED
for version 1.3 and older, and UNSIGNED for version 1.4 and newer. for version 1.3 and older, and UNSIGNED for version 1.4 and newer.
...@@ -1262,9 +1261,26 @@ This setting is persistent. ...@@ -1262,9 +1261,26 @@ This setting is persistent.
SET BINARY_COLLATION SIGNED SET BINARY_COLLATION SIGNED
" "
"Commands (Other)","SET UUID_COLLATION","
SET UUID_COLLATION { UNSIGNED | SIGNED }
","
Sets the collation used for comparing UUID columns, the default is SIGNED.
This command can only be executed if there are no tables defined.
SIGNED means signed comparison between first 64 bits of compared values treated as long values
and if they are equal a signed comparison of the last 64 bits of compared values treated as long values.
See also Java ""UUID.compareTo()"".
UNSIGNED means RFC 4122 compatible unsigned comparison.
Admin rights are required to execute this command.
This command commits an open transaction in this connection.
This setting is persistent.
","
SET UUID_COLLATION UNSIGNED
"
"Commands (Other)","SET BUILTIN_ALIAS_OVERRIDE"," "Commands (Other)","SET BUILTIN_ALIAS_OVERRIDE","
SET BUILTIN_ALIAS_OVERRIDE SET BUILTIN_ALIAS_OVERRIDE { TRUE | FALSE }
{ TRUE | FALSE } ] }
"," ","
Allows the overriding of the builtin system date/time functions Allows the overriding of the builtin system date/time functions
for unit testing purposes. for unit testing purposes.
...@@ -1436,7 +1452,6 @@ This setting can be appended to the database URL: ""jdbc:h2:test;JAVA_OBJECT_SER ...@@ -1436,7 +1452,6 @@ This setting can be appended to the database URL: ""jdbc:h2:test;JAVA_OBJECT_SER
SET JAVA_OBJECT_SERIALIZER 'com.acme.SerializerClassName' SET JAVA_OBJECT_SERIALIZER 'com.acme.SerializerClassName'
" "
"Commands (Other)","SET LAZY_QUERY_EXECUTION"," "Commands (Other)","SET LAZY_QUERY_EXECUTION","
SET LAZY_QUERY_EXECUTION int SET LAZY_QUERY_EXECUTION int
"," ","
...@@ -3206,7 +3221,6 @@ ARRAY ...@@ -3206,7 +3221,6 @@ ARRAY
An array of values. An array of values.
Mapped to ""java.lang.Object[]"" (arrays of any non-primitive type are also supported). Mapped to ""java.lang.Object[]"" (arrays of any non-primitive type are also supported).
Use a value list (1, 2) or ""PreparedStatement.setObject(.., new Object[] {..})"" to store values, Use a value list (1, 2) or ""PreparedStatement.setObject(.., new Object[] {..})"" to store values,
and ""ResultSet.getObject(..)"" or ""ResultSet.getArray(..)"" to retrieve the values. and ""ResultSet.getObject(..)"" or ""ResultSet.getArray(..)"" to retrieve the values.
"," ","
...@@ -4377,7 +4391,6 @@ Later flags overrides first ones, for example 'ic' equivalent to case sensitive ...@@ -4377,7 +4391,6 @@ Later flags overrides first ones, for example 'ic' equivalent to case sensitive
REGEXP_LIKE('Hello World', '[A-Z ]*', 'i') REGEXP_LIKE('Hello World', '[A-Z ]*', 'i')
" "
"Functions (String)","REPEAT"," "Functions (String)","REPEAT","
REPEAT(string, int) REPEAT(string, int)
"," ","
...@@ -5517,4 +5530,3 @@ Contains all values from start to end (this is a dynamic table). ...@@ -5517,4 +5530,3 @@ Contains all values from start to end (this is a dynamic table).
"," ","
SYSTEM_RANGE(0, 100) SYSTEM_RANGE(0, 100)
" "
...@@ -21,6 +21,10 @@ Change Log ...@@ -21,6 +21,10 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Issue #1620: UUIDs are unexpectedly sorted as signed
</li>
<li>PR #1614: Use bulk .addAll() operation
</li>
<li>PR #1613: Add explicit table query <li>PR #1613: Add explicit table query
</li> </li>
<li>Issue #1608: ARRAY and row value expression should not be the same <li>Issue #1608: ARRAY and row value expression should not be the same
......
...@@ -6653,7 +6653,10 @@ public class Parser { ...@@ -6653,7 +6653,10 @@ public class Parser {
return parseSetCollation(); return parseSetCollation();
} else if (readIf("BINARY_COLLATION")) { } else if (readIf("BINARY_COLLATION")) {
readIfEqualOrTo(); readIfEqualOrTo();
return parseSetBinaryCollation(); return parseSetBinaryCollation(SetTypes.BINARY_COLLATION);
} else if (readIf("UUID_COLLATION")) {
readIfEqualOrTo();
return parseSetBinaryCollation(SetTypes.UUID_COLLATION);
} else if (readIf("CLUSTER")) { } else if (readIf("CLUSTER")) {
readIfEqualOrTo(); readIfEqualOrTo();
Set command = new Set(session, SetTypes.CLUSTER); Set command = new Set(session, SetTypes.CLUSTER);
...@@ -6842,14 +6845,14 @@ public class Parser { ...@@ -6842,14 +6845,14 @@ public class Parser {
return command; return command;
} }
private Set parseSetBinaryCollation() { private Set parseSetBinaryCollation(int type) {
String name = readAliasIdentifier(); String name = readAliasIdentifier();
if (equalsToken(name, CompareMode.UNSIGNED) || equalsToken(name, CompareMode.SIGNED)) { if (equalsToken(name, CompareMode.UNSIGNED) || equalsToken(name, CompareMode.SIGNED)) {
Set command = new Set(session, SetTypes.BINARY_COLLATION); Set command = new Set(session, type);
command.setString(name); command.setString(name);
return command; return command;
} }
throw DbException.getInvalidValueException("BINARY_COLLATION", name); throw DbException.getInvalidValueException(SetTypes.getTypeName(type), name);
} }
private Set parseSetJavaObjectSerializer() { private Set parseSetJavaObjectSerializer() {
......
...@@ -466,7 +466,7 @@ public abstract class Query extends Prepared { ...@@ -466,7 +466,7 @@ public abstract class Query extends Prepared {
} }
/** /**
* Initialize the order or distinct expressions. * Initialize the 'ORDER BY' or 'DISTINCT' expressions.
* *
* @param session the session * @param session the session
* @param expressions the select list expressions * @param expressions the select list expressions
......
...@@ -355,7 +355,6 @@ public abstract class SelectGroups { ...@@ -355,7 +355,6 @@ public abstract class SelectGroups {
/** /**
* Update group-by data specified by implementation. * Update group-by data specified by implementation.
* The
*/ */
abstract void updateCurrentGroupExprData(); abstract void updateCurrentGroupExprData();
......
...@@ -123,12 +123,13 @@ public class Set extends Prepared { ...@@ -123,12 +123,13 @@ public class Set extends Prepared {
} }
case SetTypes.COLLATION: { case SetTypes.COLLATION: {
session.getUser().checkAdmin(); session.getUser().checkAdmin();
final boolean binaryUnsigned = database. CompareMode currentMode = database.getCompareMode();
getCompareMode().isBinaryUnsigned(); final boolean binaryUnsigned = currentMode.isBinaryUnsigned();
final boolean uuidUnsigned = currentMode.isUuidUnsigned();
CompareMode compareMode; CompareMode compareMode;
StringBuilder buff = new StringBuilder(stringValue); StringBuilder buff = new StringBuilder(stringValue);
if (stringValue.equals(CompareMode.OFF)) { if (stringValue.equals(CompareMode.OFF)) {
compareMode = CompareMode.getInstance(null, 0, binaryUnsigned); compareMode = CompareMode.getInstance(null, 0, binaryUnsigned, uuidUnsigned);
} else { } else {
int strength = getIntValue(); int strength = getIntValue();
buff.append(" STRENGTH "); buff.append(" STRENGTH ");
...@@ -141,8 +142,7 @@ public class Set extends Prepared { ...@@ -141,8 +142,7 @@ public class Set extends Prepared {
} else if (strength == Collator.TERTIARY) { } else if (strength == Collator.TERTIARY) {
buff.append("TERTIARY"); buff.append("TERTIARY");
} }
compareMode = CompareMode.getInstance(stringValue, strength, compareMode = CompareMode.getInstance(stringValue, strength, binaryUnsigned, uuidUnsigned);
binaryUnsigned);
} }
CompareMode old = database.getCompareMode(); CompareMode old = database.getCompareMode();
if (old.equals(compareMode)) { if (old.equals(compareMode)) {
...@@ -150,9 +150,7 @@ public class Set extends Prepared { ...@@ -150,9 +150,7 @@ public class Set extends Prepared {
} }
Table table = database.getFirstUserTable(); Table table = database.getFirstUserTable();
if (table != null) { if (table != null) {
throw DbException.get( throw DbException.get(ErrorCode.COLLATION_CHANGE_WITH_DATA_TABLE_1, table.getSQL());
ErrorCode.COLLATION_CHANGE_WITH_DATA_TABLE_1,
table.getSQL());
} }
addOrUpdateSetting(name, buff.toString(), 0); addOrUpdateSetting(name, buff.toString(), 0);
database.setCompareMode(compareMode); database.setCompareMode(compareMode);
...@@ -160,24 +158,46 @@ public class Set extends Prepared { ...@@ -160,24 +158,46 @@ public class Set extends Prepared {
} }
case SetTypes.BINARY_COLLATION: { case SetTypes.BINARY_COLLATION: {
session.getUser().checkAdmin(); session.getUser().checkAdmin();
Table table = database.getFirstUserTable(); boolean unsigned;
if (table != null) { if (stringValue.equals(CompareMode.SIGNED)) {
throw DbException.get( unsigned = false;
ErrorCode.COLLATION_CHANGE_WITH_DATA_TABLE_1, } else if (stringValue.equals(CompareMode.UNSIGNED)) {
table.getSQL()); unsigned = true;
} else {
throw DbException.getInvalidValueException("BINARY_COLLATION", stringValue);
} }
CompareMode currentMode = database.getCompareMode(); CompareMode currentMode = database.getCompareMode();
CompareMode newMode; if (currentMode.isBinaryUnsigned() != unsigned) {
Table table = database.getFirstUserTable();
if (table != null) {
throw DbException.get(ErrorCode.COLLATION_CHANGE_WITH_DATA_TABLE_1, table.getSQL());
}
}
CompareMode newMode = CompareMode.getInstance(currentMode.getName(),
currentMode.getStrength(), unsigned, currentMode.isUuidUnsigned());
addOrUpdateSetting(name, stringValue, 0);
database.setCompareMode(newMode);
break;
}
case SetTypes.UUID_COLLATION: {
session.getUser().checkAdmin();
boolean unsigned;
if (stringValue.equals(CompareMode.SIGNED)) { if (stringValue.equals(CompareMode.SIGNED)) {
newMode = CompareMode.getInstance(currentMode.getName(), unsigned = false;
currentMode.getStrength(), false);
} else if (stringValue.equals(CompareMode.UNSIGNED)) { } else if (stringValue.equals(CompareMode.UNSIGNED)) {
newMode = CompareMode.getInstance(currentMode.getName(), unsigned = true;
currentMode.getStrength(), true);
} else { } else {
throw DbException.getInvalidValueException("BINARY_COLLATION", throw DbException.getInvalidValueException("UUID_COLLATION", stringValue);
stringValue); }
CompareMode currentMode = database.getCompareMode();
if (currentMode.isUuidUnsigned() != unsigned) {
Table table = database.getFirstUserTable();
if (table != null) {
throw DbException.get(ErrorCode.COLLATION_CHANGE_WITH_DATA_TABLE_1, table.getSQL());
}
} }
CompareMode newMode = CompareMode.getInstance(currentMode.getName(),
currentMode.getStrength(), currentMode.isBinaryUnsigned(), unsigned);
addOrUpdateSetting(name, stringValue, 0); addOrUpdateSetting(name, stringValue, 0);
database.setCompareMode(newMode); database.setCompareMode(newMode);
break; break;
......
...@@ -257,7 +257,12 @@ public class SetTypes { ...@@ -257,7 +257,12 @@ public class SetTypes {
*/ */
public static final int LOCAL_RESULT_FACTORY = 49; public static final int LOCAL_RESULT_FACTORY = 49;
private static final int COUNT = LOCAL_RESULT_FACTORY + 1; /**
* The type of a SET UUID_COLLATION statement.
*/
public static final int UUID_COLLATION = 50;
private static final int COUNT = UUID_COLLATION + 1;
private static final ArrayList<String> TYPES; private static final ArrayList<String> TYPES;
...@@ -317,6 +322,7 @@ public class SetTypes { ...@@ -317,6 +322,7 @@ public class SetTypes {
list.add(COLUMN_NAME_RULES, "COLUMN_NAME_RULES"); list.add(COLUMN_NAME_RULES, "COLUMN_NAME_RULES");
list.add(AUTHENTICATOR, "AUTHENTICATOR"); list.add(AUTHENTICATOR, "AUTHENTICATOR");
list.add(LOCAL_RESULT_FACTORY, "LOCAL_RESULT_FACTORY"); list.add(LOCAL_RESULT_FACTORY, "LOCAL_RESULT_FACTORY");
list.add(UUID_COLLATION, "UUID_COLLATION");
TYPES = list; TYPES = list;
} }
......
...@@ -855,6 +855,8 @@ public class Database implements DataHandler { ...@@ -855,6 +855,8 @@ public class Database implements DataHandler {
lockMeta(systemSession); lockMeta(systemSession);
addDatabaseObject(systemSession, setting); addDatabaseObject(systemSession, setting);
} }
setSortSetting(SetTypes.BINARY_COLLATION, SysProperties.SORT_BINARY_UNSIGNED, true);
setSortSetting(SetTypes.UUID_COLLATION, SysProperties.SORT_UUID_UNSIGNED, false);
// mark all ids used in the page store // mark all ids used in the page store
if (pageStore != null) { if (pageStore != null) {
BitSet f = pageStore.getObjectIds(); BitSet f = pageStore.getObjectIds();
...@@ -875,6 +877,30 @@ public class Database implements DataHandler { ...@@ -875,6 +877,30 @@ public class Database implements DataHandler {
} }
} }
/**
* Preserves a current default value of a sorting setting if it is not the
* same as default for older versions of H2 and if it was not modified by
* user.
*
* @param type
* setting type
* @param defValue
* current default value (may be modified via system properties)
* @param oldDefault
* default value for old versions
*/
private void setSortSetting(int type, boolean defValue, boolean oldDefault) {
if (defValue == oldDefault) {
return;
}
String name = SetTypes.getTypeName(type);
if (settings.get(name) == null) {
Setting setting = new Setting(this, allocateObjectId(), name);
setting.setStringValue(defValue ? CompareMode.UNSIGNED : CompareMode.SIGNED);
lockMeta(systemSession);
addDatabaseObject(systemSession, setting);
}
}
private void handleUpgradeIssues() { private void handleUpgradeIssues() {
if (store != null && !isReadOnly()) { if (store != null && !isReadOnly()) {
...@@ -1123,11 +1149,6 @@ public class Database implements DataHandler { ...@@ -1123,11 +1149,6 @@ public class Database implements DataHandler {
} }
} }
/**
* Release IDs.
*
* @param idsToRelease IDs to release.
*/
void releaseDatabaseObjectIds(BitSet idsToRelease) { void releaseDatabaseObjectIds(BitSet idsToRelease) {
synchronized (objectIds) { synchronized (objectIds) {
objectIds.andNot(idsToRelease); objectIds.andNot(idsToRelease);
......
...@@ -418,11 +418,21 @@ public class SysProperties { ...@@ -418,11 +418,21 @@ public class SysProperties {
* System property <code>h2.sortBinaryUnsigned</code> * System property <code>h2.sortBinaryUnsigned</code>
* (default: true).<br /> * (default: true).<br />
* Whether binary data should be sorted in unsigned mode * Whether binary data should be sorted in unsigned mode
* (0xff is larger than 0x00). * (0xff is larger than 0x00) by default in new databases.
*/ */
public static final boolean SORT_BINARY_UNSIGNED = public static final boolean SORT_BINARY_UNSIGNED =
Utils.getProperty("h2.sortBinaryUnsigned", true); Utils.getProperty("h2.sortBinaryUnsigned", true);
/**
* System property {@code h2.sortUuidUnsigned}, {@code false} by default
* unless {@code h2.preview} is enabled.
* Whether UUID data should be sorted in unsigned mode
* ('ffffffff-ffff-ffff-ffff-ffffffffffff' is larger than
* '00000000-0000-0000-0000-000000000000') by default in new databases.
*/
public static final boolean SORT_UUID_UNSIGNED =
Utils.getProperty("h2.sortUuidUnsigned", PREVIEW);
/** /**
* System property <code>h2.sortNullsHigh</code> (default: false).<br /> * System property <code>h2.sortNullsHigh</code> (default: false).<br />
* Invert the default sorting behavior for NULL, such that NULL * Invert the default sorting behavior for NULL, such that NULL
......
...@@ -55,6 +55,8 @@ public class H2AuthConfig { ...@@ -55,6 +55,8 @@ public class H2AuthConfig {
} }
/** /**
* Gets configuration of authentication realms.
*
* @return configuration of authentication realms. * @return configuration of authentication realms.
*/ */
public List<RealmConfig> getRealms() { public List<RealmConfig> getRealms() {
...@@ -65,6 +67,8 @@ public class H2AuthConfig { ...@@ -65,6 +67,8 @@ public class H2AuthConfig {
} }
/** /**
* Sets configuration of authentication realms.
*
* @param realms configuration of authentication realms. * @param realms configuration of authentication realms.
*/ */
public void setRealms(List<RealmConfig> realms) { public void setRealms(List<RealmConfig> realms) {
...@@ -72,6 +76,8 @@ public class H2AuthConfig { ...@@ -72,6 +76,8 @@ public class H2AuthConfig {
} }
/** /**
* Gets configuration of the mappers external users to database roles.
*
* @return configuration of the mappers external users to database roles. * @return configuration of the mappers external users to database roles.
*/ */
public List<UserToRolesMapperConfig> getUserToRolesMappers() { public List<UserToRolesMapperConfig> getUserToRolesMappers() {
...@@ -82,6 +88,8 @@ public class H2AuthConfig { ...@@ -82,6 +88,8 @@ public class H2AuthConfig {
} }
/** /**
* Sets configuration of the mappers external users to database roles.
*
* @param userToRolesMappers configuration of the mappers external users to database roles. * @param userToRolesMappers configuration of the mappers external users to database roles.
*/ */
public void setUserToRolesMappers(List<UserToRolesMapperConfig> userToRolesMappers) { public void setUserToRolesMappers(List<UserToRolesMapperConfig> userToRolesMappers) {
......
...@@ -17,19 +17,38 @@ public class RealmConfig implements HasConfigProperties { ...@@ -17,19 +17,38 @@ public class RealmConfig implements HasConfigProperties {
private String validatorClass; private String validatorClass;
private List<PropertyConfig> properties; private List<PropertyConfig> properties;
/**
* Gets realm's name.
*
* @return realm's name.
*/
public String getName() { public String getName() {
return name; return name;
} }
/**
* Sets realm's name.
*
* @param name realm's name.
*/
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
/**
* Gets validator class name.
*
* @return validator class name.
*/
public String getValidatorClass() { public String getValidatorClass() {
return validatorClass; return validatorClass;
} }
/**
* Sets validator class name.
*
* @param validatorClass validator class name.
*/
public void setValidatorClass(String validatorClass) { public void setValidatorClass(String validatorClass) {
this.validatorClass = validatorClass; this.validatorClass = validatorClass;
} }
......
...@@ -1689,8 +1689,12 @@ public class PageStore implements CacheWriter { ...@@ -1689,8 +1689,12 @@ public class PageStore implements CacheWriter {
if (options.length > 3) { if (options.length > 3) {
binaryUnsigned = Boolean.parseBoolean(options[3]); binaryUnsigned = Boolean.parseBoolean(options[3]);
} }
boolean uuidUnsigned = SysProperties.SORT_UUID_UNSIGNED;
if (options.length > 4) {
uuidUnsigned = Boolean.parseBoolean(options[4]);
}
CompareMode mode = CompareMode.getInstance( CompareMode mode = CompareMode.getInstance(
options[0], Integer.parseInt(options[1]), binaryUnsigned); options[0], Integer.parseInt(options[1]), binaryUnsigned, uuidUnsigned);
table.setCompareMode(mode); table.setCompareMode(mode);
meta = table.getScanIndex(session); meta = table.getScanIndex(session);
} else { } else {
...@@ -1775,21 +1779,22 @@ public class PageStore implements CacheWriter { ...@@ -1775,21 +1779,22 @@ public class PageStore implements CacheWriter {
} }
String columnList = buff.toString(); String columnList = buff.toString();
CompareMode mode = table.getCompareMode(); CompareMode mode = table.getCompareMode();
String options = mode.getName()+ "," + mode.getStrength() + ","; StringBuilder options = new StringBuilder().append(mode.getName()).append(',').append(mode.getStrength())
.append(',');
if (table.isTemporary()) { if (table.isTemporary()) {
options += "temp"; options.append("temp");
} }
options += ","; options.append(',');
if (index instanceof PageDelegateIndex) { if (index instanceof PageDelegateIndex) {
options += "d"; options.append('d');
} }
options += "," + mode.isBinaryUnsigned(); options.append(',').append(mode.isBinaryUnsigned()).append(',').append(mode.isUuidUnsigned());
Row row = metaTable.getTemplateRow(); Row row = metaTable.getTemplateRow();
row.setValue(0, ValueInt.get(index.getId())); row.setValue(0, ValueInt.get(index.getId()));
row.setValue(1, ValueInt.get(type)); row.setValue(1, ValueInt.get(type));
row.setValue(2, ValueInt.get(table.getId())); row.setValue(2, ValueInt.get(table.getId()));
row.setValue(3, ValueInt.get(index.getRootPageId())); row.setValue(3, ValueInt.get(index.getRootPageId()));
row.setValue(4, ValueString.get(options)); row.setValue(4, ValueString.get(options.toString()));
row.setValue(5, ValueString.get(columnList)); row.setValue(5, ValueString.get(columnList));
row.setKey(index.getId() + 1); row.setKey(index.getId() + 1);
metaIndex.add(session, row); metaIndex.add(session, row);
......
...@@ -10,8 +10,6 @@ import java.util.ArrayList; ...@@ -10,8 +10,6 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
......
...@@ -45,14 +45,14 @@ public class CompareMode implements Comparator<Value> { ...@@ -45,14 +45,14 @@ public class CompareMode implements Comparator<Value> {
public static final String CHARSET = "CHARSET_"; public static final String CHARSET = "CHARSET_";
/** /**
* This constant means that the BINARY columns are sorted as if the bytes * This constant means that the BINARY or UUID columns are sorted as if the
* were signed. * bytes were signed.
*/ */
public static final String SIGNED = "SIGNED"; public static final String SIGNED = "SIGNED";
/** /**
* This constant means that the BINARY columns are sorted as if the bytes * This constant means that the BINARY or UUID columns are sorted as if the
* were unsigned. * bytes were unsigned.
*/ */
public static final String UNSIGNED = "UNSIGNED"; public static final String UNSIGNED = "UNSIGNED";
...@@ -79,10 +79,17 @@ public class CompareMode implements Comparator<Value> { ...@@ -79,10 +79,17 @@ public class CompareMode implements Comparator<Value> {
*/ */
private final boolean binaryUnsigned; private final boolean binaryUnsigned;
protected CompareMode(String name, int strength, boolean binaryUnsigned) { /**
* If true, sort UUID columns as if they contain unsigned bytes instead of
* Java-compatible sorting.
*/
private final boolean uuidUnsigned;
protected CompareMode(String name, int strength, boolean binaryUnsigned, boolean uuidUnsigned) {
this.name = name; this.name = name;
this.strength = strength; this.strength = strength;
this.binaryUnsigned = binaryUnsigned; this.binaryUnsigned = binaryUnsigned;
this.uuidUnsigned = uuidUnsigned;
} }
/** /**
...@@ -96,7 +103,7 @@ public class CompareMode implements Comparator<Value> { ...@@ -96,7 +103,7 @@ public class CompareMode implements Comparator<Value> {
* @return the compare mode * @return the compare mode
*/ */
public static CompareMode getInstance(String name, int strength) { public static CompareMode getInstance(String name, int strength) {
return getInstance(name, strength, SysProperties.SORT_BINARY_UNSIGNED); return getInstance(name, strength, SysProperties.SORT_BINARY_UNSIGNED, SysProperties.SORT_UUID_UNSIGNED);
} }
/** /**
...@@ -108,19 +115,21 @@ public class CompareMode implements Comparator<Value> { ...@@ -108,19 +115,21 @@ public class CompareMode implements Comparator<Value> {
* @param name the collation name or null * @param name the collation name or null
* @param strength the collation strength * @param strength the collation strength
* @param binaryUnsigned whether to compare binaries as unsigned * @param binaryUnsigned whether to compare binaries as unsigned
* @param binaryUnsigned whether to compare UUIDs as unsigned
* @return the compare mode * @return the compare mode
*/ */
public static CompareMode getInstance(String name, int strength, boolean binaryUnsigned) { public static CompareMode getInstance(String name, int strength, boolean binaryUnsigned, boolean uuidUnsigned) {
CompareMode last = lastUsed; CompareMode last = lastUsed;
if (last != null) { if (last != null) {
if (Objects.equals(last.name, name) && if (Objects.equals(last.name, name) &&
last.strength == strength && last.strength == strength &&
last.binaryUnsigned == binaryUnsigned) { last.binaryUnsigned == binaryUnsigned &&
last.uuidUnsigned == uuidUnsigned) {
return last; return last;
} }
} }
if (name == null || name.equals(OFF)) { if (name == null || name.equals(OFF)) {
last = new CompareMode(name, strength, binaryUnsigned); last = new CompareMode(name, strength, binaryUnsigned, uuidUnsigned);
} else { } else {
boolean useICU4J; boolean useICU4J;
if (name.startsWith(ICU4J)) { if (name.startsWith(ICU4J)) {
...@@ -133,9 +142,9 @@ public class CompareMode implements Comparator<Value> { ...@@ -133,9 +142,9 @@ public class CompareMode implements Comparator<Value> {
useICU4J = CAN_USE_ICU4J; useICU4J = CAN_USE_ICU4J;
} }
if (useICU4J) { if (useICU4J) {
last = new CompareModeIcu4J(name, strength, binaryUnsigned); last = new CompareModeIcu4J(name, strength, binaryUnsigned, uuidUnsigned);
} else { } else {
last = new CompareModeDefault(name, strength, binaryUnsigned); last = new CompareModeDefault(name, strength, binaryUnsigned, uuidUnsigned);
} }
} }
lastUsed = last; lastUsed = last;
...@@ -263,6 +272,10 @@ public class CompareMode implements Comparator<Value> { ...@@ -263,6 +272,10 @@ public class CompareMode implements Comparator<Value> {
return binaryUnsigned; return binaryUnsigned;
} }
public boolean isUuidUnsigned() {
return uuidUnsigned;
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == this) { if (obj == this) {
...@@ -280,12 +293,20 @@ public class CompareMode implements Comparator<Value> { ...@@ -280,12 +293,20 @@ public class CompareMode implements Comparator<Value> {
if (binaryUnsigned != o.binaryUnsigned) { if (binaryUnsigned != o.binaryUnsigned) {
return false; return false;
} }
if (uuidUnsigned != o.uuidUnsigned) {
return false;
}
return true; return true;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return getName().hashCode() ^ strength ^ (binaryUnsigned ? -1 : 0); int result = 1;
result = 31 * result + getName().hashCode();
result = 31 * result + strength;
result = 31 * result + (binaryUnsigned ? 1231 : 1237);
result = 31 * result + (uuidUnsigned ? 1231 : 1237);
return result;
} }
@Override @Override
......
...@@ -20,9 +20,8 @@ public class CompareModeDefault extends CompareMode { ...@@ -20,9 +20,8 @@ public class CompareModeDefault extends CompareMode {
private final Collator collator; private final Collator collator;
private final SmallLRUCache<String, CollationKey> collationKeys; private final SmallLRUCache<String, CollationKey> collationKeys;
protected CompareModeDefault(String name, int strength, protected CompareModeDefault(String name, int strength, boolean binaryUnsigned, boolean uuidUnsigned) {
boolean binaryUnsigned) { super(name, strength, binaryUnsigned, uuidUnsigned);
super(name, strength, binaryUnsigned);
collator = CompareMode.getCollator(name); collator = CompareMode.getCollator(name);
if (collator == null) { if (collator == null) {
throw DbException.throwInternalError(name); throw DbException.throwInternalError(name);
......
...@@ -20,8 +20,8 @@ public class CompareModeIcu4J extends CompareMode { ...@@ -20,8 +20,8 @@ public class CompareModeIcu4J extends CompareMode {
private final Comparator<String> collator; private final Comparator<String> collator;
protected CompareModeIcu4J(String name, int strength, boolean binaryUnsigned) { protected CompareModeIcu4J(String name, int strength, boolean binaryUnsigned, boolean uuidUnsigned) {
super(name, strength, binaryUnsigned); super(name, strength, binaryUnsigned, uuidUnsigned);
collator = getIcu4jCollator(name, strength); collator = getIcu4jCollator(name, strength);
} }
......
...@@ -172,15 +172,30 @@ public class ValueUuid extends Value { ...@@ -172,15 +172,30 @@ public class ValueUuid extends Value {
return 0; return 0;
} }
ValueUuid v = (ValueUuid) o; ValueUuid v = (ValueUuid) o;
if (high == v.high) { long v1 = high, v2 = v.high;
return Long.compare(low, v.low); if (v1 == v2) {
v1 = low;
v2 = v.low;
if (mode.isUuidUnsigned()) {
v1 += Long.MIN_VALUE;
v2 += Long.MIN_VALUE;
}
return Long.compare(v1, v2);
}
if (mode.isUuidUnsigned()) {
v1 += Long.MIN_VALUE;
v2 += Long.MIN_VALUE;
} }
return high > v.high ? 1 : -1; return v1 > v2 ? 1 : -1;
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return other instanceof ValueUuid && compareTypeSafe((Value) other, null) == 0; if (!(other instanceof ValueUuid)) {
return false;
}
ValueUuid v = (ValueUuid) other;
return high == v.high && low == v.low;
} }
@Override @Override
......
...@@ -49,6 +49,8 @@ public class TestAuthentication extends TestBase { ...@@ -49,6 +49,8 @@ public class TestAuthentication extends TestBase {
+ "</realm>" + "</realm>"
+ "</h2Auth>"; + "</h2Auth>";
private static final String JAAS_CONFIG_NAME = "testJaasH2";
private String externalUserPassword; private String externalUserPassword;
private DefaultAuthenticator defaultAuthenticator; private DefaultAuthenticator defaultAuthenticator;
private Session session; private Session session;
...@@ -63,7 +65,12 @@ public class TestAuthentication extends TestBase { ...@@ -63,7 +65,12 @@ public class TestAuthentication extends TestBase {
TestBase.createCaller().init().test(); TestBase.createCaller().init().test();
} }
private String getExternalUserPassword() { /**
* Gets external user password.
*
* @return external user password.
*/
String getExternalUserPassword() {
if (externalUserPassword == null) { if (externalUserPassword == null) {
externalUserPassword = UUID.randomUUID().toString(); externalUserPassword = UUID.randomUUID().toString();
} }
...@@ -74,10 +81,6 @@ public class TestAuthentication extends TestBase { ...@@ -74,10 +81,6 @@ public class TestAuthentication extends TestBase {
return "testRealm"; return "testRealm";
} }
private String getJaasConfigName() {
return "testJaasH2";
}
private String getStaticRoleName() { private String getStaticRoleName() {
return "staticRole"; return "staticRole";
} }
...@@ -86,7 +89,7 @@ public class TestAuthentication extends TestBase { ...@@ -86,7 +89,7 @@ public class TestAuthentication extends TestBase {
defaultAuthenticator = new DefaultAuthenticator(true); defaultAuthenticator = new DefaultAuthenticator(true);
defaultAuthenticator.setAllowUserRegistration(true); defaultAuthenticator.setAllowUserRegistration(true);
defaultAuthenticator.setCreateMissingRoles(true); defaultAuthenticator.setCreateMissingRoles(true);
defaultAuthenticator.addRealm(getRealmName(), new JaasCredentialsValidator(getJaasConfigName())); defaultAuthenticator.addRealm(getRealmName(), new JaasCredentialsValidator(JAAS_CONFIG_NAME));
defaultAuthenticator.addRealm(getRealmName() + "_STATIC", defaultAuthenticator.addRealm(getRealmName() + "_STATIC",
new StaticUserCredentialsValidator("staticuser[0-9]", "staticpassword")); new StaticUserCredentialsValidator("staticuser[0-9]", "staticpassword"));
defaultAuthenticator.setUserToRolesMappers(new AssignRealmNameRole("@%s"), defaultAuthenticator.setUserToRolesMappers(new AssignRealmNameRole("@%s"),
...@@ -99,7 +102,7 @@ public class TestAuthentication extends TestBase { ...@@ -99,7 +102,7 @@ public class TestAuthentication extends TestBase {
Configuration.setConfiguration(new Configuration() { Configuration.setConfiguration(new Configuration() {
@Override @Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) { public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
if (name.equals(getJaasConfigName())) { if (name.equals(JAAS_CONFIG_NAME)) {
HashMap<String, String> options = new HashMap<>(); HashMap<String, String> options = new HashMap<>();
options.put("password", getExternalUserPassword()); options.put("password", getExternalUserPassword());
return new AppConfigurationEntry[] { new AppConfigurationEntry(MyLoginModule.class.getName(), return new AppConfigurationEntry[] { new AppConfigurationEntry(MyLoginModule.class.getName(),
......
...@@ -2,3 +2,46 @@ ...@@ -2,3 +2,46 @@
-- and the EPL 1.0 (http://h2database.com/html/license.html). -- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group -- Initial Developer: H2 Group
-- --
CREATE TABLE TEST(U UUID) AS (SELECT * FROM VALUES
('00000000-0000-0000-0000-000000000000'), ('00000000-0000-0000-9000-000000000000'),
('11111111-1111-1111-1111-111111111111'), ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'));
> ok
SELECT U FROM TEST ORDER BY U;
> U
> ------------------------------------
> aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa
> 00000000-0000-0000-9000-000000000000
> 00000000-0000-0000-0000-000000000000
> 11111111-1111-1111-1111-111111111111
> rows (ordered): 4
SET UUID_COLLATION UNSIGNED;
> exception COLLATION_CHANGE_WITH_DATA_TABLE_1
DROP TABLE TEST;
> ok
SET UUID_COLLATION UNSIGNED;
> ok
CREATE TABLE TEST(U UUID) AS (SELECT * FROM VALUES
('00000000-0000-0000-0000-000000000000'), ('00000000-0000-0000-9000-000000000000'),
('11111111-1111-1111-1111-111111111111'), ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'));
> ok
SELECT U FROM TEST ORDER BY U;
> U
> ------------------------------------
> 00000000-0000-0000-0000-000000000000
> 00000000-0000-0000-9000-000000000000
> 11111111-1111-1111-1111-111111111111
> aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa
> rows (ordered): 4
DROP TABLE TEST;
> ok
SET UUID_COLLATION SIGNED;
> ok
...@@ -51,7 +51,7 @@ public class TestLocalResultFactory extends TestBase { ...@@ -51,7 +51,7 @@ public class TestLocalResultFactory extends TestBase {
*/ */
public static class MyTestLocalResultFactory extends LocalResultFactory { public static class MyTestLocalResultFactory extends LocalResultFactory {
/** Call counter for the factory methods. */ /** Call counter for the factory methods. */
private static final AtomicInteger COUNTER = new AtomicInteger(); static final AtomicInteger COUNTER = new AtomicInteger();
@Override public LocalResult create(Session session, Expression[] expressions, int visibleColumnCount) { @Override public LocalResult create(Session session, Expression[] expressions, int visibleColumnCount) {
COUNTER.incrementAndGet(); COUNTER.incrementAndGet();
......
...@@ -686,9 +686,7 @@ public class Build extends BuildBase { ...@@ -686,9 +686,7 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/lucene-queryparser-5.5.5.jar" + File.pathSeparator + "ext/lucene-queryparser-5.5.5.jar" +
File.pathSeparator + "ext/org.osgi.core-4.2.0.jar" + File.pathSeparator + "ext/org.osgi.core-4.2.0.jar" +
File.pathSeparator + "ext/org.osgi.enterprise-4.2.0.jar" + File.pathSeparator + "ext/org.osgi.enterprise-4.2.0.jar" +
File.pathSeparator + "ext/jts-core-1.15.0.jar" + File.pathSeparator + "ext/jts-core-1.15.0.jar",
File.pathSeparator + "ext/asm-6.1.jar" +
File.pathSeparator + "ext/junit-4.12.jar",
"-subpackages", "org.h2.mvstore", "-subpackages", "org.h2.mvstore",
"-exclude", "org.h2.mvstore.db"); "-exclude", "org.h2.mvstore.db");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论