每次写用ado访问数据库的程序, 都会把早年我兄弟zhang写的代码拿出来抄一抄, 这一次比较特别的是需要调用stored procedure. 我痛恨stored procedure, 因为他让逻辑分散了, 更加难以维护. 由于各种原因, 比如已有代码量巨大, 比如合作方公司要求使用stored procedure作为接口, 还是无法避免的使用这个鸟东西, 这是我老人家第一次用ado调用stored procedure. 费了一番劲, 大概3个小时才整好这个调用.
第一步肯定还是在google上搜索一批乱七八糟的无责任代码作为参考, 抄过来之后进行调试, 初步还算顺利, 整几个parameter的智能指针, 可以成功调用了, 不错, 算顺利. 接着就碰到了第一个麻烦, 返回值, 业务逻辑需要取回stored procedure 的返回值作为结果判断进行下一步逻辑. 把一个.net程序里使用ado.net调用sotred procedure的代码抄了一段, 不好使, 直接抛exception, 问一个同事, 同事帮忙研究了一番, 告之这个返回值的parameter, 一定要第一个append, 试了一把, 灵了, 能正常execute了, 但是取回的返回值不正确, 永远是0. 又郁闷了, 想起一个几年前带过的徒弟, 近来经常在写用ado调用stored procedure的程序, 直接给他打电话请教, 被告之从未成功取回过返回值. 一筹莫展, 合作公司方的dba问我, 咋样了, 程序写好了没? (how's work, if you done your work, please let me know). 很丢人, 没辙了就又把无责任代码的文章翻了翻, 看到最后一段有说明, 说是在调用command->Execute的时候返回的Recordset要关掉, 否则就拿不到返回值, 我尝试关掉, 可惜每次以调用 Recordset->Close()就抛异常, 我一看, 干脆不取这个鸟Recordset了, 果然, 返回值取回来了.
接着来了第二个麻烦, 我需要循环的调用两个stored procedure, 各有各的参数, 按照ado.net的经验, 需要Parameters.Clear(), 但是ado里的Parameters没有Clear这个接口, 看import进来的ado com的msado15.tli发现Parameters里有个Delete方法, 尝试用它吧, 确实可以用, 但是这个方法还是有其相当傻b的地方, 就是Delete不存在的Parameter会抛Exception, 而且被Delete过的Parameter不能用了,需要重新调用Command->CreateParameter()方法创建, 更sb的是这个Delete用的参数Index是参数名, 不是数字. 这两个sb地方导致在每次循环都要Command->CreateParameters和 Parameters->Delete. 虽然sb了些还算能用, 基本解决了我问题, 剩下的还有一丝担心, ado这一堆的智能指针不会tmd有虾米泄漏吧, 我的fucking service需要7*24-n (n<=4)的运行的. 不管了, 人家微软都说了, smart pointer, 相信全是聪明人的微软不会出那么弱智的东西, 对付用吧.
//如果你需要sp的返回值, 你必须第一个append这个parameter
param5 = conn->m_command->CreateParameter("@RETURNVALUE", adInteger, adParamReturnValue, 4);
conn->m_command->Parameters->Append(param5);
//如果你需要sp的返回值, 调用Execute的时候不要取Recordset,
//如果取了recordset, 返回值永远是0, 并且关闭这个recorderset的时候会抛出exception
/*recordset = */conn->m_command->Execute(NULL, NULL, adCmdStoredProc);
//Delete参数的时候必须指定参数名, 而且Delete之后这个参数就不能用了, 需要重新Create.
//在同一个command上调用其他sp之前,
//先把所有的parameter delete掉 //(不能循环, 因为delete的index不是数字是名字)
//再重新创建create并添加append新的sp需要的parameter
conn->m_command->Parameters->Delete("@PWD");
//这句代码是我抄来的, 可以取得返回值
_variant_t ret_val = conn->m_command->Parameters->GetItem((long)0)->Value;