blob: 2aafc433154d577b3de3d530cc1a87ae87100bab [file] [log] [blame]
/*
* Copyright (c) 2013, 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:
// David McCann - 2.6.0 - July 09, 2013 - Initial Implementation
package org.eclipse.persistence.tools.metadata.generation;
import static org.eclipse.persistence.platform.database.oracle.plsql.OraclePLSQLTypes.XMLType;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.persistence.internal.core.helper.CoreClassConstants;
import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.tools.oracleddl.metadata.DatabaseType;
import org.eclipse.persistence.tools.oracleddl.metadata.FieldType;
import org.eclipse.persistence.tools.oracleddl.metadata.NumericType;
import org.eclipse.persistence.tools.oracleddl.metadata.PLSQLCursorType;
import org.eclipse.persistence.tools.oracleddl.metadata.PLSQLType;
import org.eclipse.persistence.tools.oracleddl.metadata.ProcedureType;
import org.eclipse.persistence.tools.oracleddl.metadata.SizedType;
/**
* Utility class typically used when constructing JPA/JAXB metadata from a
* list of meta-model database types.
*
*/
public class Util {
public static final String ARRAY_STR = "ARRAY";
public static final String BIGINT_STR = "BIGINT";
public static final String BINARY_STR = "BINARY";
public static final String BLOB_STR = "BLOB";
public static final String BOOLEAN_STR = "BOOLEAN";
public static final String CHAR_STR = "CHAR";
public static final String CLOB_STR = "CLOB";
public static final String DATE_STR = "DATE";
public static final String DECIMAL_STR = "DECIMAL";
public static final String DOUBLE_STR = "DOUBLE";
public static final String FLOAT_STR = "FLOAT";
public static final String INTEGER_STR = "INTEGER";
public static final String LONG_STR = "LONG";
public static final String LONGRAW_STR = "LONG RAW";
public static final String LONGVARBINARY_STR = "LONGVARBINARY";
public static final String NCHAR_STR = "NCHAR";
public static final String NCLOB_STR = "NCLOB";
public static final String NUMBER_STR = "NUMBER";
public static final String NUMERIC_STR = "NUMERIC";
public static final String NVARCHAR_STR = "NVARCHAR";
public static final String NVARCHAR2_STR = "NVARCHAR2";
public static final String OTHER_STR = "OTHER";
public static final String RAW_STR = "RAW";
public static final String REAL_STR = "REAL";
public static final String ROWID_STR = "ROWID";
public static final String ROWTYPE_STR = "%ROWTYPE";
public static final String SMALLINT_STR = "SMALLINT";
public static final String STRUCT_STR = "STRUCT";
public static final String TIME_STR = "TIME";
public static final String TIMESTAMP_STR = "TIMESTAMP";
public static final String TINYINT_STR = "TINYINT";
public static final String UROWID_STR = "UROWID";
public static final String VARBINARY_STR = "VARBINARY";
public static final String VARCHAR_STR = "VARCHAR";
public static final String VARCHAR2_STR = "VARCHAR2";
public static final String BINARY_INTEGER_STR = "BINARY_INTEGER";
public static final String PLS_INTEGER_STR = "PLS_INTEGER";
public static final String NATURAL_STR = "NATURAL";
public static final String POSITIVE_STR = "POSITIVE";
public static final String SIGNTYPE_STR = "SIGNTYPE";
public static final String BINARY_INTEGER_TYPE_STR = "BinaryInteger";
public static final String PLS_BOOLEAN_TYPE_STR = "PLSQLBoolean";
public static final String PLS_INTEGER_TYPE_STR = "PLSQLInteger";
public static final String NATURAL_TYPE_STR = "Natural";
public static final String POSITIVE_TYPE_STR = "Positive";
public static final String SIGNTYPE_TYPE_STR = "SignType";
public static final String SYS_XMLTYPE_STR = "SYS.XMLTYPE";
public static final String XMLTYPE_STR = "XMLTYPE";
public static final String _TYPE_STR = "_TYPE";
public static final String COMMA = ",";
public static final String SINGLE_SPACE = " ";
public static final String COMMA_SPACE_STR = COMMA + SINGLE_SPACE;
// for CRUD operations
public static final String ALL_QUERYNAME = "findAll";
public static final String PK_QUERYNAME = "findByPrimaryKey";
public static final String CREATE_OPERATION_NAME = "create";
public static final String UPDATE_OPERATION_NAME = "update";
public static final String REMOVE_OPERATION_NAME = "delete";
public static final String OPEN_BRACKET = "(";
public static final String CLOSE_BRACKET = ")";
public static final String TYPE_STR = "Type";
public static final String SELECT_FROM_STR = "SELECT * FROM ";
public static final String WHERE_STR = " WHERE ";
public static final String AND_STR = " AND ";
public static final String SET_STR = " SET ";
public static final String VALUES_STR = " VALUES ";
public static final String UPDATE_STR = "UPDATE ";
public static final String INSERT_STR = "INSERT INTO ";
public static final String DELETE_STR = "DELETE FROM ";
public static final String EQUALS_BINDING1_STR = " = ?1";
public static final String EQUALS_BINDING_STR = " = ?";
public static final String QUESTION_STR = "?";
// SQL class names
public static final String ARRAY_CLS_STR = "java.sql.Array";
public static final String NCLOB_CLS_STR = "java.sql.NClob";
public static final String OPAQUE_CLS_STR = "java.sql.Struct";
public static final String ROWID_CLS_STR = "java.sql.RowId";
public static final String STRUCT_CLS_STR = "oracle.sql.OPAQUE";
public static final String ORACLE_TIMESTAMP_CLS_STR = "oracle.sql.TIMESTAMP";
// JDK class names
static final String ARRAYLIST_CLS_STR = "java.util.ArrayList";
// direction types
static final String IN_STR = "IN";
static final String INOUT_STR = "IN_OUT";
static final String OUT_STR = "OUT";
static final String OUT_CURSOR_STR = "OUT_CURSOR";
static final String CURSOR_STR = "CURSOR";
static final String RESULT_STR = "RESULT";
// misc
public static final String DOT = ".";
public static final String PERCENT = "%";
public static final String UNDERSCORE = "_";
public static final String ITEMS_FLD_STR = "items";
public static final String ITEMS_COL_STR = "ITEMS";
public static final int OPAQUE = 2007;
/**
* Returns a unqualified entity class name based on a given table or type name.
* The returned string will contain an upper case first char, with the
* remaining chars in lower case format.
*/
public static String getUnqualifiedEntityName(String tableName) {
String first = tableName.substring(0, 1).toUpperCase();
String rest = tableName.toLowerCase().substring(1);
return first.concat(rest);
}
/**
* Returns a entity class name based on a given table or type name. The returned
* string will contain an upper case first char, with the remaining chars in
* lower case format. The packageName will be prepended to the Entity name
* if non-null.
*/
public static String getEntityName(String tableName, String packageName) {
String entityName = getUnqualifiedEntityName(tableName);
return packageName == null ? entityName : packageName + DOT + entityName;
}
/**
* Return the JDBC type name for a given type String.
*/
public static String getJDBCTypeName(String typeName) {
// this is inefficient and should be rewritten such that checking is done once only
return getJDBCTypeNameFromType(getJDBCTypeFromTypeName(typeName));
}
/**
* Return the JDBC type (as int) for a given type name.
*/
public static int getJDBCTypeFromTypeName(String typeName) {
if (typeName.equals(NUMERIC_STR)) {
return Types.NUMERIC;
}
if (typeName.equals(VARCHAR_STR) || typeName.equals(VARCHAR2_STR)) {
return Types.VARCHAR;
}
if (typeName.equals(NVARCHAR_STR) || typeName.equals(NVARCHAR2_STR)) {
return Types.NVARCHAR;
}
if (typeName.equals(DATE_STR)) {
return Types.DATE;
}
if (typeName.equals(TIME_STR)) {
return Types.TIME;
}
if (typeName.equals(TIMESTAMP_STR)) {
return Types.TIMESTAMP;
}
if (typeName.equals(DECIMAL_STR)) {
return Types.DECIMAL;
}
if (typeName.equals(INTEGER_STR)) {
return Types.INTEGER;
}
if (typeName.equals(CHAR_STR)) {
return Types.CHAR;
}
if (typeName.equals(NCHAR_STR)) {
return Types.NCHAR;
}
if (typeName.equals(FLOAT_STR)) {
return Types.FLOAT;
}
if (typeName.equals(REAL_STR)) {
return Types.REAL;
}
if (typeName.equals(DOUBLE_STR)) {
return Types.DOUBLE;
}
if (typeName.equals(BINARY_STR)) {
return Types.BINARY;
}
if (typeName.equals(BLOB_STR)) {
return Types.BLOB;
}
if (typeName.equals(CLOB_STR) ||
typeName.equals(LONG_STR)) {
return Types.CLOB;
}
if (typeName.equals(NCLOB_STR)) {
return Types.NCLOB;
}
if (typeName.equals(RAW_STR) ||
typeName.equals(LONGRAW_STR)) {
return Types.LONGVARBINARY;
}
if (typeName.equals(ROWID_STR)) {
return Types.VARCHAR;
}
if (typeName.equals(UROWID_STR)) {
return Types.VARCHAR;
}
if (typeName.equals(BIGINT_STR)) {
return Types.BIGINT;
}
if (typeName.equals(STRUCT_STR)) {
return Types.STRUCT;
}
if (typeName.equals(ARRAY_STR)) {
return Types.ARRAY;
}
if (typeName.equals(ROWID_STR)) {
return Types.ROWID;
}
if (typeName.equalsIgnoreCase(XMLTYPE_STR) ||
typeName.equalsIgnoreCase(SYS_XMLTYPE_STR)) {
return Types.VARCHAR;
}
if (typeName.equals(BOOLEAN_STR) ||
typeName.equals(INTEGER_STR) ||
typeName.equals(SMALLINT_STR) ||
typeName.equals(TINYINT_STR)) {
return Types.INTEGER;
}
return Types.OTHER;
}
/**
* Return the JDBC type name for a given JDBC type code.
*/
public static String getJDBCTypeNameFromType(int jdbcType) {
String typeName = null;
switch (jdbcType) {
case Types.NUMERIC:
typeName = NUMERIC_STR;
break;
case Types.VARCHAR:
typeName = VARCHAR_STR;
break;
case Types.NVARCHAR:
typeName = NVARCHAR_STR;
break;
case Types.DECIMAL:
typeName = DECIMAL_STR;
break;
case Types.CHAR:
typeName = CHAR_STR;
break;
case Types.NCHAR:
typeName = NCHAR_STR;
break;
case Types.FLOAT:
typeName = FLOAT_STR;
break;
case Types.REAL:
typeName = REAL_STR;
break;
case Types.DOUBLE:
typeName = DOUBLE_STR;
break;
case Types.BINARY:
typeName = BINARY_STR;
break;
case Types.BLOB:
typeName = BLOB_STR;
break;
case Types.CLOB:
typeName = CLOB_STR;
break;
case Types.NCLOB:
typeName = NCLOB_STR;
break;
case Types.VARBINARY :
typeName = LONGVARBINARY_STR;
break;
case Types.LONGVARBINARY:
typeName = LONGVARBINARY_STR;
break;
case Types.DATE:
typeName = DATE_STR;
break;
case Types.TIME:
typeName = TIME_STR;
break;
case Types.TIMESTAMP:
typeName = TIMESTAMP_STR;
break;
case Types.BIGINT:
typeName = BIGINT_STR;
break;
case Types.ARRAY:
typeName = ARRAY_STR;
break;
case Types.STRUCT:
typeName = STRUCT_STR;
break;
case Types.ROWID:
typeName = ROWID_STR;
break;
default:
typeName = OTHER_STR;
break;
}
return typeName;
}
/**
* Return the Class name for a given type name using the provided DatabasePlatform.
* Object.class.getName() will be returned if the DatabasePlatform returns null.
*/
public static String getClassNameFromJDBCTypeName(String typeName, DatabasePlatform databasePlatform) {
return getClassFromJDBCTypeName(typeName, databasePlatform).getName();
}
/**
* Return the Class for a given type name using the provided DatabasePlatform. Object.class will
* be returned if the DatabasePlatform returns null.
*/
public static Class<?> getClassFromJDBCTypeName(String typeName, DatabasePlatform databasePlatform) {
Class<?> clz = databasePlatform.getClassTypes().get(typeName);
if (clz == null) {
return CoreClassConstants.OBJECT;
}
return clz;
}
/**
* Alter the given type name if required.
*/
protected static String processTypeName(String typeName) {
if (!(getJDBCTypeFromTypeName(typeName) == Types.OTHER)) {
if (typeName.equals(XMLTYPE_STR)) {
typeName = XMLType.name();
} else {
// OR Metadata doesn't handle VARCHAR2
if (typeName.equals(VARCHAR2_STR)) {
typeName = VARCHAR_STR;
}
// for BOOLEAN we want to wrap the type in a PLSQLrecord (in ORMetadata.getDatabaseTypeEnum) to
// force the appropriate conversion method in PLSQLStoredProcedureCall (declare block, etc)
if (!typeName.equals(BOOLEAN_STR)) {
typeName = typeName.concat(_TYPE_STR);
}
}
} else {
String oPLSQLTypeName = getOraclePLSQLTypeForName(typeName);
if (oPLSQLTypeName != null) {
typeName = oPLSQLTypeName;
}
}
return typeName;
}
/**
* Returns a Java class name based on a given qualified name. If the name has
* a package prepended to it, the the returned string will be in the format
* 'packagename.Name', otherwise the format will be 'Name'. For example, given
* the name 'test.EMPLOYEE', the method would return the string 'test.Employee'.
*
*/
public static String getGeneratedJavaClassName(String name) {
int dotIdx = name.lastIndexOf(DOT);
if (dotIdx == -1) {
// no package
return getGeneratedJavaClassName(name, null);
}
String packageName = name.substring(0, dotIdx).toLowerCase();
String typeName = name.substring(dotIdx + 1);
String first = typeName.substring(0, 1).toUpperCase();
String rest = typeName.toLowerCase().substring(1);
return packageName + DOT + first + rest;
}
/**
* Returns a Java class name based on a given name and package. The returned
* string will be in the format 'packagename.Name'. For example, given
* the name 'EMPLOYEE' and packageName 'TEST', the method would return the
* string 'test.Employee'.
*
*/
public static String getGeneratedJavaClassName(String name, String packageName) {
String first = name.substring(0, 1).toUpperCase();
String rest = name.toLowerCase().substring(1);
return packageName == null || packageName.length() == 0 ? first + rest : packageName.toLowerCase() + DOT + first + rest;
}
/**
* Return a qualified type name for the given DatabaseType. If the type is a
* PLSQLType or a PLSQLCursor, and there is a package name available on the
* type's parent, a string will be returned in the format 'package.typename'.
* Otherwise the type name will be returned.
*/
public static String getQualifiedTypeName(DatabaseType dbType) {
if (dbType.isPLSQLType()) {
String packageName = ((PLSQLType) dbType).getParentType().getPackageName();
// for %ROWTYPE we build a record with no package name - need to check for null
return packageName != null ? packageName + DOT + dbType.getTypeName() : dbType.getTypeName();
}
if (dbType.isPLSQLCursorType()) {
// handle cursor
PLSQLCursorType cursor = ((PLSQLCursorType) dbType);
return cursor.getParentType().getPackageName() + DOT + cursor.getCursorName();
}
return dbType.getTypeName();
}
/**
* Return a qualified compatible type name for the given DatabaseType. If the type is a
* PLSQLType, and there is a package name available on the type's parent, a string will
* be returned in the format 'package_typename'. Otherwise the type name will be
* returned. A compatible type is the JDBC type equivalent of a PL/SQL type.
*/
public static String getQualifiedCompatibleTypeName(DatabaseType dbType) {
String packageName = null;
if (dbType.isPLSQLType()) {
PLSQLType plsqlType = (PLSQLType) dbType;
packageName = plsqlType.getParentType().getPackageName();
}
return packageName != null ? packageName + UNDERSCORE + dbType.getTypeName() : dbType.getTypeName();
}
/**
* Indicates if a given argument type name is considered a PL/SQL scalar
* argument, i.e. is one of BOOLEAN, BINARY_INTEGER, PLS_INTEGER, etc.
*/
public static boolean isArgPLSQLScalar(String argTypeName) {
return argTypeName.equals("BOOLEAN")
|| argTypeName.equals("PLS_INTEGER")
|| argTypeName.equals("BINARY_INTEGER")
|| argTypeName.equals("NATURAL")
|| argTypeName.equals("POSITIVE")
|| argTypeName.equals("SIGNTYPE");
}
/**
* Return the Oracle PL/SQL name for a given PL/SQL scalar type.
*/
public static String getOraclePLSQLTypeForName(String typeName) {
if (typeName.equals(BINARY_INTEGER_STR))
return BINARY_INTEGER_TYPE_STR;
if (typeName.equals(BOOLEAN_STR))
return PLS_BOOLEAN_TYPE_STR;
if (typeName.equals(PLS_INTEGER_STR))
return PLS_INTEGER_TYPE_STR;
if (typeName.equals(NATURAL_STR))
return NATURAL_TYPE_STR;
if (typeName.equals(POSITIVE_STR))
return POSITIVE_TYPE_STR;
if (typeName.equals(SIGNTYPE_STR))
return SIGNTYPE_TYPE_STR;
return null;
}
/**
* Return the attribute-type name for a given FieldType.
*
* For CHAR sized type, java.lang.Character will be returned.
* For CHAR non-sized type, java.lang.String will be returned.
* For non-CHAR type, the database platform will be used to get the type name.
* If the type to be returned is oracle.sql.Timestamp, java.sql.Timestamp will be
* returned instead (to handle conversion issue with Oracle11Platform)
*/
protected static String getAttributeTypeNameForFieldType(FieldType fldType, DatabasePlatform dbPlatform) {
String typeName = getJDBCTypeName(fldType.getTypeName());
String attributeType;
if (CHAR_STR.equalsIgnoreCase(typeName) && fldType.getEnclosedType().isSizedType()) {
SizedType sizedType = (SizedType) fldType.getEnclosedType();
if (sizedType.getSize() == 1) {
attributeType = ClassConstants.CHAR.getName();
} else {
attributeType = ClassConstants.STRING.getName();
}
} else {
attributeType = getClassNameFromJDBCTypeName(typeName.toUpperCase(), dbPlatform);
}
// handle issue with java.sql.Timestamp conversion and Oracle11 platform
if (attributeType.contains(ORACLE_TIMESTAMP_CLS_STR)) {
attributeType = ClassConstants.TIMESTAMP.getName();
} else if (attributeType.contains(ClassConstants.ABYTE.getName())) {
attributeType = ClassConstants.APBYTE.getName();
}
return attributeType;
}
/**
* Return the type name to be used for a given database type. The given
* DatabaseType's typeName attribute is typically returned, however, in
* some cases special handling may be required. For example, in the
* case of a NumericType instance, "DECIMAL" should be used for the
* type name.
*/
protected static String getTypeNameForDatabaseType(DatabaseType dataType) {
String typeName = dataType.getTypeName();
if (dataType.isNumericType()) {
NumericType numericDataType = (NumericType)dataType;
if (numericDataType.getScale() > 0) {
typeName = DECIMAL_STR;
}
}
return typeName;
}
/**
* Convenience method that detects multiple procedures with the same procedure
* name, and updates the overload value on the relevant ProcedureTypes
* accordingly.
*
* The first ProcedureType will have an overload value of 0, the second 1,
* and so on.
*/
protected static void handleOverloading(List<ProcedureType> procedures) {
Map<String, List<ProcedureType>> overloadMap = new HashMap<String, List<ProcedureType>>();
for (ProcedureType procedure : procedures) {
String procedureName = procedure.getProcedureName();
List<ProcedureType> multipleProcedures = overloadMap.get(procedureName);
if (multipleProcedures == null) {
multipleProcedures = new ArrayList<ProcedureType>();
overloadMap.put(procedureName, multipleProcedures);
}
multipleProcedures.add(procedure);
}
for (List<ProcedureType> procs : overloadMap.values()) {
if (procs.size() > 1) {
for (int i = 0, len = procs.size(); i < len; i++) {
procs.get(i).setOverload(i);
}
}
}
}
}