27 Star 37 Fork 27

calvinwilliams/DirectStruct

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
LGPL-2.1
DirectStruct - C结构体工具

1.概述
2.编译安装
3.基本使用
3.1.编写IDL定义文件,用自动化代码工具dsc处理之
3.2.编写应用代码,调用网络/主机字节序化函数
3.3.编写应用代码,调用二进制序列化/反序列化函数
3.4.编写应用代码,调用XML序列化/反序列化函数
3.5.编写应用代码,调用JSON序列化/反序列化函数
3.6.编写应用代码,使用ESQL代码开发数据库应用
N-2.DirectStruct报文定义文件语法
N-1.性能压测
N.最后

------------------------------------------------------------

1.概述

DirectStruct是一个强有力的代码自动生成工具,它可以自动生成C结构体与XML、JSON、二进制(带压缩)等报文之间的转换代码,还能自动生成ESQL代码片段,在应用中直接使用自动化代码以提高开发效率,避免开发冗余和手工编码风险。

DirectStruct生成了哪些自动化代码?
* C结构体定义
* 批量初始化缺省值函数
* 网络/主机字节序化函数
* 二进制序列化/反序列化函数(可带压缩)
* XML序列化/反序列化函数(展开风格和紧缩风格)(依赖开源库fasterxml[url]http://git.oschina.net/calvinwilliams/fasterxml[/url])
* JSON序列化/反序列化函数(展开风格和紧缩风格)(依赖开源库fasterjson[url]http://git.oschina.net/calvinwilliams/fasterjson[/url])
* 嵌入式SQL代码片段以及一些嵌入式SQL函数
* 打印结构体内所有字段值函数

用DirectStruct自动生成的代码能干什么?

* 直接C结构体通讯交换 : 在特定平台之间直接把C结构体变量通过TCP扔给对方是一个很诱人的想法,阻碍我们的主要是整型字段的字节序问题,手工编码是一件冗余的事情,DirectStruct可以帮助你自动化这一过程。解决了字节序问题后就可以直接交换报文,避免了通讯发送前的打包和通讯接收后的解包,所以速度非常快,是某些追求极端性能的场景中的首选报文格式。
* 结构体序列化/反序列化 : 使用DirectStruct自动生成的序列化/反序列化函数,可以将C结构体打包成二进制报文或XML报文或JSON报文等,以及反向解包,是的,打包解包函数自动生成,省却了你不少麻烦吧。二进制报文如果启用了压缩选项,压缩后的二进制数据块大幅缩小,更便于通讯高效交换。
* 基于嵌入式SQL的数据库映射接口的代码自动化生成
* 快速打印结构体内所有字段值 : 对于一个大结构,编写他的打印所有字段值的函数是一件很无聊的事情,你可以用DirectStruct帮助你自动生成日志函数,输出到屏幕,或你自己的日志流中。
* ( 新主意增加中 ... 把你的需求告诉我吧 )

为什么使用DirectStruct?

* 灵活的报文定义语法 : 命令行工具dsc读入定义文件,生成自动化代码,支持子结构嵌套、子结构数组、定义文件包含等灵活配置方式。
* 跨平台:DirectStruct支持WINDOWS、Linux、AIX等主流操作系统,尤其是多平台中不同的表达方法,如64位整型,相同的IDL定义文件将生成不同平台的标准。

2.编译安装

for Linux
$ tar xvzf dsc-1.1.0.tar.gz
$ cd dsc-1.1.0/src
$ su
# make -f makefile.Linux clean
rm -f util.o
rm -f main.o
rm -f dsc.o
rm -f ReadDscFile.o
rm -f GenerateCCode.o
rm -f dsc
# make -f makefile.Linux install
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c util.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c main.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c dsc.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c ReadDscFile.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c GenerateCCode.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o dsc util.o main.o dsc.o ReadDscFile.o GenerateCCode.o -L.
cp -f dsc /usr/bin/

3.基本使用

本章示例都取自于test目录中的测试程序。

3.1.编写IDL定义文件,用自动化代码工具dsc处理之

[code]
$ cat IDL_AllTypes.dsc
STRUCT	AllTypes
{
	# 这是注释
	INT	1	n1	# 这也是注释
	INT	2	n2
	INT	4	n4
	INT	8	n8
	UINT	1	u1
	UINT	2	u2
	UINT	4	u4
	UINT	8	u8
	FLOAT	4	f4
	FLOAT	8	f8
	CHAR	1	ch
	UCHAR	1	uch
	STRING	32	str32
	STRING	1024	str1024
}
$ dsc -f IDL_AllTypes.dsc -c-ALL
STRUCT AllTypes
        INT 1 n1
        INT 2 n2
        INT 4 n4
        INT 8 n8 # longlong or _int64 for c
        UINT 1 u1
        UINT 2 u2
        UINT 4 u4
        UINT 8 u8
        FLOAT 4 f4
        FLOAT 8 f8
        CHAR 1 ch
        UCHAR 1 uch
        STRING 32 str32
        STRING 1024 str1024
ok!
$ ls
IDL_AllTypes.dsc
IDL_AllTypes.dsc.h
IDL_AllTypes.dsc.c
IDL_AllTypes.dsc.LOG.c
[/code]

IDL_test.dsc.h包含了自动生成的一个C结构体定义。
IDL_test.dsc.c包含了自动生成的初始化缺省函数、网络/主机字节序化、序列化/反序列化等代码。
IDL_test.dsc.LOG.c包含了自动生成的一个日志函数用于快速打印报文所有字段到标准输出或你自己的日志流上便于调试。

注意:IDL_test.dsc.h、IDL_test.dsc.c实际内容取决于参数"-c-*"

[code]
$ dsc
dsc v1.1.0 - DirectSrtuct Compiler
Copyright by calvin<calvinwilliams.c@gmail.com> 2014
USAGE : dsc -f .dsc [ -c ] [ -c-order ] [ -c-compact ] [ -c-compress ] [ -c-xml ] [ -c-LOG ] [ -c-ALL ]
[/code]
-c		基本的c结构体定义
-c-order	还包含主机/网络字节序化函数
-c-compact	还包含二进制紧凑序列化/反序列化函数
-c-compress	还包含二进制压缩序列化/反序列化函数
-c-xml		还包含XML序列化/反序列化函数(依赖于开源库fastxml)
-c-LOG		生成IDL_test.dsc.LOG.c
-c-ALL		生成以上所有

注意:test/makefile未包含处理.dsc定义文件的动作,如修改.dsc文件后需要手工处理之。

3.2.编写应用代码,调用网络/主机字节序化函数

[code]
$ cat test_netorder.c
int test_netorder()
{
	AllTypes	st ;
	int		nret = 0 ;
	
	/* client code */
	memset( & st , 0x00 , sizeof(AllTypes) );
	
	st.n1 = -0x11 ;
	st.n2 = -0x1122 ;
	st.n4 = -0x11223344 ;
	st.n8 = LL(-0x1122334455667788) ;
	st.u1 = 0x11 ;
	st.u2 = 0x1122 ;
	st.u4 = 0x11223344 ;
	st.u8 = ULL(0x1122334455667788) ;
	st.f4 = 100.00 ;
	st.f8 = 10000.00 ;
	st.ch = 'A' ;
	st.uch = 'B' ;
	strcpy( st.str32 , "calvin" );
	strcpy( st.str1024 , "XXXXXXXXXXXXXXXX" );
	
	DSCLOG_AllTypes( & st );
	
	nret = DSCNETORDER_AllTypes( & st ) ;
	if( nret )
	{
		printf( "DSCNETORDER_AllTypes failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		printf( "DSCNETORDER_AllTypes ok\n" );
	}
	
	/* ... client send communication struct to server ... */
	
	/* server code */
	nret = DSCHOSTORDER_AllTypes( & st ) ;
	if( nret )
	{
		printf( "DSCHOSTORDER_AllTypes failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		printf( "DSCHOSTORDER_AllTypes ok\n" );
	}
	
	DSCLOG_AllTypes( & st );
	
	return 0;
}
$ make -f makefile.Linux
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c test_netorder.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c IDL_AllTypes.dsc.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o test_netorder test_netorder.o IDL_AllTypes.dsc.o -L.
$ ./test_netorder
AllTypes.n1[-17]
AllTypes.n2[-4386]
AllTypes.n4[-287454020]
AllTypes.n8[-1234605616436508552]
AllTypes.u1[17]
AllTypes.u2[4386]
AllTypes.u4[287454020]
AllTypes.u8[1234605616436508552]
AllTypes.f4[100.000000]
AllTypes.f8[10000.000000]
AllTypes.ch[A]
AllTypes.uch[B]
AllTypes.str32[calvin]
AllTypes.str1024[XXXXXXXXXXXXXXXX]
DSCNETORDER_AllTypes ok
0x0000000000  ef 00 ee de ee dd cc bc ee dd cc bb aa 99 88 78 ...............x
0x0000000001  11 00 11 22 11 22 33 44 11 22 33 44 55 66 77 88 ..."."3D."3DUfw.
0x0000000002  00 00 c8 42 00 00 00 00 00 88 c3 40 41 42 63 61 ...B.......@ABca
0x0000000003  6c 76 69 6e 00 00 00 00 00 00 00 00 00 00 00 00 lvin............
0x0000000004  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 58 ...............X
0x0000000005  58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 00 XXXXXXXXXXXXXXX.
...
DSCHOSTORDER_AllTypes ok
AllTypes.n1[-17]
AllTypes.n2[-4386]
AllTypes.n4[-287454020]
AllTypes.n8[-1234605616436508552]
AllTypes.u1[17]
AllTypes.u2[4386]
AllTypes.u4[287454020]
AllTypes.u8[1234605616436508552]
AllTypes.f4[100.000000]
AllTypes.f8[10000.000000]
AllTypes.ch[A]
AllTypes.uch[B]
AllTypes.str32[calvin]
AllTypes.str1024[XXXXXXXXXXXXXXXX]
[/code]

3.3.编写应用代码,调用二进制序列化/反序列化函数

[code]
$ cat test_serialize_compact.c
int test_serialize_compact()
{
	AllTypes	st ;
	char		buf[ DSCSERIALIZE_COMPACT_BUFSIZE_AllTypes + 1 ] ;
	int		len ;
	int		nret = 0 ;
	
	/* client code */
	memset( & st , 0x00 , sizeof(AllTypes) );
	
	st.n1 = -0x11 ;
	st.n2 = -0x1122 ;
	st.n4 = -0x11223344 ;
	st.n8 = LL(-0x1122334455667788) ;
	st.u1 = 0x11 ;
	st.u2 = 0x1122 ;
	st.u4 = 0x11223344 ;
	st.u8 = ULL(0x1122334455667788) ;
	st.f4 = 100.00 ;
	st.f8 = 10000.00 ;
	st.ch = 'A' ;
	st.uch = 'B' ;
	strcpy( st.str32 , "calvin" );
	strcpy( st.str1024 , "XXXXXXXXXXXXXXXX" );
	
	memset( buf , 0x00 , sizeof(buf) );
	nret = DSCSERIALIZE_COMPACT_AllTypes( & st , buf , & len ) ;
	if( nret )
	{
		printf( "DSCSERIALIZE_COMPACT_AllTypes failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		printf( "DSCSERIALIZE_COMPACT_AllTypes ok , len[%d]\n" , len );
	}
	
	dump( buf , len );
	
	/* ... client send communication struct to server ... */
	
	/* server code */
	memset( & st , 0x00 , sizeof(AllTypes) );
	nret = DSCDESERIALIZE_COMPACT_AllTypes( buf , & len , & st ) ;
	if( nret )
	{
		printf( "DSCDESERIALIZE_COMPACT_AllTypes failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		printf( "DSCDESERIALIZE_COMPACT_AllTypes ok\n" );
	}
	
	DSCLOG_AllTypes( & st );
	
	return 0;
}
$ make -f makefile.Linux
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c test_netorder.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c test_serialize_compact.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o test_serialize_compact test_serialize_compact.o IDL_AllTypes.dsc.o -L.
$ ./test_serialize_compact
DSCSERIALIZE_COMPACT_AllTypes ok , len[1100]
0x0000000000  ef ee de ee dd cc bc ee dd cc bb aa 99 88 78 11 ..............x.
0x0000000001  11 22 11 22 33 44 11 22 33 44 55 66 77 88 00 00 ."."3D."3DUfw...
0x0000000002  c8 42 00 00 00 00 00 88 c3 40 41 42 63 61 6c 76 .B.......@ABcalv
0x0000000003  69 6e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 in..............
0x0000000004  00 00 00 00 00 00 00 00 00 00 00 00 58 58 58 58 ............XXXX
0x0000000005  58 58 58 58 58 58 58 58 58 58 58 58 00 00 00 00 XXXXXXXXXXXX....
...
DSCDESERIALIZE_COMPACT_AllTypes ok
AllTypes.n1[-17]
AllTypes.n2[-4386]
AllTypes.n4[-287454020]
AllTypes.n8[-1234605616436508552]
AllTypes.u1[17]
AllTypes.u2[4386]
AllTypes.u4[287454020]
AllTypes.u8[1234605616436508552]
AllTypes.f4[100.000000]
AllTypes.f8[10000.000000]
AllTypes.ch[A]
AllTypes.uch[B]
AllTypes.str32[calvin]
AllTypes.str1024[XXXXXXXXXXXXXXXX]
[/code]

紧凑(COMPACT)序列化的内部原理是把所有字段值在内存中的映像平铺在一个大数据块中,首尾相接,无填充空间,且整型值做字节序处理。如
STRUCT struct_name
{
	INT	4	n4
	STRING	256	str256
}
序列化后的布局为
n4(4字节)+str256(256字节)
总共260字节

使用带压缩的序列化函数可以使得最终二进制数据块更小
[code]
$ cat test_serialize_compress.c
...
int test_serialize_compress()
{
	AllTypes	st ;
	char		buf[ DSCSERIALIZE_COMPRESS_BUFSIZE_AllTypes + 1 ] ;
	int		len ;
	int		nret = 0 ;
	
	/* client code */
	memset( & st , 0x00 , sizeof(AllTypes) );
	
	st.n1 = -0x11 ;
	st.n2 = -0x1122 ;
	st.n4 = -0x11223344 ;
	st.n8 = LL(-0x1122334455667788) ;
	st.u1 = 0x11 ;
	st.u2 = 0x1122 ;
	st.u4 = 0x11223344 ;
	st.u8 = ULL(0x1122334455667788) ;
	st.f4 = 100.00 ;
	st.f8 = 10000.00 ;
	st.ch = 'A' ;
	st.uch = 'B' ;
	strcpy( st.str32 , "calvin" );
	strcpy( st.str1024 , "XXXXXXXXXXXXXXXX" );
	
	DSCLOG_AllTypes( & st );
	
	memset( buf , 0x00 , sizeof(buf) );
	nret = DSCSERIALIZE_COMPRESS_AllTypes( & st , buf , & len ) ;
	if( nret )
	{
		printf( "DSCSERIALIZE_COMPRESS_AllTypes failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		printf( "DSCSERIALIZE_COMPRESS_AllTypes ok , len[%d]\n" , len );
	}
	
	dump( buf , len );
	
	/* ... client send communication struct to server ... */
	
	/* server code */
	memset( & st , 0x00 , sizeof(AllTypes) );
	nret = DSCDESERIALIZE_COMPRESS_AllTypes( buf , & len , & st ) ;
	if( nret )
	{
		printf( "DSCDESERIALIZE_COMPRESS_AllTypes failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		printf( "DSCDESERIALIZE_COMPRESS_AllTypes ok\n" );
	}
	
	DSCLOG_AllTypes( & st );
	
	return 0;
}
...
$ make -f makefile.Linux
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c test_netorder.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c test_serialize_compress.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o test_serialize_compress test_serialize_compress.o IDL_AllTypes.dsc.o -L.
$ ./test_serialize_compress
AllTypes.n1[-17]
AllTypes.n2[-4386]
AllTypes.n4[-287454020]
AllTypes.n8[-1234605616436508552]
AllTypes.u1[17]
AllTypes.u2[4386]
AllTypes.u4[287454020]
AllTypes.u8[1234605616436508552]
AllTypes.f4[100.000000]
AllTypes.f8[10000.000000]
AllTypes.ch[A]
AllTypes.uch[B]
AllTypes.str32[calvin]
AllTypes.str1024[XXXXXXXXXXXXXXXX]
DSCSERIALIZE_COMPRESS_AllTypes ok , len[74]
0x0000000000  ef ee de 14 11 22 33 44 18 11 22 33 44 55 66 77 ....."3D.."3DUfw
0x0000000001  88 11 11 22 04 11 22 33 44 08 11 22 33 44 55 66 ...".."3D.."3DUf
0x0000000002  77 88 00 00 c8 42 00 00 00 00 00 88 c3 40 41 42 w....B.......@AB
0x0000000003  01 06 63 61 6c 76 69 6e 01 10 58 58 58 58 58 58 ..calvin..XXXXXX
0x0000000004  58 58 58 58 58 58 58 58 58 58                   XXXXXXXXXX
DSCDESERIALIZE_COMPRESS_AllTypes ok
AllTypes.n1[-17]
AllTypes.n2[-4386]
AllTypes.n4[-287454020]
AllTypes.n8[-1234605616436508552]
AllTypes.u1[17]
AllTypes.u2[4386]
AllTypes.u4[287454020]
AllTypes.u8[1234605616436508552]
AllTypes.f4[100.000000]
AllTypes.f8[10000.000000]
AllTypes.ch[A]
AllTypes.uch[B]
AllTypes.str32[calvin]
AllTypes.str1024[XXXXXXXXXXXXXXXX]
[/code]

这个示例中不压缩的二进制数据块有1100字节,压缩后只有74字节,适用于网络数据交换。

压缩(COMPRESS)序列化的内部原理是在紧凑序列化的基础上对某些类型的字段做压缩转换处理。
INT 4类型放置前置头字节,左四位为选项,目前只用到了正负数标志(正数为0,负数为1),右四位为实际存储长度,如某值的网络字节序为0x00001234,实际存储为0x1234,加上前置头,总共用3字节表达
0x02 0x12 0x34
值-0x1234也是用3字节表达
0x12 0x12 0x34
INT 8类同
UINT类型INT
STRING n类型放置前置UINT 4字段记录长度。如"abc",实际长度为3字节,前置UINT 4字段0x01 0x03,总共用5字节表达
0x01 0x03 0x61 0x62 0x63
其它字段类型不压缩转换

如
STRUCT struct_name
{
	INT	4	n4
	STRING	256	str256
}
当
n4=0x3456
str256="abc"
压缩序列化后的数据为
0x02 0x34 0x56 0x01 0x05 0x61 0x62 0x63
总共8字节,看,是不是比紧凑序列化要短的多呢,这在通讯数据交换中可以节省更多的流量。

3.4.编写应用代码,调用XML序列化/反序列化函数

XML序列化/反序列化函数依赖于开源库fasterxml。

[code]
$ cat test_serialize_xml.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "IDL_BankXmlTransaction.dsc.h"
#include "IDL_BankXmlTransaction.dsc.LOG.c"

int test_serialize_xml()
{
        BankXmlTransaction      trans ;
        char            buf[ 40960 + 1 ] ;
        int             len ;
        int             nret = 0 ;

        /* client code */
        DSCINIT_BankXmlTransaction( & trans );

        strcpy( trans.ResponseHeader.transaction_code , "P0101" );
        trans.ResponseHeader.trans_jnlsno = 12345678 ;
        trans.ResponseHeader.response_code = 0 ;
        strcpy( trans.ResponseHeader.response_desc , "OK" );

        strcpy( trans.QueryTransactionDetails.AddonMessages.AddonMessage[1].message_text , "Check channel passed" );
        strcpy( trans.QueryTransactionDetails.AddonMessages.AddonMessage[0].message_text , "Check account passed" );

        strcpy( trans.QueryTransactionDetails.TransactionDetailTitle.title_text , "DETAIL TITLE" );
        trans.QueryTransactionDetails.TransactionDetailTitle.page_no = 1 ;
        trans.QueryTransactionDetails.TransactionDetailTitle.page_size = 2 ;

        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[0].trans_date , "2014-01-01" );
        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[0].trans_time , "08:01:01" );
        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[0].outlet_id , "1001" );
        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[0].card_no , "603367123412341234" );
        trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[0].trans_amount = 100.00 ;

        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[1].trans_date , "2014-02-02" );
        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[1].trans_time , "08:02:02" );
        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[1].outlet_id , "2002" );
        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[1].card_no , "603367123412341234" );
        trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[1].trans_amount = 200.00 ;

        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[2].card_no , "<" );

        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[3].card_no , "&" );

        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[4].card_no , ">" );

        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[5].card_no , "<&>" );

        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[6].card_no , "<你&他>" );

        strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[7].card_no , "我<你&他>她" );

       DSCLOG_BankXmlTransaction( & trans );

       memset( buf , 0x00 , sizeof(buf) );
       len = sizeof(buf)-1 ;
       nret = DSCSERIALIZE_XML_BankXmlTransaction( & trans , "GBK" , buf , & len ) ;
       if( nret )
       {
               printf( "DSCSERIALIZE_XML_BankXmlTransaction failed[%d]\n" , nret );
               return nret;
       }
       else
       {
               printf( "DSCSERIALIZE_XML_BankXmlTransaction ok , len[%d]\n" , len );
       }

       printf( "[%s]\n" , buf );

       /* ... client send communication struct to server ... */

       /* server code */
       memset( & trans , 0x00 , sizeof(BankXmlTransaction) );
       nret = DSCDESERIALIZE_XML_BankXmlTransaction( NULL , buf , & len , & trans ) ;
       if( nret )
       {
               printf( "DSCDESERIALIZE_XML_BankXmlTransaction failed[%d]\n" , nret );
               return nret;
       }
       else
       {
               printf( "DSCDESERIALIZE_XML_BankXmlTransaction ok\n" );
       }

       DSCLOG_BankXmlTransaction( & trans );

       return 0;
}

int main()
{
       return -test_serialize_xml();
}
$ make
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c test_serialize_xml.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I/home/calvin/exinc/fastxml -I. -c IDL_BankXmlTransaction.dsc.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o test_serialize_xml test_serialize_xml.o IDL_BankXmlTransaction.dsc.o -L.  -L/home/calvin/exlib -lfastxl
$ ./test_serialize_xml
BankXmlTransaction.version[1]
BankXmlTransaction.ResponseHeader.transaction_code[P0101]
BankXmlTransaction.ResponseHeader.trans_jnlsno[12345678]
BankXmlTransaction.ResponseHeader.response_code[0]
BankXmlTransaction.ResponseHeader.response_desc[OK]
BankXmlTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[Check account passed]
BankXmlTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[Check channel passed]
BankXmlTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetailTitle.title_text[DETAIL TITLE]
BankXmlTransaction.QueryTransactionDetails.TransactionDetailTitle.page_no[1]
BankXmlTransaction.QueryTransactionDetails.TransactionDetailTitle.page_size[2]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[2014-01-01]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[08:01:01]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[1001]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[603367123412341234]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[100.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[2014-02-02]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[08:02:02]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[2002]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[603367123412341234]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[200.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[<]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[&]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[>]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[<&>]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[<你&他>]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[我<你&他>她]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
DSCSERIALIZE_XML_BankXmlTransaction ok , len[2734]
[<?xml version="1.0" encoding="GBK"?>
<BankXmlTransaction>
        <version>1</version>
        <ResponseHeader>
                <transaction_code>P0101</transaction_code>
                <trans_jnlsno>12345678</trans_jnlsno>
                <response_code>0</response_code>
                <response_desc>OK</response_desc>
        </ResponseHeader>
        <QueryTransactionDetails>
                <AddonMessages>
                        <AddonMessage>
                                <message_text>Check account passed</message_text>
                        </AddonMessage>
                        <AddonMessage>
                                <message_text>Check channel passed</message_text>
                        </AddonMessage>
                        <AddonMessage>
                                <message_text></message_text>
                        </AddonMessage>
                </AddonMessages>
                <TransactionDetailTitle>
                        <title_text>DETAIL TITLE</title_text>
                        <page_no>1</page_no>
                        <page_size>2</page_size>
                </TransactionDetailTitle>
                <TransactionDetails>
                        <TransactionDetail>
                                <trans_date>2014-01-01</trans_date>
                                <trans_time>08:01:01</trans_time>
                                <outlet_id>1001</outlet_id>
                                <card_no>603367123412341234</card_no>
                                <trans_amount>100.000000</trans_amount>
                        </TransactionDetail>
                        <TransactionDetail>
                                <trans_date>2014-02-02</trans_date>
                                <trans_time>08:02:02</trans_time>
                                <outlet_id>2002</outlet_id>
                                <card_no>603367123412341234</card_no>
                                <trans_amount>200.000000</trans_amount>
                        </TransactionDetail>
                        <TransactionDetail>
                                <trans_date></trans_date>
                                <trans_time></trans_time>
                                <outlet_id></outlet_id>
                                <card_no>&lt;</card_no>
                                <trans_amount>0.000000</trans_amount>
                        </TransactionDetail>
                        <TransactionDetail>
                                <trans_date></trans_date>
                                <trans_time></trans_time>
                                <outlet_id></outlet_id>
                                <card_no>&amp;</card_no>
                                <trans_amount>0.000000</trans_amount>
                        </TransactionDetail>
                        <TransactionDetail>
                                <trans_date></trans_date>
                                <trans_time></trans_time>
                                <outlet_id></outlet_id>
                                <card_no>&gt;</card_no>
                                <trans_amount>0.000000</trans_amount>
                        </TransactionDetail>
                        <TransactionDetail>
                                <trans_date></trans_date>
                                <trans_time></trans_time>
                                <outlet_id></outlet_id>
                                <card_no>&lt;&amp;&gt;</card_no>
                                <trans_amount>0.000000</trans_amount>
                        </TransactionDetail>
                        <TransactionDetail>
                                <trans_date></trans_date>
                                <trans_time></trans_time>
                                <outlet_id></outlet_id>
                                <card_no>&lt;你&amp;他&gt;</card_no>
                                <trans_amount>0.000000</trans_amount>
                        </TransactionDetail>
                        <TransactionDetail>
                                <trans_date></trans_date>
                                <trans_time></trans_time>
                                <outlet_id></outlet_id>
                                <card_no>我&lt;你&amp;他&gt;她</card_no>
                                <trans_amount>0.000000</trans_amount>
                        </TransactionDetail>
                        <TransactionDetail>
                                <trans_date></trans_date>
                                <trans_time></trans_time>
                                <outlet_id></outlet_id>
                                <card_no></card_no>
                                <trans_amount>0.000000</trans_amount>
                        </TransactionDetail>
                        <TransactionDetail>
                                <trans_date></trans_date>
                                <trans_time></trans_time>
                                <outlet_id></outlet_id>
                                <card_no></card_no>
                                <trans_amount>0.000000</trans_amount>
                        </TransactionDetail>
                </TransactionDetails>
        </QueryTransactionDetails>
</BankXmlTransaction>
]
DSCDESERIALIZE_XML_BankXmlTransaction ok
BankXmlTransaction.version[1]
BankXmlTransaction.ResponseHeader.transaction_code[P0101]
BankXmlTransaction.ResponseHeader.trans_jnlsno[12345678]
BankXmlTransaction.ResponseHeader.response_code[0]
BankXmlTransaction.ResponseHeader.response_desc[OK]
BankXmlTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[Check account passed]
BankXmlTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[Check channel passed]
BankXmlTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetailTitle.title_text[DETAIL TITLE]
BankXmlTransaction.QueryTransactionDetails.TransactionDetailTitle.page_no[1]
BankXmlTransaction.QueryTransactionDetails.TransactionDetailTitle.page_size[2]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[2014-01-01]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[08:01:01]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[1001]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[603367123412341234]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[100.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[2014-02-02]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[08:02:02]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[2002]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[603367123412341234]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[200.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[<]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[&]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[>]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[<&>]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[<你&他>]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[我<你&他>她]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankXmlTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
[/code]

3.5.编写应用代码,调用JSON序列化/反序列化函数

JSON序列化/反序列化函数依赖于开源库fasterjson。

[code]
$ cat test_serialize_json.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "IDL_BankJsonTransaction.dsc.h"
#include "IDL_BankJsonTransaction.dsc.LOG.c"

int test_serialize_json()
{
	BankJsonTransaction	trans ;
	char			buf[ 40960 + 1 ] ;
	int			len ;
	int			nret = 0 ;
	
	/* client code */
	DSCINIT_BankJsonTransaction( & trans );
	
	strcpy( trans.ResponseHeader.transaction_code , "P0101" );
	trans.ResponseHeader.trans_jnlsno = 12345678 ;
	trans.ResponseHeader.response_code = 0 ;
	strcpy( trans.ResponseHeader.response_desc , "OK" );
	
	strcpy( trans.QueryTransactionDetails.AddonMessages.AddonMessage[1].message_text , "Check channel passed" );
	strcpy( trans.QueryTransactionDetails.AddonMessages.AddonMessage[0].message_text , "Check account passed" );
	
	strcpy( trans.QueryTransactionDetails.TransactionDetailTitle.title_text , "DETAIL TITLE" );
	trans.QueryTransactionDetails.TransactionDetailTitle.page_no = 1 ;
	trans.QueryTransactionDetails.TransactionDetailTitle.page_size = 2 ;
	
	strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[0].trans_date , "2014-01-01" );
	strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[0].trans_time , "08:01:01" );
	strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[0].outlet_id , "1001" );
	strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[0].card_no , "603367123412341234" );
	trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[0].trans_amount = 100.00 ;
	
	strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[1].trans_date , "2014-02-02" );
	strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[1].trans_time , "08:02:02" );
	strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[1].outlet_id , "2002" );
	strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[1].card_no , "603367123412341234" );
	trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[1].trans_amount = 200.00 ;

	strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[2].card_no , "\"" );
	
	strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[3].card_no , "\"你\"他\"" );
	
	strcpy( trans.QueryTransactionDetails.TransactionDetails.TransactionDetail[4].card_no , "我\"你\"他\"她" );
	
	DSCLOG_BankJsonTransaction( & trans );
	
	memset( buf , 0x00 , sizeof(buf) );
	len = sizeof(buf)-1 ;
	nret = DSCSERIALIZE_JSON_BankJsonTransaction( & trans , "GBK" , buf , & len ) ;
	if( nret )
	{
		printf( "DSCSERIALIZE_JSON_BankJsonTransaction failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		printf( "DSCSERIALIZE_JSON_BankJsonTransaction ok , len[%d]\n" , len );
	}
	
	printf( "[%s]\n" , buf );
	
	/* ... client send communication struct to server ... */
	
	/* server code */
	memset( & trans , 0x00 , sizeof(BankJsonTransaction) );
	nret = DSCDESERIALIZE_JSON_BankJsonTransaction( NULL , buf , & len , & trans ) ;
	if( nret )
	{
		printf( "DSCDESERIALIZE_JSON_BankJsonTransaction failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		printf( "DSCDESERIALIZE_JSON_BankJsonTransaction ok\n" );
	}
	
	DSCLOG_BankJsonTransaction( & trans );
	
	return 0;
}

int main()
{
	return -test_serialize_json();
}
$ make
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/home/calvin/exinc/fasterxml -I/home/calvin/exinc/fasterjson  -c test_serialize_json.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o test_serialize_json test_serialize_json.o IDL_BankJsonTransaction.dsc.o -L.  -L/home/calvin/exlib -lfasterjson
$ ./test_serialize_json
BankJsonTransaction.version[1]
BankJsonTransaction.ResponseHeader.transaction_code[P0101]
BankJsonTransaction.ResponseHeader.trans_jnlsno[12345678]
BankJsonTransaction.ResponseHeader.response_code[0]
BankJsonTransaction.ResponseHeader.response_desc[OK]
BankJsonTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[Check account passed]
BankJsonTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[Check channel passed]
BankJsonTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetailTitle.title_text[DETAIL TITLE]
BankJsonTransaction.QueryTransactionDetails.TransactionDetailTitle.page_no[1]
BankJsonTransaction.QueryTransactionDetails.TransactionDetailTitle.page_size[2]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[2014-01-01]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[08:01:01]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[1001]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[603367123412341234]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[100.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[2014-02-02]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[08:02:02]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[2002]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[603367123412341234]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[200.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no["]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no["你"他"]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[我"你"他"她]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionTailDetail[index[3]].message_text[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionTailDetail[index[3]].message_text[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionTailDetail[index[3]].message_text[]
DSCSERIALIZE_JSON_BankJsonTransaction ok , len[2330]
[{
        "BankJsonTransaction" :
        {
                "version" : 1 ,
                "ResponseHeader" :
                {
                        "transaction_code" : "P0101" ,
                        "trans_jnlsno" : 12345678 ,
                        "response_code" : 0 ,
                        "response_desc" : "OK"
                } ,
                "QueryTransactionDetails" :
                {
                        "AddonMessages" :
                        {
                                "AddonMessage" :
                                [
                                {
                                        "message_text" : "Check account passed"
                                } ,
                                {
                                        "message_text" : "Check channel passed"
                                } ,
                                {
                                        "message_text" : ""
                                }
                                ]
                        } ,
                        "TransactionDetailTitle" :
                        {
                                "title_text" : "DETAIL TITLE" ,
                                "page_no" : 1 ,
                                "page_size" : 2
                        } ,
                        "TransactionDetails" :
                        {
                                "TransactionDetail" :
                                [
                                {
                                        "trans_date" : "2014-01-01" ,
                                        "trans_time" : "08:01:01" ,
                                        "outlet_id" : "1001" ,
                                        "card_no" : "603367123412341234" ,
                                        "trans_amount" : 100.000000
                                } ,
                                {
                                        "trans_date" : "2014-02-02" ,
                                        "trans_time" : "08:02:02" ,
                                        "outlet_id" : "2002" ,
                                        "card_no" : "603367123412341234" ,
                                        "trans_amount" : 200.000000
                                } ,
                                {
                                        "trans_date" : "" ,
                                        "trans_time" : "" ,
                                        "outlet_id" : "" ,
                                        "card_no" : "\"" ,
                                        "trans_amount" : 0.000000
                                } ,
                                {
                                        "trans_date" : "" ,
                                        "trans_time" : "" ,
                                        "outlet_id" : "" ,
                                        "card_no" : "\"你\"他\"" ,
                                        "trans_amount" : 0.000000
                                } ,
                                {
                                        "trans_date" : "" ,
                                        "trans_time" : "" ,
                                        "outlet_id" : "" ,
                                        "card_no" : "我\"你\"他\"她" ,
                                        "trans_amount" : 0.000000
                                } ,
                                {
                                        "trans_date" : "" ,
                                        "trans_time" : "" ,
                                        "outlet_id" : "" ,
                                        "card_no" : "" ,
                                        "trans_amount" : 0.000000
                                } ,
                                {
                                        "trans_date" : "" ,
                                        "trans_time" : "" ,
                                        "outlet_id" : "" ,
                                        "card_no" : "" ,
                                        "trans_amount" : 0.000000
                                } ,
                                {
                                        "trans_date" : "" ,
                                        "trans_time" : "" ,
                                        "outlet_id" : "" ,
                                        "card_no" : "" ,
                                        "trans_amount" : 0.000000
                                } ,
                                {
                                        "trans_date" : "" ,
                                        "trans_time" : "" ,
                                        "outlet_id" : "" ,
                                        "card_no" : "" ,
                                        "trans_amount" : 0.000000
                                } ,
                                {
                                        "trans_date" : "" ,
                                        "trans_time" : "" ,
                                        "outlet_id" : "" ,
                                        "card_no" : "" ,
                                        "trans_amount" : 0.000000
                                }
                                ] ,
                                "TransactionTailDetail" :
                                [
                                {
                                        "message_text" : ""
                                } ,
                                {
                                        "message_text" : ""
                                } ,
                                {
                                        "message_text" : ""
                                }
                                ]
                        }
                }
        }
}
]
DSCDESERIALIZE_JSON_BankJsonTransaction ok
BankJsonTransaction.version[1]
BankJsonTransaction.ResponseHeader.transaction_code[P0101]
BankJsonTransaction.ResponseHeader.trans_jnlsno[12345678]
BankJsonTransaction.ResponseHeader.response_code[0]
BankJsonTransaction.ResponseHeader.response_desc[OK]
BankJsonTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[Check account passed]
BankJsonTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[Check channel passed]
BankJsonTransaction.QueryTransactionDetails.AddonMessages.AddonMessage[index[3]].message_text[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetailTitle.title_text[DETAIL TITLE]
BankJsonTransaction.QueryTransactionDetails.TransactionDetailTitle.page_no[1]
BankJsonTransaction.QueryTransactionDetails.TransactionDetailTitle.page_size[2]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[2014-01-01]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[08:01:01]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[1001]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[603367123412341234]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[100.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[2014-02-02]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[08:02:02]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[2002]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[603367123412341234]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[200.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no["]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no["你"他"]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[我"你"他"她]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_date[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_time[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].outlet_id[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].card_no[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionDetail[index[3]].trans_amount[0.000000]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionTailDetail[index[3]].message_text[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionTailDetail[index[3]].message_text[]
BankJsonTransaction.QueryTransactionDetails.TransactionDetails.TransactionTailDetail[index[3]].message_text[]
[/code]

3.6.编写应用代码,使用ESQL代码开发数据库应用

[code]
$ cat IDL_testable.dsc
STRUCT  testable
{
        INT     2       n2
        INT     4       n4
        FLOAT   4       f4
        FLOAT   8       f8
        STRING  32      str32
        STRING  1024    str1024

        CREATE_SQL      "CREATE INDEX testable_idx1 ON testable ( n2 ) ;"
        CREATE_SQL      "CREATE UNIQUE INDEX testable_idx2 ON testable ( str32 , str1024 ) ;"
        DROP_SQL        "DROP INDEX testable_idx1 ;"
        DROP_SQL        "DROP INDEX testable_idx2 ;"
}
$ dsc -f IDL_testable.dsc -sql -ec-pqsql -c-LOG
STRUCT testable
        INT 2 n2
        INT 4 n4
        FLOAT 4 f4
        FLOAT 8 f8
        STRING 32 str32
        STRING 1024 str1024
ok!
$ ls IDL_testable.dsc*
IDL_testable.dsc         IDL_testable.dsc.ESQL.ec   IDL_testable.dsc.ESQL.eh  IDL_testable.dsc.LOG.c  IDL_testable.dsc.create.sql  IDL_testable.dsc.h
IDL_testable.dsc.ESQL.c  IDL_testable.dsc.ESQL.ecE  IDL_testable.dsc.ESQL.o   IDL_testable.dsc.c      IDL_testable.dsc.drop.sql
$ cat IDL_testable.dsc.create.sql
-- It had generated by DirectStruct v1.1.2

CREATE TABLE testable
(
	n2	SMALLINT ,
	n4	INTEGER ,
	f4	REAL ,
	f8	DOUBLE PRECISION ,
	str32	CHARACTER VARYING(32) ,
	str1024	CHARACTER VARYING(1024)
) ;

CREATE INDEX testable_idx1 ON testable ( n2 ) ;

CREATE UNIQUE INDEX testable_idx2 ON testable ( str32 , str1024 ) ;
$ ... run IDL_testable.dsc.create.sql in your database ...
$ cat test_testable.ec
#include "IDL_testable.dsc.ESQL.eh"

#include "IDL_testable.dsc.LOG.c"

int test_delete()
{
        EXEC SQL
                DELETE
                FROM    testable
                WHERE   n2 IN ( 100 , 101 , 102 ) ;
        if( SQLCODE == 100 )
        {
                printf( "DELETE ok\n" );
        }
        else if( SQLCODE )
        {
                printf( "DELETE failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "DELETE ok\n" );
        }

        return 0;
}

int test_insert()
{
        testable        t ;

        memset( & t , 0x00 , sizeof(testable) );
        t.n2 = 100 ;
        t.n4 = 56789 ;
        t.f4 = 1.2 ;
        t.f8 = 456.789 ;
        strcpy( t.str32 , "hi" );
        strcpy( t.str1024 , "hello world" );

        DSCINITV_testable();
        DSCSTOV_testable( & t );

        EXEC SQL
                INSERT
                INTO    testable
                VALUES  ( DBVLIST_testable ) ;
        if( SQLCODE )
        {
                printf( "INSERT failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "INSERT ok\n" );
        }

        memset( & t , 0x00 , sizeof(testable) );
        t.n2 = 101 ;
        t.n4 = 56789 ;
        t.f4 = 1.2 ;
        t.f8 = 456.789 ;
        strcpy( t.str32 , "hi" );
        strcpy( t.str1024 , "hello earth" );

        DSCINITV_testable();
        DSCSTOV_testable( & t );

        EXEC SQL
                INSERT
                INTO    testable
                VALUES  ( DBVLIST_testable ) ;
        if( SQLCODE )
        {
                printf( "INSERT failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "INSERT ok\n" );
        }

        memset( & t , 0x00 , sizeof(testable) );
        t.n2 = 102 ;
        t.n4 = 56789 ;
        t.f4 = 1.2 ;
        t.f8 = 456.789 ;
        strcpy( t.str32 , "hi" );
        strcpy( t.str1024 , "hello march" );

        DSCINITV_testable();
        DSCSTOV_testable( & t );

        EXEC SQL
                INSERT
                INTO    testable
                VALUES  ( DBVLIST_testable ) ;
        if( SQLCODE )
        {
                printf( "INSERT failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "INSERT ok\n" );
        }

        return 0;
}

int test_update()
{
        testable        t ;

        memset( & t , 0x00 , sizeof(testable) );
        t.n2 = 101 ;

        DSCINITV_testable();
        DSCSTOV_testable( & t );

        EXEC SQL
                SELECT  TFLIST_testable
                INTO    DBVLLIST_testable
                FROM    testable
                WHERE   n2 = :testable_n2 ;
        if( SQLCODE )
        {
                printf( "SELECT failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "SELECT ok\n" );
        }

        DSCVTOS_testable( & t );

        strcpy( t.str1024 , "hello sun" );

        DSCINITV_testable();
        DSCSTOV_testable( & t );

        EXEC SQL
                UPDATE  testable
                SET     str1024 = :testable_str1024
                WHERE   n2 = :testable_n2 ;
        if( SQLCODE )
        {
                printf( "UPDATE failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "UPDATE ok\n" );
        }

        return 0;
}

int test_cursor()
{
        testable        t ;

        int             nret = 0 ;

        EXEC SQL
                DECLARE         testable_cursor CURSOR FOR
                SELECT          TFLIST_testable
                FROM            testable
                ORDER BY        n2 ASC ;
        if( SQLCODE )
        {
                printf( "DECLARE failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "DECLARE ok\n" );
        }

        EXEC SQL
                OPEN    testable_cursor ;
        if( SQLCODE )
        {
                printf( "OPEN failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "OPEN ok\n" );
        }

        while(1)
        {
                EXEC SQL
                        FETCH   testable_cursor
                        INTO    DBVLLIST_testable ;
                if( SQLCODE == 100 )
                {
                        break;
                }
                else if( SQLCODE )
                {
                        printf( "FETCH failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                        nret = SQLCODE ;
                }
                else
                {
                        printf( "FETCH ok\n" );
                }

                memset( & t , 0x00 , sizeof(testable) );
                DSCVTOS_testable( & t );

                DSCLOG_testable( & t );
        }

        EXEC SQL
                CLOSE   testable_cursor ;
        if( SQLCODE )
        {
                printf( "CLOSE failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "CLOSE ok\n" );
        }

        if( nret )
                return nret;

        return 0;
}

EXEC SQL BEGIN DECLARE SECTION ;
char    sql[] = "DELETE FROM testable WHERE n2 = 102 ;" ;
EXEC SQL END DECLARE SECTION ;

int test_immediate()
{
        EXEC SQL
                EXECUTE IMMEDIATE :sql ;
        if( SQLCODE )
        {
                printf( "EXECUTE failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "EXECUTE ok\n" );
        }

        return 0;
}

EXEC SQL BEGIN DECLARE SECTION ;
char    sql2[] = "SELECT * FROM testable WHERE n2 >= ? ;" ;
EXEC SQL END DECLARE SECTION ;

int test_prepare()
{
        testable        t ;

        int             nret = 0 ;

        EXEC SQL
                PREPARE prepare FROM :sql2 ;
        if( SQLCODE )
        {
                printf( "PREPARE failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "PREPARE ok\n" );
        }

        testable_n2 = 101 ;

        EXEC SQL
                EXECUTE         prepare
                INTO            DBVLLIST_testable
                USING           :testable_n2 ;
        if( SQLCODE )
        {
                printf( "EXECUTE failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "EXECUTE ok\n" );
        }

        memset( & t , 0x00 , sizeof(testable) );
        DSCVTOS_testable( & t );

        DSCLOG_testable( & t );

        testable_n2 = 100 ;

        EXEC SQL
                DECLARE testable_cursor2 CURSOR FOR prepare ;
        if( SQLCODE )
        {
                printf( "DECLARE failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "DECLARE ok\n" );
        }

        EXEC SQL
                OPEN    testable_cursor2
                USING   :testable_n2 ;
        if( SQLCODE )
        {
                printf( "OPEN failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "OPEN ok\n" );
        }

        while(1)
        {
                EXEC SQL
                        FETCH   testable_cursor2
                        INTO    DBVLLIST_testable ;
                if( SQLCODE == 100 )
                {
                        break;
                }
                else if( SQLCODE )
                {
                        printf( "FETCH failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                        nret = SQLCODE ;
                }
                else
                {
                        printf( "FETCH ok\n" );
                }

                memset( & t , 0x00 , sizeof(testable) );
                DSCVTOS_testable( & t );

                DSCLOG_testable( & t );
        }

        EXEC SQL
                CLOSE   testable_cursor2 ;
        if( SQLCODE )
        {
                printf( "CLOSE failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return SQLCODE;
        }
        else
        {
                printf( "CLOSE ok\n" );
        }

        if( nret )
                return nret;

        EXEC SQL
                DEALLOCATE PREPARE prepare ;

        return 0;
}

int main()
{
        int             nret = 0 ;

        EXEC SQL
                CONNECT TO      'calvin@127.0.0.1:18432'
                USER            'calvin'
                IDENTIFIED BY   'calvin' ;
        if( SQLCODE )
        {
                printf( "CONNECT failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return 1;
        }
        else
        {
                printf( "CONNECT ok\n" );
        }

        EXEC SQL
                BEGIN WORK ;
        if( SQLCODE )
        {
                printf( "BEGIN WORK failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return 1;
        }
        else
        {
                printf( "BEGIN WORK ok\n" );
        }

        do
        {
                printf( "--- delete ---------\n" );
                nret = test_delete() ;
                if( nret )
                        break;

                printf( "--- insert ---------\n" );
                nret = test_insert() ;
                if( nret )
                        break;

                printf( "--- update ---------\n" );
                nret = test_update() ;
                if( nret )
                        break;

                printf( "--- cursor ---------\n" );
                nret = test_cursor() ;
                if( nret )
                        break;

                printf( "--- immediate ---------\n" );
                nret = test_immediate() ;
                if( nret )
                        break;

                printf( "--- prepare ---------\n" );
                nret = test_prepare() ;
                if( nret )
                        break;
        }
        while(0);
        if( nret )
        {
                EXEC SQL
                        ROLLBACK WORK ;
                if( SQLCODE )
                {
                        printf( "ROLLBACK WORK failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                        return 1;
                }
                else
                {
                        printf( "ROLLBACK WORK ok\n" );
                }
        }
        else
        {
                EXEC SQL
                        COMMIT WORK ;
                if( SQLCODE )
                {
                        printf( "COMMIT WORK failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                        return 1;
                }
                else
                {
                        printf( "COMMIT WORK ok\n" );
                }
        }

        EXEC SQL
                DISCONNECT ;
        if( SQLCODE )
        {
                printf( "DISCONNECT failed[%ld][%s]\n" , SQLCODE , SQLSTATE );
                return 1;
        }
        else
        {
                printf( "DISCONNECT ok\n" );
        }

        return 0;
}
$ make
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I/root/local/postgresql/include -E -x c IDL_testable.dsc.ESQL.ec > IDL_testable.dsc.ESQL.ecE # c预处理
ecpg -h IDL_testable.dsc.ESQL.ecE -o IDL_testable.dsc.ESQL.c # postgresql esql预处理器处理之
sed -i 's/NULL/0/g' IDL_testable.dsc.ESQL.c # 去掉ecpg加上的pqsql头文件,防止重复包含错误
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I/root/local/postgresql/include -c IDL_testable.dsc.ESQL.c # 最后的编译
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I/root/local/postgresql/include -E -x c test_testable.ec > test_testable.ecE
ecpg -h test_testable.ecE -o test_testable.c
sed -i 's/NULL/0/g' test_testable.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I/root/local/postgresql/include -c test_testable.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o test_testable IDL_testable.dsc.ESQL.o test_testable.o -L.  -L/root/local/postgresql/lib -lecpg
$ ./test_testable
CONNECT ok
BEGIN WORK ok
--- delete ---------
DELETE ok
--- insert ---------
INSERT ok
INSERT ok
INSERT ok
--- update ---------
SELECT ok
UPDATE ok
--- cursor ---------
DECLARE ok
OPEN ok
FETCH ok
testable.n2[100]
testable.n4[56789]
testable.f4[1.200000]
testable.f8[456.789000]
testable.str32[hi]
testable.str1024[hello world]
FETCH ok
testable.n2[101]
testable.n4[56789]
testable.f4[1.200000]
testable.f8[456.789000]
testable.str32[hi]
testable.str1024[hello sun]
FETCH ok
testable.n2[102]
testable.n4[56789]
testable.f4[1.200000]
testable.f8[456.789000]
testable.str32[hi]
testable.str1024[hello march]
CLOSE ok
--- immediate ---------
EXECUTE ok
--- prepare ---------
PREPARE ok
EXECUTE ok
testable.n2[101]
testable.n4[56789]
testable.f4[1.200000]
testable.f8[456.789000]
testable.str32[hi]
testable.str1024[hello sun]
DECLARE ok
OPEN ok
FETCH ok
testable.n2[100]
testable.n4[56789]
testable.f4[1.200000]
testable.f8[456.789000]
testable.str32[hi]
testable.str1024[hello world]
FETCH ok
testable.n2[101]
testable.n4[56789]
testable.f4[1.200000]
testable.f8[456.789000]
testable.str32[hi]
testable.str1024[hello sun]
CLOSE ok
COMMIT WORK ok
DISCONNECT ok
[/code]

在dsc文件中还可以使用SQLACTION指令自动生成一些ESQL函数,语法如下:
SQLACTION	"SELECT ... FROM 表名 [ WHERE ... ]"
SQLACTION	"INSERT INTO 表名"
SQLACTION	"UPDATE 表名 SET ... [ WHERE ... ]"
SQLACTION	"DELETE FROM 表名 [ WHERE ... ]"
SQLACTION	"CURSOR 游标名 SELECT ... FROM 表名 [ WHERE ... ] [ ORDER BY ... [DESC|ASC] ]"
示例如下:
[code]
$ cat IDL_userinfo.dsc
STRUCT	userinfo
{
	INT	4	user_id		DEFAULT	1	NOTNULL
	STRING	16	user_name	DEFAULT	'0000'
	STRING	128	email				NULL
	
	CREATE_SQL	"CREATE UNIQUE INDEX userinfo_idx1 ON userinfo ( user_id ) ;"
	DROP_SQL	"DROP INDEX testable_idx1 ;"
	
	SQLACTION	"SELECT user_name,email FROM userinfo WHERE user_id ="
	SQLACTION	"SELECT * FROM userinfo WHERE user_id = AND user_name ="
	SQLACTION	"INSERT INTO userinfo"
	SQLACTION	"UPDATE userinfo SET * WHERE user_id ="
	SQLACTION	"UPDATE userinfo SET email"
	SQLACTION	"DELETE FROM userinfo WHERE user_id >="
	SQLACTION	"DELETE FROM userinfo"
	SQLACTION	"CURSOR mycursor SELECT * FROM userinfo"
	SQLACTION	"CURSOR mycursor1 SELECT user_name FROM userinfo WHERE user_id >="
	SQLACTION	"CURSOR mycursor2 SELECT user_name,email FROM userinfo ORDER BY user_id ASC"
	SQLACTION	"CURSOR mycursor3 SELECT * FROM userinfo WHERE user_id >= ORDER BY user_id ASC"
}
$ dsc -f IDL_userinfo.dsc -sql -ec-pqsql
...
$ cat IDL_userinfo.dsc.ESQL.ec
...
void DSCSQLACTION_SELECT_user_name_email_FROM_userinfo_WHERE_user_id_E( userinfo *pst )
{
	DSCSTOV_userinfo( pst );
	
	EXEC SQL
		SELECT	user_name,email
		INTO	:userinfo_user_name :userinfo_user_name_id , :userinfo_email :userinfo_email_id
		FROM	userinfo
		WHERE	user_id = :userinfo_user_id
		;
	if( SQLCODE )
		return;
	
	DSCVTOS_userinfo( pst );
	
	return;
}

void DSCSQLACTION_SELECT_A_FROM_userinfo_WHERE_user_id_E_AND_user_name_E( userinfo *pst )
{
	DSCSTOV_userinfo( pst );
	
	EXEC SQL
		SELECT	*
		INTO	DBVLLIST_userinfo
		FROM	userinfo
		WHERE	user_id = :userinfo_user_id AND user_name = :userinfo_user_name
		;
	if( SQLCODE )
		return;
	
	DSCVTOS_userinfo( pst );
	
	return;
}

void DSCSQLACTION_INSERT_INTO_userinfo( userinfo *pst )
{
	DSCSTOV_userinfo( pst );
	
	EXEC SQL
		INSERT INTO	userinfo
		VALUES ( DBVLLIST_userinfo )
		;
	return;
}

void DSCSQLACTION_UPDATE_userinfo_SET_A_WHERE_user_id_E( userinfo *pst )
{
	DSCSTOV_userinfo( pst );
	
	EXEC SQL
		UPDATE	userinfo
		SET	( TFLIST_userinfo ) = ( DBVLIST_userinfo )
		WHERE	user_id = :userinfo_user_id
		;
	return;
}

void DSCSQLACTION_UPDATE_userinfo_SET_email( userinfo *pst )
{
	DSCSTOV_userinfo( pst );
	
	EXEC SQL
		UPDATE	userinfo
		SET	email = :userinfo_email
		;
	return;
}

void DSCSQLACTION_DELETE_FROM_userinfo_WHERE_user_id_GE( userinfo *pst )
{
	DSCSTOV_userinfo( pst );
	
	EXEC SQL
		DELETE
		FROM	userinfo
		WHERE	user_id >= :userinfo_user_id
		;
	return;
}

void DSCSQLACTION_DELETE_FROM_userinfo( userinfo *pst )
{
	DSCSTOV_userinfo( pst );
	
	EXEC SQL
		DELETE
		FROM	userinfo
		;
	return;
}

void DSCSQLACTION_OPEN_CURSOR_mycursor_SELECT_A_FROM_userinfo( userinfo *pst )
{
	EXEC SQL
		DECLARE	userinfo_mycursor CURSOR FOR
		SELECT	*
		FROM	userinfo
		;
	if( SQLCODE )
		return;
	
	EXEC SQL
		OPEN	userinfo_mycursor
		;	if( SQLCODE )
		return;
	
	return;
}

void DSCSQLACTION_FETCH_CURSOR_mycursor( userinfo *pst )
{
	EXEC SQL
		FETCH	userinfo_mycursor
		INTO	DBVLLIST_userinfo
		;
	if( SQLCODE )
		return;
	
	DSCVTOS_userinfo( pst );
	
	return;
}

void DSCSQLACTION_CLOSE_CURSOR_mycursor()
{
	EXEC SQL
		CLOSE	userinfo_mycursor
		;
	return;
}

void DSCSQLACTION_OPEN_CURSOR_mycursor1_SELECT_user_name_FROM_userinfo_WHERE_user_id_GE( userinfo *pst )
{
	EXEC SQL
		DECLARE	userinfo_mycursor1 CURSOR FOR
		SELECT	user_name
		FROM	userinfo
		WHERE	user_id >= :userinfo_user_id
		;
	if( SQLCODE )
		return;
	
	EXEC SQL
		OPEN	userinfo_mycursor1
		;	if( SQLCODE )
		return;
	
	return;
}

void DSCSQLACTION_FETCH_CURSOR_mycursor1( userinfo *pst )
{
	EXEC SQL
		FETCH	userinfo_mycursor1
		INTO	:userinfo_user_name :userinfo_user_name_id
		;
	if( SQLCODE )
		return;
	
	DSCVTOS_userinfo( pst );
	
	return;
}

void DSCSQLACTION_CLOSE_CURSOR_mycursor1()
{
	EXEC SQL
		CLOSE	userinfo_mycursor1
		;
	return;
}

void DSCSQLACTION_OPEN_CURSOR_mycursor2_SELECT_user_name_email_FROM_userinfo_ORDER_BY_user_id_ASC( userinfo *pst )
{
	EXEC SQL
		DECLARE	userinfo_mycursor2 CURSOR FOR
		SELECT	user_name,email
		FROM	userinfo
		ORDER BY user_id ASC
		;
	if( SQLCODE )
		return;
	
	EXEC SQL
		OPEN	userinfo_mycursor2
		;	if( SQLCODE )
		return;
	
	return;
}

void DSCSQLACTION_FETCH_CURSOR_mycursor2( userinfo *pst )
{
	EXEC SQL
		FETCH	userinfo_mycursor2
		INTO	:userinfo_user_name :userinfo_user_name_id, :userinfo_email :userinfo_email_id
		;
	if( SQLCODE )
		return;
	
	DSCVTOS_userinfo( pst );
	
	return;
}

void DSCSQLACTION_CLOSE_CURSOR_mycursor2()
{
	EXEC SQL
		CLOSE	userinfo_mycursor2
		;
	return;
}

void DSCSQLACTION_OPEN_CURSOR_mycursor3_SELECT_A_FROM_userinfo_WHERE_user_id_GE_ORDER_BY_user_id_ASC( userinfo *pst )
{
	EXEC SQL
		DECLARE	userinfo_mycursor3 CURSOR FOR
		SELECT	*
		FROM	userinfo
		WHERE	user_id >= :userinfo_user_id
		ORDER BY user_id ASC
		;
	if( SQLCODE )
		return;
	
	EXEC SQL
		OPEN	userinfo_mycursor3
		;	if( SQLCODE )
		return;
	
	return;
}

void DSCSQLACTION_FETCH_CURSOR_mycursor3( userinfo *pst )
{
	EXEC SQL
		FETCH	userinfo_mycursor3
		INTO	DBVLLIST_userinfo
		;
	if( SQLCODE )
		return;
	
	DSCVTOS_userinfo( pst );
	
	return;
}

void DSCSQLACTION_CLOSE_CURSOR_mycursor3()
{
	EXEC SQL
		CLOSE	userinfo_mycursor3
		;
	return;
}
...
[/code]
可以在你的代码中直接调用这些函数,而不用手工编码了。

还能根据不同数据库自动生成各自的连接数据库、断开数据库、事务开始、事务提交、事务回滚等函数,只要加上SQLCONN指令即可

N-2.DirectStruct报文定义文件语法

每个结构或内嵌子结构定义格式都以
[code]
STRUCT	结构名	ARRAY	数组数量
{
	...
}
[/code]
囊括,其中首行的ARRAY及后是可选的

每个字段定义行格式为
[code]
字段类型	字段长度	字段名	DEFAULT	缺省值
[/code]
其中字段类型及长度目前支持
INT 1,2,4,8 ( 8位至64位整型 )
UINT 1,2,4,8
FLOAT 4,8
CHAR 1
UCHAR 1
STRING (N)
DEFAULT及后是可选的

任何行位置可以用
[code]
INCLUDE	文件名
[/code]
引用其它.dsc文件

下面是一个综合的例子:
[code]
$ cat IDL_BankTransaction.dsc
STRUCT	BankTransaction
{
	INT	1	version				DEFAULT		1
	INCLUDE IDL_ResponseHeader.dsc
	STRUCT QueryTransactionDetails
	{
		STRUCT AddonMessages ARRAY 3
		{
			STRING	64	message_text
		}
		STRUCT TransactionDetailTitle
		{
			STRING	64	title_text
			INT	2	page_no
			INT	2	page_size
		}
		STRUCT TransactionDetails ARRAY 10
		{
			STRING	10	trans_date
			STRING	10	trans_time
			STRING	6	outlet_id
			STRING	20	card_no
			FLOAT	4	trans_amount
		}
	}
}
$ cat IDL_ResponseHeader.dsc
	STRUCT	ResponseHeader
	{
		STRING	32	transaction_code
		INT	4	trans_jnlsno
		INT	4	response_code		DEFAULT		0
		STRING	1024	response_desc		DEFAULT		"OK"
	}
[/code]
附加说明:DEFAULT后面的缺省值,由自动化生成的函数DSCINIT_BankTransaction批量初始化。

N-1.性能压测

在高性能场合中,数据序列化和反序列化效率很关键,其中主要考察最终报文大小和序列化速度。
同时,我们还拿了Google公司大名鼎鼎的Protocol Buffer来做对比实验。

压测环境:

CPU      : Intel(R) Core(TM) i3-3240 CPU 3.4GHz/3.4GHz
内存     : 2GB
操作系统 : WINDOWS XP SP3 ( VMWare 6.0.1 ( Red Hat Enterprise Linux Server release 5.4 ) )

压测版本:

DirectStruct-1.0.3
protobuf-2.3.0

压测报文结构:

DirectStruct
[code]
$ cat IDL_AllTypes2.dsc
STRUCT	AllTypes2
{
	INT	4	n4
	INT	8	n8
	UINT	4	u4
	UINT	8	u8
	FLOAT	4	f4
	FLOAT	8	f8
	STRING	32	str32
	STRING	1024	str1024
}
$ dsc -f IDL_AllTypes2.dsc -c
$ ls
IDL_AllTypes2.dsc.c	IDL_AllTypes2.dsc.h
[/code]

Google Protocol Buffer
[code]
$ cat PressProtobuf.proto
message PressProtobuf
{
	required sint32		n4 = 2 ;
	required sint64		n8 =3 ;
	required int32		un4 = 5 ;
	required int64		un8 = 6 ;
	required float		f4 = 7 ;
	required double		f8 = 8 ;
	required string		str32 = 9 ;
	required string		str1024 = 10 ;
}
$ protoc -I=. --cpp_out=. PressProtobuf.proto
$ ls
PressProtobuf.pb.cc	PressProtobuf.pb.h
[/code]

压测代码:

DirectStruct
[code]
$ cat test/test_serialize_compress_press.c
...
int test_serialize_compress_press( long count )
{
	AllTypes2	st ;
	char		buf[ DSCSERIALIZE_COMPRESS_BUFSIZE_AllTypes2 + 1 ] ;
	int		len ;
	
	long		c ;
	long		t1 , t2 , dt ;
	
	int		nret = 0 ;
	
	memset( & st , 0x00 , sizeof(AllTypes2) );
	
	st.n4 = -0x11223344 ;
	st.n8 = LL(-0x1122334455667788) ;
	st.u4 = 0x11223344 ;
	st.u8 = ULL(0x1122334455667788) ;
	st.f4 = 100.00 ;
	st.f8 = 10000.00 ;
	strcpy( st.str32 , "calvin" );
	strcpy( st.str1024 , "XXXXXXXXXXXXXXXX" );
	
	DSCLOG_AllTypes2( & st );
	
	printf( "Press begin\n" );
	time( & t1 );
	
	for( c = 0 ; c < count ; c++ )
	{
		memset( buf , 0x00 , sizeof(buf) );
		nret = DSCSERIALIZE_COMPRESS_AllTypes2( & st , buf , & len ) ;
		if( nret )
		{
			printf( "DSCSERIALIZE_COMPRESS_AllTypes2 failed[%d]\n" , nret );
			return nret;
		}
		
		memset( & st , 0x00 , sizeof(AllTypes2) );
		nret = DSCDESERIALIZE_COMPRESS_AllTypes2( buf , & len , & st ) ;
		if( nret )
		{
			printf( "DSCDESERIALIZE_COMPRESS_AllTypes2 failed[%d]\n" , nret );
			return nret;
		}
	}
	
	printf( "Press end\n" );
	time( & t2 );
	dt = t2 - t1 ;
	printf( "data compress size[%d] - compact size[%d]\n" , len , DSCSERIALIZE_COMPACT_BUFSIZE_AllTypes2 );
	printf( "Elapse %ld seconds\n" , dt );
	
	dump( buf , len );
	
	DSCLOG_AllTypes2( & st );
	
	return 0;
}
...
$ make -f makefile
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c IDL_AllTypes2.dsc.c
gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I.  -c test_serialize_compress_press.c
gcc -o test_serialize_compress_press test_serialize_compress_press.o IDL_AllTypes2.dsc.o -L.
[/code]

Google Protocol Buffer
[code]
$ cat test_protobuf/test_protobuf_press.cc
...
int test_protobuf_press( int count )
{
	PressProtobuf	press ;
	PressProtobuf	press2 ;
	string		str ;
	int		len ;
	int		c ;
	
	press.set_n4( -0x11223344 );
	press.set_n8( -0x1122334455667788LL );
	press.set_un4( 0x11223344 );
	press.set_un8( 0x1122334455667788LL );
	press.set_f4( 100.00 );
	press.set_f8( 10000.00 );
	press.set_str32( "calvin" );
	press.set_str1024( "XXXXXXXXXXXXXXXX" );
	
	printf( "[%d]\n" , press.n4() );
	printf( "[%lld]\n" , press.n8() );
	printf( "[%d]\n" , press.un4() );
	printf( "[%lld]\n" , press.un8() );
	printf( "[%f]\n" , press.f4() );
	printf( "[%lf]\n" , press.f8() );
	printf( "[%s]\n" , press.str32().c_str() );
	printf( "[%s]\n" , press.str1024().c_str() );
	
	for( c = 0 ; c < count ; c++ )
	{
		str = press.SerializeAsString() ;
		press2.ParseFromString( str );
	}
	
	len = str.length() ;
	printf( "[%d]\n" , len );
	dump( (char*)str.c_str() , len );
	
	printf( "[%d]\n" , press2.n4() );
	printf( "[%lld]\n" , press2.n8() );
	printf( "[%d]\n" , press2.un4() );
	printf( "[%lld]\n" , press2.un8() );
	printf( "[%f]\n" , press2.f4() );
	printf( "[%lf]\n" , press2.f8() );
	printf( "[%s]\n" , press2.str32().c_str() );
	printf( "[%s]\n" , press2.str1024().c_str() );
	
	return 0;
}
...
make
g++ -I. -c test_protobuf_press.cc
g++ -o test_protobuf_press test_protobuf_press.o PressProtobuf.pb.cc -L/usr/local/lib -lprotobuf -lpthread
[/code]

压测输出:

DirectStruct
[code]
time ./test_serialize_compress_press 10000000
AllTypes2.n4[-287454020]
AllTypes2.n8[-1234605616436508552]
AllTypes2.u4[287454020]
AllTypes2.u8[1234605616436508552]
AllTypes2.f4[100.000000]
AllTypes2.f8[10000.000000]
AllTypes2.str32[calvin]
AllTypes2.str1024[XXXXXXXXXXXXXXXX]
Press begin
Press end
data compress size[66] - compact size[1092]
Elapse 1 seconds
0x0000000000  04 11 22 33 44 08 11 22 33 44 55 66 77 88 04 11 .."3D.."3DUfw...
0x0000000001  22 33 44 08 11 22 33 44 55 66 77 88 00 00 c8 42 "3D.."3DUfw....B
0x0000000002  00 00 00 00 00 88 c3 40 01 06 63 61 6c 76 69 6e .......@..calvin
0x0000000003  01 10 58 58 58 58 58 58 58 58 58 58 58 58 58 58 ..XXXXXXXXXXXXXX
0x0000000004  58 58                                           XX
AllTypes2.n4[-287454020]
AllTypes2.n8[-1234605616436508552]
AllTypes2.u4[287454020]
AllTypes2.u8[1234605616436508552]
AllTypes2.f4[100.000000]
AllTypes2.f8[10000.000000]
AllTypes2.str32[calvin]
AllTypes2.str1024[XXXXXXXXXXXXXXXX]

real    0m1.080s
user    0m1.074s
sys     0m0.007s
[/code]

Google Protocol Buffer
[code]
$ time ./test_protobuf_press 10000000
[-287454020]
[-1234605616436508552]
[287454020]
[1234605616436508552]
[100.000000]
[10000.000000]
[calvin]
[XXXXXXXXXXXXXXXX]
[72]
0x0000000000  10 87 cd 91 92 02 18 8f de b3 d6 8a d1 99 a2 22 ..............."
0x0000000001  28 c4 e6 88 89 01 30 88 ef 99 ab c5 e8 8c 91 11 (.....0.........
0x0000000002  3d 00 00 c8 42 41 00 00 00 00 00 88 c3 40 4a 06 =...BA.......@J.
0x0000000003  63 61 6c 76 69 6e 52 10 58 58 58 58 58 58 58 58 calvinR.XXXXXXXX
0x0000000004  58 58 58 58 58 58 58 58                         XXXXXXXX
[-287454020]
[-1234605616436508552]
[287454020]
[1234605616436508552]
[100.000000]
[10000.000000]
[calvin]
[XXXXXXXXXXXXXXXX]

real    0m4.248s
user    0m4.235s
sys     0m0.011s
[/code]

压测结论:

* DirectStruct序列化(带压缩)后的报文大小66字节,而Google Protocol Buffer为72字节,DirectStruct在序列化和压缩报文大小上险胜。
* DirectStruct反复序列化/反序列化(带压缩)1000万次总耗时1.080s,而Google Protocol Buffer总耗时4.248s,DirectStruct在序列化性能上完胜。
* DirectStruct编译客户应用代码时不需要额外的头文件和库文件,只需要工具dsc生成的IDL_AllTypes2.dsc.c、IDL_AllTypes2.dsc.h即可,而Google Protocol Buffer不仅需要PressProtobuf.pb.cc、PressProtobuf.pb.h,还需要/usr/local/include/google/protobuf下的一大堆头文件以及/usr/local/lib/libprotobuf.a(9MB),还依赖于-lpthread,编译环境复杂。

是不是越看越心动了?那就赶紧下载来玩玩吧

N.最后

最近我正在开发一个应用平台,利用tcpdaemon做TCP服务器,利用DirectStruct+fasterxml自动生成的代码轻松解包XML到C结构体,再调用DirectStruct自动生成的ESQL代码INSERT到数据库表里,十几行代码搞定,看,自由组合DirectStruct自动生成的代码能给你带来巨大的便捷性。有了DirectStruct,以后谁还会老老实实的写大量XML转换和ESQL代码呢?

欢迎使用DirectStruct,如果你使用中碰到了问题或者有更酷的想法请告诉我,谢谢 ^_^

首页传送门 : [url]http://git.oschina.net/calvinwilliams/DirectStruct[/url]
作者邮箱   : calvinwilliams.c@gmail.com

C结构体工具DirectStruct(综合示例一)
[url]http://my.oschina.net/u/988092/blog/325072[/url]
C结构体工具DirectStruct(综合示例二)
[url]http://my.oschina.net/u/988092/blog/325073[/url]
GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. (This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.) Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {description} Copyright (C) 2014 calvinwilliams.c This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. {signature of Ty Coon}, 1 April 1990 Ty Coon, President of Vice That's all there is to it!

简介

暂无描述 展开 收起
C
LGPL-2.1
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/calvinwilliams/DirectStruct.git
git@gitee.com:calvinwilliams/DirectStruct.git
calvinwilliams
DirectStruct
DirectStruct
release

搜索帮助