使用最新版cx oracle(8.3),需要调用oracle的存储过程,发现报错“AttributeError: 'cx_Oracle.Cursor' object has no attribute 'nextset'”
原因排查
查阅DatabaseLibrary发现报错在call_stored_procedure这个函数中
进一步阅读代码,发现cx aralce的游标类,已经没有nextset方法,因此继续查阅cx oracle官方文档,找到调用存储过程的方法callproc:https://cx-oracle.readthedocs.io/en/latest/api_manual/cursor.html#Cursor.callproc
查看该方法使用示例:https://cx-oracle.readthedocs.io/en/latest/user_guide/plsql_execution.html#plsqlproc
发现调用存储过程前,需要先定义接收结果变量。执行完成后需要调用结果变量的getvalue方法获取结果。
解决方案
参考call_stored_procedure方法,重写一个调用存储过程的函数,在使用时按照使用自定义关键字的方式导入即可使用(需要注意的是,robot中不需要再导入DatabaseLibrary,因为自定义的类是继承DatabaseLibrary,具有父类的所有方法)
from DatabaseLibrary import DatabaseLibrary
from robot.api import logger
from robot.api.deco import keyword
class CustomerDatabaseLibrary(DatabaseLibrary):
@keyword('oracle_xxx')
def call_p_xxx(self, spName='pkg_xxx.p_xxx', spParams=None,
sansTran=False):
cur = None
if spParams is None:
spParams = []
try:
cur = self.__get_cur()
spName = self.__get_spName(spName)
# 定义接收结果变量,不同存储过程不一样
o_message = cur.var(str)
o_result = cur.var(str)
spParams.append(o_message)
spParams.append(o_result)
logger.info('Executing : Call Stored Procedure | %s | %s ' % (spName, spParams))
cur.callproc(spName, spParams)
retVal = [
o_message.getvalue(),
o_result.getvalue()
]
if not sansTran:
self._dbconnection.commit()
return retVal
finally:
if cur:
if not sansTran:
self._dbconnection.rollback()
def __get_cur(self):
cur = None
if self.db_api_module_name in ["cx_Oracle"]:
cur = self._dbconnection.cursor()
else:
cur = self._dbconnection.cursor(as_dict=False)
return cur
def __get_spName(self, spName=None):
PY3K = sys.version_info >= (3, 0)
if not PY3K:
spName = spName.encode('ascii', 'ignore')
return spName