Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving column names from ref cursor with cx_Oracle

In using cx_Oracle to invoke a simple stored procedure, I can easily get data back from the procedure as so:

db = db_class() #Sets up stuff, etc.
conn = db.connect() #Returns a connection to the database

cursor = conn.cursor()
l_results = cursor.var(cx_Oracle.CURSOR)

res = cursor.callproc("PROG.DATA.GET_EVENTS", [1,2,l_results]) 
#params = siteID, userID, ref cursor

res[2] ends up being some sort of enumerable I can easily iterate through like so:

data = [row for row in res[2]]

I end up with a list of lists/tuples which gives me the values, but I also need the column names. I've tried the following:

cols = cursor.description if cursor.description is not None else [] #Returns None
cols = res[2].description if res[2].description is not None else [] 
#Returns an error. Same if l_results is used instead

How do I get the column names from l_results? I've determined that l_results is a Variable object and not a cursor, so it won't work. Same with res[2]. But I just can't get the columns from curs.

curs.description after this appears to be a None value, when it should be a list of 7-item tuples

What in the world am I missing?


EDIT 1: I've tried changing it from callproc to the following. Same issue.

res = cursor.execute("BEGIN PROG.DATA.GET_EVENTS(:1,:2,:3); END;", {"1": 1,"2": 2,"3":, l_results})
cols = cursor.description #Returns None, again.

The call does return data, so I'm not sure why description isn't being set.

like image 324
Orpheus Avatar asked May 17 '18 19:05

Orpheus


1 Answers

The columns for the ref cursor can be determined from the ref cursor itself. Given a procedure like the following:

create or replace procedure so50399550 (
    a_Input1            number,
    a_Input2            number,
    a_Output            out sys_refcursor
) is
begin
    open a_Output for
    select a_Input1 as num, a_Input1 * a_Input1 as square from dual
    union all
    select a_Input2, a_Input2 * a_Input2 from dual;
end;
/

The Python code can be as follows:

refCursorVar = cursor.var(cx_Oracle.CURSOR)
cursor.callproc("so50399550", [1, 2, refCursorVar])
refCursor = refCursorVar.getvalue()
print("Rows:")
for row in refCursor:
    print(row)
print()
print("Column Info:")
for column in refCursor.description:
    print(column)
print()

BUT, you can do it much more simply using the following code. You don't have to actually create a variable. You can bind a cursor directly.

refCursor = conn.cursor()
cursor.callproc("so50399550", [1, 2, refCursor])
print("Rows:")
for row in refCursor:
    print(row)
print()
print("Column Info:")
for column in refCursor.description:
    print(column)
print()

A sample can be found here.

like image 198
Anthony Tuininga Avatar answered Nov 03 '22 20:11

Anthony Tuininga