blob: 15055de421d9ab48fffcd6f214f0b5e715855776 [file] [log] [blame]
/*
* 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
* 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:
// Mike Norman - from Proof-of-concept, become production code
package dbws.testing.shadowddlgeneration.oldjpub;
//javase imports
import java.lang.reflect.Modifier;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.List;
//EclipseLink imports
import dbws.testing.shadowddlgeneration.oldjpub.MethodFilter;
import dbws.testing.shadowddlgeneration.oldjpub.PublisherException;
import dbws.testing.shadowddlgeneration.oldjpub.Util;
import dbws.testing.shadowddlgeneration.oldjpub.MethodInfo;
import dbws.testing.shadowddlgeneration.oldjpub.ParamInfo;
import dbws.testing.shadowddlgeneration.oldjpub.ResultInfo;
import dbws.testing.shadowddlgeneration.oldjpub.SingleColumnViewRow;
import dbws.testing.shadowddlgeneration.oldjpub.ViewRow;
public abstract class SqlTypeWithMethods extends SqlTypeWithFields {
public SqlTypeWithMethods(SqlName sqlName, int typecode, boolean generateMe,
SqlType parentType, MethodFilter signatureFilter, SqlReflector reflector)
throws SQLException {
super(sqlName, typecode, generateMe, parentType, reflector);
m_methodFilter = signatureFilter;
}
/**
* Returns an array of Method objects reflecting all the methods declared by this
* SqlTypeWithMethods object. Returns an array of length 0 if the SqlTypeWithMethods declares no
* methods
*/
@Override
public List<ProcedureMethod> getDeclaredMethods() throws SQLException, PublisherException {
if (m_methods == null) {
m_methods = reflectMethods(getSqlName());
}
return m_methods;
}
@Override
public boolean hasMethods() throws SQLException, PublisherException {
List<ProcedureMethod> m = getDeclaredMethods();
return m != null && m.size() > 0;
}
private List<ProcedureMethod> reflectMethods(SqlName sqlName) throws SQLException, PublisherException {
String schema = sqlName.getSchemaName();
String type = sqlName.getTypeName();
ArrayList<ProcedureMethod> methodl = new ArrayList<ProcedureMethod>();
/* get method information */
MethodInfo[] minfo = getMethodInfo(schema, type);
for (int minfoi = 0; minfoi < minfo.length; minfoi++) {
String methodName = minfo[minfoi].methodName;
String methodType = minfo[minfoi].methodType;
String methodNo = minfo[minfoi].methodNo;
int results = minfo[minfoi].results;
int parameters = minfo[minfoi].parameters;
// Pre-approve the method, to avoid unwanted methods during Toplevel publishing.
boolean preApproved = true;
if (m_methodFilter != null) {
preApproved = m_methodFilter.acceptMethod(new ProcedureMethod(methodName, null, -1, null,
null, null, null, null, 0), true);
}
if (!preApproved) {
continue;
}
int modifiers;
modifiers = Modifier.PUBLIC;
if (methodType.equals("MAP")) {
modifiers = modifiers ^ PublisherModifier.MAP;
}
else if (methodType.equals("ORDER")) {
modifiers = modifiers ^ PublisherModifier.ORDER;
}
TypeClass returnType = null;
ResultInfo resultInfo = null;
/* get return type information */
if (results > 0) {
resultInfo = getResultInfo(schema, type, methodName, methodNo);
if (resultInfo != null) {
try {
String resultTypeOwner = resultInfo.resultTypeOwner;
String resultTypeName = resultInfo.resultTypeName;
String resultTypeSubname = resultInfo.resultTypeSubname;
String resultTypeMod = resultInfo.resultTypeMod;
boolean ncharFormOfUse = resultInfo.ncharFormOfUse;
String resultMethodName = resultInfo.methodName;
String resultMethodNo = resultInfo.methodNo;
int sequence = resultInfo.sequence;
returnType = m_reflector.addPlsqlDBType(resultTypeOwner, resultTypeName,
resultTypeSubname, resultTypeMod, ncharFormOfUse, type,
resultMethodName, resultMethodNo, sequence, this);
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
/* get parameter information */
int paramCount = parameters;
List<TypeClass> paramTypes_v = new ArrayList<TypeClass>();
List<String> paramNames_v = new ArrayList<String>();
List<Integer> paramModes_v = new ArrayList<Integer>();
List<Boolean> paramNCharFormOfUse_v = new ArrayList<Boolean>();
int firstNoDefault = -1;
boolean[] paramDefaults = new boolean[paramCount];
if (paramCount > 0) {
ParamInfo[] pinfo = null;
pinfo = getParamInfo(schema, type, methodName, methodNo);
String[] paramTypeOwner = new String[paramCount];
String[] paramName = new String[paramCount];
String[] paramTypeName = new String[paramCount];
String[] paramTypeSubname = new String[paramCount];
String[] paramTypeMod = new String[paramCount];
String[] paramMode = new String[paramCount];
boolean[] mcharFormOfUse = new boolean[paramCount];
String[] paramMethodName = new String[paramCount];
String[] paramMethodNo = new String[paramCount];
int[] sequence = new int[paramCount];
int[] objectId = new int[paramCount];
for (int i = pinfo.length - 1; i >= 0; i--) {
paramTypeOwner[i] = pinfo[i].paramTypeOwner;
paramName[i] = pinfo[i].paramName;
paramTypeName[i] = pinfo[i].paramTypeName;
paramTypeSubname[i] = pinfo[i].paramTypeSubname;
paramTypeMod[i] = pinfo[i].paramTypeMod;
paramMode[i] = pinfo[i].paramMode;
mcharFormOfUse[i] = pinfo[i].ncharFormOfUse;
paramMethodName[i] = pinfo[i].methodName;
paramMethodNo[i] = pinfo[i].methodNo;
sequence[i] = pinfo[i].sequence;
objectId[i] = pinfo[i].objectId;
}
paramDefaults = new boolean[pinfo.length];
for (int i = pinfo.length - 1; i >= 0; i--) {
paramDefaults[i] = hasDefault(objectId[i], paramMethodName[i], sequence[i],
paramMethodNo[i]);
}
for (int i = pinfo.length - 1; i >= 0; i--) {
if (!paramDefaults[i]) {
firstNoDefault = i;
break;
}
}
for (int i = 0; i < paramCount && paramMethodName[i] != null; i++) {
try {
paramNames_v.add(paramName[i]);
String mode = paramMode[i];
paramModes_v.add(Integer.valueOf((mode == null) ? ProcedureMethod.INOUT : (mode
.equals("IN") ? ProcedureMethod.IN : (mode.equals("OUT") ? ProcedureMethod.OUT
: ProcedureMethod.INOUT))));
paramTypes_v.add(m_reflector.addPlsqlDBType(paramTypeOwner[i],
paramTypeName[i], paramTypeSubname[i], paramTypeMod[i],
mcharFormOfUse[i], type, paramMethodName[i], paramMethodNo[i],
sequence[i], this));
paramNCharFormOfUse_v.add(Boolean.valueOf(mcharFormOfUse[i]));
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
int len = paramTypes_v.size();
if (len != paramCount) {
System.err.println("WARNING: incorrect parameter number for method " + methodName
+ ". Expect " + paramCount + " with actual " + len);
}
TypeClass[] paramTypes = new TypeClass[len];
String[] paramNames = new String[len];
int[] paramModes = new int[len];
boolean[] paramNCharFormOfUse = new boolean[len];
for (int i = 0; i < len; i++) {
paramTypes[i] = (paramTypes_v.get(i));
paramNames[i] = paramNames_v.get(i);
paramModes[i] = paramModes_v.get(i).intValue();
paramNCharFormOfUse[i] = paramNCharFormOfUse_v.get(i).booleanValue();
}
paramTypes = generateDefaultArgsHolderParamTypes(paramTypes, paramDefaults,
paramNCharFormOfUse);
ProcedureMethod method = null;
for (int paramLen = firstNoDefault + 1; paramLen <= paramCount; paramLen++) {
if (this instanceof SqlPackageType && returnType != null && resultInfo != null
&& returnType.equals(SqlReflector.REF_CURSOR_TYPE)) {
method = new PlsqlCursorMethod(type, methodName, methodNo, modifiers,
resultInfo.sequence, paramTypes, paramNames, paramModes, paramDefaults,
paramLen, false, m_reflector);
}
else if (this instanceof SqlPackageType) {
method = new PlsqlMethod(methodName, methodNo, modifiers, returnType,
paramTypes, paramNames, paramModes, paramDefaults, paramLen);
}
else {
method = new ProcedureMethod(methodName, methodNo, modifiers, returnType, paramTypes,
paramNames, paramModes, paramDefaults, paramLen);
}
if (acceptMethod(method, false)) {
methodl.add(method);
if (returnType != null && resultInfo != null
&& returnType.equals(SqlReflector.REF_CURSOR_TYPE)) {
method = new PlsqlCursorMethod(type, methodName, methodNo, modifiers,
resultInfo.sequence, paramTypes, paramNames, paramModes, paramDefaults,
paramLen, true, /* returnBeans */
m_reflector);
if (((PlsqlCursorMethod)method).getReturnColCount() != 0) {
methodl.add(method);
}
}
}
}
}
Collections.sort(methodl);
return methodl;
}
protected abstract MethodInfo[] getMethodInfo(String schema, String name) throws SQLException;
protected boolean acceptMethod(ProcedureMethod method, boolean preApprove) {
boolean accept = true;
if (m_methodFilter != null) {
accept = m_methodFilter.acceptMethod(method, preApprove);
}
return accept;
}
protected abstract ResultInfo getResultInfo(String schema, String name, String method,
String methodNo) throws SQLException;
protected abstract ParamInfo[] getParamInfo(String schema, String name, String method,
String methodNo) throws SQLException;
@SuppressWarnings("unused")
protected boolean hasDefault(int object_id, String methodName, int sequence, String overload)
throws SQLException {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
final int objectIdIdx = 1;
final int objectNameIdx = 2;
final int seqIdx = 3;
int hasDefaultInt = 0;
/*
* Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null;
*
* conn = m_reflector.getConnection();
*
* if (overload == null || overload.equals("")) { stmt =conn.prepareStatement(
* "SELECT DEFAULTED FROM ALL_ARGUMENTS WHERE OBJECT_ID=:1 AND OBJECT_NAME=:2 AND SEQUENCE=:3 AND OVERLOAD IS NULL"
* ); } else { stmt =conn.prepareStatement(
* "SELECT DEFAULTED FROM ALL_ARGUMENTS WHERE OBJECT_ID=:1 AND OBJECT_NAME=:2 AND SEQUENCE=:3 AND OVERLOAD='"
* + overload + "'"); } stmt.setInt(objectIdIdx, object_id); stmt.setString(objectNameIdx,
* methodName); stmt.setInt(seqIdx, sequence); try { rs = stmt.executeQuery(); if
* (rs.next()) { String defaulted = rs.getString(1); hasDefaultInt =
* "Y".equalsIgnoreCase(defaulted) ? 1 : 0; }
*/
try {
Iterator<ViewRow> rowIter;
if (overload == null || overload.equals("")) {
rowIter = m_viewCache.getRows(Util.ALL_ARGUMENTS, new String[]{"DEFAULTED"},
new String[]{"OBJECT_ID", "OBJECT_NAME", "SEQUENCE", "OVERLOAD"}, new Object[]{
Integer.valueOf(object_id), methodName, Integer.valueOf(sequence), null},
new String[0]);
}
else {
rowIter = m_viewCache.getRows(Util.ALL_ARGUMENTS, new String[]{"DEFAULTED"},
new String[]{"OBJECT_ID", "OBJECT_NAME", "SEQUENCE", "OVERLOAD"}, new Object[]{
Integer.valueOf(object_id), methodName, Integer.valueOf(sequence), overload},
new String[0]);
}
if (rowIter.hasNext()) {
SingleColumnViewRow row = (SingleColumnViewRow)rowIter.next();
String defaulted = row.getValue();
hasDefaultInt = "Y".equalsIgnoreCase(defaulted) ? 1 : 0;
}
else {
throw new SQLException(
"Pre-10.2 database do not support DEFAULTED in ALL_ARGUMENTS");
}
}
catch (Exception se) { // SQLException: ORA-00904: "DEFAULTED": invalid identifier
// se.printStackTrace();
// conn = m_reflector.getConnection();
try {
// DEFAULTED ONLY EXISTS in Database 10.2
final int oidIdx = 1;
final int methodNameIdx = 2;
final int sequenceIdx = 3;
final int overloadIdx = 4;
/*
* if (stmt != null) { stmt.close(); } if (rs != null) { rs.close(); }
*
* stmt =
* conn.prepareStatement("SELECT SYS.SQLJUTL.HAS_DEFAULT(:1, :2, :3, :4) FROM DUAL"
* ); stmt.setInt(oidIdx, object_id); stmt.setString(methodNameIdx, methodName);
* stmt.setInt(sequenceIdx, sequence); if (overload == null || overload.equals(""))
* { stmt.setInt(overloadIdx, 0); } else { stmt.setInt(overloadIdx,
* Integer.parseInt(overload)); } rs = stmt.executeQuery(); boolean hasNext =
* rs.next(); if (hasNext) { hasDefaultInt = rs.getInt(1); }
*/
String sqljutl = "SYS.SQLJUTL.HAS_DEFAULT(" + object_id + ", " + "'"
+ methodName.toUpperCase() + "', " + sequence + ","
+ ((overload == null || overload.equals("")) ? "0" : overload) + ")";
Iterator<ViewRow> rowIter = m_viewCache.getRows(Util.DUAL, new String[]{sqljutl},
new String[0], new Object[0], new String[0]);
if (rowIter.hasNext()) {
SingleColumnViewRow row = (SingleColumnViewRow)rowIter.next();
if (row.getValue() != null) {
hasDefaultInt = Integer.parseInt(row.getValue());
}
}
}
catch (Exception e8) {
e8.printStackTrace();
System.err
.println("WARNING: please install SYS.SQLJUTL for appropriate treatement of PL/SQL default arguments.");
}
}
finally {
try {
if (stmt != null) {
stmt.close();
}
}
catch (SQLException e) {
// Close resources, ignore exceptions.
}
try {
if (rs != null) {
rs.close();
}
}
catch (SQLException e) {
// Close resources, ignore exceptions.
}
}
if (hasDefaultInt == 1) {
return true;
}
return false;
}
TypeClass[] generateDefaultArgsHolderParamTypes(TypeClass[] paramTypes, boolean[] paramDefaults,
boolean[] ncharFormOfUse) throws SQLException, PublisherException {
TypeClass[] defaultParamTypes = paramTypes;
boolean hasDefault = false;
for (int i = 0; i < paramDefaults.length; i++) {
if (paramDefaults[i]) {
hasDefault = true;
}
}
if (hasDefault) {
defaultParamTypes = new TypeClass[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) {
if (paramDefaults[i]) {
defaultParamTypes[i] = m_reflector.addDefaultArgsHolderType(
(SqlType)paramTypes[i], getSqlName().getSimpleName(), this,
ncharFormOfUse[i]);
}
else {
defaultParamTypes[i] = paramTypes[i];
}
}
}
return defaultParamTypes;
}
protected List<ProcedureMethod> m_methods;
protected MethodFilter m_methodFilter = null;
}