如何使用十六进制字符串格式的列在 Informix 中处理 bitand 操作

How to process bitand operation in Informix with column in hex string format

在 table 中,我有一个包含十六进制值的字符串列。例如值 '000000000000000a' 表示 10。现在我需要处理 bitand 操作:bitand(tableName.hexColumn, ?)。当我阅读此函数的 Informix 规范时,它需要 2 个 int。所以我的问题是:处理这个操作更简单的方法是什么?

PS:Informix 中可能没有解决方案,所以我将不得不创建自己的 bitandhexstring 函数,其中输入将是 2 个字符串和十六进制形式,但我不知道从哪里开始。

有多种问题需要处理:

  1. 您的十六进制字符串有 16 位数字,因此这些值大概(通常)是 64 位数量。这意味着您需要确保 BITAND 函数具有处理 BIGINT(或者可能是 INT8 — 我不会再次提及 INT8,但在提及 BIGINT 时名义上是一个选项)数据的变体。

  2. 您需要将十六进制字符串转换为 BIGINT。

  3. 不清楚您是否需要将结果 BIGINT 转换回十六进制字符串。

在 Mac OS X 10.10.4 上使用 Informix 11.70.FC6 进行的一些测试表明 BITAND 对于 64 位数字是安全的。这是个好消息!

HEX 函数,当传递一个 BIGINT 时,returns 一个以 0x 开头并包含数字的十六进制表示的 CHAR(20) 字符串,这样或多或少的地址指向 3 .残差问题是'how to convert 16-byte strings of hex digits to a BIGINT value'。名义上,强制转换操作如:

 CAST('0xde3962e8c68a8001' AS BIGINT)

应该可以完成这项工作(但请参阅下文)。可能有比蛮力和无知存储过程更好的方法,但我不能立即确定它是什么。


告诫讲师。

在测试时,我尝试了两个查询:

SELECT bi, HEX(bi)                         FROM Test_BigInt;
SELECT bi, HEX(bi), SUBSTR(HEX(bi), 3, 16) FROM Test_BigInt;

在 table Test_BigInt 上具有 BIGINT 类型的单个列 bi(不为空,因为它发生了,但那不是 material)。

第一个查询运行良好。 HEX(bi) 表达式的类型是 CHAR(20),值类似于

                   0    0x0000000000000000
 6898532535585831936    0x5fbc82ca87117c00
-2300268458811555839    0xe013ce0628808001

第二个查询适用于 bi (0, 1, 2) 的小值,但当值变大时会生成错误 -1215: Value exceeds limit of INTEGER precision。问题不直接出在 SUBSTR 函数上。这是在 Mac OS X 10.10.4 上使用 Informix 11.70.FC6 进行的测试 — 在 2015-07-08 进行了测试。以下一对查询按预期工作(这是我声称问题不在 SUBSTR 函数本身的理由)。

SELECT bi, HEX(bi) AS hex_bi FROM Test_BigInt INTO TEMP t;
SELECT bi, hex_bi, SUBSTR(hex_bi, 3, 16) FROM t;

在字符串操作上下文中使用HEX结果时,似乎是一个交互问题。我在尝试将空字符串连接到 HEX 的结果时首先遇到问题:HEX(bi) || ''。事实证明这是不必要的,因为 HEX 的结果报告为 CHAR(20),但也表明 SUBSTR 不是直接的错误。

我也试过 CAST 将十六进制字符串转换为 BIGINT:

SELECT CAST('0xde3962e8c68a8001' AS BIGINT) FROM dual;
BIGINT
-964001791
SELECT HEX(CAST('0xde3962e8c68a8001' AS BIGINT)) FROM dual;
CHAR(18)
0xffffffffc68a8001

哎呀!转换处理不当。这不是新软件(已经超过 2 年了),但很有可能除非其他人发现了这个错误,否则它可能还没有被修复,即使在最新版本中也是如此。

我已经通过后台渠道向 IBM/Informix 报告了此事。


将十六进制字符串转换为 BIGINT 的存储过程

CREATE PROCEDURE hexval(c CHAR(1)) RETURNING INTEGER;
    RETURN INSTR("0123456789abcdef", lower(c)) - 1;
END PROCEDURE;

CREATE PROCEDURE hexstr_to_bigint(ival VARCHAR(18)) RETURNING bigint;
    DEFINE oval DECIMAL(20,0);
    DEFINE i,j,len INTEGER;
    LET ival = LOWER(ival);
    IF (ival[1,2] = '0x') THEN LET ival = ival[3,18]; END IF;
    LET len = LENGTH(ival);
    LET oval = 0;
    FOR i = 1 TO len
        LET j = hexval(SUBSTR(ival, i, 1));
        LET oval = oval * 16 + j;
    END FOR;
    IF (oval > 9223372036854775807) THEN
        LET oval = oval - 18446744073709551616;
    END IF;
    RETURN oval;
END PROCEDURE;

休闲测试:

execute procedure hexstr_to_bigint('000A');
10
execute procedure hexstr_to_bigint('FFff');
65535
execute procedure hexstr_to_bigint('FFFFffffFFFFffff');
-1
execute procedure hexstr_to_bigint('0XFFFFffffFFFFffff');
-1
execute procedure hexstr_to_bigint('000000000000000A');
10

这些值是正确的。