Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for %TYPE operator parsing error #1565

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022 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 @@ -47,6 +47,7 @@
import dbws.testing.oxdescriptor.OXDescriptorTestSuite;
import dbws.testing.plsqlcollection.PLSQLCollectionTestSuite;
import dbws.testing.plsqlrecord.PLSQLRecordTestSuite;
import dbws.testing.plsqlrecord.PLSQLTypeReturnTestSuite;
import dbws.testing.plsqlrecord2.PLSQLRecord2TestSuite;
import dbws.testing.prependedpackage.PrependedPackageTestSuite;
import dbws.testing.prependedschema.PrependedSchemaTestSuite;
Expand Down Expand Up @@ -89,6 +90,7 @@
OXDescriptorTestSuite.class,
PLSQLCollectionTestSuite.class,
PLSQLRecordTestSuite.class,
PLSQLTypeReturnTestSuite.class,
PLSQLRecord2TestSuite.class,
PrependedPackageTestSuite.class,
PrependedSchemaTestSuite.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
* Copyright (c) 2022 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 v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - Initial implementation
*/
package dbws.testing.plsqlrecord;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.StringReader;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

//java eXtension imports
import javax.wsdl.WSDLException;

//EclipseLink imports
import org.eclipse.persistence.internal.xr.Invocation;
import org.eclipse.persistence.internal.xr.Operation;
import org.eclipse.persistence.oxm.XMLMarshaller;
//JUnit4 imports
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.w3c.dom.Document;

//test imports
import dbws.testing.DBWSTestSuite;

public class PLSQLTypeReturnTestSuite extends DBWSTestSuite {
static final String EMPREC_TYPE = "TYPE EMP_RECORD_PACKAGE_EMPREC";

static final String CREATE_EMPTYPE_TABLE = "CREATE TABLE EMPTYPEX1 (" + "\nEMPNO NUMERIC(4) NOT NULL,"
+ "\nENAME VARCHAR(25)," + "\nPRIMARY KEY (EMPNO)" + "\n)";
static final String[] POPULATE_EMPTYPE_TABLE = new String[] {
"INSERT INTO EMPTYPEX1 (EMPNO, ENAME) VALUES (69, 'Holly')",
"INSERT INTO EMPTYPEX1 (EMPNO, ENAME) VALUES (70, 'Brooke')",
"INSERT INTO EMPTYPEX1 (EMPNO, ENAME) VALUES (71, 'Patty')" };
static final String DROP_EMPTYPE_TABLE = "DROP TABLE EMPTYPEX1";

static final String CREATE_EMP_RECORD_PACKAGE = "CREATE PACKAGE EMP_RECORD_PACKAGE IS\r\n" +
"FUNCTION get_emp_record(l_empno in number) return EMPTYPEX1.ENAME%TYPE;\r\n" +
"END EMP_RECORD_PACKAGE;";
static final String DROP_EMP_RECORD_PACKAGE = "DROP PACKAGE EMP_RECORD_PACKAGE";

static final String DROP_EMP_RECORD_PACKAGE_BODY = "DROP PACKAGE BODY EMP_RECORD_PACKAGE";

static final String CREATE_EMP_RECORD_PACKAGE_BODY = "create or replace PACKAGE BODY EMP_RECORD_PACKAGE IS\r\n" +
"function get_emp_record(l_empno in number) return EMPTYPEX1.ENAME%TYPE\r\n" +
"is\r\n" +
"ename_result EMPTYPEX1.ENAME%TYPE;\r\n" +
"BEGIN\r\n" +
"SELECT ENAME into ename_result\r\n" +
"FROM EMPTYPEX1\r\n" +
"WHERE \r\n" +
"EMPNO = l_empno;\r\n" +
"return ename_result;\r\n" +
"END;\r\n" +
"END EMP_RECORD_PACKAGE;\r\n";

static boolean ddlCreate = true;
static boolean ddlDrop = true;
static boolean ddlDebug = true;

@BeforeClass
public static void setUp() throws WSDLException {
if (conn == null) {
try {
conn = buildConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
String ddlCreateProp = System.getProperty(DATABASE_DDL_CREATE_KEY, DEFAULT_DATABASE_DDL_CREATE);
if ("true".equalsIgnoreCase(ddlCreateProp)) {
ddlCreate = true;
}
String ddlDropProp = System.getProperty(DATABASE_DDL_DROP_KEY, DEFAULT_DATABASE_DDL_DROP);
if ("true".equalsIgnoreCase(ddlDropProp)) {
ddlDrop = true;
}
String ddlDebugProp = System.getProperty(DATABASE_DDL_DEBUG_KEY, DEFAULT_DATABASE_DDL_DEBUG);
if ("true".equalsIgnoreCase(ddlDebugProp)) {
ddlDebug = true;
}
if (ddlCreate) {
runDdl(conn, CREATE_EMP_RECORD_PACKAGE, ddlDebug);
runDdl(conn, CREATE_EMP_RECORD_PACKAGE_BODY, ddlDebug);
runDdl(conn, CREATE_EMPTYPE_TABLE, ddlDebug);
try {
Statement stmt = conn.createStatement();
for (int i = 0; i < POPULATE_EMPTYPE_TABLE.length; i++) {
stmt.addBatch(POPULATE_EMPTYPE_TABLE[i]);
}
stmt.executeBatch();
} catch (SQLException e) {
if (ddlDebug) {
e.printStackTrace();
}
}
}
DBWS_BUILDER_XML_USERNAME =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<dbws-builder xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
"<properties>" +
"<property name=\"projectName\">PLSQLRecord</property>" +
"<property name=\"logLevel\">on</property>" +
"<property name=\"username\">";
DBWS_BUILDER_XML_PASSWORD =
"</property><property name=\"password\">";
DBWS_BUILDER_XML_URL =
"</property><property name=\"url\">";
DBWS_BUILDER_XML_DRIVER =
"</property><property name=\"driver\">";
DBWS_BUILDER_XML_PLATFORM =
"</property><property name=\"platformClassname\">";
DBWS_BUILDER_XML_MAIN =
"</property>" +
"</properties>" +
"<plsql-procedure " +
"name=\"TestRecWithPercentTypeField\" " +
"catalogPattern=\"EMP_RECORD_PACKAGE\" " +
"procedurePattern=\"get_emp_record\" " +
"/>" +
"</dbws-builder>";

builder = null;
DBWSTestSuite.setUp(".");

// execute shadow type ddl to generate JDBC equivalents of PL/SQL types
ArrayList<String> ddls = new ArrayList<String>();
for (String ddl : builder.getTypeDDL()) {
ddls.add(ddl);
}
// execute the DDLs in order to avoid dependency issues
executeDDLForString(ddls, EMPREC_TYPE);
}

/**
* Execute the DDL in the provided list containing the given DDL string.
*
*/
protected static void executeDDLForString(List<String> ddls, String ddlString) {
for (int i = 0; i < ddls.size(); i++) {
String ddl = ddls.get(i);
if (ddl.contains(ddlString)) {
runDdl(conn, ddl, ddlDebug);
break;
}
}
}

@AfterClass
public static void tearDown() {
if (ddlDrop) {
runDdl(conn, DROP_EMP_RECORD_PACKAGE_BODY, ddlDebug);
runDdl(conn, DROP_EMP_RECORD_PACKAGE, ddlDebug);
runDdl(conn, DROP_EMPTYPE_TABLE, ddlDebug);

// drop shadow type ddl
for (String ddl : builder.getTypeDropDDL()) {
// may need to strip off trailing ';'
try {
int lastIdx = ddl.lastIndexOf(";");
if (lastIdx == (ddl.length() - 1)) {
ddl = ddl.substring(0, ddl.length() - 1);
}
} catch (Exception xxx) {
}
runDdl(conn, ddl, ddlDebug);
}
}
}

@Test
public void testRecWithPercentTypeField() {
Invocation invocation = new Invocation("TestRecWithPercentTypeField");
invocation.setParameter("l_empno", 69);
Operation op = xrService.getOperation(invocation.getName());
System.out.println("XRSERVICE " + xrService);
System.out.println("invocation " + invocation.getName());
System.out.println("op " + invocation.getName());
Object result = op.invoke(xrService, invocation);
assertNotNull("result is null", result);
Document doc = xmlPlatform.createDocument();
XMLMarshaller marshaller = xrService.getXMLContext().createMarshaller();
marshaller.marshal(result, doc);
Document controlDoc = xmlParser.parse(new StringReader(EMPREC_XML));
assertTrue("Expected:\n" + documentToString(controlDoc) + "\nActual:\n" + documentToString(doc),
comparer.isNodeEqual(controlDoc, doc));
}

public static final String EMPREC_XML = "<emp_record_package_emprecType xmlns=\"urn:PLSQLRecord\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
+ "<emp_id>69</emp_id>" + "<emp_name>Holly</emp_name>" + "</emp_record_package_emprecType>";

}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
import static org.eclipse.persistence.tools.dbws.Util.isNullStream;
import static org.eclipse.persistence.tools.dbws.Util.requiresSimpleXMLFormat;
import static org.eclipse.persistence.tools.dbws.Util.sqlMatch;

import org.eclipse.persistence.tools.oracleddl.metadata.DatabaseTypeCompositeTestable;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
Expand Down Expand Up @@ -1313,6 +1313,15 @@ protected org.eclipse.persistence.internal.helper.DatabaseType buildDatabaseType
plsqlCollection.setNestedType(buildDatabaseTypeFromMetadataType(((PLSQLCollectionType) dType).getEnclosedType(), catalog));
return plsqlCollection;
}

if(dType.isTYPEType()) {
OracleArrayType typeType = new OracleArrayType();
typeType.setTypeName(typeName);
typeType.setCompatibleType(compatibleType);
typeType.setJavaTypeName(getGeneratedWrapperClassName(javaTypeName, dbwsBuilder.getProjectName()));
typeType.setNestedType(buildDatabaseTypeFromMetadataType(((TYPEType) dType).getEnclosedType(), null));
return typeType;
}
// handle advanced Oracle types
if (dType.isVArrayType()) {
OracleArrayType varray = new OracleArrayType();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2022 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 @@ -459,6 +459,8 @@ protected Result buildResultForStoredFunction(ArgumentType returnArgument, Strin
rargJdbcType = STRUCT;
} else if (rargDataType.isVArrayType() || rargDataType.isObjectTableType()) {
rargJdbcType = ARRAY;
} else if (rargDataType.isTYPEType()) {
rargJdbcType = Util.getJDBCTypeFromTypeName(returnArgument.getTypeName());
}
} else {
rargJdbcType = Util.getJDBCTypeFromTypeName(returnArgument.getTypeName());
Expand Down Expand Up @@ -1306,6 +1308,23 @@ protected void buildQueryForProcedureType(ProcedureType procType, Project orProj
DatabaseType dataType = returnArg.getEnclosedType();
if (dataType.isVArrayType() || dataType.isObjectTableType()) {
call = new StoredFunctionCall(Types.ARRAY, returnArg.getTypeName(), javaTypeName, buildFieldForNestedType(dataType));
} else if (dataType.isTYPEType()) {
String javaType = dataType.getTypeName();
int resultType = Util.getJDBCTypeFromTypeName(javaType);
call = new StoredFunctionCall();
// need special handling for Date types
if (resultType == Types.DATE || resultType == Types.TIME || resultType == Types.TIMESTAMP) {
((StoredFunctionCall) call).setResult(null, ClassConstants.TIMESTAMP);
} else if (returnArg.getEnclosedType() == ScalarDatabaseTypeEnum.XMLTYPE_TYPE) {
// special handling for XMLType types
((StoredFunctionCall) call).setResult(getJDBCTypeForTypeName(XMLTYPE_STR), XMLTYPE_STR,
ClassConstants.OBJECT);
} else if (resultType == Types.OTHER || resultType == Types.CLOB) {
// default to OBJECT for OTHER, CLOB and LONG types
((StoredFunctionCall) call).setResult(null, ClassConstants.OBJECT);
} else {
((StoredFunctionCall) call).setResult(null, resultType);
}
} else {
// assumes ObjectType
call = new StoredFunctionCall(Types.STRUCT, returnArg.getTypeName(), javaTypeName);
Expand Down Expand Up @@ -1422,6 +1441,8 @@ protected void buildQueryForProcedureType(ProcedureType procType, Project orProj

if (argType.isVArrayType() || argType.isObjectTableType()) {
call.addNamedOutputArgument(arg.getArgumentName(), arg.getArgumentName(), Types.ARRAY, argType.getTypeName(), wrapperClass, buildFieldForNestedType(argType));
} else if (argType.isTYPEType()) {
call.addNamedOutputArgument(arg.getArgumentName(), arg.getArgumentName(), Util.getJDBCTypeFromTypeName(argType.getTypeName()));
} else {
// assumes ObjectType
call.addNamedOutputArgument(arg.getArgumentName(), arg.getArgumentName(), Types.STRUCT, argType.getTypeName(), wrapperClass);
Expand Down