提交 00eb5f57 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add h2.sortUuidUnsigned and SetTypes.UUID_COLLATION

上级 a21503c9
......@@ -1261,6 +1261,24 @@ This setting is persistent.
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","
SET BUILTIN_ALIAS_OVERRIDE { TRUE | FALSE }
","
......
......@@ -6653,7 +6653,10 @@ public class Parser {
return parseSetCollation();
} else if (readIf("BINARY_COLLATION")) {
readIfEqualOrTo();
return parseSetBinaryCollation();
return parseSetBinaryCollation(SetTypes.BINARY_COLLATION);
} else if (readIf("UUID_COLLATION")) {
readIfEqualOrTo();
return parseSetBinaryCollation(SetTypes.UUID_COLLATION);
} else if (readIf("CLUSTER")) {
readIfEqualOrTo();
Set command = new Set(session, SetTypes.CLUSTER);
......@@ -6842,14 +6845,14 @@ public class Parser {
return command;
}
private Set parseSetBinaryCollation() {
private Set parseSetBinaryCollation(int type) {
String name = readAliasIdentifier();
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);
return command;
}
throw DbException.getInvalidValueException("BINARY_COLLATION", name);
throw DbException.getInvalidValueException(SetTypes.getTypeName(type), name);
}
private Set parseSetJavaObjectSerializer() {
......
......@@ -123,12 +123,13 @@ public class Set extends Prepared {
}
case SetTypes.COLLATION: {
session.getUser().checkAdmin();
final boolean binaryUnsigned = database.
getCompareMode().isBinaryUnsigned();
CompareMode currentMode = database.getCompareMode();
final boolean binaryUnsigned = currentMode.isBinaryUnsigned();
final boolean uuidUnsigned = currentMode.isUuidUnsigned();
CompareMode compareMode;
StringBuilder buff = new StringBuilder(stringValue);
if (stringValue.equals(CompareMode.OFF)) {
compareMode = CompareMode.getInstance(null, 0, binaryUnsigned);
compareMode = CompareMode.getInstance(null, 0, binaryUnsigned, uuidUnsigned);
} else {
int strength = getIntValue();
buff.append(" STRENGTH ");
......@@ -141,8 +142,7 @@ public class Set extends Prepared {
} else if (strength == Collator.TERTIARY) {
buff.append("TERTIARY");
}
compareMode = CompareMode.getInstance(stringValue, strength,
binaryUnsigned);
compareMode = CompareMode.getInstance(stringValue, strength, binaryUnsigned, uuidUnsigned);
}
CompareMode old = database.getCompareMode();
if (old.equals(compareMode)) {
......@@ -150,9 +150,7 @@ public class Set extends Prepared {
}
Table table = database.getFirstUserTable();
if (table != null) {
throw DbException.get(
ErrorCode.COLLATION_CHANGE_WITH_DATA_TABLE_1,
table.getSQL());
throw DbException.get(ErrorCode.COLLATION_CHANGE_WITH_DATA_TABLE_1, table.getSQL());
}
addOrUpdateSetting(name, buff.toString(), 0);
database.setCompareMode(compareMode);
......@@ -162,21 +160,39 @@ public class Set extends Prepared {
session.getUser().checkAdmin();
Table table = database.getFirstUserTable();
if (table != null) {
throw DbException.get(
ErrorCode.COLLATION_CHANGE_WITH_DATA_TABLE_1,
table.getSQL());
throw DbException.get(ErrorCode.COLLATION_CHANGE_WITH_DATA_TABLE_1, table.getSQL());
}
CompareMode currentMode = database.getCompareMode();
CompareMode newMode;
if (stringValue.equals(CompareMode.SIGNED)) {
newMode = CompareMode.getInstance(currentMode.getName(),
currentMode.getStrength(), false, currentMode.isUuidUnsigned());
} else if (stringValue.equals(CompareMode.UNSIGNED)) {
newMode = CompareMode.getInstance(currentMode.getName(),
currentMode.getStrength(), true, currentMode.isUuidUnsigned());
} else {
throw DbException.getInvalidValueException("BINARY_COLLATION", stringValue);
}
addOrUpdateSetting(name, stringValue, 0);
database.setCompareMode(newMode);
break;
}
case SetTypes.UUID_COLLATION: {
session.getUser().checkAdmin();
Table table = database.getFirstUserTable();
if (table != null) {
throw DbException.get(ErrorCode.COLLATION_CHANGE_WITH_DATA_TABLE_1, table.getSQL());
}
CompareMode currentMode = database.getCompareMode();
CompareMode newMode;
if (stringValue.equals(CompareMode.SIGNED)) {
newMode = CompareMode.getInstance(currentMode.getName(),
currentMode.getStrength(), false);
currentMode.getStrength(), currentMode.isBinaryUnsigned(), false);
} else if (stringValue.equals(CompareMode.UNSIGNED)) {
newMode = CompareMode.getInstance(currentMode.getName(),
currentMode.getStrength(), true);
currentMode.getStrength(), currentMode.isBinaryUnsigned(), true);
} else {
throw DbException.getInvalidValueException("BINARY_COLLATION",
stringValue);
throw DbException.getInvalidValueException("UUID_COLLATION", stringValue);
}
addOrUpdateSetting(name, stringValue, 0);
database.setCompareMode(newMode);
......
......@@ -257,7 +257,12 @@ public class SetTypes {
*/
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;
......@@ -317,6 +322,7 @@ public class SetTypes {
list.add(COLUMN_NAME_RULES, "COLUMN_NAME_RULES");
list.add(AUTHENTICATOR, "AUTHENTICATOR");
list.add(LOCAL_RESULT_FACTORY, "LOCAL_RESULT_FACTORY");
list.add(UUID_COLLATION, "UUID_COLLATION");
TYPES = list;
}
......
......@@ -418,11 +418,21 @@ public class SysProperties {
* System property <code>h2.sortBinaryUnsigned</code>
* (default: true).<br />
* 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 =
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 />
* Invert the default sorting behavior for NULL, such that NULL
......
......@@ -1689,8 +1689,12 @@ public class PageStore implements CacheWriter {
if (options.length > 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(
options[0], Integer.parseInt(options[1]), binaryUnsigned);
options[0], Integer.parseInt(options[1]), binaryUnsigned, uuidUnsigned);
table.setCompareMode(mode);
meta = table.getScanIndex(session);
} else {
......@@ -1775,21 +1779,22 @@ public class PageStore implements CacheWriter {
}
String columnList = buff.toString();
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()) {
options += "temp";
options.append("temp");
}
options += ",";
options.append(',');
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.setValue(0, ValueInt.get(index.getId()));
row.setValue(1, ValueInt.get(type));
row.setValue(2, ValueInt.get(table.getId()));
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.setKey(index.getId() + 1);
metaIndex.add(session, row);
......
......@@ -45,14 +45,14 @@ public class CompareMode implements Comparator<Value> {
public static final String CHARSET = "CHARSET_";
/**
* This constant means that the BINARY columns are sorted as if the bytes
* were signed.
* This constant means that the BINARY or UUID columns are sorted as if the
* bytes were signed.
*/
public static final String SIGNED = "SIGNED";
/**
* This constant means that the BINARY columns are sorted as if the bytes
* were unsigned.
* This constant means that the BINARY or UUID columns are sorted as if the
* bytes were unsigned.
*/
public static final String UNSIGNED = "UNSIGNED";
......@@ -79,10 +79,16 @@ public class CompareMode implements Comparator<Value> {
*/
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.strength = strength;
this.binaryUnsigned = binaryUnsigned;
this.uuidUnsigned = uuidUnsigned;
}
/**
......@@ -96,7 +102,7 @@ public class CompareMode implements Comparator<Value> {
* @return the compare mode
*/
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 +114,21 @@ public class CompareMode implements Comparator<Value> {
* @param name the collation name or null
* @param strength the collation strength
* @param binaryUnsigned whether to compare binaries as unsigned
* @param binaryUnsigned whether to compare UUIDs as unsigned
* @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;
if (last != null) {
if (Objects.equals(last.name, name) &&
last.strength == strength &&
last.binaryUnsigned == binaryUnsigned) {
last.binaryUnsigned == binaryUnsigned &&
last.uuidUnsigned == uuidUnsigned) {
return last;
}
}
if (name == null || name.equals(OFF)) {
last = new CompareMode(name, strength, binaryUnsigned);
last = new CompareMode(name, strength, binaryUnsigned, uuidUnsigned);
} else {
boolean useICU4J;
if (name.startsWith(ICU4J)) {
......@@ -133,9 +141,9 @@ public class CompareMode implements Comparator<Value> {
useICU4J = CAN_USE_ICU4J;
}
if (useICU4J) {
last = new CompareModeIcu4J(name, strength, binaryUnsigned);
last = new CompareModeIcu4J(name, strength, binaryUnsigned, uuidUnsigned);
} else {
last = new CompareModeDefault(name, strength, binaryUnsigned);
last = new CompareModeDefault(name, strength, binaryUnsigned, uuidUnsigned);
}
}
lastUsed = last;
......@@ -263,6 +271,10 @@ public class CompareMode implements Comparator<Value> {
return binaryUnsigned;
}
public boolean isUuidUnsigned() {
return uuidUnsigned;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
......@@ -280,12 +292,20 @@ public class CompareMode implements Comparator<Value> {
if (binaryUnsigned != o.binaryUnsigned) {
return false;
}
if (uuidUnsigned != o.uuidUnsigned) {
return false;
}
return true;
}
@Override
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
......
......@@ -20,9 +20,8 @@ public class CompareModeDefault extends CompareMode {
private final Collator collator;
private final SmallLRUCache<String, CollationKey> collationKeys;
protected CompareModeDefault(String name, int strength,
boolean binaryUnsigned) {
super(name, strength, binaryUnsigned);
protected CompareModeDefault(String name, int strength, boolean binaryUnsigned, boolean uuidUnsigned) {
super(name, strength, binaryUnsigned, uuidUnsigned);
collator = CompareMode.getCollator(name);
if (collator == null) {
throw DbException.throwInternalError(name);
......
......@@ -20,8 +20,8 @@ public class CompareModeIcu4J extends CompareMode {
private final Comparator<String> collator;
protected CompareModeIcu4J(String name, int strength, boolean binaryUnsigned) {
super(name, strength, binaryUnsigned);
protected CompareModeIcu4J(String name, int strength, boolean binaryUnsigned, boolean uuidUnsigned) {
super(name, strength, binaryUnsigned, uuidUnsigned);
collator = getIcu4jCollator(name, strength);
}
......
......@@ -172,15 +172,30 @@ public class ValueUuid extends Value {
return 0;
}
ValueUuid v = (ValueUuid) o;
if (high == v.high) {
return Long.compare(low, v.low);
long v1 = high, v2 = v.high;
if (v1 == v2) {
v1 = low;
v2 = v.low;
if (mode.isUuidUnsigned()) {
v1 += Long.MIN_VALUE;
v2 += Long.MIN_VALUE;
}
return high > v.high ? 1 : -1;
return Long.compare(v1, v2);
}
if (mode.isUuidUnsigned()) {
v1 += Long.MIN_VALUE;
v2 += Long.MIN_VALUE;
}
return v1 > v2 ? 1 : -1;
}
@Override
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
......
......@@ -2,3 +2,46 @@
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- 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
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论