| /* |
| * 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((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(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); |
| paramNCharFormOfUse[i] = paramNCharFormOfUse_v.get(i); |
| } |
| |
| 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[]{ |
| object_id, methodName, 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[]{ |
| object_id, methodName, 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; |
| } |