Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 353417 - DBWS should support non-associative PLSQL collections
Summary: DBWS should support non-associative PLSQL collections
Status: RESOLVED FIXED
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Nobody - feel free to take it CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-07-29 10:10 EDT by Mike Norman CLA
Modified: 2022-06-09 10:27 EDT (History)
2 users (show)

See Also:


Attachments
Proposed fix. (9.16 KB, patch)
2012-01-05 15:28 EST, David McCann CLA
no flags Details | Diff
Supporting test cases. (27.86 KB, patch)
2012-01-05 15:28 EST, David McCann CLA
no flags Details | Diff
Proposed fix v2 (post review) (51.97 KB, patch)
2012-01-06 10:47 EST, David McCann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mike Norman CLA 2011-07-29 10:10:40 EDT
From the issue raised in the OTN TopLink forum:
   http://forums.oracle.com/forums/thread.jspa?threadID=2257216

A simple PLSQL collection type is used in a Stored Procedure call query:

CREATE OR REPLACE PACKAGE MY_PACKAGE AS 
    TYPE MY_ARRAY IS TABLE OF VARCHAR2(20); 
    PROCEDURE TEST(NAMES IN MY_ARRAY, CNT OUT NUMERIC);  
END MY_PACKAGE;

CREATE OR REPLACE PACKAGE BODY MY_PACKAGE AS
  PROCEDURE TEST(NAMES IN MY_ARRAY, CNT OUT NUMERIC) AS
  BEGIN
    CNT := NAMES.COUNT;
  END TEST;
END MY_PACKAGE;

        PLSQLCollection myArrayType = new PLSQLCollection();
        myArrayType.setTypeName("MY_PACKAGE.MY_ARRAY");
        myArrayType.setCompatibleType("MY_PACKAGE_MY_ARRAY");
        myArrayType.setJavaType(ArrayList.class);
        myArrayType.setNestedType(JDBCTypes.VARCHAR_TYPE);

        PLSQLStoredProcedureCall testCall = new PLSQLStoredProcedureCall();
        testCall.setProcedureName("MY_PACKAGE.TEST");
        testCall.addNamedArgument("NAMES", myArrayType);
        testCall.addNamedOutputArgument("CNT", JDBCTypes.INTEGER_TYPE);
        ValueReadQuery query = new ValueReadQuery();
        query.addArgument("NAMES", ArrayList.class);
        query.setCall(testCall);

        ArrayList<String> items = new ArrayList<String>();
        items.add("first string");
        items.add("second string");
        items.add("third string");
        items.add("fourth string");
        items.add("fifth string");
        items.add("sixth string");
        items.add("seventh string");
        items.add("eighth string");
        items.add("nineth string");
        items.add("tenth string");
        Object value = null;
        try {
            List<Object> args = new ArrayList<Object>();
            args.add(items);
            value = session.executeQuery(query, args);
        }
        catch (Exception e) {
            e.printStackTrace();
        }

The following anonymous PLSQL block is generated:
DECLARE
  NAMES_TARGET MY_PACKAGE.MY_ARRAY;
  NAMES_COMPAT MY_PACKAGE_MY_ARRAY := :1;
  CNT_TARGET INTEGER;
  FUNCTION EL_SQL2PL_1(aSqlItem MY_PACKAGE_MY_ARRAY) RETURN MY_PACKAGE.MY_ARRAY IS
      aPlsqlItem MY_PACKAGE.MY_ARRAY;
  BEGIN
      IF aSqlItem.COUNT > 0 THEN
          FOR I IN 1..aSqlItem.COUNT LOOP
              aPlsqlItem(I) := aSqlItem(I);
          END LOOP;
      END IF;
      RETURN aPlsqlItem;
  END EL_SQL2PL_1;
BEGIN
  NAMES_TARGET := EL_SQL2PL_1(NAMES_COMPAT);
  MY_PACKAGE.TEST(NAMES=>NAMES_TARGET, CNT=>CNT_TARGET);
  :2 := CNT_TARGET;
END;

An exception is thrown:
...
ORA-06531: Reference to uninitialized collection
ORA-06512: at line 11
...
Comment 1 Mike Norman CLA 2011-07-29 10:17:57 EDT
The behaviour of PLSQL collection contructors changed when associative
array were added to the language (9i). Non-associative collections require
the constructor to be called:
...
      aPlsqlItem MY_PACKAGE.MY_ARRAY;
  BEGIN
      IF aSqlItem.COUNT > 0 THEN
          aPlsqlItem := MY_PACKAGE.MY_ARRAY();
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
          FOR I IN 1..aSqlItem.COUNT LOOP
              aPlsqlItem(I) := aSqlItem(I);
          END LOOP;

The unfortunate thing is that the above code throws a 'weird' error
when the collection IS associative

PLS-00222: no function with name 'MY_ARRAY' exists in this scope

We need a way to get metadata information discovered at design-time
(is the collection associative?) passed to EclipseLink runtime so that
the generated nested function code in the anonymous PLSQL block can take
the incompatible behaviour into account and generate (or not) the appropriate
constructor call.
Comment 2 David McCann CLA 2012-01-05 15:28:25 EST
Created attachment 209102 [details]
Proposed fix.
Comment 3 David McCann CLA 2012-01-05 15:28:40 EST
Created attachment 209103 [details]
Supporting test cases.
Comment 4 David McCann CLA 2012-01-06 10:47:53 EST
Created attachment 209134 [details]
Proposed fix v2 (post review)

Changed xpath of isNonAssociative mapping on the PLSQLargument descriptor from a text node to an attribute - '@non-associative'.
Comment 5 David McCann CLA 2012-01-06 10:51:43 EST
Reviewed by:  michael.norman@oracle.com 
Tests:  all DBWS unit tests pass as expected; core LRG passes; added NonAssociativePLSQLCollectionTestSuite
Revision: 10652
Comment 6 David McCann CLA 2012-01-06 10:52:01 EST
Fixed.
Comment 7 Eclipse Webmaster CLA 2022-06-09 10:27:11 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink