dxi_ddd启动时校验映射规则

前端之家收集整理的这篇文章主要介绍了dxi_ddd启动时校验映射规则前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

DAS 1.1测试时内部服务器在处理接收的单据时崩溃的情况(有产生crash文件).导致程序不再进行后续处理.

在测试环境已出现两种错误配置导致崩溃的情况。

为此已增加启动时校验规则配置功能处理这类问题.


情形1:<command>语句的别名字段在目标表中不存在

产生异常的代码位置及说明如下:

for (int col=0;col<fld_num;col++) {

FieldDescriptor *fd = rs->GetFieldInfo(col);
const char *val = rs->GetFieldValue(row,col); ///< @todo 很大的性能提升空间
stFieldInfo *fi = ti->FindField(fd->name);
/// fi==NULL,导致下面的CvtFieldConstValueString访问时异常
/// 如果在启动前校验过规则,则此处可以assert(fi!=0)

string ret_val;
if (ISEMPTY_STR(val)) {
GetFieldDefaultValue(pdbor,fi->type2_,ret_val);
}
else {
if (CvtFieldConstValueString(pdbor,val,ret_val)) {
return -1;
}
}

ti是关于表tsm_returnsheet_jk的信息.该表没有Refsheetid字段(fd->name).导致: fi==NULL

说明dxi_ddd的配置文件错误.检查后确定错误的配置项如下指示:

<dest_db>
<ds_name>JXJ_DB</ds_name> <!--目标数据源名称,缺省为默认目标数据源-->
<master_table_name>tsm_returnsheet_jk</master_table_name> <!-- 目标主表名称,仅用于业务主键冲突时删除原数据-->
<key_field prop="0">sheetid,bizstoreid</key_field> <!--prop表示属性 bit0: 1表示是自增长字段,注意填写导入目标表中的主键,需要填写目标表中的字段名-->
</dest_db>

<tables><!--表映射 -->
<table>
<name>tsm_returnsheet_jk</name><!--目标主表名 -->
<command>
select
bizcode as bizstoreid,
sheet_id as sheetid,
f007v_1105 as bizsupplyid,
F011v_1105 as shopid,
Refsheet_id as retntsheetid(修正前为refsheetid),
Reserve4 as sheetstatus,
f018d_1105 as returndate,
Dep_id as deptid,
Reserve3 as totalvalue
from tb_1105,tb_jxjorgcode
where sheet_id='@sheet_id' and src_orgid=@src_orgid
and orgid=src_orgid
</command>
</table>

</tables>


修改CRule::check_dest_db,在插件加载时检查规则.在该函数增加以下代码:
       USEDBC(pdbor,src_ds_->dbc_name_.c_str());
        ///< 检查select语句配置是否正确,包括是否是有效的SELECT,及目标表是否存在对应字段
        /// cmd_可能已经有where条件了,且可能有参数:@参数名
        SelectNode parser;
        parser.SetDbAccessor(pdbor);
        try {
            parser.Parse(table->cmd_.cmd_.c_str());        
        }catch(...) {
            return -1;
        }
        ///< 不查任何记录,只用来检查字段
        parser.SetClauseString(SelectNode::SC_WHERE,"0>0");
        string sql = parser.GetCookedsql();
        AUTO_QUERY_RECORDSET(CRecordset,prs,pdbor);
        prs = pdbor->Query(adCmdText,sql.c_str());
        if (prs==0) {
            return -1;
        }
        int fld_num = prs->GetFieldCount();
        for (int i=0;i<fld_num;i++) {
            FieldInfo fld;
            prs->GetFieldInfo(i,&fld);

            CAutoVector<stFieldInfo*>::iterator it_fld = ti->fields_.begin();
            bool found = false;
            while(it_fld!=ti->fields_.end()) {
                stFieldInfo *fi = *it_fld;
                if (stricmp(fld.m_strName,fi->name_.c_str())==0) {
                    found = true;
                    break;
                }
                it_fld++;
            }
            if (!found) {
                nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_ERROR,"CRule::check_dest_db,表%s映射语句错误,没有字段%s.\n",dest_ds_->dbc_name_.c_str(),table->name_.c_str(),fld.m_strName);
                return -1;
            }
        }

情形2: 任务主键列在<src_db>的<key_field>中不存在

规则的<src_db>的<key_field>内容和tb_change_log的app_key的列不一致.
导致以下代码位置产生问题:

int dxi_ddd_ns::CTask::HandleTable(CTableRelationNode *node,CMsg *msg) {
string tbl_name = node->GetName();
CTable *table = rule_->find_table(tbl_name.c_str());

RuleCommand *rc = &table->cmd_;
///< 确定对应表的抽取语句(参数化sql)
string sql = rc->cmd_;
///< 确定参数(父表对应字段的值)
int para_num = rc->GetParamNum();
vector<string> vs;
for (int k=0;k<para_num;k++) {
stParamPair *pp = rc->GetParam(k);
CTaskKey *key = find_key(pp->name_.c_str());
///< @note 如果上述配置错误,会导致key==0,下面的语句产生异常.
///< 增加启动时检查配置后可以assert(key!=0)

string val = key->field_val_;
vs.push_back(val);
}
///< 生成最终执行的sql语句
char *buffer;
if (rc->Instance(&buffer,vs))
return -1;
sql = buffer;
delete []buffer;

USEDBC(pdbor,rule_->src_ds_->dbc_name_.c_str());
AUTO_QUERY_RECORDSET(CRecordset,pdbor);
prs = pdbor->Query(adCmdText,sql.c_str());
if (prs==0) {
return -1;
}

if (prs->ISEOf()) ////< 如果没有查找到数据则不继续处理
return 0;

int rs_num = msg->GetRowsets();
string para_name = LogMsg(INNER_TABLE_FMT,rs_num+1);
msg->AddParam(para_name.c_str(),tbl_name.c_str());
CRowset *rs = new CRowset;
msg->AddRowset(rs);
stRowsetInfo *ri = new stRowsetInfo;
ri->rs_ = rs;
ri->tbl_name_ = tbl_name;
RSS_[tbl_name] = ri;

if (RecordFieldToRowset(prs,rs))
return -2;

while(!prs->ISEOf()) {
if (RecordToRowset(prs,rs))
return -4;
if (HandleDetail(node,msg))
return -5;
prs->Move();
}


return 0;
}

通过增加启动时校验规则,发现和报告此类配置错误.

增改的代码如下:
(1)dxi_ddd.cpp
CRule::check_src_db增加以下代码
///< 检查主表的映射语句中的参数是否与key_field一致
CTable *table = this->find_table(dest_master_table_name_.c_str());
RuleCommand *rc = &table->cmd_;
string sql = rc->cmd_;
int para_num = rc->GetParamNum();
vector<string> vs;
for (int k=0;k<para_num;k++) {
stParamPair *pp = rc->GetParam(k);
CTaskKey *key = ::find_key(pp->name_.c_str(),this->src_keys_);
if (key==0) {
nlogger_->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CRule::check_src_db()%s.配置错误:主表的<command>参数没有出现在<key_field>中.\n",
src_ds_->dbc_name_.c_str(),ti->name_.c_str());
return -1;
}
}

////////////////////////////////////////////////////////////////////////////////
CTaskKey* find_key(const char *key_name,CAutoVector<CTaskKey*> &keys) {
CAutoVector<dxi_ddd_ns::CTaskKey*>::iterator iter = keys.begin();
while(iter!=keys.end()) {
dxi_ddd_ns::CTaskKey *key = *iter;
if (stricmp(key->field_name_.c_str(),key_name)==0)
return key;
iter++;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
CTaskKey* CTask::find_key(const char *key_name) {
return ::find_key(key_name,keys_);
}

(2)dxi_ddd.h using namespace dxi_ddd_ns; CTaskKey* find_key(const char *key_name,CAutoVector<CTaskKey*> &keys);

猜你在找的设计模式相关文章