Oracle code:
CREATE OR REPLACE PACKAGE pkg_hr_sample AS
  PROCEDURE
add_department(p_department_id   OUT NUMBER,
                          
p_department_name IN VARCHAR2,
                          
p_manager_id      IN NUMBER,
                          
p_location_id     IN NUMBER);
  FUNCTION
get_employee_count(p_department_id IN NUMBER) RETURN NUMBER;
  PROCEDURE
find_employees(p_query   IN VARCHAR2 DEFAULT NULL,
                          
p_date    IN DATE DEFAULT NULL,
                          
p_results OUT SYS_REFCURSOR);
END pkg_hr_sample;
/
CREATE OR REPLACE PACKAGE BODY pkg_hr_sample AS
  PROCEDURE
add_department(p_department_id   OUT NUMBER,
                          
p_department_name IN VARCHAR2,
                          
p_manager_id      IN NUMBER,
                          
p_location_id     IN NUMBER) AS
  BEGIN
    INSERT INTO departments
      (department_id,
department_name, manager_id, location_id)
    VALUES
      (departments_seq.nextval,
       p_department_name,
       p_manager_id,
       p_location_id)
    RETURNING department_id INTO p_department_id;
    COMMIT;
  END add_department;
  FUNCTION
get_employee_count(p_department_id IN NUMBER) RETURN NUMBER AS
    l_count NUMBER;
  BEGIN
    SELECT COUNT(*)
      INTO l_count
      FROM employees
     WHERE department_id = p_department_id;
    RETURN l_count;
  END
get_employee_count;
  PROCEDURE
find_employees(p_query   IN VARCHAR2 DEFAULT NULL,
                           p_date    IN DATE DEFAULT NULL,
                          
p_results OUT SYS_REFCURSOR)
AS
  BEGIN
    IF p_query IS NOT NULL THEN
      OPEN p_results FOR
        SELECT *
          FROM employees e
         WHERE (upper(first_name || '
' || last_name || ' ' || email) LIKE
               '%' || upper(p_query) || '%');
    ELSE
      OPEN p_results FOR
        SELECT * FROM employees e WHERE e.hire_date = p_date;
    END IF;
  END find_employees;
END pkg_hr_sample;
/
Three different access methods are introduced in the above
example: a procedure with IN and OUT parameters, a function returning a number
and a procedure with an OUT REF CURSOR parameter. Each one requires a different
way of calling as shown below.
Python code:
import
cx_Oracle
class
HR:
  def
__enter__(self):
    self.__db = cx_Oracle.Connection('hr/hr@pdborcl')
    self.__cursor = self.__db.cursor()
    return
self 
  def
__exit__(self): 
    self.__cursor.close()
    self.__db.close()
  '''
  def __exit__(self, type, value, traceback):
    self.__cursor.close()
    self.__db.close()
  '''
  def
add_department(self, p_department_name, p_manager_id,
p_location_id):
    l_department_id = self.__cursor.var(cx_Oracle.NUMBER)
    self.__cursor.callproc("PKG_HR_SAMPLE.ADD_DEPARTMENT",
      [l_department_id, p_department_name,
p_manager_id, p_location_id]) 
    # there are no OUT
parameters in Python, regular return here
    return
l_department_id    
  def
get_employee_count(self, p_department_id):
    l_count = self.__cursor.callfunc("PKG_HR_SAMPLE.GET_EMPLOYEE_COUNT",
      cx_Oracle.NUMBER, [p_department_id]) 
    return
l_count 
  def
find_employees(self, p_query, p_date):
    # as it comes to all
complex types we need to tell Oracle Client
    # what type to expect
from an OUT parameter
    l_cur = self.__cursor.var(cx_Oracle.CURSOR)
    l_query, l_date, l_emp = self.__cursor.callproc("PKG_HR_SAMPLE.FIND_EMPLOYEES",
[p_query, p_date, l_cur]) 
    return
list(l_emp)
  def
__init__(self):
    HR.__enter__(self)  
    o_count=HR.get_employee_count(self,
p_department_id=90)
    print('No.
of Employees: ',o_count)
    print('')
    o_cur= HR.find_employees(self,None,"28-Sep-05")
    print('Start:
Date output')
    for
result in o_cur:
        #print(result)
        print(result[0],",",result[1],"
",result[2])
    print('End:
Date output')
    print('')
    print('Start:
Name output')
    o_cur2= HR.find_employees(self,"Steven",None)
    for
result2 in o_cur2:
        #print(result)
        print(result2[0],",",result2[1],"
",result2[2])
    print('End:
Name output')
    HR.__exit__(self)
HR()
Output:
No. of Employees:  3.0
Start: Date output
110 , Fname1   Lname1
End: Date output
Start: Name output
100 , Fname1   Lname1
128 , Fname2   Lname2
End: Name output
Based
upon the above example, calling stored procedures from Python is regulated
through some basic rules:
          ·      
Procedures
are called with cx_Oracle.Cursor.callproc(proc, [params]) whereas functions
with              cx_Oracle.Cursor.callfunc(proc, returnType, [params]). Functions require
their return type to              be  defined in advance - the get_employee_count() method
declares the return type from                           
                  PKG_HR_SAMPLE.GET_EMPLOYEE_COUNT to be a
cx_Oracle.NUMBER
         ·      
Complex
types such as REF CURSORs can be returned using cx_Oracle Variable objects as               parameters in callproc/callfunc calls.
I hope you all have enjoyed reading this article. Comments are
welcome....
Related Posts:
- Setting up Oracle, Python and Eclipse
- Connect Python 3.6 with Oracle 12c on Windows 7 x64
Related Posts:
- Setting up Oracle, Python and Eclipse
- Connect Python 3.6 with Oracle 12c on Windows 7 x64