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); (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|