title: Different behavior for REF CURSOR between Oracle 10g and 11g when unique index present?
body: <h3>Description</h3>
  
  <p>I have an Oracle stored procedure that has been running for 7 or so years both locally on development instances and on multiple client test and production instances running Oracle 8, then 9, then 10, and recently 11. It has worked consistently until the upgrade to Oracle 11g. Basically, the procedure opens a reference cursor, updates a table then completes. In 10g the cursor will contain the expected results but in 11g the cursor will be empty. No DML or DDL changed after the upgrade to 11g. This behavior is consistent on every 10g or 11g instance I've tried (10.2.0.3, 10.2.0.4, 11.1.0.7, 11.2.0.1 - all running on Windows).</p>
  
  <p>The specific code is much more complicated but to explain the issue in somewhat realistic overview: I have some data in a header table and a bunch of child tables that will be output to PDF. The header table has a boolean (NUMBER(1) where 0 is false and 1 is true) column indicating whether that data has been processed yet. </p>
  
  <p>The view is limited to only show rows in that have not been processed (the view also joins on some other tables, makes some inline queries and function calls, etc). So at the time when the cursor is opened, the view shows one or more rows, then after the cursor is opened an update statement runs to flip the flag in the header table, a commit is issued, then the procedure completes.  </p>
  
  <p>On 10g, the cursor opens, it contains the row, then the update statement flips the flag and running the procedure a second time would yield no data. </p>
  
  <p>On 11g, the cursor <i>never</i> contains the row, it's as if the cursor does not open until after the update statement runs.</p>
  
  <p><i>I'm concerned that something may have changed in 11g (hopefully a setting that can be configured) that might affect other procedures and other applications. What I'd like to know is whether anyone knows why the behavior is different between the two database versions and whether the issue can be resolved without code changes.</i></p>
  
  <p><b>Update 1:</b> I managed to track the issue down to a unique constraint. It seems that when the unique constraint is present in 11g the issue is reproducible 100% of the time regardless of whether I'm running the real world code against the actual objects or the following simple example. </p>
  
  <p><b>Update 2:</b> I was able to completely eliminate the view from the equation. I have updated the simple example to show the problem exists even when querying directly against the table.</p>
  
  <h3>Simple Example</h3>
  
  <pre><code>CREATE TABLE tbl1
  (
    col1  VARCHAR2(10),
    col2  NUMBER(1)
  );
  
  INSERT INTO tbl1 (col1, col2) VALUES ('TEST1', 0);
  
  /* View is no longer required to demonstrate the problem
  CREATE OR REPLACE VIEW vw1 (col1, col2) 
  AS 
  SELECT col1, col2 
    FROM tbl1 
   WHERE col2 = 0;
  */
  
  CREATE OR REPLACE PACKAGE pkg1
  AS
     TYPE refWEB_CURSOR IS REF CURSOR;
  
     PROCEDURE proc1 (crs  OUT  refWEB_CURSOR);
  
  END pkg1;
  
  CREATE OR REPLACE PACKAGE BODY pkg1 
  IS
     PROCEDURE proc1 (crs  OUT  refWEB_CURSOR)
     IS
     BEGIN
  
        OPEN crs FOR
          SELECT col1
            FROM tbl1
           WHERE col1 = 'TEST1'
             AND col2 = 0;
  
        UPDATE tbl1
           SET col2 = 1
         WHERE col1 = 'TEST1';
  
        COMMIT;
  
     END proc1;
  
  END pkg1;
  </code></pre>
  
  <h3>Anonymous Block Demo</h3>
  
  <pre><code>DECLARE 
     crs1  pkg1.refWEB_CURSOR;
  
     TYPE rectype1 IS RECORD (
        col1  vw1.col1%TYPE
     );
  
     rec1  rectype1;
  BEGIN 
     pkg1.proc1 ( crs1 );
  
     DBMS_OUTPUT.PUT_LINE('begin first test');
  
     LOOP
        FETCH crs1
         INTO rec1;
  
        EXIT WHEN crs1%NOTFOUND;
  
        DBMS_OUTPUT.PUT_LINE(rec1.col1);
  
     END LOOP;  
  
     DBMS_OUTPUT.PUT_LINE('end first test');
  
  END; 
  
  /* After creating this index, the problem is seen */
  CREATE UNIQUE INDEX unique_col1 ON tbl1 (col1);
  
  /* Reset data to initial values */
  TRUNCATE TABLE tbl1;
  
  INSERT INTO tbl1 (col1, col2) VALUES ('TEST1', 0);
  
  DECLARE 
     crs1  pkg1.refWEB_CURSOR;
  
     TYPE rectype1 IS RECORD (
        col1  vw1.col1%TYPE
     );
  
     rec1  rectype1;
  BEGIN 
     pkg1.proc1 ( crs1 );
  
     DBMS_OUTPUT.PUT_LINE('begin second test');
  
     LOOP
        FETCH crs1
         INTO rec1;
  
        EXIT WHEN crs1%NOTFOUND;
  
        DBMS_OUTPUT.PUT_LINE(rec1.col1);
  
     END LOOP;  
  
     DBMS_OUTPUT.PUT_LINE('end second test');
  
  END; 
  </code></pre>
  
  <p>Example of what the output on 10g would be:<br>
  &nbsp;&nbsp;begin first test<br>
  &nbsp;&nbsp;TEST1<br>
  &nbsp;&nbsp;end first test<br>
  &nbsp;&nbsp;begin second test<br>
  &nbsp;&nbsp;TEST1<br>
  &nbsp;&nbsp;end second test  </p>
  
  <p>Example of what the output on 11g would be:<br>
  &nbsp;&nbsp;begin first test<br>
  &nbsp;&nbsp;TEST1<br>
  &nbsp;&nbsp;end first test<br>
  &nbsp;&nbsp;begin second test<br>
  &nbsp;&nbsp;end second test  </p>
  
  <h3>Clarification</h3>
  
  <p>I can't remove the COMMIT because in the real world scenario the procedure is called from a web application. When the data provider on the front end calls the procedure it will issue an implicit COMMIT when disconnecting from the database anyways. So if I remove the COMMIT in the procedure then yes, the anonymous block demo would work but the real world scenario would not because the COMMIT would still happen. </p>
  
  <h3>Question</h3>
  
  <p>Why is 11g behaving differently? Is there anything I can do other than re-write the code?</p>