提交 53c52c7c authored 作者: andrei's avatar andrei

Merge remote-tracking branch 'h2database/master' into txcommit-atomic

...@@ -3291,6 +3291,19 @@ This method returns a double. ...@@ -3291,6 +3291,19 @@ This method returns a double.
LOG10(A) LOG10(A)
" "
"Functions (Numeric)","ORA_HASH","
ORA_HASH(expression [, bucketLong [, seedLong]])
","
Computes a hash value.
Optional bucket argument determines the maximum returned value.
This argument should be between 0 and 4294967295, default is 4294967295.
Optional seed argument is combined with the given expression to return the different values for the same expression.
This argument should be between 0 and 4294967295, default is 0.
This method returns a long value between 0 and the specified or default bucket value inclusive.
","
ORA_HASH(A)
"
"Functions (Numeric)","RADIANS"," "Functions (Numeric)","RADIANS","
RADIANS(numeric) RADIANS(numeric)
"," ","
...@@ -3413,7 +3426,7 @@ CALL TRIM(CHAR(0) FROM UTF8TOSTRING( ...@@ -3413,7 +3426,7 @@ CALL TRIM(CHAR(0) FROM UTF8TOSTRING(
" "
"Functions (Numeric)","HASH"," "Functions (Numeric)","HASH","
HASH(algorithmString, dataBytes, iterationInt) HASH(algorithmString, expression [, iterationInt])
"," ","
Calculate the hash value using an algorithm, and repeat this process for a number of iterations. Calculate the hash value using an algorithm, and repeat this process for a number of iterations.
Currently, the only algorithm supported is SHA256. Currently, the only algorithm supported is SHA256.
......
...@@ -21,8 +21,14 @@ Change Log ...@@ -21,8 +21,14 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Issue #1038: ora_hash function implementation off by one
</li>
<li>PR #1054: Introduce overflow bit in tx state
</li>
<li>Issue #1047: Support DISTINCT in custom aggregate functions <li>Issue #1047: Support DISTINCT in custom aggregate functions
</li> </li>
<li>PR #1051: Atomic change of transaction state
</li>
<li>PR #1046: Split off Transaction TransactionMap VersionedValue <li>PR #1046: Split off Transaction TransactionMap VersionedValue
</li> </li>
<li>PR #1045: TransactionStore move into separate org.h2.mvstore.tx package <li>PR #1045: TransactionStore move into separate org.h2.mvstore.tx package
......
...@@ -41,8 +41,7 @@ class AggregateDataCount extends AggregateData { ...@@ -41,8 +41,7 @@ class AggregateDataCount extends AggregateData {
count = 0; count = 0;
} }
} }
Value v = ValueLong.get(count); return ValueLong.get(count).convertTo(dataType);
return v.convertTo(dataType);
} }
} }
...@@ -9,7 +9,6 @@ import org.h2.engine.Database; ...@@ -9,7 +9,6 @@ import org.h2.engine.Database;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
/** /**
* Data stored while calculating a COUNT(*) aggregate. * Data stored while calculating a COUNT(*) aggregate.
...@@ -30,8 +29,7 @@ class AggregateDataCountAll extends AggregateData { ...@@ -30,8 +29,7 @@ class AggregateDataCountAll extends AggregateData {
if (distinct) { if (distinct) {
throw DbException.throwInternalError(); throw DbException.throwInternalError();
} }
Value v = ValueLong.get(count); return ValueLong.get(count).convertTo(dataType);
return v == null ? ValueNull.INSTANCE : v.convertTo(dataType);
} }
} }
...@@ -11,6 +11,7 @@ import java.io.InputStream; ...@@ -11,6 +11,7 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.sql.Connection; import java.sql.Connection;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
...@@ -30,7 +31,6 @@ import org.h2.schema.Schema; ...@@ -30,7 +31,6 @@ import org.h2.schema.Schema;
import org.h2.schema.Sequence; import org.h2.schema.Sequence;
import org.h2.security.BlockCipher; import org.h2.security.BlockCipher;
import org.h2.security.CipherFactory; import org.h2.security.CipherFactory;
import org.h2.security.SHA256;
import org.h2.store.fs.FileUtils; import org.h2.store.fs.FileUtils;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
...@@ -39,6 +39,7 @@ import org.h2.table.Table; ...@@ -39,6 +39,7 @@ import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.tools.CompressTool; import org.h2.tools.CompressTool;
import org.h2.tools.Csv; import org.h2.tools.Csv;
import org.h2.util.Bits;
import org.h2.util.DateTimeFunctions; import org.h2.util.DateTimeFunctions;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils; import org.h2.util.IOUtils;
...@@ -79,7 +80,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -79,7 +80,7 @@ public class Function extends Expression implements FunctionCall {
TRUNCATE = 27, SECURE_RAND = 28, HASH = 29, ENCRYPT = 30, TRUNCATE = 27, SECURE_RAND = 28, HASH = 29, ENCRYPT = 30,
DECRYPT = 31, COMPRESS = 32, EXPAND = 33, ZERO = 34, DECRYPT = 31, COMPRESS = 32, EXPAND = 33, ZERO = 34,
RANDOM_UUID = 35, COSH = 36, SINH = 37, TANH = 38, LN = 39, RANDOM_UUID = 35, COSH = 36, SINH = 37, TANH = 38, LN = 39,
BITGET = 40; BITGET = 40, ORA_HASH = 41;
public static final int ASCII = 50, BIT_LENGTH = 51, CHAR = 52, public static final int ASCII = 50, BIT_LENGTH = 51, CHAR = 52,
CHAR_LENGTH = 53, CONCAT = 54, DIFFERENCE = 55, HEXTORAW = 56, CHAR_LENGTH = 53, CONCAT = 54, DIFFERENCE = 55, HEXTORAW = 56,
...@@ -91,7 +92,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -91,7 +92,7 @@ public class Function extends Expression implements FunctionCall {
STRINGDECODE = 80, STRINGTOUTF8 = 81, UTF8TOSTRING = 82, STRINGDECODE = 80, STRINGTOUTF8 = 81, UTF8TOSTRING = 82,
XMLATTR = 83, XMLNODE = 84, XMLCOMMENT = 85, XMLCDATA = 86, XMLATTR = 83, XMLNODE = 84, XMLCOMMENT = 85, XMLCDATA = 86,
XMLSTARTDOC = 87, XMLTEXT = 88, REGEXP_REPLACE = 89, RPAD = 90, XMLSTARTDOC = 87, XMLTEXT = 88, REGEXP_REPLACE = 89, RPAD = 90,
LPAD = 91, CONCAT_WS = 92, TO_CHAR = 93, TRANSLATE = 94, ORA_HASH = 95, LPAD = 91, CONCAT_WS = 92, TO_CHAR = 93, TRANSLATE = 94, /* 95 */
TO_DATE = 96, TO_TIMESTAMP = 97, ADD_MONTHS = 98, TO_TIMESTAMP_TZ = 99; TO_DATE = 96, TO_TIMESTAMP = 97, ADD_MONTHS = 98, TO_TIMESTAMP_TZ = 99;
public static final int CURDATE = 100, CURTIME = 101, DATE_ADD = 102, public static final int CURDATE = 100, CURTIME = 101, DATE_ADD = 102,
...@@ -211,7 +212,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -211,7 +212,7 @@ public class Function extends Expression implements FunctionCall {
addFunction("TRUNCATE", TRUNCATE, VAR_ARGS, Value.NULL); addFunction("TRUNCATE", TRUNCATE, VAR_ARGS, Value.NULL);
// same as TRUNCATE // same as TRUNCATE
addFunction("TRUNC", TRUNCATE, VAR_ARGS, Value.NULL); addFunction("TRUNC", TRUNCATE, VAR_ARGS, Value.NULL);
addFunction("HASH", HASH, 3, Value.BYTES); addFunction("HASH", HASH, VAR_ARGS, Value.BYTES);
addFunction("ENCRYPT", ENCRYPT, 3, Value.BYTES); addFunction("ENCRYPT", ENCRYPT, 3, Value.BYTES);
addFunction("DECRYPT", DECRYPT, 3, Value.BYTES); addFunction("DECRYPT", DECRYPT, 3, Value.BYTES);
addFunctionNotDeterministic("SECURE_RAND", SECURE_RAND, 1, Value.BYTES); addFunctionNotDeterministic("SECURE_RAND", SECURE_RAND, 1, Value.BYTES);
...@@ -221,6 +222,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -221,6 +222,7 @@ public class Function extends Expression implements FunctionCall {
addFunctionNotDeterministic("RANDOM_UUID", RANDOM_UUID, 0, Value.UUID); addFunctionNotDeterministic("RANDOM_UUID", RANDOM_UUID, 0, Value.UUID);
addFunctionNotDeterministic("SYS_GUID", RANDOM_UUID, 0, Value.UUID); addFunctionNotDeterministic("SYS_GUID", RANDOM_UUID, 0, Value.UUID);
addFunctionNotDeterministic("UUID", RANDOM_UUID, 0, Value.UUID); addFunctionNotDeterministic("UUID", RANDOM_UUID, 0, Value.UUID);
addFunction("ORA_HASH", ORA_HASH, VAR_ARGS, Value.LONG);
// string // string
addFunction("ASCII", ASCII, 1, Value.INT); addFunction("ASCII", ASCII, 1, Value.INT);
addFunction("BIT_LENGTH", BIT_LENGTH, 1, Value.LONG); addFunction("BIT_LENGTH", BIT_LENGTH, 1, Value.LONG);
...@@ -274,7 +276,6 @@ public class Function extends Expression implements FunctionCall { ...@@ -274,7 +276,6 @@ public class Function extends Expression implements FunctionCall {
addFunction("RPAD", RPAD, VAR_ARGS, Value.STRING); addFunction("RPAD", RPAD, VAR_ARGS, Value.STRING);
addFunction("LPAD", LPAD, VAR_ARGS, Value.STRING); addFunction("LPAD", LPAD, VAR_ARGS, Value.STRING);
addFunction("TO_CHAR", TO_CHAR, VAR_ARGS, Value.STRING); addFunction("TO_CHAR", TO_CHAR, VAR_ARGS, Value.STRING);
addFunction("ORA_HASH", ORA_HASH, VAR_ARGS, Value.INT);
addFunction("TRANSLATE", TRANSLATE, 3, Value.STRING); addFunction("TRANSLATE", TRANSLATE, 3, Value.STRING);
addFunction("REGEXP_LIKE", REGEXP_LIKE, VAR_ARGS, Value.BOOLEAN); addFunction("REGEXP_LIKE", REGEXP_LIKE, VAR_ARGS, Value.BOOLEAN);
...@@ -1201,8 +1202,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1201,8 +1202,7 @@ public class Function extends Expression implements FunctionCall {
break; break;
} }
case HASH: case HASH:
result = ValueBytes.getNoCopy(getHash(v0.getString(), result = getHash(v0.getString(), v1, v2 == null ? 1 : v2.getInt());
v1.getBytesNoCopy(), v2.getInt()));
break; break;
case ENCRYPT: case ENCRYPT:
result = ValueBytes.getNoCopy(encrypt(v0.getString(), result = ValueBytes.getNoCopy(encrypt(v0.getString(),
...@@ -1221,6 +1221,11 @@ public class Function extends Expression implements FunctionCall { ...@@ -1221,6 +1221,11 @@ public class Function extends Expression implements FunctionCall {
compress(v0.getBytesNoCopy(), algorithm)); compress(v0.getBytesNoCopy(), algorithm));
break; break;
} }
case ORA_HASH:
result = oraHash(v0,
v1 == null ? 0xffff_ffffL : v1.getLong(),
v2 == null ? 0L : v2.getLong());
break;
case DIFFERENCE: case DIFFERENCE:
result = ValueInt.get(getDifference( result = ValueInt.get(getDifference(
v0.getString(), v1.getString())); v0.getString(), v1.getString()));
...@@ -1371,11 +1376,6 @@ public class Function extends Expression implements FunctionCall { ...@@ -1371,11 +1376,6 @@ public class Function extends Expression implements FunctionCall {
v1.getInt(), v2 == null ? null : v2.getString(), false), v1.getInt(), v2 == null ? null : v2.getString(), false),
database.getMode().treatEmptyStringsAsNull); database.getMode().treatEmptyStringsAsNull);
break; break;
case ORA_HASH:
result = ValueLong.get(oraHash(v0.getString(),
v1 == null ? null : v1.getInt(),
v2 == null ? null : v2.getInt()));
break;
case TO_CHAR: case TO_CHAR:
switch (v0.getType()){ switch (v0.getType()){
case Value.TIME: case Value.TIME:
...@@ -1726,14 +1726,22 @@ public class Function extends Expression implements FunctionCall { ...@@ -1726,14 +1726,22 @@ public class Function extends Expression implements FunctionCall {
return newData; return newData;
} }
private static byte[] getHash(String algorithm, byte[] bytes, int iterations) { private static Value getHash(String algorithm, Value value, int iterations) {
if (!"SHA256".equalsIgnoreCase(algorithm)) { if (!"SHA256".equalsIgnoreCase(algorithm)) {
throw DbException.getInvalidValueException("algorithm", algorithm); throw DbException.getInvalidValueException("algorithm", algorithm);
} }
for (int i = 0; i < iterations; i++) { if (iterations <= 0) {
bytes = SHA256.getHash(bytes, false); throw DbException.getInvalidValueException("iterations", iterations);
} }
return bytes; MessageDigest md = hashImpl(value, "SHA-256");
if (md == null) {
return ValueNull.INSTANCE;
}
byte[] b = md.digest();
for (int i = 1; i < iterations; i++) {
b = md.digest(b);
}
return ValueBytes.getNoCopy(b);
} }
private static String substring(String s, int start, int length) { private static String substring(String s, int start, int length) {
...@@ -1942,17 +1950,65 @@ public class Function extends Expression implements FunctionCall { ...@@ -1942,17 +1950,65 @@ public class Function extends Expression implements FunctionCall {
return new String(chars); return new String(chars);
} }
private static Integer oraHash(String s, Integer bucket, Integer seed) { private static Value oraHash(Value value, long bucket, long seed) {
int hc = s.hashCode(); if ((bucket & 0xffff_ffff_0000_0000L) != 0L) {
if (seed != null && seed.intValue() != 0) { throw DbException.getInvalidValueException("bucket", bucket);
hc *= seed.intValue() * 17;
} }
if (bucket == null || bucket.intValue() <= 0) { if ((seed & 0xffff_ffff_0000_0000L) != 0L) {
// do nothing throw DbException.getInvalidValueException("seed", seed);
} else {
hc %= bucket.intValue();
} }
return hc; MessageDigest md = hashImpl(value, "SHA-1");
if (md == null) {
return ValueNull.INSTANCE;
}
if (seed != 0L) {
byte[] b = new byte[4];
Bits.writeInt(b, 0, (int) seed);
md.update(b);
}
long hc = Bits.readLong(md.digest(), 0);
// Strip sign and use modulo operation to get value from 0 to bucket inclusive
return ValueLong.get((hc & Long.MAX_VALUE) % (bucket + 1));
}
private static MessageDigest hashImpl(Value value, String algorithm) {
MessageDigest md;
switch (value.getType()) {
case Value.NULL:
return null;
case Value.STRING:
case Value.STRING_FIXED:
case Value.STRING_IGNORECASE:
try {
md = MessageDigest.getInstance(algorithm);
md.update(value.getString().getBytes(StandardCharsets.UTF_8));
} catch (Exception ex) {
throw DbException.convert(ex);
}
break;
case Value.BLOB:
case Value.CLOB:
try {
md = MessageDigest.getInstance(algorithm);
byte[] buf = new byte[4096];
try (InputStream is = value.getInputStream()) {
for (int r; (r = is.read(buf)) > 0; ) {
md.update(buf, 0, r);
}
}
} catch (Exception ex) {
throw DbException.convert(ex);
}
break;
default:
try {
md = MessageDigest.getInstance(algorithm);
md.update(value.getBytesNoCopy());
} catch (Exception ex) {
throw DbException.convert(ex);
}
}
return md;
} }
private static int makeRegexpFlags(String stringFlags) { private static int makeRegexpFlags(String stringFlags) {
...@@ -2040,6 +2096,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -2040,6 +2096,7 @@ public class Function extends Expression implements FunctionCall {
min = 1; min = 1;
max = 3; max = 3;
break; break;
case HASH:
case REPLACE: case REPLACE:
case LOCATE: case LOCATE:
case INSTR: case INSTR:
......
...@@ -818,12 +818,49 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme ...@@ -818,12 +818,49 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
} }
/** /**
* Return a result set that contains the last generated auto-increment key * Return a result set with generated keys from the latest executed command or
* for this connection, if there was one. If no key was generated by the * an empty result set if keys were not generated or were not requested with
* last modification statement, then an empty result set is returned. * {@link Statement#RETURN_GENERATED_KEYS}, column indexes, or column names.
* The returned result set only contains the data for the very last row. * <p>
* Generated keys are only returned from inserted rows from {@code INSERT},
* {@code MERGE INTO}, and {@code MERGE INTO ... USING} commands. Generated keys
* are not returned if exact values of generated columns were specified
* explicitly in SQL command. All columns with inserted generated values are
* included in the result if command was executed with
* {@link Statement#RETURN_GENERATED_KEYS} parameter.
* </p>
* <p>
* If SQL command inserts multiple rows with generated keys each such inserted
* row is returned. Batch methods are also supported. When multiple rows are
* returned each row contains only generated values for this row. It's possible
* to insert several rows with generated values in different columns with some
* specific commands, in this special case the returned result set contains all
* used columns, but each row will contain only generated values, columns that
* were not generated for this row will contain {@code null} values.
* </p>
* <p>
* H2 treats inserted value as generated in the following cases:
* </p>
* <ul>
* <li>Columns with sequences including {@code IDENTITY} columns and columns
* with {@code AUTO_INCREMENT} if value was generated automatically (not
* specified in command).</li>
* <li>Columns with other default values that are not evaluated into constant
* expressions (like {@code DEFAULT RANDOM_UUID()}) also only if default value
* was inserted.</li>
* <li>Columns that were set by triggers.</li>
* <li>Columns with values specified in command with invocation of some sequence
* (like {@code INSERT INTO ... VALUES (NEXT VALUE FOR ...)}).</li>
* </ul>
* <p>
* Exact required columns for the returning result set may be specified on
* execution of command with names or indexes of columns to limit output or
* reorder columns in result set. Specifying of some column has no effect on
* treatment of inserted values as generated or not. If some value is not
* determined to be generated it will not be returned even on explicit request.
* </p>
* *
* @return the result set with one row and one column containing the key * @return the possibly empty result set with generated keys
* @throws SQLException if this object is closed * @throws SQLException if this object is closed
*/ */
@Override @Override
......
...@@ -752,7 +752,6 @@ public class DataType { ...@@ -752,7 +752,6 @@ public class DataType {
// "java.lang.Short"; // "java.lang.Short";
return Short.class.getName(); return Short.class.getName();
case Value.INT: case Value.INT:
case Value.ENUM:
// "java.lang.Integer"; // "java.lang.Integer";
return Integer.class.getName(); return Integer.class.getName();
case Value.LONG: case Value.LONG:
...@@ -780,6 +779,7 @@ public class DataType { ...@@ -780,6 +779,7 @@ public class DataType {
case Value.STRING: case Value.STRING:
case Value.STRING_IGNORECASE: case Value.STRING_IGNORECASE:
case Value.STRING_FIXED: case Value.STRING_FIXED:
case Value.ENUM:
// "java.lang.String"; // "java.lang.String";
return String.class.getName(); return String.class.getName();
case Value.BLOB: case Value.BLOB:
......
...@@ -54,11 +54,6 @@ public class ValueEnum extends ValueEnumBase { ...@@ -54,11 +54,6 @@ public class ValueEnum extends ValueEnumBase {
} }
} }
@Override
protected int compareSecure(final Value v, final CompareMode mode) {
return Integer.compare(getInt(), v.getInt());
}
/** /**
* Create an ENUM value from the provided enumerators * Create an ENUM value from the provided enumerators
* and value. * and value.
......
...@@ -112,7 +112,6 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -112,7 +112,6 @@ public class TestFunctions extends TestBase implements AggregateFunction {
testNvl2(); testNvl2();
testConcatWs(); testConcatWs();
testTruncate(); testTruncate();
testOraHash();
testToCharFromDateTime(); testToCharFromDateTime();
testToCharFromNumber(); testToCharFromNumber();
testToCharFromText(); testToCharFromText();
...@@ -1280,20 +1279,6 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -1280,20 +1279,6 @@ public class TestFunctions extends TestBase implements AggregateFunction {
conn.close(); conn.close();
} }
private void testOraHash() throws SQLException {
deleteDb("functions");
Connection conn = getConnection("functions");
Statement stat = conn.createStatement();
String testStr = "foo";
assertResult(String.valueOf("foo".hashCode()), stat,
String.format("SELECT ORA_HASH('%s') FROM DUAL", testStr));
assertResult(String.valueOf("foo".hashCode()), stat,
String.format("SELECT ORA_HASH('%s', 0) FROM DUAL", testStr));
assertResult(String.valueOf("foo".hashCode()), stat,
String.format("SELECT ORA_HASH('%s', 0, 0) FROM DUAL", testStr));
conn.close();
}
private void testToDateException() { private void testToDateException() {
try { try {
ToDateParser.toDate("1979-ThisWillFail-12", "YYYY-MM-DD"); ToDateParser.toDate("1979-ThisWillFail-12", "YYYY-MM-DD");
......
...@@ -119,7 +119,7 @@ public class TestScript extends TestBase { ...@@ -119,7 +119,7 @@ public class TestScript extends TestBase {
for (String s : new String[] { "abs", "acos", "asin", "atan", "atan2", for (String s : new String[] { "abs", "acos", "asin", "atan", "atan2",
"bitand", "bitget", "bitor", "bitxor", "ceil", "compress", "bitand", "bitget", "bitor", "bitxor", "ceil", "compress",
"cos", "cosh", "cot", "decrypt", "degrees", "encrypt", "exp", "cos", "cosh", "cot", "decrypt", "degrees", "encrypt", "exp",
"expand", "floor", "hash", "length", "log", "mod", "pi", "expand", "floor", "hash", "length", "log", "mod", "ora-hash", "pi",
"power", "radians", "rand", "random-uuid", "round", "power", "radians", "rand", "random-uuid", "round",
"roundmagic", "secure-rand", "sign", "sin", "sinh", "sqrt", "roundmagic", "secure-rand", "sign", "sin", "sinh", "sqrt",
"tan", "tanh", "truncate", "zero" }) { "tan", "tanh", "truncate", "zero" }) {
......
...@@ -3,8 +3,23 @@ ...@@ -3,8 +3,23 @@
-- Initial Developer: H2 Group -- Initial Developer: H2 Group
-- --
call hash('SHA256', 'Hello', 0);
> exception
call hash('SHA256', 'Hello');
>> 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
call hash('SHA256', 'Hello', 1);
>> 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
call hash('SHA256', stringtoutf8('Hello'), 1); call hash('SHA256', stringtoutf8('Hello'), 1);
>> 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969 >> 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
CALL HASH('SHA256', 'Password', 1000);
>> c644a176ce920bde361ac336089b06cc2f1514dfa95ba5aabfe33f9a22d577f0
CALL HASH('SHA256', STRINGTOUTF8('Password'), 1000); CALL HASH('SHA256', STRINGTOUTF8('Password'), 1000);
>> c644a176ce920bde361ac336089b06cc2f1514dfa95ba5aabfe33f9a22d577f0 >> c644a176ce920bde361ac336089b06cc2f1514dfa95ba5aabfe33f9a22d577f0
call hash('unknown', 'Hello', 1);
> exception
-- Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
SELECT ORA_HASH(NULL);
>> null
SELECT ORA_HASH(NULL, 0);
>> null
SELECT ORA_HASH(NULL, 0, 0);
>> null
SELECT ORA_HASH(1);
>> 3509391659
SELECT ORA_HASH(1, -1);
> exception
SELECT ORA_HASH(1, 0);
>> 0
SELECT ORA_HASH(1, 4294967295);
>> 3509391659
SELECT ORA_HASH(1, 4294967296)
> exception
SELECT ORA_HASH(1, 4294967295, -1);
> exception
SELECT ORA_HASH(1, 4294967295, 0);
>> 3509391659
SELECT ORA_HASH(1, 4294967295, 10);
>> 2441322222
SELECT ORA_HASH(1, 4294967295, 4294967295);
>> 3501171530
SELECT ORA_HASH(1, 4294967295, 4294967296);
> exception
CREATE TABLE TEST(I BINARY, B BLOB, S VARCHAR, C CLOB);
> ok
INSERT INTO TEST VALUES ('010203', '010203', 'abc', 'abc');
> update count: 1
SELECT ORA_HASH(I) FROM TEST;
>> 2562861693
SELECT ORA_HASH(B) FROM TEST;
>> 2562861693
SELECT ORA_HASH(S) FROM TEST;
>> 1191608682
SELECT ORA_HASH(C) FROM TEST;
>> 1191608682
DROP TABLE TEST;
> ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论