CMultiSheet::HandleDelete中空转问题(2014-5-21)
以下代码对应的未修改前的版本,存在不必要的无意义操作循环。
假设订单(主从结构)表.
在处理从表时,会对从表的每条记录递归处理其下级从表.
int CMultiSheet::HandleDelete(CTableRelationNode *parent,CRecordset *prs,vector<string> &v_delete) {
USEDBC(pdbor,this->dbc_name_.c_str());
FAIL_RETURN(pdbor->BeginTrans(),,-1);
int result = 0;
unsigned short child_num = parent->ChildCount();
for (int i=0;i<child_num;i++) {
CTableRelationNode *child = dynamic_cast<CTableRelationNode*>(parent->GetChild(i));
char *select_cmd,*delete_cmd;
vector<string> vs1,vs2;
struct stA {
const char *p;
char **buffer;
CParamStrParser *parser;
vector<string> *vs;
} va[] = {
{ child->select_cmd_.c_str(),&select_cmd,&child->select_parser_,&vs1},
{ child->delete_cmd_.c_str(),&delete_cmd,&child->delete_parser_,&vs2},
};
for (int j=0;j<sizeof(va)/sizeof(va[0]);j++) {
stA &a = va[j];
int para_num = a.parser->GetParamNum();
for (int k=0;k<para_num;k++) {
stParamPair *pp = a.parser->GetParam(k);
_variant_t vtVavl;
if (!prs->GetFieldValue(pp->name_.c_str(),vtVavl))
return -1;
string val = ExVariantToString(vtVavl);
stFieldInfo *fi = parent->tbl_info_.FindField(pp->name_.c_str());
string s;
if (CvtFieldConstValueString(pdbor,fi->type2_,val.c_str(),s))
return -1;
a.vs->push_back(s);
}
///< 生成最终执行的SQL语句
a.parser->Instance(a.buffer,*a.vs);
}
string sql = *va[0].buffer;
delete []*va[0].buffer;
v_delete.push_back(*va[1].buffer);
delete []*va[1].buffer;
if (child->ChildCount()>0) { ///< 只有有子表时才遍历每条记录
AUTO_QUERY_RECORDSET(CRecordset,prs2,pdbor);
prs2 = pdbor->Query(adCmdText,sql.c_str());
if (prs2==0) {
return -2;
}
while(!prs2->IsEof()) {
if (HandleDelete(child,prs,v_delete)) {
result = -5;
break;
}
if (!prs2->Move()) {
result = -6;
break;
}
}
}
}
return result;
}
增加第44行的判定.
dxi_ddd支持更新操作(2014-5-21)
在DAS开发测试过程中,发现dxi_ddd不支持在出现主键冲突时采用更新.(代码中已明确记录不支持,应该是当时不需要)dxi_ddd开发时因时间因素和不是必要特性而没有支持主键冲突时采用更新处理.
在DAS系统中,实际情况存在此需要,可能的场景:
.基础资料更新
.业务数据更新
主要修改如下:
.short on_dup_key_; /// 主键冲突处理方式 忽略-1,继续尝试-2,更新-3 默认:2
CTask::HandleDetail
.增加删除语句的生成部分.
CTask::Run
.增加仅在主键冲突更新数据时才执行删除的控制
.原来的SetCommandTimeout使用逻辑有问题:本意是执行前设置为INFINITE,但原来的代码没有达到预期
int CTask::HandleDetail(CTableRelationNode *parent,CRecordset *prs,CMsg *msg) {
GetLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CTask::HandleDetail ...\n");
int result = 0;
int sub_node_num = parent->ChildCount();
if(sub_node_num == 0) return 0;
IDbAccessor *pdbor = prs->GetAccessor();
for (int i=0;i<sub_node_num;i++) {
CTableRelationNode *sub_node = (CTableRelationNode*)parent->GetChild(i);
dxi_ddd_ns::CTable *table = rule_->find_table(sub_node->GetName());
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());
string val = key->field_val_;
vs.push_back(val);
}
///< 生成最终执行的SQL语句
char *buffer;
if (rc->Instance(&buffer,vs))
return -1;
sql = buffer;
delete []buffer;
char *select_cmd,*delete_cmd;
struct stA {
const char *p;
char **buffer;
} va[] = {
// { table->select_cmd_.c_str(),&select_cmd},
{ table->delete_cmd_.c_str(),&delete_cmd},
};
for (int k=0;k<sizeof(va)/sizeof(va[0]);k++) {
stA &a = va[k];
CParamStrParser parser;
string cmd = a.p;
parser.Parse(cmd.c_str());
int para_num = parser.GetParamNum();
vector<string> vs;
USEDBC(pdbor2,this->rule_->dest_ds_->dbc_name_.c_str());
for (int k=0;k<para_num;k++) {
stParamPair *pp = parser.GetParam(k);
_variant_t vtVal;
if (!prs->GetFieldValue(pp->name_.c_str(),vtVal)) {
return -1;
}
stTableInfo *ti = rule_->dest_ds_->find_table(table->name_.c_str());
stFieldInfo *fi = ti->FindField(pp->name_.c_str());
string val = ExVariantToString(vtVal);
string ret_val;
if (CvtFieldConstValueString(pdbor2,fi->type2_,val.c_str(),ret_val))
return -1;
vs.push_back(ret_val);
}
///< 生成最终执行的SQL语句
parser.Instance(a.buffer,vs);
}
delete_cmd_.push_back(*va[0].buffer);
delete []*va[0].buffer;
AUTO_QUERY_RECORDSET(CRecordset,prs2,pdbor);
prs2 = pdbor->Query(adCmdText,sql.c_str());
if (prs2==0) {
return -2;
}
CRowset *rs = 0;
CAutoMap<string,stRowsetInfo*>::iterator iter = rss_.find(table->name_.c_str());
if (rs==0) {
int rs_num = msg->GetRowsets();
string para_name = LogMsg(INNER_TABLE_FMT,rs_num+1);
msg->AddParam(para_name.c_str(),table->name_.c_str());
rs = new CRowset;
msg->AddRowset(rs);
stRowsetInfo *ri = new stRowsetInfo;
ri->rs_ = rs;
ri->tbl_name_ = table->name_;
rss_[table->name_] = ri;
if (RecordFieldToRowset(prs2,rs))
return -3;
}
unsigned long ulDetailCount = 0;
while(!prs2->IsEof()) {
if (RecordToRowset(prs2,rs))
return -4;
if (HandleDetail(sub_node,prs2,msg)) {
result = -5;
break;
}
if (!prs2->Move()) {
return -6;
}
}
}
GetLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CTask::HandleDetail ok.\n");
return 0;
}
////////////////////////////////////////////////////////////////////////////////
int dxi_ddd_ns::CTask::Run(int &handle_status) {
clock_t beg0 = clock();
GetLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CTask::Run ...\n");
last_error_ = 0;
handle_status = -1; ///< @note 定义接口错误(在统一的错误编码范围) -1表示未定义的错误
///< 根据任务定义信息抽取数据,生成UMX数据包
GetLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"执行GetData...\n");
clock_t beg = clock();
CMsg *msg = GetData();
if (msg==0)
return -1;
GetLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CTask::GetData 耗时%.2f秒.\n",(double)(clock()-beg)/CLOCKS_PER_SEC);
if (msg->GetRowsets()==0) { ///< 如果没有找到数据,则CMsg没有行集信息(@note 不是行集记录数为空的行集)
return -5;
}
beg = clock();
USEDBC(pdbor,rule_->dest_ds_->dbc_name_.c_str());
///< @note 如果命令处理耗时非常长,则需要延长CommandTimeout超时设置,0表示无限等待
int cmd_timeout = pdbor->GetCommandTimeout();
pdbor->SetCommandTimeout(0);
FAIL_RETURN(pdbor->BeginTrans(),,-1);
if ((rule_->prop_&1)==0) {
CAutoVector<CTableData*> tables;
if (SyncData(msg, pdbor, tables)) {
pdbor->RollbackTrans();
pdbor->SetCommandTimeout(cmd_timeout);
msg->Release();
return -3;
}
msg->Release();
GetLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CTask::分析数据耗时%.2f秒.\n",(double)(clock()-beg)/CLOCKS_PER_SEC);
//开始执行SQL语句
GetLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"准备更新...\n");
beg = clock();
if (rule_->on_dup_key_==3) { ///< 仅在主键冲突更新数据时才执行删除
vector<string>::reverse_iterator iter = delete_cmd_.rbegin();
while(iter!=delete_cmd_.rend()) {
string cmd = *iter;
if (!pdbor->Execute(adCmdText,cmd.c_str())) {
// pdbor->SetCommandTimeout(0);
pdbor->RollbackTrans();
return -2;
}
iter++;
}
}
GetLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CTask::删除原数据耗时%.2f秒.\n",(double)(clock()-beg)/CLOCKS_PER_SEC);
//再执行insert语句
beg = clock();
CAutoVector<CTableData*>::iterator table_iter = tables.begin();
for(; table_iter != tables.end(); table_iter++)
{
CTableData* table = *table_iter;
if(pdbor->GetDBExt()->BatchInsert(table->tbl_name_.c_str(), table->fld_list_.c_str(), table->vs, BATCH_INSERT_NUM))
{
if (pdbor->GetDBExt()->IsDuplicateKeyError(pdbor->GetLastErrorCode())) {
handle_status = 7;
if (rule_->on_dup_key_==1) {
pdbor->SetCommandTimeout(cmd_timeout);
pdbor->RollbackTrans();
return 0;
}
}
pdbor->SetCommandTimeout(cmd_timeout);
pdbor->RollbackTrans();
return -3;
}
}
}
else {
if (SyncData(msg, pdbor)) {
pdbor->RollbackTrans();
pdbor->SetCommandTimeout(cmd_timeout);
msg->Release();
if (last_error_==CE_PRIKEY_REPEAT) {
handle_status = 7;
if (rule_->on_dup_key_==1)
return 0;
}
return -3;
}
msg->Release();
}
FAIL_RETURN(pdbor->CommitTrans(),pdbor->SetCommandTimeout(cmd_timeout),-4);
pdbor->SetCommandTimeout(cmd_timeout);
GetLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CTask::Run ok 总耗时%.2f秒.\n",(double)(clock()-beg0)/CLOCKS_PER_SEC);
handle_status = 0;
return 0;
}
增加第29-64行的代码.