通用单据处理支持主表修改,对于复杂数据类型,当仅主表数据的部分数据项改变时只同步这些已变化的字段,减少不必要的开销。
接口表记录变更的方式是记录每个变更字段的当前值。
每个字段的变更描述格式为:字段名=[值长度,属性,值]。
多个字段之间用逗号(",")分隔。
此格式可以避免转义问题(如值内容中出现"],"的情况).
属性目前用于区分是否是base64编码,这可用于binary类型字段的支持,可扩展。
字段类型在同步到目标库时根据数据库的结构信息决定,不需要在此指定。
以下为用Flex开发的解析变更字段表达式的解析器代码。
/* name: fld_list.y */
%{ #define MAX_FIELD_NAME_LEN 64 struct stFieldInfo { struct stFieldInfo *field_list = 0;
<S_FIELDNAME>([" "\t])*"="([" "\t])*\[([" "\t])* { <S_EQUEL>[0-9]* { <S_DATA_LEN2>[0-9]* { <S_DATA_PROP>([" "\t])*","([" "\t])* { <S_DATA_PROP2>. { BEGIN S_FIELDVAL; <S_FIELDVAL>([" "\t])*\]([" "\t])*[,]? { %% int add_field(struct stFieldInfo *fld) { return 0; int print_fld_list() { fld = fld->next; return 0; int main() yylex(); print_fld_list(); getch(); return 0;
|
此示例的输出为:
name:f123, len=3,prop=3,data=abc. |
上述代码是不可重入的。
修改代码以支持多线程环境使用。修改后的代码如下(FLEX 2.5.35版本):
/* name: fld_list.y */
%option reentrant %option noyywrap %option extra-type="struct stWorkData*"
%x S_FIELDNAME %x S_EQUEL %x S_DATA_LEN %x S_DATA_LEN2 %x S_DATA_PROP %x S_DATA_PROP2 %x S_FIELDVAL %x S_END
%{
#define YY_NO_UNISTD_H #include <string.h> #include <stdlib.h>
#define MAX_FIELD_NAME_LEN 64
struct stFieldInfo { char *name; unsigned int len; int prop; char *buffer;
struct stFieldInfo *next; };
struct stWorkData { char *fld_name; /*字段名称 */ unsigned int data_len; /* 字段值长度*/ int data_prop; /*字段属性*/ char *data_buffer; /* 字段值 */ struct stFieldInfo *field_list; struct stFieldInfo *last_field; };
int add_field(struct stWorkData *wkdata,struct stFieldInfo *fld); %}
FLDNAME [A-Za-z\_]+([A-Za-z\_]|[0-9])* DELIM ([" "\t])* NUMBERS [0-9]* %% {FLDNAME} { yyextra->fld_name = strdup(yyget_text(yyscanner)); BEGIN S_FIELDNAME; }
<S_FIELDNAME>{DELIM}"="{DELIM}\[{DELIM} { BEGIN S_EQUEL; }
<S_EQUEL>{NUMBERS} { yyextra->data_len = atoi(yyget_text(yyscanner)); BEGIN S_DATA_LEN; } <S_DATA_LEN>{DELIM}","{DELIM} { BEGIN S_DATA_LEN2; }
<S_DATA_LEN2>{NUMBERS} { yyextra->data_prop = atoi(yyget_text(yyscanner)); BEGIN S_DATA_PROP; }
<S_DATA_PROP>{DELIM}","{DELIM} { BEGIN S_DATA_PROP2; }
<S_DATA_PROP2>. { int c; unsigned int len = 0; char *p; yyextra->data_buffer = malloc(yyextra->data_len+1); yyextra->data_buffer[0] = yyget_text(yyscanner)[0]; p = yyextra->data_buffer; p++; len++; while(len<yyextra->data_len&&(c=input(yyscanner))&&c!=EOF) { *p = c; p++; len++; } if (c==EOF||len<yyextra->data_len) yyterminate(); yyextra->data_buffer[len] = '\0';
BEGIN S_FIELDVAL; }
<S_FIELDVAL>{DELIM}\]{DELIM}[,]? { struct stFieldInfo *fld = malloc(sizeof(struct stFieldInfo)); fld->name = yyextra->fld_name; fld->len = yyextra->data_len; fld->prop = yyextra->data_prop; fld->buffer = yyextra->data_buffer; fld->next = 0; add_field(yyextra,fld);
BEGIN INITIAL; } . { ECHO; }
%%
int add_field(struct stWorkData *wkdata,struct stFieldInfo *fld) { if (wkdata->field_list==0) { wkdata->field_list = fld; wkdata->last_field = fld; return 0; } wkdata->last_field->next = fld; wkdata->last_field = fld;
return 0; }
int print_fld_list(struct stWorkData *wkdata) { int fld_num = 0; struct stFieldInfo *fld = wkdata->field_list; while(fld!=0) { printf("name:%s, len=%d,prop=%d,data=%s.\n",fld->name,fld->len,fld->prop,fld->buffer); fld_num++;
fld = fld->next; } printf("field_num:%d.\n",fld_num);
return 0; }
int main() { yyscan_t scanner; struct stWorkData wkdata;
char *str_input = "f123=[3,3,abc],f23=[5,1,xxxxx]";
wkdata.data_len = 0; wkdata.data_prop = 0; wkdata.field_list = 0; wkdata.last_field = 0;
yylex_init ( &scanner ); yylex_init_extra( &wkdata, &scanner ); yy_scan_string(str_input,scanner);
yylex ( scanner ); yylex_destroy ( scanner );
print_fld_list(&wkdata);
getch();
return 0; }
|
- FLEX&Bison参考资料:
Lexical Analysis With Flex
http://flex.sourceforge.net/manual/
Bison Quick Tutorial
http://gps.nju.edu.cn:88/mediawiki/index.php/Bison_Quick_Tutorial
Flex 2.5.35 and Win32 / Visual C++
http://www.thebinaryidiot.com/archives/2011/01/29/flex-2-5-35-and-win32-visual-studio-cpp/