Skip to content

Commit

Permalink
SQL Struct with @lob (BLOB, CLOB) used as stored procedure parameter …
Browse files Browse the repository at this point in the history
…type - fix (#1339)

Bugfix and unit test.

Signed-off-by: Radek Felcman <radek.felcman@oracle.com>
  • Loading branch information
rfelcman committed Nov 29, 2021
1 parent 26e1fe7 commit fc558d4
Show file tree
Hide file tree
Showing 9 changed files with 380 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2019 IBM Corporation. All rights reserved.
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2021 IBM Corporation. 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
Expand Down Expand Up @@ -3425,6 +3425,16 @@ public Struct createStruct(String structTypeName, Object[] attributes, AbstractS
return createStruct(structTypeName,attributes,unwrappedConnection);
}

/**
* 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.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2018 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
Expand Down Expand Up @@ -181,17 +181,17 @@ public void buildOutDeclare(StringBuilder sb, PLSQLargument outArg) {// Validate
}

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(");");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2018 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
Expand Down Expand Up @@ -340,7 +340,7 @@ public Struct buildStructureFromRow(AbstractRecord row, AbstractSession session,
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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
* Copyright (c) 2019 IBM Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -641,12 +641,12 @@ protected void buildDeclareBlock(StringBuilder sb, List<PLSQLargument> arguments
* must be added in inverse order to resolve dependencies.
*/
protected void addNestedFunctionsForArgument(List functions, PLSQLargument argument,
DatabaseType databaseType, Set<DatabaseType> processed) {
DatabaseType databaseType, Set<DatabaseType> processed) {
if ((databaseType == null)
|| !databaseType.isComplexDatabaseType()
|| databaseType.isJDBCType()
|| argument.cursorOutput
|| processed.contains(databaseType)) {
|| !databaseType.isComplexDatabaseType()
|| databaseType.isJDBCType()
|| argument.cursorOutput
|| processed.contains(databaseType)) {
return;
}
ComplexDatabaseType type = (ComplexDatabaseType)databaseType;
Expand All @@ -670,20 +670,26 @@ protected void addNestedFunctionsForArgument(List functions, PLSQLargument argum
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);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2018 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
Expand All @@ -16,6 +16,19 @@
// - 426852: @GeneratedValue(strategy=GenerationType.IDENTITY) support in Oracle 12c
package org.eclipse.persistence.platform.database.oracle;

import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Struct;
import java.util.Vector;

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;

/**
* <p><b>Purpose:</b>
* Supports usage of certain Oracle JDBC specific APIs for the Oracle 12 database.
Expand All @@ -24,4 +37,42 @@ public class Oracle12Platform extends Oracle11Platform {
public Oracle12Platform() {
super();
}

/**
* 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 createStruct(structTypeName, attributes, connection);
}

/**
* Create java.sql.Struct from given parameters.
* @param structTypeName - the SQL type name of the SQL structured type that this Struct object maps to.
* @param attributes - the attributes that populate the returned object
* @param connection - DB connection
* @return Struct
*/
@Override
public Struct createStruct(String structTypeName, Object[] attributes, Connection connection) throws SQLException {
return connection.createStruct(structTypeName, attributes);
}
}
Original file line number Diff line number Diff line change
@@ -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 javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.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 + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -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 javax.persistence.Column;
import javax.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 +
'}';
}
}
Loading

0 comments on commit fc558d4

Please sign in to comment.