Informix CDC - 从bytearray转换十进制,日期等

时间:2017-03-21 06:49:54

标签: c# informix

我尝试在C#中使用Informix Change Data Capture! CDC正在运行,我得到有关插入,更新,删除的数据,但我无法从bytearray转换一些数据。

有谁知道如何在c#中转换这些值?

  • bytearray 62,28,0,0应为十进制(6,2)-72.00
  • bytearray 193,72,0,0应为十进制(6,2)72.00
  • bytearray 193,1,18,0,0,0,0,0应为十进制(14,4)1.1800
  • bytearray 194,1,0,0,0,0,0应为十进制(12,0)100
  • bytearray 194,4,1,67,89,0,0,0,0应为十进制(15,4)401.6789
  • bytearray 0,0,166,33应为日期09.06.16(DMY格式)

1 个答案:

答案 0 :(得分:1)

处理数据类型的字节数组会使您陷入深度字节错误。

DATE

DATE类型更易于处理。

  • DATE值是4字节整数。
  • 存储自参考日期起的天数,即1899-12-31(因此第1天为1900-01-01)。
  • 格式是big-endian。

您的数据是(十进制)字节0,0,166,33,它映射到十进制整数42529(或十六进制0xA621),当我运行时:

sqlcmd -d stores -e 'select date(42529) from dual'

我回答了答案:

2016-06-09

这是你所期望的。 (SQLCMD程序可以从ESQL / C部分的国际Informix用户组(IIUG)软件存储库获得。它与微软的johnny-come-lately程序​​同名无关。)我与之合作环境中的DBDATE=y4md-,因此是日期格式。我的dual数据库中有一个名为stores的行表;如果您愿意,可以使用sysmaster:sysdual代替。负日期有效;他们使用所谓的“预感”公历,并且不会在1752年,1584年或任何其他日期之前恢复到朱利安历法。最长有效日期为9999-12-31。

DECIMAL

DECIMAL类型要复杂得多。磁盘格式由类型限定符控制。 decimal.h目录中有一个标题$INFORMIXDIR/incl/esql,其中包含以下信息:

/*
 * Packed Format  (format in records in files)
 *
 *    First byte =
 *        top 1 bit = sign 0=neg, 1=pos
 *        low 7 bits = Exponent in excess 64 format
 *    Rest of bytes = base 100 digits in 100 complement format
 *    Notes --  This format sorts numerically with just a
 *              simple byte by byte unsigned comparison.
 *              Zero is represented as 80,00,00,... (hex).
 *              Negative numbers have the exponent complemented
 *              and the base 100 digits in 100's complement
 */

我写的一些与此相关的代码添加了信息:

**    --    Negative numbers have the exponent complemented (exp = (~exp
**          & 0x7F)) and the base 100 digits in 100's complement.
**          That is, last non-zero digit is subtracted from 100;
**          previous digits from 99.

如果你擅长解析密集的英语,那实际上是对相关内容进行了相当准确的描述,但需要进行大量的解析。

让我们看看你的前两个值:

  • bytearray 62,28,0,0应为十进制(6,2)-72.00
  • bytearray 193,72,0,0应为十进制(6,2)72.00

十进制的值在第一个字节中有一个符号位和一个指数(此处为62 = 0x3E和193 = 0xC1字节),然后是后续字节中的十进制数字。 DECIMAL(6,2)值在小数点前有一到四位小数,小数点后有0到2位,总共有6位十进制数或三位数(基数为100)。这就是为什么这两个值在磁盘上使用4个字节。

0xC1字节的前导位设置为表示正数。指数为0x41,即十进制65.这是'超64'模式,因此实际指数值为1,这意味着小数点出现在第一个字节之后。数字72清晰可见。因此,0xC1,0x48,0x00,0x00确实映射到+72.00。类似地,28是70的100s补码,指数的第一位是0,因此该值是负的。指数值0x3E确实是用0x7F屏蔽的0x41的按位反转:

0100 0001    0x41
1011 1110    ~0x41
0011 1110    (~0x41) & 0x7F

在C语言中(不是C# - 我不知道在C#中可以使用哪些设施),我创建了这个程序。 lddecimal()函数是标准(Informix提供的)函数,用于将磁盘上的DECIMAL格式转换为内存格式(dec_t - C结构类型)。 dump_decimal()dec_fix()函数不是标准函数(但您可以使用SQLCMD的源代码找到它们的代码)。第一个以明确的格式打印结构中的信息。第二个打印结构中表示的值作为定点小数(1的第三个参数表示应始终打印符号)。

#include "decsci.h"
#include "dumpesql.h"
#include <stdio.h>

#define DIM(x)  (sizeof(x)/sizeof(*(x)))

struct dec_info
{
    int length;
    int dec_places;
    char bytes[9];
};

static const struct dec_info values[] =
{
    { 4, 2, {  62, 28,  0,  0,  0 } },
    { 4, 2, { 193, 72,  0,  0,  0 } },
    { 8, 4, { 193,  1, 18,  0,  0 } },
    { 7, 0, { 194,  1,  0,  0,  0 } },
    { 9, 4, { 194,  4,  1, 67, 89 } },
};

int main(void)
{
    for (int i = 0; i < DIM(values); i++)
    {
        dec_t dv = { 0 };
        printf("\nBytes:  ");
        for (int j = 0; j < values[i].length; j++)
            printf(" 0x%.2X", values[i].bytes[j] & 0xFF);
        putchar('\n');

        lddecimal(values[i].bytes, values[i].length, &dv);

        char ds[60];
        dec_fix(&dv, values[i].dec_places, 1, ds, sizeof(ds));
        printf("Decimal: %s\n", ds);

        char tag[20];
        snprintf(tag, sizeof(tag), "Example %d", i);
        dump_decimal(stdout, tag, &dv);
    }
    return(0);
}

此代码的输出为:

Bytes:   0x3E 0x1C 0x00 0x00
Decimal: -72.00
DECIMAL: Example 0 -- address 0x7FFF59282400
E:   +1, S = 0 (-), N =  1, M = 72 [ unused:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]

Bytes:   0xC1 0x48 0x00 0x00
Decimal: +72.00
DECIMAL: Example 1 -- address 0x7FFF59282400
E:   +1, S = 1 (+), N =  1, M = 72 [ unused:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]

Bytes:   0xC1 0x01 0x12 0x00 0x00 0x00 0x00 0x00
Decimal: +1.1800
DECIMAL: Example 2 -- address 0x7FFF59282400
E:   +1, S = 1 (+), N =  2, M = 01 18 [ unused:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]

Bytes:   0xC2 0x01 0x00 0x00 0x00 0x00 0x00
Decimal: +100
DECIMAL: Example 3 -- address 0x7FFF59282400
E:   +2, S = 1 (+), N =  1, M = 01 [ unused:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]

Bytes:   0xC2 0x04 0x01 0x43 0x59 0x00 0x00 0x00 0x00
Decimal: +401.6789
DECIMAL: Example 4 -- address 0x7FFF59282400
E:   +2, S = 1 (+), N =  4, M = 04 01 67 89 [ unused:  00 00 00 00 00 00 00 00 00 00 00 00 ]

将其转换为C#将需要我没有的专业知识,但它会告诉您需要做什么或找到什么。

请注意,DATETIME和INTERVAL类型也在其磁盘和内存表示中使用DECIMAL。