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,fi->type2_,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,prs,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,prs,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);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值