如何在 JavaScript 中为 BigQuery 实现 T-SQL CHECKSUM()?
How to Implement T-SQL CHECKSUM() in JavaScript for BigQuery?
我要寻找的最终结果是实现 T-SQL CHECKSUM in BigQuery with a JavaScript UDF。我会满足于翻译 C/C++ 源代码,但如果有人已经完成了这项工作,那么我很乐意使用它。
或者,如果有人能想出一种方法来在 Microsoft SQL 服务器中存储的字符串与 BigQuery 中存储的字符串之间创建等效的哈希码,那对我也有帮助。
- 更新:我通过 HABO 的 link 在用 T-SQL 编写的注释中找到了一些源代码来执行相同的 CHECKSUM 但我很难将其转换为 JavaScript 本质上无法处理 64 位整数。我正在玩一些小例子,发现该算法适用于每个字节的低半字节仅。
- 更新 2:我真的很想复制这个算法,我可以看到一些明确的模式,但我的大脑无法胜任将其提炼成逆向工程解决方案的任务。我确实发现
BINARY_CHECKSUM()
和 CHECKSUM()
return 不同,所以前者的工作对后者没有帮助。
我花了一整天的时间对此进行逆向工程,首先转储单个 ASCII 字符和成对字符的所有结果。这表明每个字符都有自己不同的 "XOR code" 并且字母无论大小写都相同。之后该算法非常容易理解:向左旋转 4 位并通过查找 table.
中存储的代码进行异或运算。
var xorcodes = [
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
0, 33, 34, 35, 36, 37, 38, 39, // !"#$%&'
40, 41, 42, 43, 44, 45, 46, 47, // ()*+,-./
132, 133, 134, 135, 136, 137, 138, 139, // 01234567
140, 141, 48, 49, 50, 51, 52, 53, 54, // 89:;<=>?@
142, 143, 144, 145, 146, 147, 148, 149, // ABCDEFGH
150, 151, 152, 153, 154, 155, 156, 157, // IJKLMNOP
158, 159, 160, 161, 162, 163, 164, 165, // QRSTUVWX
166, 167, 55, 56, 57, 58, 59, 60, // YZ[\]^_`
142, 143, 144, 145, 146, 147, 148, 149, // abcdefgh
150, 151, 152, 153, 154, 155, 156, 157, // ijklmnop
158, 159, 160, 161, 162, 163, 164, 165, // qrstuvwx
166, 167, 61, 62, 63, 64, 65, 66, // yz{|}~
];
function rol(x, n) {
// simulate a rotate shift left (>>> preserves the sign bit)
return (x<<n) | (x>>>(32-n));
}
function checksum(s) {
var checksum = 0;
for (var i = 0; i < s.length; i++) {
checksum = rol(checksum, 4);
var c = s.charCodeAt(i);
var xorcode = 0;
if (c < xorcodes.length) {
xorcode = xorcodes[c];
}
checksum ^= xorcode;
}
return checksum;
};
有关详细信息,请参阅 https://github.com/neilodonuts/tsql-checksum-javascript。
免责声明:我只研究过 SQL 服务器中 VARCHAR
字符串的兼容性,排序规则设置为 SQL_Latin1_General_CP1_CI_AS
。这不适用于多列或整数,但我确信底层算法使用相同的代码,因此不难理解。它似乎也不同于 db<>fiddle 可能是由于整理:https://github.com/neilodonuts/tsql-checksum-javascript/blob/master/data/dbfiddle-differences.png ...里程可能会有所不同!
fyi,对于那些陷入 T-SQL 遗留模式的人来说,这里有一个经过测试的 C# 实现,对于我一直使用的大多数 strings/ints 来说看起来不错:
public static int[] xorcodes = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
0, 33, 34, 35, 36, 37, 38, 39, // !"#$%&'
40, 41, 42, 43, 44, 45, 46, 47, // ()*+,-./
132, 133, 134, 135, 136, 137, 138, 139, // 01234567
140, 141, 48, 49, 50, 51, 52, 53, 54, // 89:;<=>?@
142, 143, 144, 145, 146, 147, 148, 149, // ABCDEFGH
150, 151, 152, 153, 154, 155, 156, 157, // IJKLMNOP
158, 159, 160, 161, 162, 163, 164, 165, // QRSTUVWX
166, 167, 55, 56, 57, 58, 59, 60, // YZ[\]^_`
142, 143, 144, 145, 146, 147, 148, 149, // abcdefgh
150, 151, 152, 153, 154, 155, 156, 157, // ijklmnop
158, 159, 160, 161, 162, 163, 164, 165, // qrstuvwx
166, 167, 61, 62, 63, 64, 65, 66, // yz{|}~
};
public static int rol(int x, int n) {
// simulate a rotate shift left (>>> preserves the sign bit)
return ((int)x << n) | ((int)((uint)x >> (32 - n)));
}
public static int checksum(string s) {
int checksum = 0;
for (var i = 0; i < s.Length; i++) {
checksum = rol(checksum, 4);
var c = ((int)s[i]);
int xorcode = 0;
if (c < xorcodes.Length) {
xorcode = xorcodes[c];
}
checksum ^= xorcode;
}
return checksum;
}
我要寻找的最终结果是实现 T-SQL CHECKSUM in BigQuery with a JavaScript UDF。我会满足于翻译 C/C++ 源代码,但如果有人已经完成了这项工作,那么我很乐意使用它。
或者,如果有人能想出一种方法来在 Microsoft SQL 服务器中存储的字符串与 BigQuery 中存储的字符串之间创建等效的哈希码,那对我也有帮助。
- 更新:我通过 HABO 的 link 在用 T-SQL 编写的注释中找到了一些源代码来执行相同的 CHECKSUM 但我很难将其转换为 JavaScript 本质上无法处理 64 位整数。我正在玩一些小例子,发现该算法适用于每个字节的低半字节仅。
- 更新 2:我真的很想复制这个算法,我可以看到一些明确的模式,但我的大脑无法胜任将其提炼成逆向工程解决方案的任务。我确实发现
BINARY_CHECKSUM()
和CHECKSUM()
return 不同,所以前者的工作对后者没有帮助。
我花了一整天的时间对此进行逆向工程,首先转储单个 ASCII 字符和成对字符的所有结果。这表明每个字符都有自己不同的 "XOR code" 并且字母无论大小写都相同。之后该算法非常容易理解:向左旋转 4 位并通过查找 table.
中存储的代码进行异或运算。var xorcodes = [
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
0, 33, 34, 35, 36, 37, 38, 39, // !"#$%&'
40, 41, 42, 43, 44, 45, 46, 47, // ()*+,-./
132, 133, 134, 135, 136, 137, 138, 139, // 01234567
140, 141, 48, 49, 50, 51, 52, 53, 54, // 89:;<=>?@
142, 143, 144, 145, 146, 147, 148, 149, // ABCDEFGH
150, 151, 152, 153, 154, 155, 156, 157, // IJKLMNOP
158, 159, 160, 161, 162, 163, 164, 165, // QRSTUVWX
166, 167, 55, 56, 57, 58, 59, 60, // YZ[\]^_`
142, 143, 144, 145, 146, 147, 148, 149, // abcdefgh
150, 151, 152, 153, 154, 155, 156, 157, // ijklmnop
158, 159, 160, 161, 162, 163, 164, 165, // qrstuvwx
166, 167, 61, 62, 63, 64, 65, 66, // yz{|}~
];
function rol(x, n) {
// simulate a rotate shift left (>>> preserves the sign bit)
return (x<<n) | (x>>>(32-n));
}
function checksum(s) {
var checksum = 0;
for (var i = 0; i < s.length; i++) {
checksum = rol(checksum, 4);
var c = s.charCodeAt(i);
var xorcode = 0;
if (c < xorcodes.length) {
xorcode = xorcodes[c];
}
checksum ^= xorcode;
}
return checksum;
};
有关详细信息,请参阅 https://github.com/neilodonuts/tsql-checksum-javascript。
免责声明:我只研究过 SQL 服务器中 VARCHAR
字符串的兼容性,排序规则设置为 SQL_Latin1_General_CP1_CI_AS
。这不适用于多列或整数,但我确信底层算法使用相同的代码,因此不难理解。它似乎也不同于 db<>fiddle 可能是由于整理:https://github.com/neilodonuts/tsql-checksum-javascript/blob/master/data/dbfiddle-differences.png ...里程可能会有所不同!
fyi,对于那些陷入 T-SQL 遗留模式的人来说,这里有一个经过测试的 C# 实现,对于我一直使用的大多数 strings/ints 来说看起来不错:
public static int[] xorcodes = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
0, 33, 34, 35, 36, 37, 38, 39, // !"#$%&'
40, 41, 42, 43, 44, 45, 46, 47, // ()*+,-./
132, 133, 134, 135, 136, 137, 138, 139, // 01234567
140, 141, 48, 49, 50, 51, 52, 53, 54, // 89:;<=>?@
142, 143, 144, 145, 146, 147, 148, 149, // ABCDEFGH
150, 151, 152, 153, 154, 155, 156, 157, // IJKLMNOP
158, 159, 160, 161, 162, 163, 164, 165, // QRSTUVWX
166, 167, 55, 56, 57, 58, 59, 60, // YZ[\]^_`
142, 143, 144, 145, 146, 147, 148, 149, // abcdefgh
150, 151, 152, 153, 154, 155, 156, 157, // ijklmnop
158, 159, 160, 161, 162, 163, 164, 165, // qrstuvwx
166, 167, 61, 62, 63, 64, 65, 66, // yz{|}~
};
public static int rol(int x, int n) {
// simulate a rotate shift left (>>> preserves the sign bit)
return ((int)x << n) | ((int)((uint)x >> (32 - n)));
}
public static int checksum(string s) {
int checksum = 0;
for (var i = 0; i < s.Length; i++) {
checksum = rol(checksum, 4);
var c = ((int)s[i]);
int xorcode = 0;
if (c < xorcodes.Length) {
xorcode = xorcodes[c];
}
checksum ^= xorcode;
}
return checksum;
}