Home » SQL & PL/SQL » SQL & PL/SQL » Delayed update to global variable via pipelined function? (Oracle DB 10g 10.2.0.4.0)
Delayed update to global variable via pipelined function? [message #627285] Mon, 10 November 2014 12:21 Go to next message
GHott
Messages: 8
Registered: August 2007
Junior Member
I'm having a strange issue that I've tired many different things to remedy - but I just can't seem to get it to execute like I want it to. My package spec and body is below. When calling the paginate_avail_fy_areas procedure, the g_tot_fy_areas variable is always an execution behind. I'm not sure if I'm explaining that appropriately with my previous statement - so let me give an example of what happens in the order they happen:

- compile the package spec/body
- execute anonymous block to call paginate_avail_fy_areas
- the correct ref cursor data is always returned, but after a fresh (first) compile of the spec/body - the out_tot_rows is ALWAYS 0 - doesn't matter what variables I send it
- execute the exact same anonymous block again - returns correct ref cursor data AND the correct out_tot_rows
- execute the anonymous block again, this time with different variables such that it should return a different out_tot_rows - it returns the correct ref cursor data, but the out_tot_rows is still the same from the previous execution
- execute this exact same anonymous block again, this time the out_tot_rows value is correct
- this same thing continues to happen

I can't for the life of me figure this out and I'm not the greatest at SQL/PL-SQL. I'm wondering if it has to do with the pipelined function messing with things and/or maybe it's a pointer/memory weirdness that has to do with the pipelined function? Any help or suggestions would be greatly appreciated.

Version: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit

Here is the package spec/body:

 --spec
CREATE OR REPLACE PACKAGE test_facility_pkg AS 
     --type record
     TYPE t_fy_area_rec IS RECORD( 
        sorted_row_number NUMBER
       ,fy_facility_id facility_area.fy_facility_id%TYPE
       ,area_id facility_area.area_id%TYPE
       ,area_name facility_area.area_name%TYPE
       ,building_number facility_area.building_number%TYPE
    ); 
    
    --type table
    TYPE t_fy_area_tab IS TABLE OF t_fy_area_rec;
    
    --get_filtered_fy_areas
    FUNCTION get_filtered_fy_areas (
        in_facility_id NUMBER
       ,in_filter_crit CHAR_ARRAY
       ,in_sort_col VARCHAR2
       ,in_sort_dir VARCHAR2
    )
    RETURN t_fy_area_tab PIPELINED;
 
    --paginate_avail_fy_areas
    PROCEDURE paginate_avail_fy_areas (
        in_facility_id IN  NUMBER
       ,in_filter_crit IN  CHAR_ARRAY
       ,in_num_rows IN  NUMBER DEFAULT 25
       ,in_page_num IN  NUMBER DEFAULT  1
       ,in_sort_col IN  VARCHAR2
       ,in_sort_dir IN  VARCHAR2 DEFAULT 'DESC'
       ,out_tot_rows OUT NUMBER
       ,out_fy_areas OUT SYS_REFCURSOR
       ,out_msg OUT VARCHAR2
     );
   
END test_facility_pkg; --package spec
/

--body
CREATE OR REPLACE PACKAGE BODY test_facility_pkg AS

     --total filtered facility areas global variable
     g_tot_fy_areas NUMBER(10) := 0;

    --get_filtered_fy_areas    
    FUNCTION get_filtered_fy_areas (
        in_facility_id IN  NUMBER
       ,in_filter_crit IN  CHAR_ARRAY
       ,in_sort_col IN  VARCHAR2
       ,in_sort_dir IN  VARCHAR2
     )
    RETURN t_fy_area_tab PIPELINED
    IS
       --gather areas for a facility and sort them based on input
       CURSOR c_unfiltered_fy_areas IS
            SELECT *
            FROM (
                 SELECT fy_facility_id,area_id,area_name,building_number
                 FROM facility_area
                 WHERE fy_facility_id = in_facility_id
                 ORDER BY
                 DECODE(LOWER(in_sort_col)
                      ,'fy_facility_id',TO_CHAR(fy_facility_id)
                      ,'area_id',TO_CHAR(area_id)
                      ,'area_name',TO_CHAR(area_name)
                      ,'building_number',TO_CHAR(building_number)
                      ,TO_CHAR(area_name))
            )
           ORDER BY
                CASE WHEN UPPER(in_sort_dir) = 'DESC' THEN
                ROWNUM * -1
                ELSE ROWNUM END;
 
       t_fy_area_recs t_fy_area_rec;
       rec c_unfiltered_fy_areas%ROWTYPE;
       v_filter_crit CHAR_ARRAY := CHAR_ARRAY();
       v_counter NUMBER := 1;
       v_processed NUM_ARRAY := NUM_ARRAY();
 
     BEGIN
       test_facility_pkg.g_tot_fy_areas := 0;
       IF in_filter_crit.FIRST IS NULL OR in_filter_crit.COUNT = 0 OR in_filter_crit IS NULL THEN
            v_filter_crit.EXTEND;
            v_filter_crit(1) := '%';
       ELSE
            FOR i IN 1 .. in_filter_crit.COUNT LOOP
                 v_filter_crit.EXTEND;
                 v_filter_crit(i) := '%'||in_filter_crit(i)||'%';
            END LOOP;
       END IF;
 
       FOR rec IN c_unfiltered_fy_areas LOOP
            FOR j IN 1 .. v_filter_crit.COUNT LOOP
                 IF (rec.area_name LIKE v_filter_crit(j) OR rec.building_number LIKE v_filter_crit(j))
                 AND rec.area_id NOT MEMBER OF v_processed THEN
                      t_fy_area_recs.sorted_row_number := v_counter;
                      t_fy_area_recs.fy_facility_id := rec.fy_facility_id;
                      t_fy_area_recs.area_id := rec.area_id;
                      t_fy_area_recs.area_name := rec.area_name;
                      t_fy_area_recs.building_number := rec.building_number;
                      v_processed.EXTEND(1);
                      v_processed(v_counter) := rec.area_id;
                      v_counter := v_counter + 1;
                       test_facility_pkg.g_tot_fy_areas :=  test_facility_pkg.g_tot_fy_areas+1;                         
                      PIPE ROW(t_fy_area_recs);
                 END IF; --selected columns match LIKE filter criteria
            END LOOP; --filter criteria array loop
       END LOOP; --unfiltered facility areas cursor
 
       v_processed.DELETE;
       v_filter_crit.DELETE;

       test_facility_pkg.g_tot_fy_areas := v_counter-1;
 
       RETURN;
    END get_filtered_fy_areas; --function

    PROCEDURE paginate_avail_fy_areas (
       in_facility_id      IN  NUMBER
       ,in_filter_crit      IN  CHAR_ARRAY
       ,in_num_rows      IN  NUMBER DEFAULT 25
       ,in_page_num      IN  NUMBER DEFAULT  1
       ,in_sort_col           IN  VARCHAR2
       ,in_sort_dir           IN  VARCHAR2 DEFAULT 'DESC'
       ,out_tot_rows      OUT NUMBER
       ,out_fy_areas      OUT SYS_REFCURSOR
       ,out_msg           OUT VARCHAR2
         )
     IS
     BEGIN
       OPEN out_fy_areas FOR
            SELECT r.*
            FROM (
                 SELECT DISTINCT q.*
                 FROM TABLE(get_filtered_fy_areas(
                       in_facility_id
                      ,in_filter_crit
                      ,in_sort_col
                      ,in_sort_dir
                      )) q
                 ORDER BY q.sorted_row_number ASC
               ) r
            WHERE 
                ((in_page_num <= 0
                   AND 1=1
                 )
                OR
                (in_page_num > 0
                  AND r.sorted_row_number BETWEEN (((in_page_num-1)*in_num_rows)+1) AND (in_page_num*in_num_rows)
               ));

       out_tot_rows := test_facility_pkg.g_tot_fy_areas;
       out_msg  := 'SUCCESS';
   END paginate_avail_fy_areas; --function

END test_facility_pkg; --pacakge body
/



This is the anonymous block I run in SQL developer to test the package:

CLEAR BUFFER;
SET serveroutput ON SIZE 1000000;

var r REFCURSOR;
var b NUMBER;

DECLARE
  A_filter_crit    CHAR_ARRAY := CHAR_ARRAY();
  v_fy_facility_id  NUMBER;
  v_number_of_rows  NUMBER;
  v_page_number    NUMBER;
  v_sort_column    VARCHAR2(50);
  v_sort_direction  VARCHAR2(50);
  tot_rows NUMBER;
  errmsg VARCHAR2(5000);  
 
BEGIN
  A_filter_crit.EXTEND;
  A_filter_crit(1) := 'H';
  A_filter_crit.EXTEND;
  A_filter_crit(1) := '1';
  
  v_fy_facility_id  := 7021;
  v_number_of_rows  := 4;
  v_page_number    := 1;
  v_sort_column    := 'area_id';
  v_sort_direction  := 'ASC';
  
  test_facility_pkg.paginate_avail_fy_areas(
     v_fy_facility_id
    ,A_filter_crit
    ,v_number_of_rows
    ,v_page_number
    ,v_sort_column
    ,v_sort_direction
    ,:b
    ,:r
    ,errmsg
  );

END;
/ 
print r;
print b;
Re: Delayed update to global variable via pipelined function? [message #627286 is a reply to message #627285] Mon, 10 November 2014 12:24 Go to previous messageGo to next message
BlackSwan
Messages: 26766
Registered: January 2009
Location: SoCal
Senior Member
>- execute anonymous block to call paginate_avail_fy_areas

PL/SQL can or may act differently when executed via anonymous block when compared to executed as named procedure since privileges acquired via ROLE do not apply within named PL/SQL procedures; but do apply for anonymous block.
Re: Delayed update to global variable via pipelined function? [message #627288 is a reply to message #627286] Mon, 10 November 2014 12:29 Go to previous messageGo to next message
GHott
Messages: 8
Registered: August 2007
Junior Member
BlackSwan wrote on Mon, 10 November 2014 12:24
>- execute anonymous block to call paginate_avail_fy_areas

PL/SQL can or may act differently when executed via anonymous block when compared to executed as named procedure since privileges acquired via ROLE do not apply within named PL/SQL procedures; but do apply for anonymous block.


Hi BlackSwan, I appreciate your help so quickly. Unfortunately, I have also attempted this through my calling Java code via JDBC storedProcedure with the same result Sad
Re: Delayed update to global variable via pipelined function? [message #627303 is a reply to message #627288] Mon, 10 November 2014 14:47 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
This is expected behaviour.
The pipeline procedure is run when you fetch rows from it. Every time you fetch a row a procedure runs upto the pipe_row command and then stops and waits for the next fetch.
The bit of the code that sets the global is only run after the last row is fetched.

And opening a ref cursor doesn't fetch any rows.

Simplest solution is to not use a pipelined function - you don't need it.
Re: Delayed update to global variable via pipelined function? [message #627310 is a reply to message #627303] Mon, 10 November 2014 15:01 Go to previous message
GHott
Messages: 8
Registered: August 2007
Junior Member
That makes sense, thank you for your help!
Previous Topic: Pick random rows
Next Topic: log_table
Goto Forum:
  


Current Time: Fri Apr 19 12:39:26 CDT 2024