/* * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, * Version 1.0, and under the Eclipse Public License, Version 1.0 * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ package org.h2.value; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.UUID; import org.h2.constant.ErrorCode; import org.h2.message.DbException; import org.h2.util.Utils; import org.h2.util.MathUtils; import org.h2.util.StringUtils; /** * Implementation of the UUID data type. */ public class ValueUuid extends Value { /** * The precision of this value in number of bytes. */ private static final int PRECISION = 16; /** * The display size of the textual representation of a UUID. * Example: cd38d882-7ada-4589-b5fb-7da0ca559d9a */ private static final int DISPLAY_SIZE = 36; private final long high, low; private ValueUuid(long high, long low) { this.high = high; this.low = low; } public int hashCode() { return (int) ((high >>> 32) ^ high ^ (low >>> 32) ^ low); } /** * Create a new UUID using the pseudo random number generator. * * @return the new UUID */ public static ValueUuid getNewRandom() { long high = MathUtils.secureRandomLong(); long low = MathUtils.secureRandomLong(); // version 4 (random) high = (high & (~0xf000L)) | 0x4000L; // variant (Leach-Salz) low = (low & 0x3fffffffffffffffL) | 0x8000000000000000L; return new ValueUuid(high, low); } /** * Get or create a UUID for the given 16 bytes. * * @param binary the byte array (must be at least 16 bytes long) * @return the UUID */ public static ValueUuid get(byte[] binary) { if (binary.length < 16) { return get(StringUtils.convertBytesToHex(binary)); } long high = Utils.readLong(binary, 0); long low = Utils.readLong(binary, 8); return (ValueUuid) Value.cache(new ValueUuid(high, low)); } /** * Get or create a UUID for the given high and low order values. * * @param high the most significant bits * @param low the least significant bits * @return the UUID */ public static ValueUuid get(long high, long low) { return (ValueUuid) Value.cache(new ValueUuid(high, low)); } /** * Get or create a UUID for the given text representation. * * @param s the text representation of the UUID * @return the UUID */ public static ValueUuid get(String s) { long low = 0, high = 0; for (int i = 0, j = 0, length = s.length(); i < length; i++) { char c = s.charAt(i); if (c >= '0' && c <= '9') { low = (low << 4) | (c - '0'); } else if (c >= 'a' && c <= 'f') { low = (low << 4) | (c - 'a' + 0xa); } else if (c == '-') { continue; } else if (c >= 'A' && c <= 'F') { low = (low << 4) | (c - 'A' + 0xa); } else if (c <= ' ') { continue; } else { throw DbException.get(ErrorCode.DATA_CONVERSION_ERROR_1, s); } if (j++ == 15) { high = low; low = 0; } } return (ValueUuid) Value.cache(new ValueUuid(high, low)); } public String getSQL() { return StringUtils.quoteStringSQL(getString()); } public int getType() { return Value.UUID; } public long getPrecision() { return PRECISION; } private static void appendHex(StringBuilder buff, long x, int bytes) { for (int i = bytes * 8 - 4; i >= 0; i -= 8) { buff.append(Integer.toHexString((int) (x >> i) & 0xf)). append(Integer.toHexString((int) (x >> (i - 4)) & 0xf)); } } public String getString() { StringBuilder buff = new StringBuilder(36); appendHex(buff, high >> 32, 4); buff.append('-'); appendHex(buff, high >> 16, 2); buff.append('-'); appendHex(buff, high, 2); buff.append('-'); appendHex(buff, low >> 48, 2); buff.append('-'); appendHex(buff, low, 6); return buff.toString(); } protected int compareSecure(Value o, CompareMode mode) { if (o == this) { return 0; } ValueUuid v = (ValueUuid) o; if (high == v.high) { return MathUtils.compareLong(low, v.low); } return high > v.high ? 1 : -1; } public boolean equals(Object other) { return other instanceof ValueUuid && compareSecure((Value) other, null) == 0; } public Object getObject() { return new UUID(high, low); } public byte[] getBytes() { byte[] buff = new byte[16]; for (int i = 0; i < 8; i++) { buff[i] = (byte) ((high >> (8 * (7 - i))) & 255); buff[8 + i] = (byte) ((low >> (8 * (7 - i))) & 255); } return buff; } public void set(PreparedStatement prep, int parameterIndex) throws SQLException { prep.setBytes(parameterIndex, getBytes()); } /** * Get the most significant 64 bits of this UUID. * * @return the high order bits */ public long getHigh() { return high; } /** * Get the least significant 64 bits of this UUID. * * @return the low order bits */ public long getLow() { return low; } public int getDisplaySize() { return DISPLAY_SIZE; } }