SQL Struct with @Lob (BLOB, CLOB) used as stored procedure parameter type - fix (#1302)
SQL Struct with @Lob (BLOB, CLOB) used as stored procedure parameter type - fix
Bugfix and unit test.
Signed-off-by: Radek Felcman <radek.felcman@oracle.com>
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/databaseaccess/DatabasePlatform.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/databaseaccess/DatabasePlatform.java
index 04b0cff..301862b 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/databaseaccess/DatabasePlatform.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/databaseaccess/DatabasePlatform.java
@@ -3389,6 +3389,16 @@
/**
* INTERNAL:
+ * This method builds a Struct using the unwrapped connection within the session
+ * @return Struct
+ */
+ public Struct createStruct(String structTypeName, Object[] attributes, AbstractRecord row, Vector orderedFields, AbstractSession session, Connection connection) throws SQLException {
+ java.sql.Connection unwrappedConnection = getConnection(session, connection);
+ return createStruct(structTypeName,attributes,unwrappedConnection);
+ }
+
+ /**
+ * INTERNAL:
* Platforms that support java.sql.Array may override this method.
* @return Array
*/
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/ComplexDatabaseType.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/ComplexDatabaseType.java
index 7feff65..7128406 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/ComplexDatabaseType.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/ComplexDatabaseType.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -189,17 +189,17 @@
@Override
public void buildBeginBlock(StringBuilder sb, PLSQLargument arg, PLSQLStoredProcedureCall call) {
- String sql2PlName = call.getSQL2PlName(this);
- if (sql2PlName == null) {
+ String conversionRoutine = ((this.getTypeName().equals(this.getCompatibleType()))) ? call.getPl2SQLName(this) : call.getSQL2PlName(this);
+ if (conversionRoutine == null) {
// TODO exception
- throw new NullPointerException("no SQL2Pl conversion routine for " + typeName);
+ throw new NullPointerException("no SQL2Pl or Pl2SQL conversion routine for " + typeName);
}
String target = databaseTypeHelper.buildTarget(arg);
String compat = databaseTypeHelper.buildCompatible(arg);
sb.append(" ");
sb.append(target);
sb.append(" := ");
- sb.append(sql2PlName);
+ sb.append(conversionRoutine);
sb.append("(");
sb.append(compat);
sb.append(");");
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/mappings/structures/ObjectRelationalDataTypeDescriptor.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/mappings/structures/ObjectRelationalDataTypeDescriptor.java
index eef5a11..3ab71ea 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/mappings/structures/ObjectRelationalDataTypeDescriptor.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/mappings/structures/ObjectRelationalDataTypeDescriptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -339,7 +339,7 @@
fields[index] = row.get(field);
}
- structure = session.getPlatform().createStruct(getStructureName(), fields, session, connection);
+ structure = session.getPlatform().createStruct(getStructureName(), fields, row, getOrderedFields(), session, connection);
} catch (java.sql.SQLException exception) {
throw DatabaseException.sqlException(exception, session, false);
} finally {
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredProcedureCall.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredProcedureCall.java
index 04d568b..5e8b38e 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredProcedureCall.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredProcedureCall.java
@@ -670,20 +670,26 @@
if (info == null) {
info = generateNestedFunction(type, isNestedTable);
}
- if (argument.direction == IN) {
- if (!functions.contains(info.sql2PlConv)) {
- functions.add(info.sql2PlConv);
- }
- } else if (argument.direction == INOUT) {
- if (!functions.contains(info.sql2PlConv)) {
- functions.add(info.sql2PlConv);
- }
+ if (type.getTypeName().equals(type.getCompatibleType())) {
if (!functions.contains(info.pl2SqlConv)) {
functions.add(info.pl2SqlConv);
}
- } else if (argument.direction == OUT) {
- if (!functions.contains(info.pl2SqlConv)) {
- functions.add(info.pl2SqlConv);
+ } else {
+ if (argument.direction == IN) {
+ if (!functions.contains(info.sql2PlConv)) {
+ functions.add(info.sql2PlConv);
+ }
+ } else if (argument.direction == INOUT) {
+ if (!functions.contains(info.sql2PlConv)) {
+ functions.add(info.sql2PlConv);
+ }
+ if (!functions.contains(info.pl2SqlConv)) {
+ functions.add(info.pl2SqlConv);
+ }
+ } else if (argument.direction == OUT) {
+ if (!functions.contains(info.pl2SqlConv)) {
+ functions.add(info.pl2SqlConv);
+ }
}
}
}
diff --git a/foundation/org.eclipse.persistence.oracle/src/main/java/org/eclipse/persistence/platform/database/oracle/Oracle12Platform.java b/foundation/org.eclipse.persistence.oracle/src/main/java/org/eclipse/persistence/platform/database/oracle/Oracle12Platform.java
index af6022b..2c70171 100644
--- a/foundation/org.eclipse.persistence.oracle/src/main/java/org/eclipse/persistence/platform/database/oracle/Oracle12Platform.java
+++ b/foundation/org.eclipse.persistence.oracle/src/main/java/org/eclipse/persistence/platform/database/oracle/Oracle12Platform.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -18,12 +18,22 @@
import java.io.IOException;
import java.io.Writer;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Struct;
import java.util.Map;
import java.util.Set;
+import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.exceptions.ConversionException;
import org.eclipse.persistence.exceptions.ValidationException;
+import org.eclipse.persistence.internal.helper.ClassConstants;
+import org.eclipse.persistence.internal.helper.DatabaseField;
+import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.EmptyRecord;
import org.eclipse.persistence.logging.SessionLog;
@@ -151,4 +161,29 @@
}
}
+ /**
+ * INTERNAL:
+ * This method builds a Struct using the unwrapped connection within the session
+ * @return Struct
+ */
+ @Override
+ public Struct createStruct(String structTypeName, Object[] attributes, AbstractRecord row, Vector orderedFields, AbstractSession session, Connection connection) throws SQLException {
+ for (int index = 0; index < orderedFields.size(); index++) {
+ DatabaseField field = (DatabaseField)orderedFields.elementAt(index);
+ if (row.getField(field) != null && row.getField(field).getTypeName() != null) {
+ if (ClassConstants.BLOB.getTypeName().equals(row.getField(field).getTypeName())) {
+ Blob blob = connection.createBlob();
+ blob.setBytes(1L, (byte[]) row.get(field));
+ attributes[index] = blob;
+ } else if (ClassConstants.CLOB.getTypeName().equals(row.getField(field).getTypeName())) {
+ Clob clob = connection.createClob();
+ clob.setString(1L, (String) attributes[index]);
+ attributes[index] = clob;
+ }
+ } else {
+ attributes[index] = row.get(field);
+ }
+ }
+ return super.createStruct(structTypeName, attributes, session, connection);
+ }
}
diff --git a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/plsql/InnerObjBlob.java b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/plsql/InnerObjBlob.java
new file mode 100644
index 0000000..16949ab
--- /dev/null
+++ b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/plsql/InnerObjBlob.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+// Contributors:
+// Oracle - initial implementation
+package org.eclipse.persistence.testing.models.jpa.plsql;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Embeddable;
+import jakarta.persistence.Lob;
+import org.eclipse.persistence.annotations.Struct;
+
+import java.util.Arrays;
+
+@Embeddable
+@Struct(name="PLSQL_P_PLSQL_INNER_BLOB_REC", fields={"BLOB_ID", "BLOB_CONTENT", "CLOB_CONTENT"})
+public class InnerObjBlob {
+
+ public InnerObjBlob() {
+ }
+
+ public InnerObjBlob(int blobId, byte[] blobContent, String clobContent) {
+ this.blobId = blobId;
+ this.blobContent = blobContent;
+ this.clobContent = clobContent;
+ }
+
+ @Column(name="BLOB_ID")
+ private int blobId;
+
+ @Column(name="BLOB_CONTENT")
+ @Lob
+ private byte[] blobContent;
+
+ @Column(name="CLOB_CONTENT")
+ @Lob
+ private String clobContent;
+
+ public int getBlobId() {
+ return blobId;
+ }
+
+ public void setBlobId(int blobId) {
+ this.blobId = blobId;
+ }
+
+ public byte[] getBlobContent() {
+ return blobContent;
+ }
+
+ public void setBlobContent(byte[] blobContent) {
+ this.blobContent = blobContent;
+ }
+
+ public String getClobContent() {
+ return clobContent;
+ }
+
+ public void setClobContent(String clobContent) {
+ this.clobContent = clobContent;
+ }
+
+ @Override
+ public String toString() {
+ return "InnerObjBlob{" +
+ "blobId=" + blobId +
+ ", blobContent=" + Arrays.toString(blobContent) +
+ ", clobContent='" + clobContent + '\'' +
+ '}';
+ }
+}
diff --git a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/plsql/OuterObjBlob.java b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/plsql/OuterObjBlob.java
new file mode 100644
index 0000000..db45308
--- /dev/null
+++ b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/plsql/OuterObjBlob.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+// Contributors:
+// Oracle - initial implementation
+package org.eclipse.persistence.testing.models.jpa.plsql;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Embeddable;
+import org.eclipse.persistence.annotations.Struct;
+
+@Embeddable
+@Struct(name="PLSQL_P_PLSQL_OUTER_STRUCT_REC", fields={"STRUCT_ID", "STRUCT_CONTENT"})
+public class OuterObjBlob {
+
+ public OuterObjBlob() {
+ }
+
+ public OuterObjBlob(int structId, InnerObjBlob structContent) {
+ this.structId = structId;
+ this.structContent = structContent;
+ }
+
+ @Column(name="STRUCT_ID")
+ private int structId;
+
+ @Column(name="STRUCT_CONTENT")
+ private InnerObjBlob structContent;
+
+ public int getStructId() {
+ return structId;
+ }
+
+ public void setStructId(int structId) {
+ this.structId = structId;
+ }
+
+ public InnerObjBlob getStructContent() {
+ return structContent;
+ }
+
+ public void setStructContent(InnerObjBlob structContent) {
+ this.structContent = structContent;
+ }
+
+ @Override
+ public String toString() {
+ return "OuterObjBBlob{" +
+ "structId=" + structId +
+ ", structContent=" + structContent +
+ '}';
+ }
+}
diff --git a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/plsql/SaveComplexBlob.java b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/plsql/SaveComplexBlob.java
new file mode 100644
index 0000000..ad84ea6
--- /dev/null
+++ b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/plsql/SaveComplexBlob.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+// Contributors:
+// Oracle - initial implementation
+package org.eclipse.persistence.testing.models.jpa.plsql;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import org.eclipse.persistence.annotations.Direction;
+import org.eclipse.persistence.platform.database.oracle.annotations.*;
+
+@Entity
+@NamedPLSQLStoredFunctionQueries(value = {
+ @NamedPLSQLStoredFunctionQuery(name = "PLSQL_BLOB_REC_IN", functionName = "PLSQL_P.PLSQL_BLOB_REC_IN",
+ parameters = {@PLSQLParameter(name = "P_BLOB_REC", direction = Direction.IN, databaseType = "PLSQL_P_PLSQL_INNER_BLOB_REC"),
+ @PLSQLParameter(name = "P_CITY", direction = Direction.IN, databaseType = "VARCHAR_TYPE")},
+ returnParameter = @PLSQLParameter(name = "RESULT", direction = Direction.OUT, databaseType = "VARCHAR_TYPE")),
+ @NamedPLSQLStoredFunctionQuery(name = "PLSQL_STRUCT_INSTRUCT_REC_IN", functionName = "PLSQL_P.PLSQL_STRUCT_INSTRUCT_REC_IN",
+ parameters = {@PLSQLParameter(name = "P_BLOB_REC", databaseType = "PLSQL_P_PLSQL_INNER_BLOB_REC"),
+ @PLSQLParameter(name = "P_STRUCT_REC", databaseType = "PLSQL_P_PLSQL_OUTER_STRUCT_REC"),
+ @PLSQLParameter(name = "P_CITY", databaseType = "VARCHAR_TYPE")},
+ returnParameter = @PLSQLParameter(name = "RESULT", direction = Direction.OUT, databaseType = "VARCHAR_TYPE"))
+ }
+)
+@PLSQLRecords(value = {
+ @PLSQLRecord(name = "PLSQL_P_PLSQL_INNER_BLOB_REC", compatibleType = "PLSQL_P_PLSQL_INNER_BLOB_REC", javaType = InnerObjBlob.class,
+ fields = {
+ @PLSQLParameter(name = "BLOB_ID", databaseType = "NUMERIC_TYPE"),
+ @PLSQLParameter(name = "BLOB_CONTENT", databaseType = "BLOB_TYPE"),
+ @PLSQLParameter(name = "CLOB_CONTENT", databaseType = "CLOB_TYPE")
+ }
+ ),
+ @PLSQLRecord(name = "PLSQL_P_PLSQL_OUTER_STRUCT_REC", compatibleType = "PLSQL_P_PLSQL_OUTER_STRUCT_REC", javaType = OuterObjBlob.class,
+ fields = {
+ @PLSQLParameter(name = "STRUCT_ID", databaseType = "NUMERIC_TYPE"),
+ @PLSQLParameter(name = "STRUCT_CONTENT", databaseType = "PLSQL_P_PLSQL_INNER_BLOB_REC")
+ }
+
+ )
+}
+)
+public class SaveComplexBlob {
+
+ @Id
+ @Column(name = "RESULT")
+ private String result;
+
+ public String getResult() {
+ return result;
+ }
+
+ public void setResult(String result) {
+ this.result = result;
+ }
+}
diff --git a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/plsql/PLSQLTestSuite.java b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/plsql/PLSQLTestSuite.java
index 681fcf2..c58f304 100644
--- a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/plsql/PLSQLTestSuite.java
+++ b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/plsql/PLSQLTestSuite.java
@@ -15,6 +15,7 @@
package org.eclipse.persistence.testing.tests.jpa.plsql;
import java.math.BigDecimal;
+import java.util.Base64;
import java.util.List;
import jakarta.persistence.EntityManager;
@@ -26,16 +27,16 @@
import org.eclipse.persistence.internal.helper.DatabaseType;
import org.eclipse.persistence.internal.jpa.EJBQueryImpl;
import org.eclipse.persistence.platform.database.oracle.annotations.OracleArray;
-import org.eclipse.persistence.platform.database.oracle.annotations.PLSQLParameter;
import org.eclipse.persistence.platform.database.oracle.jdbc.OracleArrayType;
import org.eclipse.persistence.platform.database.oracle.jdbc.OracleObjectType;
import org.eclipse.persistence.platform.database.oracle.plsql.PLSQLStoredProcedureCall;
import org.eclipse.persistence.platform.database.oracle.plsql.PLSQLargument;
-import org.eclipse.persistence.queries.DataReadQuery;
import org.eclipse.persistence.sessions.DatabaseSession;
import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
import org.eclipse.persistence.testing.models.jpa.plsql.Address;
import org.eclipse.persistence.testing.models.jpa.plsql.Employee;
+import org.eclipse.persistence.testing.models.jpa.plsql.InnerObjBlob;
+import org.eclipse.persistence.testing.models.jpa.plsql.OuterObjBlob;
import org.eclipse.persistence.testing.models.jpa.plsql.Phone;
public class PLSQLTestSuite extends JUnitTestCase {
@@ -49,7 +50,9 @@
suite.addTest(new PLSQLTestSuite("testTableOut"));
suite.addTest(new PLSQLTestSuite("testEmpRecordInOut"));
suite.addTest(new PLSQLTestSuite("testConsultant"));
- suite.addTest(new PLSQLTestSuite("testOracleTypeProcessing"));
+ suite.addTest(new PLSQLTestSuite("testOracleTypeProcessing"));
+ suite.addTest(new PLSQLTestSuite("testBlobInStruct"));
+ suite.addTest(new PLSQLTestSuite("testStructInStruct"));
return suite;
}
@@ -136,6 +139,12 @@
// Types
try {
+ session.executeNonSelectingSQL("DROP TYPE PLSQL_P_PLSQL_INNER_BLOB_REC FORCE");
+ } catch (Exception ignore) {}
+ try {
+ session.executeNonSelectingSQL("DROP TYPE PLSQL_P_PLSQL_OUTER_STRUCT_REC FORCE");
+ } catch (Exception ignore) {}
+ try {
session.executeNonSelectingSQL("DROP TYPE PLSQL_P_PLSQL_EMP_REC FORCE");
} catch (Exception ignore) {}
try {
@@ -151,6 +160,10 @@
session.executeNonSelectingSQL("CREATE OR REPLACE TYPE PLSQL_P_PLSQL_PHONE_LIST AS VARRAY(30) OF PLSQL_P_PLSQL_PHONE_REC");
session.executeNonSelectingSQL("CREATE OR REPLACE TYPE PLSQL_P_PLSQL_EMP_REC AS OBJECT ("
+ "EMP_ID NUMBER(10), NAME VARCHAR2(30), ACTIVE NUMBER(1), ADDRESS PLSQL_P_PLSQL_ADDRESS_REC, PHONES PLSQL_P_PLSQL_PHONE_LIST)");
+ session.executeNonSelectingSQL("CREATE OR REPLACE TYPE PLSQL_P_PLSQL_INNER_BLOB_REC AS OBJECT ("
+ + "BLOB_ID NUMBER(10), BLOB_CONTENT BLOB, CLOB_CONTENT CLOB)");
+ session.executeNonSelectingSQL("CREATE OR REPLACE TYPE PLSQL_P_PLSQL_OUTER_STRUCT_REC AS OBJECT ("
+ + "STRUCT_ID NUMBER(10), STRUCT_CONTENT PLSQL_P_PLSQL_INNER_BLOB_REC)");
session.executeNonSelectingSQL("CREATE OR REPLACE TYPE PLSQL_P_PLSQL_CITY_LIST AS VARRAY(255) OF VARCHAR2(100)");
session.executeNonSelectingSQL("CREATE OR REPLACE TYPE PLSQL_P_PLSQL_ADDRESS_LIST AS VARRAY(255) OF PLSQL_P_PLSQL_ADDRESS_REC");
session.executeNonSelectingSQL("CREATE OR REPLACE TYPE PLSQL_P_PLSQL_EMP_LIST AS VARRAY(255) OF PLSQL_P_PLSQL_EMP_REC");
@@ -178,6 +191,8 @@
+ "PROCEDURE PLSQL_EMP_INOUT(P_EMP IN OUT PLSQL_EMP_REC, P_CITY IN OUT VARCHAR2); \n"
+ "PROCEDURE PLSQL_ADDRESS_CUR_OUT(P_ADDRESS OUT PLSQL_ADDRESS_CUR); \n"
+ "PROCEDURE PLSQL_ADDRESS_REC_CUR_OUT(P_ADDRESS OUT PLSQL_ADDRESS_REC_CUR); \n"
+ + "FUNCTION PLSQL_BLOB_REC_IN(P_BLOB_REC IN PLSQL_P_PLSQL_INNER_BLOB_REC, P_CITY IN VARCHAR2) RETURN VARCHAR2; \n"
+ + "FUNCTION PLSQL_STRUCT_INSTRUCT_REC_IN(P_BLOB_REC IN PLSQL_P_PLSQL_INNER_BLOB_REC, P_STRUCT_REC IN PLSQL_P_PLSQL_OUTER_STRUCT_REC, P_CITY IN VARCHAR2) RETURN VARCHAR2; \n"
+ "END PLSQL_P; \n");
session.executeNonSelectingSQL("CREATE OR REPLACE PACKAGE BODY PLSQL_P AS \n"
+ "PROCEDURE PLSQL_CITY_LIST_IN(P_CITY_LIST IN PLSQL_CITY_LIST, P_CITY IN VARCHAR2) AS \n"
@@ -238,7 +253,16 @@
+ "BEGIN \n"
+ "OPEN P_ADDRESS FOR SELECT * FROM PLSQL_ADDRESS; \n"
+ "END PLSQL_ADDRESS_REC_CUR_OUT; \n"
- + "END PLSQL_P; \n");
+ + "FUNCTION PLSQL_BLOB_REC_IN(P_BLOB_REC IN PLSQL_P_PLSQL_INNER_BLOB_REC, P_CITY IN VARCHAR2) RETURN VARCHAR2 IS \n"
+ + "BEGIN \n"
+ + "RETURN P_CITY || TO_CHAR(P_BLOB_REC.BLOB_ID) || TO_CHAR(DBMS_LOB.GETLENGTH(P_BLOB_REC.BLOB_CONTENT)) || TO_CHAR(P_BLOB_REC.CLOB_CONTENT); \n"
+ + "END PLSQL_BLOB_REC_IN; \n"
+ + "FUNCTION PLSQL_STRUCT_INSTRUCT_REC_IN(P_BLOB_REC IN PLSQL_P_PLSQL_INNER_BLOB_REC, P_STRUCT_REC IN PLSQL_P_PLSQL_OUTER_STRUCT_REC, P_CITY IN VARCHAR2) RETURN VARCHAR2 IS \n"
+ + "BEGIN \n"
+ + "RETURN P_CITY || TO_CHAR(P_BLOB_REC.BLOB_ID) || TO_CHAR(DBMS_LOB.GETLENGTH(P_BLOB_REC.BLOB_CONTENT)) || TO_CHAR(P_STRUCT_REC.STRUCT_ID) || TO_CHAR(DBMS_LOB.GETLENGTH(P_STRUCT_REC.STRUCT_CONTENT.BLOB_CONTENT)) || TO_CHAR(P_BLOB_REC.CLOB_CONTENT); \n"
+ + "END PLSQL_STRUCT_INSTRUCT_REC_IN; \n"
+ + "END PLSQL_P; \n"
+ );
session.executeNonSelectingSQL("CREATE TABLE PLSQL_CONSULTANT ("
+ "EMP_ID NUMBER(10), NAME VARCHAR2(30), ACTIVE NUMBER(1), ADDRESS PLSQL_P_PLSQL_ADDRESS_REC, PHONES PLSQL_P_PLSQL_PHONE_LIST, PRIMARY KEY (EMP_ID))");
}
@@ -466,4 +490,53 @@
closeEntityManagerAndTransaction(em);
}
}
+
+ /**
+ * Test Blob data-type in Struct (SQL Object type) which is passed/used as stored procedure/function parameter.
+ */
+ public void testBlobInStruct() {
+ if (!getServerSession().getPlatform().isOracle()) {
+ return;
+ }
+ EntityManager em = createEntityManager();
+ beginTransaction(em);
+ try {
+ Query query = em.createNamedQuery("PLSQL_BLOB_REC_IN");
+ InnerObjBlob innerObjBlob = new InnerObjBlob(1, Base64.getDecoder().decode("AQI="), "abcd");
+ query.setParameter("P_CITY", "Prague");
+ query.setParameter("P_BLOB_REC", innerObjBlob);
+ Object result = query.getSingleResult();
+ if (!"Prague12abcd".equals(result.toString())) {
+ fail("Incorrect result.");
+ }
+ } finally {
+ closeEntityManagerAndTransaction(em);
+ }
+ }
+
+
+ /**
+ * Test Struct (SQL Object type) with Blob data-type in Struct (SQL Object type) which is passed/used as stored procedure/function parameter.
+ */
+ public void testStructInStruct() {
+ if (!getServerSession().getPlatform().isOracle()) {
+ return;
+ }
+ EntityManager em = createEntityManager();
+ beginTransaction(em);
+ try {
+ Query query = em.createNamedQuery("PLSQL_STRUCT_INSTRUCT_REC_IN");
+ InnerObjBlob innerObjBlob = new InnerObjBlob(1, Base64.getDecoder().decode("AQI="), "abcd");
+ OuterObjBlob outerObjBlob = new OuterObjBlob(33, innerObjBlob);
+ query.setParameter("P_CITY", "Prague");
+ query.setParameter("P_BLOB_REC", innerObjBlob);
+ query.setParameter("P_STRUCT_REC", outerObjBlob);
+ Object result = query.getSingleResult();
+ if (!"Prague1233abcd".equals(result.toString())) {
+ fail("Incorrect result.");
+ }
+ } finally {
+ closeEntityManagerAndTransaction(em);
+ }
+ }
}