我尝试在C#中使用Informix Change Data Capture! CDC正在运行,我得到有关插入,更新,删除的数据,但我无法从bytearray转换一些数据。
有谁知道如何在c#中转换这些值?
答案 0 :(得分:1)
处理数据类型的字节数组会使您陷入深度字节错误。
DATE类型更易于处理。
您的数据是(十进制)字节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.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.
如果你擅长解析密集的英语,那实际上是对相关内容进行了相当准确的描述,但需要进行大量的解析。
让我们看看你的前两个值:
十进制的值在第一个字节中有一个符号位和一个指数(此处为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。