提交 35ebcbe1 编写于 作者: sq3536's avatar sq3536

提交

上级 1a7808a1
package liquibase.database.core;
import liquibase.CatalogAndSchema;
import liquibase.Scope;
import liquibase.database.AbstractJdbcDatabase;
import liquibase.database.DatabaseConnection;
import liquibase.database.OfflineConnection;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.exception.ValidationErrors;
import liquibase.executor.ExecutorService;
import liquibase.logging.LogService;
import liquibase.logging.LogType;
import liquibase.statement.DatabaseFunction;
import liquibase.statement.SequenceCurrentValueFunction;
import liquibase.statement.SequenceNextValueFunction;
import liquibase.statement.core.RawCallStatement;
import liquibase.statement.core.RawSqlStatement;
import liquibase.structure.DatabaseObject;
import liquibase.structure.core.Catalog;
import liquibase.structure.core.Index;
import liquibase.structure.core.PrimaryKey;
import liquibase.structure.core.Schema;
import liquibase.util.JdbcUtils;
import liquibase.util.StringUtils;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.util.ResourceBundle.getBundle;
/**
* Encapsulates Oracle database support.
*/
public class OracleDatabase extends AbstractJdbcDatabase {
private static final Pattern PROXY_USER = Pattern.compile(".*(?:thin|oci)\\:(.+)/@.*");
public static final String PRODUCT_NAME = "oracle";
private static ResourceBundle coreBundle = getBundle("liquibase/i18n/liquibase-core");
protected final int SHORT_IDENTIFIERS_LENGTH = 30;
protected final int LONG_IDENTIFIERS_LEGNTH = 128;
public static final int ORACLE_12C_MAJOR_VERSION = 12;
private Set<String> reservedWords = new HashSet<>();
private Set<String> userDefinedTypes;
private Map<String, String> savedSessionNlsSettings;
private Boolean canAccessDbaRecycleBin;
private Integer databaseMajorVersion;
private Integer databaseMinorVersion;
/**
* Default constructor for an object that represents the Oracle Database DBMS.
*/
public OracleDatabase() {
super.unquotedObjectsAreUppercased = true;
//noinspection HardCodedStringLiteral
super.setCurrentDateTimeFunction("SYSTIMESTAMP");
// Setting list of Oracle's native functions
//noinspection HardCodedStringLiteral
dateFunctions.add(new DatabaseFunction("SYSDATE"));
//noinspection HardCodedStringLiteral
dateFunctions.add(new DatabaseFunction("SYSTIMESTAMP"));
//noinspection HardCodedStringLiteral
dateFunctions.add(new DatabaseFunction("CURRENT_TIMESTAMP"));
//noinspection HardCodedStringLiteral
super.sequenceNextValueFunction = "%s.nextval";
//noinspection HardCodedStringLiteral
super.sequenceCurrentValueFunction = "%s.currval";
}
@Override
public int getPriority() {
return PRIORITY_DEFAULT;
}
private final void tryProxySessionn(final String url, final Connection con) {
Matcher m = PROXY_USER.matcher(url);
if (m.matches()) {
Properties props = new Properties();
props.put("PROXY_USER_NAME", m.group(1));
try {
Method method = con.getClass().getMethod("openProxySession", int.class, Properties.class);
method.setAccessible(true);
method.invoke(con, 1, props);
} catch (Exception e) {
Scope.getCurrentScope().getLog(getClass()).info(LogType.LOG, "Could not open proxy session on OracleDatabase: " + e.getCause().getMessage());
}
}
}
@Override
public void setConnection(DatabaseConnection conn) {
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,
// HardCodedStringLiteral
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,
// HardCodedStringLiteral
reservedWords.addAll(Arrays.asList("GROUP", "USER", "SESSION", "PASSWORD", "RESOURCE", "START", "SIZE", "UID", "DESC", "ORDER")); //more reserved words not returned by driver
Connection sqlConn = null;
if (!(conn instanceof OfflineConnection)) {
try {
/*
* Don't try to call getWrappedConnection if the conn instance is
* is not a JdbcConnection. This happens for OfflineConnection.
* see https://liquibase.jira.com/browse/CORE-2192
*/
if (conn instanceof JdbcConnection) {
sqlConn = ((JdbcConnection) conn).getWrappedConnection();
}
} catch (Exception e) {
throw new UnexpectedLiquibaseException(e);
}
if (sqlConn != null) {
tryProxySessionn(conn.getURL(), sqlConn);
try {
//noinspection HardCodedStringLiteral
reservedWords.addAll(Arrays.asList(sqlConn.getMetaData().getSQLKeywords().toUpperCase().split(",\\s*")));
} catch (SQLException e) {
//noinspection HardCodedStringLiteral
LogService.getLog(getClass()).info(LogType.LOG, "Could get sql keywords on OracleDatabase: " + e.getMessage());
//can not get keywords. Continue on
}
try {
Method method = sqlConn.getClass().getMethod("setRemarksReporting", Boolean.TYPE);
method.setAccessible(true);
method.invoke(sqlConn, true);
} catch (Exception e) {
//noinspection HardCodedStringLiteral
LogService.getLog(getClass()).info(LogType.LOG, "Could not set remarks reporting on OracleDatabase: " + e.getMessage());
//cannot set it. That is OK
}
Statement statement = null;
ResultSet resultSet = null;
try {
statement = sqlConn.createStatement();
//noinspection HardCodedStringLiteral
resultSet = statement.executeQuery("SELECT value FROM v$parameter WHERE name = 'compatible'");
String compatibleVersion = null;
if (resultSet.next()) {
//noinspection HardCodedStringLiteral
compatibleVersion = resultSet.getString("value");
}
if (compatibleVersion != null) {
Matcher majorVersionMatcher = Pattern.compile("(\\d+)\\.(\\d+)\\..*").matcher(compatibleVersion);
if (majorVersionMatcher.matches()) {
this.databaseMajorVersion = Integer.valueOf(majorVersionMatcher.group(1));
this.databaseMinorVersion = Integer.valueOf(majorVersionMatcher.group(2));
}
}
} catch (SQLException e) {
@SuppressWarnings("HardCodedStringLiteral") String message = "Cannot read from v$parameter: " + e.getMessage();
//noinspection HardCodedStringLiteral
LogService.getLog(getClass()).info(LogType.LOG, "Could not set check compatibility mode on OracleDatabase, assuming not running in any sort of compatibility mode: " + message);
} finally {
JdbcUtils.close(resultSet, statement);
}
}
}
super.setConnection(conn);
}
@Override
public String getShortName() {
//noinspection HardCodedStringLiteral
return "oracle";
}
@Override
protected String getDefaultDatabaseProductName() {
//noinspection HardCodedStringLiteral
return "Oracle";
}
@Override
public int getDatabaseMajorVersion() throws DatabaseException {
if (databaseMajorVersion == null) {
return super.getDatabaseMajorVersion();
} else {
return databaseMajorVersion;
}
}
@Override
public int getDatabaseMinorVersion() throws DatabaseException {
if (databaseMinorVersion == null) {
return super.getDatabaseMinorVersion();
} else {
return databaseMinorVersion;
}
}
@Override
public Integer getDefaultPort() {
return 1521;
}
@Override
public String getJdbcCatalogName(CatalogAndSchema schema) {
return null;
}
@Override
public String getJdbcSchemaName(CatalogAndSchema schema) {
return correctObjectName((schema.getCatalogName() == null) ? schema.getSchemaName() : schema.getCatalogName(), Schema.class);
}
@Override
protected String getAutoIncrementClause(final String generationType, final Boolean defaultOnNull) {
if (StringUtils.isEmpty(generationType)) {
return "";
}
String autoIncrementClause = "GENERATED %s AS IDENTITY"; // %s -- [ ALWAYS | BY DEFAULT [ ON NULL ] ]
String generationStrategy = generationType;
if (Boolean.TRUE.equals(defaultOnNull) && generationType.toUpperCase().equals("BY DEFAULT")) {
generationStrategy += " ON NULL";
}
return String.format(autoIncrementClause, generationStrategy);
}
@Override
public String generatePrimaryKeyName(String tableName) {
if (tableName.length() > 27) {
//noinspection HardCodedStringLiteral
return "PK_" + tableName.toUpperCase(Locale.US).substring(0, 27);
} else {
//noinspection HardCodedStringLiteral
return "PK_" + tableName.toUpperCase(Locale.US);
}
}
@Override
public boolean supportsInitiallyDeferrableColumns() {
return true;
}
@Override
public boolean isReservedWord(String objectName) {
return reservedWords.contains(objectName.toUpperCase());
}
@Override
public boolean supportsSequences() {
return true;
}
/**
* Oracle supports catalogs in liquibase terms
*
* @return false
*/
@Override
public boolean supportsSchemas() {
return false;
}
@Override
protected String getConnectionCatalogName() throws DatabaseException {
if (getConnection() instanceof OfflineConnection) {
return getConnection().getCatalog();
}
try {
//noinspection HardCodedStringLiteral
return ExecutorService.getInstance().getExecutor(this).queryForObject(new RawCallStatement("select sys_context( 'userenv', 'current_schema' ) from dual"), String.class);
} catch (Exception e) {
//noinspection HardCodedStringLiteral
LogService.getLog(getClass()).info(LogType.LOG, "Error getting default schema", e);
}
return null;
}
@Override
public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException {
return PRODUCT_NAME.equalsIgnoreCase(conn.getDatabaseProductName())||conn.getDatabaseProductName().equals("DM DBMS"); //遇到达梦则使用oracle模式
}
@Override
public String getDefaultDriver(String url) {
//noinspection HardCodedStringLiteral
if (url.startsWith("jdbc:oracle")) {
return "oracle.jdbc.OracleDriver";
}
return null;
}
@Override
public String getDefaultCatalogName() {//NOPMD
return (super.getDefaultCatalogName() == null) ? null : super.getDefaultCatalogName().toUpperCase(Locale.US);
}
/**
* <p>Returns an Oracle date literal with the same value as a string formatted using ISO 8601.</p>
*
* <p>Convert an ISO8601 date string to one of the following results:
* to_date('1995-05-23', 'YYYY-MM-DD')
* to_date('1995-05-23 09:23:59', 'YYYY-MM-DD HH24:MI:SS')</p>
* <p>
* Implementation restriction:<br>
* Currently, only the following subsets of ISO8601 are supported:<br>
* <ul>
* <li>YYYY-MM-DD</li>
* <li>YYYY-MM-DDThh:mm:ss</li>
* </ul>
*/
@Override
public String getDateLiteral(String isoDate) {
String normalLiteral = super.getDateLiteral(isoDate);
if (isDateOnly(isoDate)) {
StringBuffer val = new StringBuffer();
//noinspection HardCodedStringLiteral
val.append("TO_DATE(");
val.append(normalLiteral);
//noinspection HardCodedStringLiteral
val.append(", 'YYYY-MM-DD')");
return val.toString();
} else if (isTimeOnly(isoDate)) {
StringBuffer val = new StringBuffer();
//noinspection HardCodedStringLiteral
val.append("TO_DATE(");
val.append(normalLiteral);
//noinspection HardCodedStringLiteral
val.append(", 'HH24:MI:SS')");
return val.toString();
} else if (isTimestamp(isoDate)) {
StringBuffer val = new StringBuffer(26);
//noinspection HardCodedStringLiteral
val.append("TO_TIMESTAMP(");
val.append(normalLiteral);
//noinspection HardCodedStringLiteral
val.append(", 'YYYY-MM-DD HH24:MI:SS.FF')");
return val.toString();
} else if (isDateTime(isoDate)) {
int seppos = normalLiteral.lastIndexOf('.');
if (seppos != -1) {
normalLiteral = normalLiteral.substring(0, seppos) + "'";
}
StringBuffer val = new StringBuffer(26);
//noinspection HardCodedStringLiteral
val.append("TO_DATE(");
val.append(normalLiteral);
//noinspection HardCodedStringLiteral
val.append(", 'YYYY-MM-DD HH24:MI:SS')");
return val.toString();
}
//noinspection HardCodedStringLiteral
return "UNSUPPORTED:" + isoDate;
}
@Override
public boolean isSystemObject(DatabaseObject example) {
if (example == null) {
return false;
}
if (this.isLiquibaseObject(example)) {
return false;
}
if (example instanceof Schema) {
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
if ("SYSTEM".equals(example.getName()) || "SYS".equals(example.getName()) || "CTXSYS".equals(example.getName()) || "XDB".equals(example.getName())) {
return true;
}
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
if ("SYSTEM".equals(example.getSchema().getCatalogName()) || "SYS".equals(example.getSchema().getCatalogName()) || "CTXSYS".equals(example.getSchema().getCatalogName()) || "XDB".equals(example.getSchema().getCatalogName())) {
return true;
}
} else if (isSystemObject(example.getSchema())) {
return true;
}
if (example instanceof Catalog) {
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
if (("SYSTEM".equals(example.getName()) || "SYS".equals(example.getName()) || "CTXSYS".equals(example.getName()) || "XDB".equals(example.getName()))) {
return true;
}
} else if (example.getName() != null) {
//noinspection HardCodedStringLiteral
if (example.getName().startsWith("BIN$")) { //oracle deleted table
boolean filteredInOriginalQuery = this.canAccessDbaRecycleBin();
if (!filteredInOriginalQuery) {
filteredInOriginalQuery = StringUtils.trimToEmpty(example.getSchema().getName()).equalsIgnoreCase(this.getConnection().getConnectionUserName());
}
if (filteredInOriginalQuery) {
return !((example instanceof PrimaryKey) || (example instanceof Index) || (example instanceof
liquibase.statement.UniqueConstraint));
} else {
return true;
}
} else //noinspection HardCodedStringLiteral
if (example.getName().startsWith("AQ$")) { //oracle AQ tables
return true;
} else //noinspection HardCodedStringLiteral
if (example.getName().startsWith("DR$")) { //oracle index tables
return true;
} else //noinspection HardCodedStringLiteral
if (example.getName().startsWith("SYS_IOT_OVER")) { //oracle system table
return true;
} else //noinspection HardCodedStringLiteral,HardCodedStringLiteral
if ((example.getName().startsWith("MDRT_") || example.getName().startsWith("MDRS_")) && example.getName().endsWith("$")) {
// CORE-1768 - Oracle creates these for spatial indices and will remove them when the index is removed.
return true;
} else //noinspection HardCodedStringLiteral
if (example.getName().startsWith("MLOG$_")) { //Created by materliaized view logs for every table that is part of a materialized view. Not available for DDL operations.
return true;
} else //noinspection HardCodedStringLiteral
if (example.getName().startsWith("RUPD$_")) { //Created by materialized view log tables using primary keys. Not available for DDL operations.
return true;
} else //noinspection HardCodedStringLiteral
if (example.getName().startsWith("WM$_")) { //Workspace Manager backup tables.
return true;
} else //noinspection HardCodedStringLiteral
if ("CREATE$JAVA$LOB$TABLE".equals(example.getName())) { //This table contains the name of the Java object, the date it was loaded, and has a BLOB column to store the Java object.
return true;
} else //noinspection HardCodedStringLiteral
if ("JAVA$CLASS$MD5$TABLE".equals(example.getName())) { //This is a hash table that tracks the loading of Java objects into a schema.
return true;
} else //noinspection HardCodedStringLiteral
if (example.getName().startsWith("ISEQ$$_")) { //System-generated sequence
return true;
} else //noinspection HardCodedStringLiteral
if (example.getName().startsWith("USLOG$")) { //for update materialized view
return true;
} else if (example.getName().startsWith("SYS_FBA")) { //for Flashback tables
return true;
}
}
return super.isSystemObject(example);
}
@Override
public boolean supportsTablespaces() {
return true;
}
@Override
public boolean supportsAutoIncrement() {
// Oracle supports Identity beginning with version 12c
boolean isAutoIncrementSupported = false;
try {
if (getDatabaseMajorVersion() >= 12) {
isAutoIncrementSupported = true;
}
// Returning true will generate create table command with 'IDENTITY' clause, example:
// CREATE TABLE AutoIncTest (IDPrimaryKey NUMBER(19) GENERATED BY DEFAULT AS IDENTITY NOT NULL, TypeID NUMBER(3) NOT NULL, Description NVARCHAR2(50), CONSTRAINT PK_AutoIncTest PRIMARY KEY (IDPrimaryKey));
// While returning false will continue to generate create table command without 'IDENTITY' clause, example:
// CREATE TABLE AutoIncTest (IDPrimaryKey NUMBER(19) NOT NULL, TypeID NUMBER(3) NOT NULL, Description NVARCHAR2(50), CONSTRAINT PK_AutoIncTest PRIMARY KEY (IDPrimaryKey));
} catch (DatabaseException ex) {
isAutoIncrementSupported = false;
}
return isAutoIncrementSupported;
}
// public Set<UniqueConstraint> findUniqueConstraints(String schema) throws DatabaseException {
// Set<UniqueConstraint> returnSet = new HashSet<UniqueConstraint>();
//
// List<Map> maps = new Executor(this).queryForList(new RawSqlStatement("SELECT UC.CONSTRAINT_NAME, UCC.TABLE_NAME, UCC.COLUMN_NAME FROM USER_CONSTRAINTS UC, USER_CONS_COLUMNS UCC WHERE UC.CONSTRAINT_NAME=UCC.CONSTRAINT_NAME AND CONSTRAINT_TYPE='U' ORDER BY UC.CONSTRAINT_NAME"));
//
// UniqueConstraint constraint = null;
// for (Map map : maps) {
// if (constraint == null || !constraint.getName().equals(constraint.getName())) {
// returnSet.add(constraint);
// Table table = new Table((String) map.get("TABLE_NAME"));
// constraint = new UniqueConstraint(map.get("CONSTRAINT_NAME").toString(), table);
// }
// }
// if (constraint != null) {
// returnSet.add(constraint);
// }
//
// return returnSet;
// }
@Override
public boolean supportsRestrictForeignKeys() {
return false;
}
@Override
public int getDataTypeMaxParameters(String dataTypeName) {
//noinspection HardCodedStringLiteral
if ("BINARY_FLOAT".equals(dataTypeName.toUpperCase())) {
return 0;
}
//noinspection HardCodedStringLiteral
if ("BINARY_DOUBLE".equals(dataTypeName.toUpperCase())) {
return 0;
}
return super.getDataTypeMaxParameters(dataTypeName);
}
public String getSystemTableWhereClause(String tableNameColumn) {
List<String> clauses = new ArrayList<String>(Arrays.asList("BIN$",
"AQ$",
"DR$",
"SYS_IOT_OVER",
"MLOG$_",
"RUPD$_",
"WM$_",
"ISEQ$$_",
"USLOG$",
"SYS_FBA"));
for (int i = 0; i < clauses.size(); i++) {
clauses.set(i, tableNameColumn + " NOT LIKE '" + clauses.get(i) + "%'");
}
return "(" + StringUtils.join(clauses, " AND ") + ")";
}
@Override
public boolean jdbcCallsCatalogsSchemas() {
return true;
}
public Set<String> getUserDefinedTypes() {
if (userDefinedTypes == null) {
userDefinedTypes = new HashSet<>();
if ((getConnection() != null) && !(getConnection() instanceof OfflineConnection)) {
try {
try {
//noinspection HardCodedStringLiteral
userDefinedTypes.addAll(ExecutorService.getInstance().getExecutor(this).queryForList(new RawSqlStatement("SELECT DISTINCT TYPE_NAME FROM ALL_TYPES"), String.class));
} catch (DatabaseException e) { //fall back to USER_TYPES if the user cannot see ALL_TYPES
//noinspection HardCodedStringLiteral
userDefinedTypes.addAll(ExecutorService.getInstance().getExecutor(this).queryForList(new RawSqlStatement("SELECT TYPE_NAME FROM USER_TYPES"), String.class));
}
} catch (DatabaseException e) {
//ignore error
}
}
}
return userDefinedTypes;
}
@Override
public String generateDatabaseFunctionValue(DatabaseFunction databaseFunction) {
//noinspection HardCodedStringLiteral
if ((databaseFunction != null) && "current_timestamp".equalsIgnoreCase(databaseFunction.toString())) {
return databaseFunction.toString();
}
if ((databaseFunction instanceof SequenceNextValueFunction) || (databaseFunction instanceof
SequenceCurrentValueFunction)) {
String quotedSeq = super.generateDatabaseFunctionValue(databaseFunction);
// replace "myschema.my_seq".nextval with "myschema"."my_seq".nextval
return quotedSeq.replaceFirst("\"([^\\.\"]+)\\.([^\\.\"]+)\"", "\"$1\".\"$2\"");
}
return super.generateDatabaseFunctionValue(databaseFunction);
}
@Override
public ValidationErrors validate() {
ValidationErrors errors = super.validate();
DatabaseConnection connection = getConnection();
if ((connection == null) || (connection instanceof OfflineConnection)) {
//noinspection HardCodedStringLiteral
LogService.getLog(getClass()).info(LogType.LOG, "Cannot validate offline database");
return errors;
}
if (!canAccessDbaRecycleBin()) {
errors.addWarning(getDbaRecycleBinWarning());
}
return errors;
}
public String getDbaRecycleBinWarning() {
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,
// HardCodedStringLiteral
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
return "Liquibase needs to access the DBA_RECYCLEBIN table so we can automatically handle the case where " +
"constraints are deleted and restored. Since Oracle doesn't properly restore the original table names " +
"referenced in the constraint, we use the information from the DBA_RECYCLEBIN to automatically correct this" +
" issue.\n" +
"\n" +
"The user you used to connect to the database (" + getConnection().getConnectionUserName() +
") needs to have \"SELECT ON SYS.DBA_RECYCLEBIN\" permissions set before we can perform this operation. " +
"Please run the following SQL to set the appropriate permissions, and try running the command again.\n" +
"\n" +
" GRANT SELECT ON SYS.DBA_RECYCLEBIN TO " + getConnection().getConnectionUserName() + ";";
}
public boolean canAccessDbaRecycleBin() {
if (canAccessDbaRecycleBin == null) {
DatabaseConnection connection = getConnection();
if ((connection == null) || (connection instanceof OfflineConnection)) {
return false;
}
Statement statement = null;
try {
statement = ((JdbcConnection) connection).createStatement();
@SuppressWarnings("HardCodedStringLiteral") ResultSet resultSet = statement.executeQuery("select 1 from dba_recyclebin where 0=1");
resultSet.close(); //don't need to do anything with the result set, just make sure statement ran.
this.canAccessDbaRecycleBin = true;
} catch (Exception e) {
//noinspection HardCodedStringLiteral
if ((e instanceof SQLException) && e.getMessage().startsWith("ORA-00942")) { //ORA-00942: table or view does not exist
this.canAccessDbaRecycleBin = false;
} else {
//noinspection HardCodedStringLiteral
LogService.getLog(getClass()).warning(LogType.LOG, "Cannot check dba_recyclebin access", e);
this.canAccessDbaRecycleBin = false;
}
} finally {
JdbcUtils.close(null, statement);
}
}
return canAccessDbaRecycleBin;
}
@Override
public boolean supportsNotNullConstraintNames() {
return true;
}
/**
* Tests if the given String would be a valid identifier in Oracle DBMS. In Oracle, a valid identifier has
* the following form (case-insensitive comparison):
* 1st character: A-Z
* 2..n characters: A-Z0-9$_#
* The maximum length of an identifier differs by Oracle version and object type.
*/
public boolean isValidOracleIdentifier(String identifier, Class<? extends DatabaseObject> type) {
if ((identifier == null) || (identifier.length() < 1))
return false;
if (!identifier.matches("^(i?)[A-Z][A-Z0-9\\$\\_\\#]*$"))
return false;
/*
* @todo It seems we currently do not have a class for tablespace identifiers, and all other classes
* we do know seem to be supported as 12cR2 long identifiers, so:
*/
return (identifier.length() <= LONG_IDENTIFIERS_LEGNTH);
}
/**
* Returns the maximum number of bytes (NOT: characters) for an identifier. For Oracle <=12c Release 20, this
* is 30 bytes, and starting from 12cR2, up to 128 (except for tablespaces, PDB names and some other rather rare
* object types).
*
* @return the maximum length of an object identifier, in bytes
*/
public int getIdentifierMaximumLength() {
try {
if (getDatabaseMajorVersion() < ORACLE_12C_MAJOR_VERSION) {
return SHORT_IDENTIFIERS_LENGTH;
} else if ((getDatabaseMajorVersion() == ORACLE_12C_MAJOR_VERSION) && (getDatabaseMinorVersion() <= 1)) {
return SHORT_IDENTIFIERS_LENGTH;
} else {
return LONG_IDENTIFIERS_LEGNTH;
}
} catch (DatabaseException ex) {
throw new UnexpectedLiquibaseException("Cannot determine the Oracle database version number", ex);
}
}
}
package liquibase.snapshot;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.*;
import liquibase.CatalogAndSchema;
import liquibase.database.AbstractJdbcDatabase;
import liquibase.database.Database;
import liquibase.database.DatabaseConnection;
import liquibase.database.core.*;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.executor.jvm.ColumnMapRowMapper;
import liquibase.executor.jvm.RowMapperNotNullConstraintsResultSetExtractor;
import liquibase.logging.LogService;
import liquibase.logging.LogType;
import liquibase.structure.DatabaseObject;
import liquibase.structure.core.Catalog;
import liquibase.structure.core.Schema;
import liquibase.structure.core.Table;
import liquibase.structure.core.View;
import liquibase.util.JdbcUtils;
import liquibase.util.StringUtils;
public class JdbcDatabaseSnapshot extends DatabaseSnapshot {
private boolean warnedAboutDbaRecycleBin;
private static final boolean ignoreWarnAboutDbaRecycleBin = Boolean.getBoolean( "liquibase.ignoreRecycleBinWarning" );
private CachingDatabaseMetaData cachingDatabaseMetaData;
private Set<String> userDefinedTypes;
public JdbcDatabaseSnapshot(DatabaseObject[] examples, Database database, SnapshotControl snapshotControl) throws DatabaseException, InvalidExampleException {
super(examples, database, snapshotControl);
}
public JdbcDatabaseSnapshot(DatabaseObject[] examples, Database database) throws DatabaseException, InvalidExampleException {
super(examples, database);
}
public CachingDatabaseMetaData getMetaDataFromCache() throws SQLException {
if (cachingDatabaseMetaData == null) {
DatabaseMetaData databaseMetaData = null;
if (getDatabase().getConnection() != null) {
databaseMetaData = ((JdbcConnection) getDatabase().getConnection()).getUnderlyingConnection().getMetaData();
}
cachingDatabaseMetaData = new CachingDatabaseMetaData(this.getDatabase(), databaseMetaData);
}
return cachingDatabaseMetaData;
}
public class CachingDatabaseMetaData {
private static final String ASANY_NO_FOREIGN_KEYS_FOUND_SQLSTATE = "WW012";
private static final String SQL_FILTER_MATCH_ALL = "%";
private DatabaseMetaData databaseMetaData;
private Database database;
public CachingDatabaseMetaData(Database database, DatabaseMetaData metaData) {
this.databaseMetaData = metaData;
this.database = database;
}
public java.sql.DatabaseMetaData getDatabaseMetaData() {
return databaseMetaData;
}
public List<CachedRow> getForeignKeys(final String catalogName, final String schemaName, final String tableName,
final String fkName) throws DatabaseException {
ForeignKeysResultSetCache foreignKeysResultSetCache = new ForeignKeysResultSetCache(database, catalogName, schemaName, tableName, fkName);
ResultSetCache importedKeys = getResultSetCache("getImportedKeys");
importedKeys.setBulkTracking(!(database instanceof MSSQLDatabase));
return importedKeys.get(foreignKeysResultSetCache);
}
public List<CachedRow> getIndexInfo(final String catalogName, final String schemaName, final String tableName, final String indexName) throws DatabaseException, SQLException {
List<CachedRow> indexes = getResultSetCache("getIndexInfo").get(new ResultSetCache.UnionResultSetExtractor(database) {
public boolean isBulkFetchMode;
@Override
public ResultSetCache.RowData rowKeyParameters(CachedRow row) {
return new ResultSetCache.RowData(row.getString("TABLE_CAT"), row.getString("TABLE_SCHEM"), database, row.getString("TABLE_NAME"), row.getString("INDEX_NAME"));
}
@Override
public ResultSetCache.RowData wantedKeyParameters() {
return new ResultSetCache.RowData(catalogName, schemaName, database, tableName, indexName);
}
@Override
public boolean bulkContainsSchema(String schemaKey) {
return getAllCatalogsStringScratchData() != null && database instanceof OracleDatabase;
}
@Override
public String getSchemaKey(CachedRow row) {
return row.getString("TABLE_SCHEM");
}
@Override
public List<CachedRow> fastFetch() throws SQLException, DatabaseException {
List<CachedRow> returnList = new ArrayList<>();
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
if (database instanceof OracleDatabase) {
warnAboutDbaRecycleBin();
//oracle getIndexInfo is buggy and slow. See Issue 1824548 and http://forums.oracle.com/forums/thread.jspa?messageID=578383&#578383
String sql =
"SELECT " +
"c.INDEX_NAME, " +
"3 AS TYPE, " +
"c.TABLE_OWNER AS TABLE_SCHEM, " +
"c.TABLE_NAME, " +
"c.COLUMN_NAME, " +
"c.COLUMN_POSITION AS ORDINAL_POSITION, " +
"e.COLUMN_EXPRESSION AS FILTER_CONDITION, " +
"CASE I.UNIQUENESS WHEN 'UNIQUE' THEN 0 ELSE 1 END AS NON_UNIQUE, " +
"CASE c.DESCEND WHEN 'Y' THEN 'D' WHEN 'DESC' THEN 'D' WHEN 'N' THEN 'A' WHEN 'ASC' THEN 'A' END AS ASC_OR_DESC, " +
"CASE WHEN tablespace_name = (SELECT default_tablespace FROM user_users) " +
"THEN NULL ELSE tablespace_name END AS tablespace_name " +
"FROM ALL_IND_COLUMNS c " +
"JOIN ALL_INDEXES i ON i.owner=c.index_owner AND i.index_name = c.index_name and i.table_owner = c.table_owner " +
"LEFT OUTER JOIN all_ind_expressions e ON e.index_owner=c.index_owner AND e.index_name = c.index_name AND e.column_position = c.column_position " +
"LEFT OUTER JOIN " + "user_recyclebin" + " d ON d.object_name=c.table_name ";
if (!isBulkFetchMode || getAllCatalogsStringScratchData() == null) {
sql += "WHERE c.TABLE_OWNER = '" + database.correctObjectName(catalogAndSchema.getCatalogName(), Schema.class) + "' ";
} else {
sql += "WHERE c.TABLE_OWNER IN ('" + database.correctObjectName(catalogAndSchema.getCatalogName(), Schema.class) + "', " + getAllCatalogsStringScratchData() + ")";
}
sql += "AND i.OWNER = c.TABLE_OWNER " +
"AND d.object_name IS NULL ";
if (!isBulkFetchMode && (tableName != null)) {
sql += " AND c.TABLE_NAME='" + tableName + "'";
}
if (!isBulkFetchMode && (indexName != null)) {
sql += " AND c.INDEX_NAME='" + indexName + "'";
}
sql += " ORDER BY c.INDEX_NAME, ORDINAL_POSITION";
returnList.addAll(executeAndExtract(sql, database));
} else if (database instanceof MSSQLDatabase) {
String tableCat = "original_db_name()";
if (9 <= database.getDatabaseMajorVersion()) {
tableCat = "db_name()";
}
//fetch additional index info
String sql = "SELECT " +
tableCat + " as TABLE_CAT, " +
"object_schema_name(i.object_id) as TABLE_SCHEM, " +
"object_name(i.object_id) as TABLE_NAME, " +
"CASE is_unique WHEN 1 then 0 else 1 end as NON_UNIQUE, " +
"object_name(i.object_id) as INDEX_QUALIFIER, " +
"i.name as INDEX_NAME, " +
"case i.type when 1 then 1 ELSE 3 end as TYPE, " +
"key_ordinal as ORDINAL_POSITION, " +
"COL_NAME(c.object_id,c.column_id) AS COLUMN_NAME, " +
"case is_descending_key when 0 then 'A' else 'D' end as ASC_OR_DESC, " +
"null as CARDINALITY, " +
"null as PAGES, " +
"i.filter_definition as FILTER_CONDITION, " +
"o.type AS INTERNAL_OBJECT_TYPE, " +
"i.*, " +
"c.*, " +
"s.* " +
"FROM sys.indexes i " +
"join sys.index_columns c on i.object_id=c.object_id and i.index_id=c.index_id " +
"join sys.stats s on i.object_id=s.object_id and i.name=s.name " +
"join sys.objects o on i.object_id=o.object_id " +
"WHERE object_schema_name(i.object_id)='" + database.correctObjectName(catalogAndSchema.getSchemaName(), Schema.class) + "'";
if (!isBulkFetchMode && (tableName != null)) {
sql += " AND object_name(i.object_id)='" + database.escapeStringForDatabase(tableName) + "'";
}
if (!isBulkFetchMode && (indexName != null)) {
sql += " AND i.name='" + database.escapeStringForDatabase(indexName) + "'";
}
sql += "ORDER BY i.object_id, i.index_id, c.key_ordinal";
returnList.addAll(executeAndExtract(sql, database));
} else if (database instanceof Db2zDatabase) {
String sql = "SELECT i.CREATOR AS TABLE_SCHEM, " +
"i.TBNAME AS TABLE_NAME, " +
"i.NAME AS INDEX_NAME, " +
"3 AS TYPE, " +
"k.COLNAME AS COLUMN_NAME, " +
"k.COLSEQ AS ORDINAL_POSITION, " +
"CASE UNIQUERULE WHEN 'D' then 1 else 0 end as NON_UNIQUE, " +
"k.ORDERING AS ORDER, " +
"i.CREATOR AS INDEX_QUALIFIER " +
"FROM SYSIBM.SYSKEYS k " +
"JOIN SYSIBM.SYSINDEXES i ON k.IXNAME = i.NAME " +
"WHERE i.CREATOR = '" + database.correctObjectName(catalogAndSchema.getSchemaName(), Schema.class) + "'";
if (!isBulkFetchMode && tableName != null) {
sql += " AND i.TBNAME='" + database.escapeStringForDatabase(tableName) + "'";
}
if (!isBulkFetchMode && indexName != null) {
sql += " AND i.NAME='" + database.escapeStringForDatabase(indexName) + "'";
}
sql += "ORDER BY i.NAME, k.COLSEQ";
returnList.addAll(executeAndExtract(sql, database));
} else {
/*
* If we do not know in which table to look for the index, things get a little bit ugly.
* First, we get a collection of all tables within the catalogAndSchema, then iterate through
* them until we (hopefully) find the index we are looking for.
*/
List<String> tables = new ArrayList<>();
if (tableName == null) {
// Build a list of all candidate tables in the catalog/schema that might contain the index
for (CachedRow row : getTables(((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema), ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema), null)) {
tables.add(row.getString("TABLE_NAME"));
}
} else {
tables.add(tableName);
}
// Iterate through all the candidate tables and try to find the index.
for (String tableName : tables) {
ResultSet rs = databaseMetaData.getIndexInfo(
((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema),
((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema),
tableName,
false,
true);
List<CachedRow> rows = extract(rs, (database instanceof InformixDatabase));
returnList.addAll(rows);
}
}
return returnList;
}
@Override
public List<CachedRow> bulkFetch() throws SQLException, DatabaseException {
this.isBulkFetchMode = true;
return fastFetch();
}
@Override
boolean shouldBulkSelect(String schemaKey, ResultSetCache resultSetCache) {
if (database instanceof OracleDatabase || database instanceof MSSQLDatabase) {
return JdbcDatabaseSnapshot.this.getAllCatalogsStringScratchData() != null || (tableName == null && indexName == null) || super.shouldBulkSelect(schemaKey, resultSetCache);
}
return false;
}
});
return indexes;
}
protected void warnAboutDbaRecycleBin() {
if (!ignoreWarnAboutDbaRecycleBin && !warnedAboutDbaRecycleBin && !(((OracleDatabase) database).canAccessDbaRecycleBin())) {
LogService.getLog(getClass()).warning(LogType.LOG, ((OracleDatabase) database).getDbaRecycleBinWarning());
warnedAboutDbaRecycleBin = true;
}
}
/**
* Return the columns for the given catalog, schema, table, and column.
*/
public List<CachedRow> getColumns(final String catalogName, final String schemaName, final String tableName, final String columnName) throws SQLException, DatabaseException {
if ((database instanceof MSSQLDatabase) && (userDefinedTypes == null)) {
userDefinedTypes = new HashSet<>();
DatabaseConnection databaseConnection = database.getConnection();
if (databaseConnection instanceof JdbcConnection) {
Statement stmt = null;
ResultSet resultSet = null;
try {
stmt = ((JdbcConnection) databaseConnection).getUnderlyingConnection().createStatement();
resultSet = stmt.executeQuery("select name from " + (catalogName == null ? "" : "[" + catalogName + "].") + "sys.types where is_user_defined=1");
while (resultSet.next()) {
userDefinedTypes.add(resultSet.getString("name").toLowerCase());
}
} finally {
JdbcUtils.close(resultSet, stmt);
}
}
}
GetColumnResultSetCache getColumnResultSetCache = new GetColumnResultSetCache(database, catalogName,
schemaName, tableName, columnName);
return getResultSetCache("getColumns").get(getColumnResultSetCache);
}
/**
* Return the NotNullConstraints for the given catalog, schema, table, and column.
*/
public List<CachedRow> getNotNullConst(final String catalogName, final String schemaName,
final String tableName) throws DatabaseException {
if(!(database instanceof OracleDatabase)) {
return Collections.emptyList();
}
GetNotNullConstraintsResultSetCache getNotNullConstraintsResultSetCache = new GetNotNullConstraintsResultSetCache(database, catalogName,
schemaName, tableName);
return getResultSetCache("getNotNullConst").get(getNotNullConstraintsResultSetCache);
}
private class GetColumnResultSetCache extends ResultSetCache.SingleResultSetExtractor {
final String catalogName;
final String schemaName;
final String tableName;
final String columnName;
private GetColumnResultSetCache(Database database, String catalogName, String schemaName, String tableName, String columnName) {
super(database);
this.catalogName = catalogName;
this.schemaName = schemaName;
this.tableName = tableName;
this.columnName = columnName;
}
@Override
public ResultSetCache.RowData rowKeyParameters(CachedRow row) {
return new ResultSetCache.RowData(row.getString("TABLE_CAT"), row.getString("TABLE_SCHEM"), database, row.getString("TABLE_NAME"), row.getString("COLUMN_NAME"));
}
@Override
public ResultSetCache.RowData wantedKeyParameters() {
return new ResultSetCache.RowData(catalogName, schemaName, database, tableName, columnName);
}
@Override
public boolean bulkContainsSchema(String schemaKey) {
String catalogs = getAllCatalogsStringScratchData();
return catalogs != null && schemaKey != null
&& catalogs.contains("'" + schemaKey.toUpperCase() + "'")
&& database instanceof OracleDatabase;
}
@Override
public String getSchemaKey(CachedRow row) {
return row.getString("TABLE_SCHEM");
}
@Override
boolean shouldBulkSelect(String schemaKey, ResultSetCache resultSetCache) {
return !(tableName.equalsIgnoreCase(database.getDatabaseChangeLogTableName()) || tableName.equalsIgnoreCase(database.getDatabaseChangeLogLockTableName()));
}
@Override
public List<CachedRow> fastFetchQuery() throws SQLException, DatabaseException {
if (database instanceof OracleDatabase) {
return oracleQuery(false);
} else if (database instanceof MSSQLDatabase) {
return mssqlQuery(false);
}
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
try {
return extract(
databaseMetaData.getColumns(
((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema),
((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema),
tableName,
SQL_FILTER_MATCH_ALL)
);
} catch (SQLException e) {
if (shouldReturnEmptyColumns(e)) { //view with table already dropped. Act like it has no columns.
return new ArrayList<>();
} else {
throw e;
}
}
}
@Override
public List<CachedRow> bulkFetchQuery() throws SQLException, DatabaseException {
if (database instanceof OracleDatabase) {
return oracleQuery(true);
} else if (database instanceof MSSQLDatabase) {
return mssqlQuery(true);
}
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
try {
return extract(databaseMetaData.getColumns(((AbstractJdbcDatabase) database)
.getJdbcCatalogName(catalogAndSchema), ((AbstractJdbcDatabase) database)
.getJdbcSchemaName(catalogAndSchema), SQL_FILTER_MATCH_ALL, SQL_FILTER_MATCH_ALL));
} catch (SQLException e) {
if (shouldReturnEmptyColumns(e)) {
return new ArrayList<>();
} else {
throw e;
}
}
}
protected boolean shouldReturnEmptyColumns(SQLException e) {
return e.getMessage().contains("references invalid table"); //view with table already dropped. Act like it has no columns.
}
protected List<CachedRow> oracleQuery(boolean bulk) throws DatabaseException, SQLException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
boolean getMapDateToTimestamp = true;
String jdbcSchemaName = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema);
boolean collectIdentityData = database.getDatabaseMajorVersion() >= OracleDatabase.ORACLE_12C_MAJOR_VERSION;
String sql = "select NULL AS TABLE_CAT, OWNER AS TABLE_SCHEM, 'NO' as IS_AUTOINCREMENT, cc.COMMENTS AS REMARKS," +
"OWNER, TABLE_NAME, COLUMN_NAME, DATA_TYPE AS DATA_TYPE_NAME, DATA_TYPE_MOD, DATA_TYPE_OWNER, " +
// note: oracle reports DATA_LENGTH=4*CHAR_LENGTH when using VARCHAR( <N> CHAR ), thus BYTEs
"DECODE (c.data_type, 'CHAR', 1, 'VARCHAR2', 12, 'NUMBER', 3, 'LONG', -1, 'DATE', " + (getMapDateToTimestamp ? "93" : "91") + ", 'RAW', -3, 'LONG RAW', -4, 'BLOB', 2004, 'CLOB', 2005, 'BFILE', -13, 'FLOAT', 6, 'TIMESTAMP(6)', 93, 'TIMESTAMP(6) WITH TIME ZONE', -101, 'TIMESTAMP(6) WITH LOCAL TIME ZONE', -102, 'INTERVAL YEAR(2) TO MONTH', -103, 'INTERVAL DAY(2) TO SECOND(6)', -104, 'BINARY_FLOAT', 100, 'BINARY_DOUBLE', 101, 'XMLTYPE', 2009, 1111) AS data_type, " +
"DECODE( CHAR_USED, 'C',CHAR_LENGTH, DATA_LENGTH ) as DATA_LENGTH, " +
"DATA_PRECISION, DATA_SCALE, NULLABLE, COLUMN_ID as ORDINAL_POSITION, DEFAULT_LENGTH, " +
"DATA_DEFAULT, " +
"NUM_BUCKETS, CHARACTER_SET_NAME, " +
"CHAR_COL_DECL_LENGTH, CHAR_LENGTH, " +
"CHAR_USED, VIRTUAL_COLUMN ";
if (collectIdentityData) {
sql += ", DEFAULT_ON_NULL, IDENTITY_COLUMN, ic.GENERATION_TYPE ";
}
sql += "FROM ALL_TAB_COLS c " +
"JOIN ALL_COL_COMMENTS cc USING ( OWNER, TABLE_NAME, COLUMN_NAME ) ";
if (collectIdentityData) {
sql += "LEFT JOIN ALL_TAB_IDENTITY_COLS ic USING (OWNER, TABLE_NAME, COLUMN_NAME ) ";
}
if (!bulk || getAllCatalogsStringScratchData() == null) {
sql += "WHERE OWNER='" + jdbcSchemaName + "' AND (hidden_column='NO' or hidden_column is null)";
} else {
sql += "WHERE OWNER IN ('" + jdbcSchemaName + "', " + getAllCatalogsStringScratchData() + ") AND (hidden_column='NO' or hidden_column is null)";
}
if (!bulk) {
if (tableName != null) {
sql += " AND TABLE_NAME='" + database.escapeStringForDatabase(tableName) + "'";
}
if (columnName != null) {
sql += " AND COLUMN_NAME='" + database.escapeStringForDatabase(columnName) + "'";
}
}
sql += " AND " + ((OracleDatabase) database).getSystemTableWhereClause("TABLE_NAME");
sql += " ORDER BY OWNER, TABLE_NAME, c.COLUMN_ID";
return this.executeAndExtract(sql, database);
}
protected List<CachedRow> mssqlQuery(boolean bulk) throws DatabaseException, SQLException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
String databaseName = StringUtils.trimToNull(database.correctObjectName(catalogAndSchema.getCatalogName(), Catalog.class));
String dbIdParam;
String databasePrefix;
if (databaseName == null) {
databasePrefix = "";
dbIdParam = "";
} else {
dbIdParam = ", db_id('"+databaseName+"')";
databasePrefix = "[" + databaseName + "].";
}
String sql = "select " +
"db_name(" + (databaseName == null ? "" : "db_id('" + databaseName + "')") + ") AS TABLE_CAT, " +
"object_schema_name(c.object_id"+dbIdParam+") AS TABLE_SCHEM, " +
"object_name(c.object_id"+dbIdParam+") AS TABLE_NAME, " +
"c.name AS COLUMN_NAME, " +
"is_filestream, " +
"is_rowguidcol, " +
"CASE WHEN c.is_identity = 'true' THEN 'YES' ELSE 'NO' END as IS_AUTOINCREMENT, " +
"{REMARKS_COLUMN_PLACEHOLDER}" +
"t.name AS TYPE_NAME, " +
"dc.name as COLUMN_DEF_NAME, " +
"dc.definition as COLUMN_DEF, " +
// data type mapping from https://msdn.microsoft.com/en-us/library/ms378878(v=sql.110).aspx
"CASE t.name " +
"WHEN 'bigint' THEN " + java.sql.Types.BIGINT + " " +
"WHEN 'binary' THEN " + java.sql.Types.BINARY + " " +
"WHEN 'bit' THEN " + java.sql.Types.BIT + " " +
"WHEN 'char' THEN " + java.sql.Types.CHAR + " " +
"WHEN 'date' THEN " + java.sql.Types.DATE + " " +
"WHEN 'datetime' THEN " + java.sql.Types.TIMESTAMP + " " +
"WHEN 'datetime2' THEN " + java.sql.Types.TIMESTAMP + " " +
"WHEN 'datetimeoffset' THEN -155 " +
"WHEN 'decimal' THEN " + java.sql.Types.DECIMAL + " " +
"WHEN 'float' THEN " + java.sql.Types.DOUBLE + " " +
"WHEN 'image' THEN " + java.sql.Types.LONGVARBINARY + " " +
"WHEN 'int' THEN " + java.sql.Types.INTEGER + " " +
"WHEN 'money' THEN " + java.sql.Types.DECIMAL + " " +
"WHEN 'nchar' THEN " + java.sql.Types.NCHAR + " " +
"WHEN 'ntext' THEN " + java.sql.Types.LONGNVARCHAR + " " +
"WHEN 'numeric' THEN " + java.sql.Types.NUMERIC + " " +
"WHEN 'nvarchar' THEN " + java.sql.Types.NVARCHAR + " " +
"WHEN 'real' THEN " + Types.REAL + " " +
"WHEN 'smalldatetime' THEN " + java.sql.Types.TIMESTAMP + " " +
"WHEN 'smallint' THEN " + java.sql.Types.SMALLINT + " " +
"WHEN 'smallmoney' THEN " + java.sql.Types.DECIMAL + " " +
"WHEN 'text' THEN " + java.sql.Types.LONGVARCHAR + " " +
"WHEN 'time' THEN " + java.sql.Types.TIME + " " +
"WHEN 'timestamp' THEN " + java.sql.Types.BINARY + " " +
"WHEN 'tinyint' THEN " + java.sql.Types.TINYINT + " " +
"WHEN 'udt' THEN " + java.sql.Types.VARBINARY + " " +
"WHEN 'uniqueidentifier' THEN " + java.sql.Types.CHAR + " " +
"WHEN 'varbinary' THEN " + java.sql.Types.VARBINARY + " " +
"WHEN 'varbinary(max)' THEN " + java.sql.Types.VARBINARY + " " +
"WHEN 'varchar' THEN " + java.sql.Types.VARCHAR + " " +
"WHEN 'varchar(max)' THEN " + java.sql.Types.VARCHAR + " " +
"WHEN 'xml' THEN " + java.sql.Types.LONGVARCHAR + " " +
"WHEN 'LONGNVARCHAR' THEN " + java.sql.Types.SQLXML + " " +
"ELSE " + Types.OTHER + " END AS data_type, " +
"CASE WHEN c.is_nullable = 'true' THEN 1 ELSE 0 END AS NULLABLE, " +
"10 as NUM_PREC_RADIX, " +
"c.column_id as ORDINAL_POSITION, " +
"c.scale as DECIMAL_DIGITS, " +
"c.max_length as COLUMN_SIZE, " +
"c.precision as DATA_PRECISION " +
"FROM "+databasePrefix+"sys.columns c " +
"inner join "+databasePrefix+"sys.types t on c.user_type_id=t.user_type_id " +
"{REMARKS_JOIN_PLACEHOLDER}" +
"left outer join "+databasePrefix+"sys.default_constraints dc on dc.parent_column_id = c.column_id AND dc.parent_object_id=c.object_id AND type_desc='DEFAULT_CONSTRAINT' " +
"WHERE object_schema_name(c.object_id"+dbIdParam+")='" + ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema) + "'";
if (!bulk) {
if (tableName != null) {
sql += " and object_name(c.object_id"+dbIdParam+")='" + database.escapeStringForDatabase(tableName) + "'";
}
if (columnName != null) {
sql += " and c.name='" + database.escapeStringForDatabase(columnName) + "'";
}
}
sql += "order by object_schema_name(c.object_id"+dbIdParam+"), object_name(c.object_id"+dbIdParam+"), c.column_id";
// sys.extended_properties is added to Azure on V12: https://feedback.azure.com/forums/217321-sql-database/suggestions/6549815-add-sys-extended-properties-for-meta-data-support
if ((!((MSSQLDatabase) database).isAzureDb()) // Either NOT AzureDB (=SQL Server 2008 or higher)
|| (database.getDatabaseMajorVersion() >= 12)) { // or at least AzureDB v12
// SQL Server 2005 or later
// https://technet.microsoft.com/en-us/library/ms177541.aspx
sql = sql.replace("{REMARKS_COLUMN_PLACEHOLDER}", "CAST([ep].[value] AS [nvarchar](MAX)) AS [REMARKS], ");
sql = sql.replace("{REMARKS_JOIN_PLACEHOLDER}", "left outer join "+databasePrefix+"[sys].[extended_properties] AS [ep] ON [ep].[class] = 1 " +
"AND [ep].[major_id] = c.object_id " +
"AND [ep].[minor_id] = column_id " +
"AND [ep].[name] = 'MS_Description' ");
} else {
sql = sql.replace("{REMARKS_COLUMN_PLACEHOLDER}", "");
sql = sql.replace("{REMARKS_JOIN_PLACEHOLDER}", "");
}
List<CachedRow> rows = this.executeAndExtract(sql, database);
for (CachedRow row : rows) {
String typeName = row.getString("TYPE_NAME");
if ("nvarchar".equals(typeName) || "nchar".equals(typeName)) {
Integer size = row.getInt("COLUMN_SIZE");
if (size > 0) {
row.set("COLUMN_SIZE", size / 2);
}
} else if ((row.getInt("DATA_PRECISION") != null) && (row.getInt("DATA_PRECISION") > 0)) {
row.set("COLUMN_SIZE", row.getInt("DATA_PRECISION"));
}
}
return rows;
}
@Override
protected List<CachedRow> extract(ResultSet resultSet, boolean informixIndexTrimHint) throws SQLException {
List<CachedRow> rows = super.extract(resultSet, informixIndexTrimHint);
if ((database instanceof MSSQLDatabase) && !userDefinedTypes.isEmpty()) { //UDT types in MSSQL don't take parameters
for (CachedRow row : rows) {
String dataType = (String) row.get("TYPE_NAME");
if (userDefinedTypes.contains(dataType.toLowerCase())) {
row.set("COLUMN_SIZE", null);
row.set("DECIMAL_DIGITS ", null);
}
}
}
return rows;
}
}
private class ForeignKeysResultSetCache extends ResultSetCache.UnionResultSetExtractor {
final String catalogName;
final String schemaName;
final String tableName;
final String fkName;
private ForeignKeysResultSetCache(Database database, String catalogName, String schemaName, String tableName, String fkName) {
super(database);
this.catalogName = catalogName;
this.schemaName = schemaName;
this.tableName = tableName;
this.fkName = fkName;
}
@Override
public ResultSetCache.RowData rowKeyParameters(CachedRow row) {
return new ResultSetCache.RowData(row.getString("FKTABLE_CAT"), row.getString("FKTABLE_SCHEM"), database, row.getString("FKTABLE_NAME"), row.getString("FK_NAME"));
}
@Override
public ResultSetCache.RowData wantedKeyParameters() {
return new ResultSetCache.RowData(catalogName, schemaName, database, tableName, fkName);
}
@Override
public boolean bulkContainsSchema(String schemaKey) {
return database instanceof OracleDatabase;
}
@Override
public String getSchemaKey(CachedRow row) {
return row.getString("FKTABLE_SCHEM");
}
@Override
public List<CachedRow> fastFetch() throws SQLException, DatabaseException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
List<CachedRow> returnList = new ArrayList<CachedRow>();
List<String> tables = new ArrayList<String>();
String jdbcCatalogName = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema);
String jdbcSchemaName = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema);
if (database instanceof DB2Database) {
return executeAndExtract(getDB2Sql(jdbcSchemaName, tableName), database);
} else if (database instanceof Db2zDatabase) {
return executeAndExtract(getDB2ZOSSql(jdbcSchemaName, tableName), database);
} else {
if (tableName == null) {
for (CachedRow row : getTables(jdbcCatalogName, jdbcSchemaName, null)) {
tables.add(row.getString("TABLE_NAME"));
}
} else {
tables.add(tableName);
}
for (String foundTable : tables) {
if (database instanceof OracleDatabase) {
throw new RuntimeException("Should have bulk selected");
} else {
returnList.addAll(extract(databaseMetaData.getImportedKeys(jdbcCatalogName, jdbcSchemaName, foundTable)));
}
}
return returnList;
}
}
@Override
public List<CachedRow> bulkFetch() throws SQLException, DatabaseException {
if (database instanceof OracleDatabase) {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
String jdbcSchemaName = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema);
String sql = getOracleSql(jdbcSchemaName);
return executeAndExtract(sql, database);
} else if (database instanceof DB2Database) {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
String jdbcSchemaName = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema);
return executeAndExtract(getDB2Sql(jdbcSchemaName, null), database);
} else if (database instanceof Db2zDatabase) {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
String jdbcSchemaName = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema);
return executeAndExtract(getDB2ZOSSql(jdbcSchemaName, null), database);
} else if (database instanceof MSSQLDatabase) {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
String jdbcSchemaName = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema);
String sql = getMSSQLSql(jdbcSchemaName, tableName);
return executeAndExtract(sql, database);
} else {
throw new RuntimeException("Cannot bulk select");
}
}
protected String getOracleSql(String jdbcSchemaName) {
String sql = "SELECT /*+rule*/" +
" NULL AS pktable_cat, " +
" p.owner as pktable_schem, " +
" p.table_name as pktable_name, " +
" pc.column_name as pkcolumn_name, " +
" NULL as fktable_cat, " +
" f.owner as fktable_schem, " +
" f.table_name as fktable_name, " +
" fc.column_name as fkcolumn_name, " +
" fc.position as key_seq, " +
" NULL as update_rule, " +
" decode (f.delete_rule, 'CASCADE', 0, 'SET NULL', 2, 1) as delete_rule, " +
" f.constraint_name as fk_name, " +
" p.constraint_name as pk_name, " +
" decode(f.deferrable, 'DEFERRABLE', 5, 'NOT DEFERRABLE', 7, 'DEFERRED', 6) deferrability, " +
" f.validated as fk_validate " +
"FROM " +
"all_cons_columns pc " +
"INNER JOIN all_constraints p " +
"ON pc.owner = p.owner " +
"AND pc.constraint_name = p.constraint_name " +
"INNER JOIN all_constraints f " +
"ON pc.owner = f.r_owner " +
"AND pc.constraint_name = f.r_constraint_name " +
"INNER JOIN all_cons_columns fc " +
"ON fc.owner = f.owner " +
"AND fc.constraint_name = f.constraint_name " +
"AND fc.position = pc.position ";
if (getAllCatalogsStringScratchData() == null) {
sql += "WHERE f.owner = '" + jdbcSchemaName + "' ";
} else {
sql += "WHERE f.owner IN ('" + jdbcSchemaName + "', " + getAllCatalogsStringScratchData() + ") ";
}
sql += "AND p.constraint_type in ('P', 'U') " +
"AND f.constraint_type = 'R' " +
"AND p.table_name NOT LIKE 'BIN$%' " +
"ORDER BY fktable_schem, fktable_name, key_seq";
return sql;
}
protected String getMSSQLSql(String jdbcSchemaName, String tableName) {
//comes from select object_definition(object_id('sp_fkeys'))
return "select " +
"convert(sysname,db_name()) AS PKTABLE_CAT, " +
"convert(sysname,schema_name(o1.schema_id)) AS PKTABLE_SCHEM, " +
"convert(sysname,o1.name) AS PKTABLE_NAME, " +
"convert(sysname,c1.name) AS PKCOLUMN_NAME, " +
"convert(sysname,db_name()) AS FKTABLE_CAT, " +
"convert(sysname,schema_name(o2.schema_id)) AS FKTABLE_SCHEM, " +
"convert(sysname,o2.name) AS FKTABLE_NAME, " +
"convert(sysname,c2.name) AS FKCOLUMN_NAME, " +
"isnull(convert(smallint,k.constraint_column_id), convert(smallint,0)) AS KEY_SEQ, " +
"convert(smallint, case ObjectProperty(f.object_id, 'CnstIsUpdateCascade') when 1 then 0 else 1 end) AS UPDATE_RULE, " +
"convert(smallint, case ObjectProperty(f.object_id, 'CnstIsDeleteCascade') when 1 then 0 else 1 end) AS DELETE_RULE, " +
"convert(sysname,object_name(f.object_id)) AS FK_NAME, " +
"convert(sysname,i.name) AS PK_NAME, " +
"convert(smallint, 7) AS DEFERRABILITY " +
"from " +
"sys.objects o1, " +
"sys.objects o2, " +
"sys.columns c1, " +
"sys.columns c2, " +
"sys.foreign_keys f inner join " +
"sys.foreign_key_columns k on (k.constraint_object_id = f.object_id) inner join " +
"sys.indexes i on (f.referenced_object_id = i.object_id and f.key_index_id = i.index_id) " +
"where " +
"o1.object_id = f.referenced_object_id and " +
"o2.object_id = f.parent_object_id and " +
"c1.object_id = f.referenced_object_id and " +
"c2.object_id = f.parent_object_id and " +
"c1.column_id = k.referenced_column_id and " +
"c2.column_id = k.parent_column_id and " +
"((object_schema_name(o1.object_id)='" + jdbcSchemaName + "'" +
" and convert(sysname,schema_name(o2.schema_id))='" + jdbcSchemaName + "' and " +
"convert(sysname,o2.name)='" + tableName + "' ) or ( convert(sysname,schema_name" +
"(o2.schema_id))='" + jdbcSchemaName + "' and convert(sysname,o2.name)='" + tableName +
"' )) order by 5, 6, 7, 9, 8";
}
protected String getDB2Sql(String jdbcSchemaName, String tableName) {
return "SELECT " +
" pk_col.tabschema AS pktable_cat, " +
" pk_col.tabname as pktable_name, " +
" pk_col.colname as pkcolumn_name, " +
" fk_col.tabschema as fktable_cat, " +
" fk_col.tabname as fktable_name, " +
" fk_col.colname as fkcolumn_name, " +
" fk_col.colseq as key_seq, " +
" decode (ref.updaterule, 'A', 3, 'R', 1, 1) as update_rule, " +
" decode (ref.deleterule, 'A', 3, 'C', 0, 'N', 2, 'R', 1, 1) as delete_rule, " +
" ref.constname as fk_name, " +
" ref.refkeyname as pk_name, " +
" 7 as deferrability " +
"FROM " +
"syscat.references ref " +
"join syscat.keycoluse fk_col on ref.constname=fk_col.constname and ref.tabschema=fk_col.tabschema and ref.tabname=fk_col.tabname " +
"join syscat.keycoluse pk_col on ref.refkeyname=pk_col.constname and ref.reftabschema=pk_col.tabschema and ref.reftabname=pk_col.tabname " +
"WHERE ref.tabschema = '" + jdbcSchemaName + "' " +
"and pk_col.colseq=fk_col.colseq " +
(tableName != null ? " AND fk_col.tabname='" + tableName + "' " : "") +
"ORDER BY fk_col.colseq";
}
protected String getDB2ZOSSql(String jdbcSchemaName, String tableName) {
return "SELECT " +
" ref.REFTBCREATOR AS pktable_cat, " +
" ref.REFTBNAME as pktable_name, " +
" pk_col.colname as pkcolumn_name, " +
" ref.CREATOR as fktable_cat, " +
" ref.TBNAME as fktable_name, " +
" fk_col.colname as fkcolumn_name, " +
" fk_col.colseq as key_seq, " +
" decode (ref.deleterule, 'A', 3, 'C', 0, 'N', 2, 'R', 1, 1) as delete_rule, " +
" ref.relname as fk_name, " +
" pk_col.colname as pk_name, " +
" 7 as deferrability " +
"FROM " +
"SYSIBM.SYSRELS ref " +
"join SYSIBM.SYSFOREIGNKEYS fk_col on ref.relname = fk_col.RELNAME and ref.CREATOR = fk_col.CREATOR and ref.TBNAME = fk_col.TBNAME " +
"join SYSIBM.SYSKEYCOLUSE pk_col on ref.REFTBCREATOR = pk_col.TBCREATOR and ref.REFTBNAME = pk_col.TBNAME " +
"WHERE ref.CREATOR = '" + jdbcSchemaName + "' " +
"and pk_col.colseq=fk_col.colseq " +
(tableName != null ? " AND ref.TBNAME='" + tableName + "' " : "") +
"ORDER BY fk_col.colseq";
}
@Override
boolean shouldBulkSelect(String schemaKey, ResultSetCache resultSetCache) {
if (database instanceof AbstractDb2Database || database instanceof MSSQLDatabase) {
return super.shouldBulkSelect(schemaKey, resultSetCache); //can bulk and fast fetch
} else {
return database instanceof OracleDatabase; //oracle is slow, always bulk select while you are at it. Other databases need to go through all tables.
}
}
}
private class GetNotNullConstraintsResultSetCache extends ResultSetCache.SingleResultSetExtractor {
final String catalogName;
final String schemaName;
final String tableName;
private GetNotNullConstraintsResultSetCache(Database database, String catalogName, String schemaName, String tableName) {
super(database);
this.catalogName = catalogName;
this.schemaName = schemaName;
this.tableName = tableName;
}
@Override
public ResultSetCache.RowData rowKeyParameters(CachedRow row) {
return new ResultSetCache.RowData(row.getString("TABLE_CAT"), row.getString("TABLE_SCHEMA"),
database, row.getString("TABLE_NAME"));
}
@Override
public ResultSetCache.RowData wantedKeyParameters() {
return new ResultSetCache.RowData(catalogName, schemaName, database, tableName);
}
@Override
public boolean bulkContainsSchema(String schemaKey) {
return database instanceof OracleDatabase;
}
@Override
public String getSchemaKey(CachedRow row) {
return row.getString("TABLE_SCHEMA");
}
@Override
boolean shouldBulkSelect(String schemaKey, ResultSetCache resultSetCache) {
if (tableName.equalsIgnoreCase(database.getDatabaseChangeLogTableName()) ||
tableName.equalsIgnoreCase(database.getDatabaseChangeLogLockTableName())) {
return false;
}
return true;
}
@Override
public List<CachedRow> fastFetchQuery() throws SQLException, DatabaseException {
if (database instanceof OracleDatabase) {
return oracleQuery(false);
}
return Collections.emptyList();
}
@Override
public List<CachedRow> bulkFetchQuery() throws SQLException, DatabaseException {
if (database instanceof OracleDatabase) {
return oracleQuery(true);
}
return Collections.emptyList();
}
private List<CachedRow> oracleQuery(boolean bulk) throws DatabaseException, SQLException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
String jdbcSchemaName = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema);
String jdbcTableName = database.escapeStringForDatabase(tableName);
String sqlToSelectNotNullConstraints = "SELECT NULL AS TABLE_CAT, atc.OWNER AS TABLE_SCHEMA, atc.OWNER, atc.TABLE_NAME, " +
"atc.COLUMN_NAME, NULLABLE, ac.VALIDATED as VALIDATED, ac.SEARCH_CONDITION, ac.CONSTRAINT_NAME " +
"FROM ALL_TAB_COLS atc " +
"JOIN all_cons_columns acc ON atc.OWNER = acc.OWNER AND atc.TABLE_NAME = acc.TABLE_NAME AND atc.COLUMN_NAME = acc.COLUMN_NAME " +
"JOIN all_constraints ac ON atc.OWNER = ac.OWNER AND atc.TABLE_NAME = ac.TABLE_NAME AND acc.CONSTRAINT_NAME = ac.CONSTRAINT_NAME ";
if (!bulk || getAllCatalogsStringScratchData() == null) {
sqlToSelectNotNullConstraints += " WHERE atc.OWNER='" + jdbcSchemaName + "' AND atc.hidden_column='NO' AND ac.CONSTRAINT_TYPE='C' and ac.search_condition is not null ";
} else {
sqlToSelectNotNullConstraints += " WHERE atc.OWNER IN ('" + jdbcSchemaName + "', " + getAllCatalogsStringScratchData() + ") "
+ " AND atc.hidden_column='NO' AND ac.CONSTRAINT_TYPE='C' and ac.search_condition is not null ";
}
sqlToSelectNotNullConstraints += (!bulk && tableName != null && !tableName.isEmpty()) ? " AND atc.TABLE_NAME='" + jdbcTableName + "'":"";
return this.executeAndExtract(sqlToSelectNotNullConstraints, database);
}
@Override
protected List<CachedRow> extract(ResultSet resultSet, boolean informixIndexTrimHint) throws SQLException {
List<CachedRow> cachedRowList = new ArrayList<CachedRow>();
if (!(database instanceof OracleDatabase)) {
return cachedRowList;
}
resultSet.setFetchSize(database.getFetchSize());
List<Map> result;
try {
result = (List<Map>) new RowMapperNotNullConstraintsResultSetExtractor(new ColumnMapRowMapper() {
@Override
protected Object getColumnValue(ResultSet rs, int index) throws SQLException {
Object value = super.getColumnValue(rs, index);
if (value == null || !(value instanceof String)) {
return value;
}
return value.toString().trim();
}
}).extractData(resultSet);
for (Map row : result) {
cachedRowList.add(new CachedRow(row));
}
} finally {
JdbcUtils.closeResultSet(resultSet);
}
return cachedRowList;
}
}
public List<CachedRow> getTables(final String catalogName, final String schemaName, final String table) throws DatabaseException {
return getResultSetCache("getTables").get(new ResultSetCache.SingleResultSetExtractor(database) {
@Override
boolean shouldBulkSelect(String schemaKey, ResultSetCache resultSetCache) {
return table == null || getAllCatalogsStringScratchData() != null || super.shouldBulkSelect(schemaKey, resultSetCache);
}
@Override
public ResultSetCache.RowData rowKeyParameters(CachedRow row) {
return new ResultSetCache.RowData(row.getString("TABLE_CAT"), row.getString("TABLE_SCHEM"), database, row.getString("TABLE_NAME"));
}
@Override
public ResultSetCache.RowData wantedKeyParameters() {
return new ResultSetCache.RowData(catalogName, schemaName, database, table);
}
@Override
public boolean bulkContainsSchema(String schemaKey) {
return database instanceof OracleDatabase;
}
@Override
public String getSchemaKey(CachedRow row) {
return row.getString("TABLE_SCHEM");
}
@Override
public List<CachedRow> fastFetchQuery() throws SQLException, DatabaseException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
if (database instanceof OracleDatabase) {
return queryOracle(catalogAndSchema, table);
} else if (database instanceof MSSQLDatabase) {
return queryMssql(catalogAndSchema, table);
} else if (database instanceof Db2zDatabase) {
return queryDb2Zos(catalogAndSchema, table);
}
String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema);
String schema = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema);
return extract(databaseMetaData.getTables(catalog, schema, ((table == null) ?
SQL_FILTER_MATCH_ALL : table), new String[]{"TABLE"}));
}
@Override
public List<CachedRow> bulkFetchQuery() throws SQLException, DatabaseException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
if (database instanceof OracleDatabase) {
return queryOracle(catalogAndSchema, null);
} else if (database instanceof MSSQLDatabase) {
return queryMssql(catalogAndSchema, null);
} else if (database instanceof Db2zDatabase) {
return queryDb2Zos(catalogAndSchema, null);
}
String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema);
String schema = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema);
return extract(databaseMetaData.getTables(catalog, schema, SQL_FILTER_MATCH_ALL, new String[]{"TABLE"}));
}
private List<CachedRow> queryMssql(CatalogAndSchema catalogAndSchema, String tableName) throws DatabaseException, SQLException {
String ownerName = database.correctObjectName(catalogAndSchema.getSchemaName(), Schema.class);
String databaseName = StringUtils.trimToNull(database.correctObjectName(catalogAndSchema.getCatalogName(), Catalog.class));
String dbIdParam;
String databasePrefix;
if (databaseName == null) {
databasePrefix = "";
dbIdParam = "";
} else {
dbIdParam = ", db_id('"+databaseName+"')";
databasePrefix = "[" + databaseName + "].";
}
//From select object_definition(object_id('sp_tables'))
String sql = "select " +
"db_name(" + (databaseName == null ? "" : "db_id('" + databaseName + "')") + ") AS TABLE_CAT, " +
"convert(sysname,object_schema_name(o.object_id" + dbIdParam + ")) AS TABLE_SCHEM, " +
"convert(sysname,o.name) AS TABLE_NAME, " +
"'TABLE' AS TABLE_TYPE, " +
"CAST(ep.value as varchar(max)) as REMARKS " +
"from " + databasePrefix + "sys.all_objects o " +
"left outer join sys.extended_properties ep on ep.name='MS_Description' and major_id=o.object_id and minor_id=0 " +
"where " +
"o.type in ('U') " +
"and has_perms_by_name(" + (databaseName == null ? "" : "quotename('" + databaseName + "') + '.' + ") + "quotename(object_schema_name(o.object_id" + dbIdParam + ")) + '.' + quotename(o.name), 'object', 'select') = 1 " +
"and charindex(substring(o.type,1,1),'U') <> 0 " +
"and object_schema_name(o.object_id" + dbIdParam + ")='" + database.escapeStringForDatabase(ownerName) + "'";
if (tableName != null) {
sql += " AND o.name='" + database.escapeStringForDatabase(tableName) + "' ";
}
sql += "order by 4, 1, 2, 3";
return executeAndExtract(sql, database);
}
private List<CachedRow> queryOracle(CatalogAndSchema catalogAndSchema, String tableName) throws DatabaseException, SQLException {
String ownerName = database.correctObjectName(catalogAndSchema.getCatalogName(), Schema.class);
String sql = "SELECT null as TABLE_CAT, a.OWNER as TABLE_SCHEM, a.TABLE_NAME as TABLE_NAME, " +
"a.TEMPORARY as TEMPORARY, a.DURATION as DURATION, 'TABLE' as TABLE_TYPE, " +
"c.COMMENTS as REMARKS, CASE WHEN A.tablespace_name = " +
"(SELECT DEFAULT_TABLESPACE FROM USER_USERS) THEN NULL ELSE tablespace_name END AS tablespace_name " +
"from ALL_TABLES a " +
"join ALL_TAB_COMMENTS c on a.TABLE_NAME=c.table_name and a.owner=c.owner ";
String allCatalogsString = getAllCatalogsStringScratchData();
if (tableName != null || allCatalogsString == null) {
sql += "WHERE a.OWNER='" + ownerName + "'";
} else {
sql += "WHERE a.OWNER IN ('" + ownerName + "', " + allCatalogsString + ")";
}
if (tableName != null) {
sql += " AND a.TABLE_NAME='" + tableName + "'";
}
return executeAndExtract(sql, database);
}
private List<CachedRow> queryDb2Zos(CatalogAndSchema catalogAndSchema, String tableName) throws DatabaseException, SQLException {
String ownerName = database.correctObjectName(catalogAndSchema.getCatalogName(), Schema.class);
String sql = "SELECT CREATOR AS TABLE_SCHEM, " +
"NAME AS TABLE_NAME, " +
"'TABLE' AS TABLE_TYPE, " +
"REMARKS " +
"FROM SYSIBM.SYSTABLES " +
"WHERE TYPE = 'T' ";
if (ownerName != null) {
sql += "AND CREATOR='" + ownerName + "'";
}
if (tableName != null) {
sql += " AND NAME='" + tableName + "'";
}
return executeAndExtract(sql, database);
}
});
}
public List<CachedRow> getViews(final String catalogName, final String schemaName, String viewName) throws DatabaseException {
final String view;
if (database instanceof DB2Database) {
view = database.correctObjectName(viewName, View.class);
}
else {
view = viewName;
}
return getResultSetCache("getViews").get(new ResultSetCache.SingleResultSetExtractor(database) {
@Override
boolean shouldBulkSelect(String schemaKey, ResultSetCache resultSetCache) {
return view == null || getAllCatalogsStringScratchData() != null || super.shouldBulkSelect(schemaKey, resultSetCache);
}
@Override
public ResultSetCache.RowData rowKeyParameters(CachedRow row) {
return new ResultSetCache.RowData(row.getString("TABLE_CAT"), row.getString("TABLE_SCHEM"), database, row.getString("TABLE_NAME"));
}
@Override
public ResultSetCache.RowData wantedKeyParameters() {
return new ResultSetCache.RowData(catalogName, schemaName, database, view);
}
@Override
public boolean bulkContainsSchema(String schemaKey) {
return database instanceof OracleDatabase;
}
@Override
public String getSchemaKey(CachedRow row) {
return row.getString("TABLE_SCHEM");
}
@Override
public List<CachedRow> fastFetchQuery() throws SQLException, DatabaseException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
if (database instanceof OracleDatabase) {
return queryOracle(catalogAndSchema, view);
}
String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema);
String schema = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema);
return extract(databaseMetaData.getTables(catalog, schema, ((view == null) ? SQL_FILTER_MATCH_ALL
: view), new String[]{"VIEW"}));
}
@Override
public List<CachedRow> bulkFetchQuery() throws SQLException, DatabaseException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
if (database instanceof OracleDatabase) {
return queryOracle(catalogAndSchema, null);
}
String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema);
String schema = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema);
return extract(databaseMetaData.getTables(catalog, schema, SQL_FILTER_MATCH_ALL, new String[]{"VIEW"}));
}
private List<CachedRow> queryOracle(CatalogAndSchema catalogAndSchema, String viewName) throws DatabaseException, SQLException {
String ownerName = database.correctObjectName(catalogAndSchema.getCatalogName(), Schema.class);
String sql = "SELECT null as TABLE_CAT, a.OWNER as TABLE_SCHEM, a.VIEW_NAME as TABLE_NAME, 'TABLE' as TABLE_TYPE, c.COMMENTS as REMARKS, TEXT as OBJECT_BODY" ;
if(database.getDatabaseMajorVersion() > 10){
sql += ", EDITIONING_VIEW";
}
sql += " from ALL_VIEWS a " +
"join ALL_TAB_COMMENTS c on a.VIEW_NAME=c.table_name and a.owner=c.owner ";
if (viewName != null || getAllCatalogsStringScratchData() == null) {
sql += "WHERE a.OWNER='" + ownerName + "'";
} else {
sql += "WHERE a.OWNER IN ('" + ownerName + "', " + getAllCatalogsStringScratchData() + ")";
}
if (viewName != null) {
sql += " AND a.VIEW_NAME='" + database.correctObjectName(viewName, View.class) + "'";
}
sql += " AND a.VIEW_NAME not in (select mv.name from all_registered_mviews mv where mv.owner=a.owner)";
return executeAndExtract(sql, database);
}
});
}
public List<CachedRow> getPrimaryKeys(final String catalogName, final String schemaName, final String table) throws DatabaseException {
return getResultSetCache("getPrimaryKeys").get(new ResultSetCache.SingleResultSetExtractor(database) {
@Override
public ResultSetCache.RowData rowKeyParameters(CachedRow row) {
return new ResultSetCache.RowData(row.getString("TABLE_CAT"), row.getString("TABLE_SCHEM"), database, row.getString("TABLE_NAME"));
}
@Override
public ResultSetCache.RowData wantedKeyParameters() {
return new ResultSetCache.RowData(catalogName, schemaName, database, table);
}
@Override
public boolean bulkContainsSchema(String schemaKey) {
return database instanceof OracleDatabase;
}
@Override
public String getSchemaKey(CachedRow row) {
return row.getString("TABLE_SCHEM");
}
@Override
public List<CachedRow> fastFetchQuery() throws SQLException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
try {
List<CachedRow> foundPks = new ArrayList<>();
if (table == null) {
List<CachedRow> tables = CachingDatabaseMetaData.this.getTables(catalogName, schemaName, null);
for (CachedRow table : tables) {
List<CachedRow> pkInfo = getPkInfo(schemaName, catalogAndSchema, table.getString("TABLE_NAME"));
if (pkInfo != null) {
foundPks.addAll(pkInfo);
}
}
return foundPks;
} else {
List<CachedRow> pkInfo = getPkInfo(schemaName, catalogAndSchema, table);
if (pkInfo != null) {
foundPks.addAll(pkInfo);
}
}
return foundPks;
} catch (DatabaseException e) {
throw new SQLException(e);
}
}
private List<CachedRow> getPkInfo(String schemaName, CatalogAndSchema catalogAndSchema, String tableName) throws DatabaseException, SQLException {
List<CachedRow> pkInfo;
if (database instanceof MSSQLDatabase) {
String sql = mssqlSql(catalogAndSchema, tableName);
pkInfo = executeAndExtract(sql, database);
} else {
if (database instanceof Db2zDatabase) {
String sql = "SELECT 'NULL' AS TABLE_CAT," +
" SYSTAB.TBCREATOR AS TABLE_SCHEM, " +
"SYSTAB.TBNAME AS TABLE_NAME, " +
"COLUSE.COLNAME AS COLUMN_NAME, " +
"COLUSE.COLSEQ AS KEY_SEQ, " +
"SYSTAB.CONSTNAME AS PK_NAME " +
"FROM SYSIBM.SYSTABCONST SYSTAB " +
"JOIN SYSIBM.SYSKEYCOLUSE COLUSE " +
"ON SYSTAB.TBCREATOR = COLUSE.TBCREATOR " +
"WHERE SYSTAB.TYPE = 'P' " +
"AND SYSTAB.TBNAME='" + table + "' " +
"AND SYSTAB.TBCREATOR='" + schemaName + "' " +
"AND SYSTAB.TBNAME=COLUSE.TBNAME " +
"AND SYSTAB.CONSTNAME=COLUSE.CONSTNAME " +
"ORDER BY COLUSE.COLNAME";
try {
return executeAndExtract(sql, database);
} catch (DatabaseException e) {
throw new SQLException(e);
}
} else if (database instanceof OracleDatabase) {
warnAboutDbaRecycleBin();
String sql = "SELECT NULL AS table_cat, c.owner AS table_schem, c.table_name, c.column_name as COLUMN_NAME, c.position AS key_seq, c.constraint_name AS pk_name, k.VALIDATED as VALIDATED " +
"FROM all_cons_columns c, all_constraints k " +
"LEFT JOIN " + "user_recyclebin" + " d ON d.object_name=k.table_name " +
"WHERE k.constraint_type = 'P' " +
"AND d.object_name IS NULL " +
"AND k.table_name = '" + table + "' " +
"AND k.owner = '" + ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema) + "' " +
"AND k.constraint_name = c.constraint_name " +
"AND k.table_name = c.table_name " +
"AND k.owner = c.owner " +
"ORDER BY column_name";
try {
return executeAndExtract(sql, database);
} catch (DatabaseException e) {
throw new SQLException(e);
}
} else {
return extract(
databaseMetaData.getPrimaryKeys(
((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema),
((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema),
table
)
);
}
}
return pkInfo;
}
private String mssqlSql(CatalogAndSchema catalogAndSchema, String tableName) throws DatabaseException {
String sql;
sql =
"SELECT " +
"DB_NAME() AS [TABLE_CAT], " +
"[s].[name] AS [TABLE_SCHEM], " +
"[t].[name] AS [TABLE_NAME], " +
"[c].[name] AS [COLUMN_NAME], " +
"CASE [ic].[is_descending_key] WHEN 0 THEN N'A' WHEN 1 THEN N'D' END AS [ASC_OR_DESC], " +
"[ic].[key_ordinal] AS [KEY_SEQ], " +
"[kc].[name] AS [PK_NAME] " +
"FROM [sys].[schemas] AS [s] " +
"INNER JOIN [sys].[tables] AS [t] " +
"ON [t].[schema_id] = [s].[schema_id] " +
"INNER JOIN [sys].[key_constraints] AS [kc] " +
"ON [kc].[parent_object_id] = [t].[object_id] " +
"INNER JOIN [sys].[indexes] AS [i] " +
"ON [i].[object_id] = [kc].[parent_object_id] " +
"AND [i].[index_id] = [kc].[unique_index_id] " +
"INNER JOIN [sys].[index_columns] AS [ic] " +
"ON [ic].[object_id] = [i].[object_id] " +
"AND [ic].[index_id] = [i].[index_id] " +
"INNER JOIN [sys].[columns] AS [c] " +
"ON [c].[object_id] = [ic].[object_id] " +
"AND [c].[column_id] = [ic].[column_id] " +
"WHERE [s].[name] = N'" + database.escapeStringForDatabase(catalogAndSchema.getSchemaName()) + "' " + // The schema name was corrected in the customized CatalogAndSchema
(tableName == null ? "" : "AND [t].[name] = N'" + database.escapeStringForDatabase(database.correctObjectName(tableName, Table.class)) + "' ") +
"AND [kc].[type] = 'PK' " +
"AND [ic].[key_ordinal] > 0 " +
"ORDER BY " +
"[ic].[key_ordinal]";
return sql;
}
@Override
public List<CachedRow> bulkFetchQuery() throws SQLException {
if (database instanceof OracleDatabase) {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
warnAboutDbaRecycleBin();
try {
String sql = "SELECT NULL AS table_cat, c.owner AS table_schem, c.table_name, c.column_name, c.position AS key_seq,c.constraint_name AS pk_name, k.VALIDATED as VALIDATED FROM " +
"all_cons_columns c, " +
"all_constraints k " +
"LEFT JOIN " + "user_recyclebin" + " d ON d.object_name=k.table_name " +
"WHERE k.constraint_type = 'P' " +
"AND d.object_name IS NULL ";
if (getAllCatalogsStringScratchData() == null) {
sql += "AND k.owner='" + catalogAndSchema.getCatalogName() + "' ";
} else {
sql += "AND k.owner IN ('" + catalogAndSchema.getCatalogName() + "', " + getAllCatalogsStringScratchData() + ")";
}
sql += "AND k.constraint_name = c.constraint_name " +
"AND k.table_name = c.table_name " +
"AND k.owner = c.owner " +
"ORDER BY column_name";
return executeAndExtract(sql, database);
} catch (DatabaseException e) {
throw new SQLException(e);
}
} else if (database instanceof MSSQLDatabase) {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
try {
return executeAndExtract(mssqlSql(catalogAndSchema, null), database);
} catch (DatabaseException e) {
throw new SQLException(e);
}
}
return null;
}
@Override
boolean shouldBulkSelect(String schemaKey, ResultSetCache resultSetCache) {
if ((database instanceof OracleDatabase) || (database instanceof MSSQLDatabase)) {
return table == null || getAllCatalogsStringScratchData() != null || super.shouldBulkSelect(schemaKey, resultSetCache);
} else {
return false;
}
}
});
}
public List<CachedRow> getUniqueConstraints(final String catalogName, final String schemaName, final String tableName) throws DatabaseException {
return getResultSetCache("getUniqueConstraints").get(new ResultSetCache.SingleResultSetExtractor(database) {
@Override
boolean shouldBulkSelect(String schemaKey, ResultSetCache resultSetCache) {
return tableName == null || getAllCatalogsStringScratchData() != null || super.shouldBulkSelect(schemaKey, resultSetCache);
}
@Override
public boolean bulkContainsSchema(String schemaKey) {
return database instanceof OracleDatabase;
}
@Override
public String getSchemaKey(CachedRow row) {
return row.getString("CONSTRAINT_SCHEM");
}
@Override
public ResultSetCache.RowData rowKeyParameters(CachedRow row) {
return new ResultSetCache.RowData(catalogName, schemaName, database, row.getString("TABLE_NAME"));
}
@Override
public ResultSetCache.RowData wantedKeyParameters() {
return new ResultSetCache.RowData(catalogName, schemaName, database, tableName);
}
@Override
public List<CachedRow> fastFetchQuery() throws SQLException, DatabaseException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
return executeAndExtract(createSql(((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema), ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema), tableName), JdbcDatabaseSnapshot.this.getDatabase(), (database instanceof InformixDatabase));
}
@Override
public List<CachedRow> bulkFetchQuery() throws SQLException, DatabaseException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
return executeAndExtract(createSql(((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema), ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema), null), JdbcDatabaseSnapshot.this.getDatabase());
}
private String createSql(String catalogName, String schemaName, String tableName) throws SQLException {
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);
String jdbcCatalogName = database.correctObjectName(((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema), Catalog.class);
String jdbcSchemaName = database.correctObjectName(((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema), Schema.class);
Database database = JdbcDatabaseSnapshot.this.getDatabase();
String sql;
if( database instanceof Ingres9Database ) {
sql = "select CONSTRAINT_NAME, TABLE_NAME from iiconstraints where schema_name ='"
+ schemaName + "' and constraint_type='U'";
if (tableName != null) {
sql += " and table_name='" + tableName + "'";
}
} else if ((database instanceof MySQLDatabase) || (database instanceof HsqlDatabase) || (database
instanceof MariaDBDatabase)) {
sql = "select CONSTRAINT_NAME, TABLE_NAME "
+ "from " + database.getSystemSchema() + ".table_constraints "
+ "where constraint_schema='" + jdbcCatalogName + "' "
+ "and constraint_type='UNIQUE'";
if (tableName != null) {
sql += " and table_name='" + tableName + "'";
}
} else if (database instanceof PostgresDatabase) {
sql = "select CONSTRAINT_NAME, TABLE_NAME "
+ "from " + database.getSystemSchema() + ".table_constraints "
+ "where constraint_catalog='" + jdbcCatalogName + "' "
+ "and constraint_schema='" + jdbcSchemaName + "' "
+ "and constraint_type='UNIQUE'";
if (tableName != null) {
sql += " and table_name='" + tableName + "'";
}
} else if (database instanceof MSSQLDatabase) {
sql =
"SELECT " +
"[TC].[CONSTRAINT_NAME], " +
"[TC].[TABLE_NAME], " +
"[TC].[CONSTRAINT_CATALOG] AS INDEX_CATALOG, " +
"[TC].[CONSTRAINT_SCHEMA] AS INDEX_SCHEMA, " +
"[IDX].[TYPE_DESC], " +
"[IDX].[name] AS INDEX_NAME " +
"FROM [INFORMATION_SCHEMA].[TABLE_CONSTRAINTS] AS [TC] " +
"JOIN sys.indexes AS IDX ON IDX.name=[TC].[CONSTRAINT_NAME] AND object_schema_name(object_id)=[TC].[CONSTRAINT_SCHEMA] " +
"WHERE [TC].[CONSTRAINT_TYPE] = 'UNIQUE' " +
"AND [TC].[CONSTRAINT_CATALOG] = N'" + database.escapeStringForDatabase(jdbcCatalogName) + "' " +
"AND [TC].[CONSTRAINT_SCHEMA] = N'" + database.escapeStringForDatabase(jdbcSchemaName) + "'";
if (tableName != null) {
sql += " AND [TC].[TABLE_NAME] = N'" + database.escapeStringForDatabase(database.correctObjectName(tableName, Table.class)) + "'";
}
} else if (database instanceof OracleDatabase) {
warnAboutDbaRecycleBin();
sql = "select uc.owner AS CONSTRAINT_SCHEM, uc.constraint_name, uc.table_name,uc.status,uc.deferrable,uc.deferred,ui.tablespace_name, ui.index_name, ui.owner as INDEX_CATALOG, uc.VALIDATED as VALIDATED, ac.COLUMN_NAME as COLUMN_NAME " +
"from all_constraints uc " +
"join all_indexes ui on uc.index_name = ui.index_name and uc.owner=ui.table_owner and uc.table_name=ui.table_name " +
"LEFT OUTER JOIN " + "user_recyclebin" + " d ON d.object_name=ui.table_name " +
"LEFT JOIN all_cons_columns ac ON ac.OWNER = uc.OWNER AND ac.TABLE_NAME = uc.TABLE_NAME AND ac.CONSTRAINT_NAME = uc.CONSTRAINT_NAME "+
"where uc.constraint_type='U' ";
if (tableName != null || getAllCatalogsStringScratchData() == null) {
sql += "and uc.owner = '" + jdbcSchemaName + "'";
} else {
sql += "and uc.owner IN ('" + jdbcSchemaName + "', " + getAllCatalogsStringScratchData() + ")";
}
sql += "AND d.object_name IS NULL ";
if (tableName != null) {
sql += " and uc.table_name = '" + tableName + "'";
}
} else if (database instanceof DB2Database) {
// if we are on DB2 AS400 iSeries
if (database.getDatabaseProductName().startsWith("DB2 UDB for AS/400")) {
sql = "select constraint_name as constraint_name, table_name as table_name from QSYS2.TABLE_CONSTRAINTS where table_schema='" + jdbcSchemaName + "' and constraint_type='UNIQUE'";
if (tableName != null) {
sql += " and table_name = '" + tableName + "'";
}
// DB2 z/OS
}
// here we are on DB2 UDB
else {
sql = "select distinct k.constname as constraint_name, t.tabname as TABLE_NAME from syscat.keycoluse k, syscat.tabconst t "
+ "where k.constname = t.constname "
+ "and t.tabschema = '" + jdbcSchemaName + "' "
+ "and t.type='U'";
if (tableName != null) {
sql += " and t.tabname = '" + tableName + "'";
}
}
} else if (database instanceof Db2zDatabase) {
sql = "select distinct k.constname as constraint_name, t.tbname as TABLE_NAME from SYSIBM.SYSKEYCOLUSE k, SYSIBM.SYSTABCONST t "
+ "where k.constname = t.constname "
+ "and k.TBCREATOR = t.TBCREATOR "
+ "and t.TBCREATOR = '" + jdbcSchemaName + "' ";
if (tableName != null) {
sql += " and t.tbname = '" + tableName + "'";
}
} else if (database instanceof FirebirdDatabase) {
sql = "SELECT TRIM(RDB$INDICES.RDB$INDEX_NAME) AS CONSTRAINT_NAME, " +
"TRIM(RDB$INDICES.RDB$RELATION_NAME) AS TABLE_NAME " +
"FROM RDB$INDICES "
+ "LEFT JOIN RDB$RELATION_CONSTRAINTS "
+ "ON RDB$RELATION_CONSTRAINTS.RDB$INDEX_NAME = RDB$INDICES.RDB$INDEX_NAME "
+ "WHERE RDB$INDICES.RDB$UNIQUE_FLAG IS NOT NULL "
+ "AND ("
+ "RDB$RELATION_CONSTRAINTS.RDB$CONSTRAINT_TYPE IS NULL "
+ "OR TRIM(RDB$RELATION_CONSTRAINTS.RDB$CONSTRAINT_TYPE)='UNIQUE') "
+ "AND NOT(RDB$INDICES.RDB$INDEX_NAME LIKE 'RDB$%')";
if (tableName != null) {
sql += " AND TRIM(RDB$INDICES.RDB$RELATION_NAME)='" + tableName + "'";
}
} else if (database instanceof DerbyDatabase) {
sql = "select c.constraintname as CONSTRAINT_NAME, tablename AS TABLE_NAME "
+ "from sys.systables t, sys.sysconstraints c, sys.sysschemas s "
+ "where s.schemaname='" + jdbcCatalogName + "' "
+ "and t.tableid = c.tableid "
+ "and t.schemaid=s.schemaid "
+ "and c.type = 'U'";
if (tableName != null) {
sql += " AND t.tablename = '" + tableName + "'";
}
} else if (database instanceof InformixDatabase) {
sql = "select unique sysindexes.idxname as CONSTRAINT_NAME, sysindexes.idxtype, systables.tabname as TABLE_NAME "
+ "from sysindexes, systables "
+ "left outer join sysconstraints on sysconstraints.tabid = systables.tabid and sysconstraints.constrtype = 'P' "
+ "where sysindexes.tabid = systables.tabid and sysindexes.idxtype = 'U' "
+ "and sysconstraints.idxname != sysindexes.idxname "
+ "and sysconstraints.tabid = sysindexes.tabid";
if (tableName != null) {
sql += " and systables.tabname = '" + database.correctObjectName(tableName, Table.class) + "'";
}
} else if (database instanceof SybaseDatabase) {
LogService.getLog(getClass()).warning(LogType.LOG, "Finding unique constraints not currently supported for Sybase");
return null; //TODO: find sybase sql
} else if (database instanceof SybaseASADatabase) {
sql = "select sysconstraint.constraint_name, sysconstraint.constraint_type, systable.table_name " +
"from sysconstraint, systable " +
"where sysconstraint.table_object_id = systable.object_id " +
"and sysconstraint.constraint_type = 'U'";
if (tableName != null) {
sql += " and systable.table_name = '" + tableName + "'";
}
} else {
sql = "select CONSTRAINT_NAME, CONSTRAINT_TYPE, TABLE_NAME "
+ "from " + database.getSystemSchema() + ".constraints "
+ "where constraint_schema='" + jdbcSchemaName + "' "
+ "and constraint_catalog='" + jdbcCatalogName + "' "
+ "and constraint_type='UNIQUE'";
if (tableName != null) {
sql += " and table_name='" + tableName + "'";
}
}
return sql;
}
});
}
}
private String getAllCatalogsStringScratchData() {
return (String) JdbcDatabaseSnapshot.this.getScratchData(ALL_CATALOGS_STRING_SCRATCH_KEY);
}
}
package cn.ibizlab.core.lite.extensions.domain;
import cn.ibizlab.core.lite.domain.MetaRelationship;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Getter;
import lombok.NoArgsConstructor;
......@@ -27,4 +28,6 @@ public class RelationshipModel {
private String entityId;
private MetaRelationship relation;
}
......@@ -4,8 +4,10 @@ import cn.ibizlab.core.lite.domain.*;
import cn.ibizlab.core.lite.extensions.domain.MetaEntityModel;
import cn.ibizlab.core.lite.extensions.domain.SysModel;
import cn.ibizlab.core.lite.extensions.mapping.MetaEntityMapping;
import cn.ibizlab.core.lite.filter.MetaFieldSearchContext;
import cn.ibizlab.core.lite.service.*;
import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.util.helper.DataObject;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
......@@ -126,7 +128,7 @@ public class LiteCoreService {
entity.setEntityId(entity.getDefaultKey(true).toString());
create.add(entity);
}
gloabEntity.put(sysModel.getSystemid()+"."+entity.getEntityName(),entity.getEntityId());
gloabEntity.put((sysModel.getSystemid()+"."+entity.getEntityName()).toUpperCase(),entity.getEntityId());
String moduleId=entity.getModuleId();
String moduleName=entity.getModuleName();
if(!ObjectUtils.isEmpty(moduleId) && !ObjectUtils.isEmpty(moduleName)){
......@@ -163,24 +165,60 @@ public class LiteCoreService {
* @param sysModel
*/
private void syncDEField(SysModel sysModel,int saveMode) {
Map<String,String> delField = new HashMap<>();
Map param=new HashMap();
param.put("id",sysModel.getSystemid());
List<JSONObject> oldField=fieldService.select("select fieldid as \"FIELDID\",fieldname as \"FIELDNAME\",t.entityid as \"ENTITYID\",t.entityname as \"ENTITYNAME\" from ibzfield t inner join ibzentity t1 on t.entityid =t1.entityid where t1.systemid = #{et.id}",param);
for(JSONObject field: oldField){
delField.put(field.getString("ENTITYNAME")+"."+field.getString("FIELDNAME"),field.getString("FIELDID"));
}
Map<String,MetaField> delField = new HashMap<>();
MetaFieldSearchContext context=new MetaFieldSearchContext();
context.setSize(Integer.MAX_VALUE);
context.setN_systemid_eq(sysModel.getSystemid());
fieldService.searchDefault(context).getContent().forEach(item->{
delField.put((item.getEntityName()+"."+item.getFieldName()).toUpperCase(),item);
});
List<MetaField> create=new ArrayList<>();
List<MetaField> update=new ArrayList<>();
List<MetaField> change=new ArrayList<>();
Set<MetaField> list = sysModel.getField();
list.forEach(field -> {
if(gloabEntity.containsKey(sysModel.getSystemid()+"."+field.getEntityName()))
field.setEntityId(gloabEntity.get(sysModel.getSystemid()+"."+field.getEntityName()));
if(delField.containsKey(field.getEntityName()+"."+field.getFieldName()))
if(gloabEntity.containsKey((sysModel.getSystemid()+"."+field.getEntityName()).toUpperCase()))
field.setEntityId(gloabEntity.get((sysModel.getSystemid()+"."+field.getEntityName()).toUpperCase()));
String fieldKey=(field.getEntityName()+"."+field.getFieldName()).toUpperCase();
if(delField.containsKey(fieldKey))
{
field.setFieldId(delField.get(field.getEntityName()+"."+field.getFieldName()));
MetaField oldField = delField.get(fieldKey);
field.setFieldId(oldField.getFieldId());
update.add(field);
delField.remove(field.getEntityName()+"."+field.getFieldName());
if((!DataObject.getStringValue(oldField.getFieldType(),"").equalsIgnoreCase(DataObject.getStringValue(field.getFieldType(),"")))
||(DataObject.getIntegerValue(oldField.getDataLength(),0)!=DataObject.getIntegerValue(field.getDataLength(),0)&&(!DataObject.getStringValue(oldField.getFieldType(),"").startsWith("DATE")))
||DataObject.getIntegerValue(oldField.getNullable(),0)!=DataObject.getIntegerValue(field.getNullable(),0)
||(!DataObject.getStringValue(oldField.getUnionKey(),"").equalsIgnoreCase(DataObject.getStringValue(field.getUnionKey(),"")))
||(DataObject.getIntegerValue(oldField.getKeyField(),0)!=DataObject.getIntegerValue(field.getKeyField(),0))
||(!DataObject.getStringValue(oldField.getPredefined(),"").equalsIgnoreCase(DataObject.getStringValue(field.getPredefined(),"")))
||((!DataObject.getStringValue(oldField.getExpression(),"").equalsIgnoreCase(DataObject.getStringValue(field.getExpression(),"")))&&DataObject.getIntegerValue(oldField.getPhysicalField(),1)==0)
)
{
MetaField newField=new MetaField();
newField.setFieldId(oldField.getFieldId());
newField.setEntityName(field.getEntityName());
newField.setFieldName(field.getFieldName());
newField.setDataType(field.getDataType());
newField.setFieldType(field.getFieldType());
newField.setDataLength(field.getDataLength());
newField.setDataPreci(field.getDataPreci());
newField.setNullable(field.getNullable());
newField.setUnionKey(field.getUnionKey());
if(!StringUtils.isEmpty(field.getExpression()))
newField.setExpression(field.getExpression());
if(!StringUtils.isEmpty(field.getPredefined()))
newField.setPredefined(field.getPredefined());
newField.setKeyField(field.getKeyField());
change.add(newField);
}
delField.remove(fieldKey);
}
else {
field.setFieldId(field.getDefaultKey(true).toString());
......@@ -192,10 +230,21 @@ public class LiteCoreService {
// if(delField.size()>0)
// fieldService.removeBatch(delField.values());
//存储或更新资源saveOrUpdate
if(create.size()>0&&saveMode!=ONLYUPDATE)
change.forEach(newField->{
System.out.println(newField.getEntityName()+"."+newField.getFieldName()+" "+newField.getDataType()+"("+newField.getDataLength()+(DataObject.getIntegerValue(newField.getDataPreci(),0)==0?")":(","+newField.getDataPreci()+")"))
+(DataObject.getIntegerValue(newField.getNullable(),0)==0?" not null":" null")+" "+DataObject.getStringValue(newField.getUnionKey(),""));
});
if(create.size()>0&&saveMode!=ONLYUPDATE) {
fieldService.createBatch(create);
if(update.size()>0&&saveMode!=ONLYCREATE)
}
if(change.size()>0&&saveMode==ONLYCREATE) {
fieldService.updateBatch(change);
}
if(update.size()>0&&saveMode!=ONLYCREATE) {
fieldService.updateBatch(update);
}
}
/**
......
package cn.ibizlab.core.lite.extensions.service;
import cn.ibizlab.core.lite.domain.*;
import cn.ibizlab.core.lite.domain.DstApp;
import cn.ibizlab.core.lite.domain.DstSystem;
import cn.ibizlab.core.lite.domain.MetaEntity;
import cn.ibizlab.core.lite.domain.MetaModel;
import cn.ibizlab.core.lite.extensions.domain.EntityModel;
import cn.ibizlab.core.lite.extensions.domain.FieldModel;
import cn.ibizlab.core.lite.extensions.domain.RelationshipModel;
import cn.ibizlab.core.lite.extensions.model.DataModel;
import cn.ibizlab.core.lite.extensions.util.LiteStorage;
import cn.ibizlab.core.lite.filter.MetaEntitySearchContext;
import cn.ibizlab.core.lite.filter.MetaFieldSearchContext;
import cn.ibizlab.core.lite.service.*;
import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.util.domain.FileItem;
import cn.ibizlab.util.errors.InternalServerErrorException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.sql.Wrapper;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.util.*;
import static cn.ibizlab.util.service.SimpleFileService.getExtensionName;
@Service
public class LiteModelService {
......@@ -55,11 +62,6 @@ public class LiteModelService {
@Lazy
private IMetaRelationshipService metaRelationshipService;
@Autowired
@Lazy
private IDstDataSourceService dstDataSourceService;
@Autowired
@Lazy
private IMetaDataSetService metaDataSetService;
......@@ -91,27 +93,30 @@ public class LiteModelService {
EntityModel entityModel = new EntityModel();
entityModel.setEntity(entity);
entityModel.setDataSets(metaDataSetService.selectByEntityId(entity.getEntityId()));
Map<String, RelationshipModel> parentSet = new LinkedHashMap();
List<RelationshipModel> references = new ArrayList<>();
metaRelationshipService.selectByEntityId(entity.getEntityId()).forEach(item->
{
RelationshipModel model = new RelationshipModel();
MetaEntity parentEntity = LiteStorage.getMetaEntity(item.getRefEntityId());
if(parentEntity!=null){
model.setCodeName(item.getCodeName());
model.setDataSourceName(parentEntity.getDsName());
model.setEntityCodeName(parentEntity.getCodeName());
model.setEntityId(parentEntity.getEntityId());
model.setEntityLogicName(parentEntity.getLogicName());
model.setEntityName(parentEntity.getEntityName());
model.setSystemId(parentEntity.getSystemId());
model.setTableName(parentEntity.getTableName());
parentSet.put(item.getId(),model);
references.add(model);
}
});
if (entity != null) {
entityModel.setDataSets(metaDataSetService.selectByEntityId(entity.getEntityId()));
metaRelationshipService.selectByEntityId(entity.getEntityId()).forEach(item->
{
RelationshipModel model = new RelationshipModel();
MetaEntity parentEntity = LiteStorage.getMetaEntity(item.getRefEntityId());
if(parentEntity!=null){
model.setRelation(item);
model.setCodeName(item.getCodeName());
model.setDataSourceName(parentEntity.getDsName());
model.setEntityCodeName(parentEntity.getCodeName());
model.setEntityId(parentEntity.getEntityId());
model.setEntityLogicName(parentEntity.getLogicName());
model.setEntityName(parentEntity.getEntityName());
model.setSystemId(parentEntity.getSystemId());
model.setTableName(parentEntity.getTableName());
parentSet.put(item.getId(),model);
references.add(model);
}
});
}
entityModel.setReferences(references);
List<RelationshipModel> nesteds = new ArrayList<>();
......@@ -120,6 +125,7 @@ public class LiteModelService {
RelationshipModel model = new RelationshipModel();
MetaEntity subEntity = LiteStorage.getMetaEntity(item.getEntityId());
if(subEntity!=null){
model.setRelation(item);
model.setCodeName(StringUtils.isEmpty(item.getNestedName())?item.getCodeName()+"_"+item.getEntityName():item.getNestedName());
model.setDataSourceName(subEntity.getDsName());
model.setEntityCodeName(subEntity.getCodeName());
......@@ -166,9 +172,7 @@ public class LiteModelService {
public void initMetaEntity()
{
metaEntityService.list().forEach(metaEntity -> {
LiteStorage.putMetaEntity(metaEntity);
});
metaEntityService.list().forEach(LiteStorage::putMetaEntity);
}
@Autowired
......@@ -195,6 +199,8 @@ public class LiteModelService {
@Lazy
private IDstSystemService dstSystemService;
@Value("${ibiz.filePath:/app/file/}")
private String fileRoot;
@Cacheable( value="syspssystem",key = "'row:all-dst-apps'")
public LinkedHashMap<String, DstApp> getApps() {
......@@ -209,9 +215,7 @@ public class LiteModelService {
system.setApps(system.getSysstructure().getSysApps(true));
dstSystemService.update(system);
}
system.getApps().forEach(app-> {
appNode.put(app.getId(),app);
});
system.getApps().forEach(app-> appNode.put(app.getId(),app));
});
return appNode;
}
......@@ -247,4 +251,65 @@ public class LiteModelService {
return list;
}
public FileItem uploadFile(MultipartFile multipartFile) {
FileItem item;
// 获取文件名
String fileName = multipartFile.getOriginalFilename();
// 获取文件后缀
String extname = "."+getExtensionName(fileName);
try {
String fileid = DigestUtils.md5DigestAsHex(multipartFile.getInputStream());
String fileFullPath = this.fileRoot+"ibizutil"+File.separator+File.separator+fileName;
File file = new File(fileFullPath);
File parent = new File(file.getParent());
if(!parent.exists()) {
parent.mkdirs();
}
FileCopyUtils.copy(multipartFile.getInputStream(), Files.newOutputStream(file.toPath()));
item = new FileItem(fileid, fileName, fileid, fileName, (int)multipartFile.getSize(), extname);
} catch (IOException e) {
throw new InternalServerErrorException("文件上传失败,"+e);
}
return item;
}
public String saveFile(String jsonObject) {
// 获取文件名
String fileName = "packageModel_"+UUID.randomUUID().toString().replace("-","").toUpperCase();
// 获取文件后缀
String extname = ".json";
try {
String fileFullPath = this.fileRoot+"ibizutil"+File.separator+fileName+extname;
File file = new File(fileFullPath);
File parent = new File(file.getParent());
if(!parent.exists()) {
parent.mkdirs();
}
writeFile(fileFullPath,jsonObject);
} catch (Exception e) {
throw new InternalServerErrorException("文件上传失败,"+e);
}
return fileName+extname;
}
public File getFile(String fileId) {
String dirpath = this.fileRoot + "ibizutil" + File.separator + fileId;
File parent = new File(dirpath);
if (parent.exists()) {
return parent;
}
throw new InternalServerErrorException("文件未找到");
}
public static void writeFile(String filePath, String sets) throws IOException {
FileWriter fw = new FileWriter(filePath);
PrintWriter out = new PrintWriter(fw);
out.write(sets);
out.println();
fw.close();
out.close();
}
}
......@@ -63,7 +63,7 @@ public class DstLiquibaseService{
@Value("${ibiz.generateDs.catalogName:}")
protected String catalogName;
@Value("${ibiz.generateDs.generateField:tables,views,columns,indexes,foreignkeys,primarykeys,uniqueconstraints}")
@Value("${ibiz.generateDs.generateField:tables,columns,indexes,foreignkeys,primarykeys,uniqueconstraints}")
protected String generateField;
@Value("${ibiz.generateDs.includeCatalog:false}")
......@@ -170,6 +170,26 @@ public class DstLiquibaseService{
sysModel.setSystemid((String) commonMessage.get(0).get("author"));
sysModel.setSystemname((String) commonMessage.get(0).get("author"));
}
Hashtable<String,Set<String>> keysets=new Hashtable<String,Set<String>>();
for (int i = 0;i < commonMessage.size(); i++) {
temp = (Map) commonMessage.get(i).get("addPrimaryKey");
if(ObjectUtil.isEmpty(temp)){
continue;
}
if(ObjectUtil.isEmpty(temp.get("tableName"))||ObjectUtil.isEmpty(temp.get("columnNames"))){
continue;
}
String tableName=temp.get("tableName").toString().toUpperCase();
String columnNames=temp.get("columnNames").toString().toUpperCase().replace(" ", "");
Set<String> sets=new LinkedHashSet<>();
for(String str:columnNames.split(","))
{
sets.add(str);
}
keysets.put(tableName, sets);
}
// 第三层 获取实体对象List 在这层可以放入subEntitys、parentEntitys等关系字段
for (int i = 0;i < commonMessage.size(); i++) {
temp = (Map) commonMessage.get(i).get("createTable");
......@@ -178,12 +198,14 @@ public class DstLiquibaseService{
}
metaEntityModel = new MetaEntityModel();
// 为了获取MetaEntityModel下那些基本类型字段(此处可补充MetaEntityModel等描述字段)
metaEntityModel.setEntityName(temp.get("tableName") == null ? "" : temp.get("tableName").toString().toUpperCase());
metaEntityModel.setCodeName(temp.get("tableName") == null ? "" : temp.get("tableName").toString().toUpperCase());
metaEntityModel.setTableName(temp.get("tableName") == null ? "" : temp.get("tableName").toString().toUpperCase());
metaEntityModel.setLogicName(temp.get("tableName") == null ? "" : temp.get("tableName").toString().toUpperCase());
String tableName=temp.get("tableName") == null ? "" : temp.get("tableName").toString().toUpperCase();
metaEntityModel.setEntityName(tableName);
metaEntityModel.setCodeName(tableName);
metaEntityModel.setTableName(tableName);
metaEntityModel.setLogicName(temp.get("remarks") == null ? metaEntityModel.getEntityName() : temp.get("remarks").toString().toUpperCase());
metaEntityModel.setSystemId((String) commonMessage.get(0).get("author"));
if(!(temp.get("column") instanceof List))
continue;
column = (List<Map>) temp.get("column");
......@@ -192,6 +214,12 @@ public class DstLiquibaseService{
List<MetaRelationship> parentRelationships = new CopyOnWriteArrayList<>();
List<MetaRelationship> subRelationships = new CopyOnWriteArrayList<>();
List<MetaField> unionKeys=new ArrayList<>();
Set<String> keyset=keysets.get(tableName);
if(keyset==null){
keyset = new LinkedHashSet<>();
}
for (int j = 0; j < column.size();j++){
// (此处可补充MetaField描述字段,以及父子外键关系等)
metaField = new MetaField();
......@@ -210,7 +238,7 @@ public class DstLiquibaseService{
if(metaField.getDataType().indexOf("CHAR")>=0) {
metaField.setFieldType("TEXT");
if(metaField.getDataLength()>=1000)
metaField.setFieldType("LONGTEXT1000");
metaField.setFieldType("LONGTEXT_1000");
}
else if((metaField.getDataType().indexOf("NUMB")>=0&&(metaField.getDataPreci()==null||metaField.getDataPreci()==0)&&metaField.getDataLength()>9)||(metaField.getDataType().indexOf("BIGINT")>=0)||(metaField.getDataType().indexOf("LONG")>=0))
metaField.setFieldType("BIGINT");
......@@ -222,32 +250,60 @@ public class DstLiquibaseService{
metaField.setFieldType("LONGTEXT");
else if(metaField.getDataType().indexOf("TIME")>=0)
metaField.setFieldType("DATETIME");
else if(metaField.getDataType().indexOf("DATE")>=0)
else if(metaField.getDataType().indexOf("DATE")>=0) {
metaField.setFieldType("DATE");
}
if(metaField.getFieldType().startsWith("DATE") &&metaField.getDataType().startsWith("TIME") )
{
if(metaField.getFieldName().equalsIgnoreCase("ZHXGSJ")
||metaField.getFieldName().equalsIgnoreCase("ZSJKBGSJ")
||metaField.getFieldName().equalsIgnoreCase("UPDATEDATE") )
{
metaField.setFieldType("DATETIME");
metaField.setPredefined("UPDATEDATE");
}
else if(metaField.getFieldName().equalsIgnoreCase("CJSJ")||metaField.getFieldName().equalsIgnoreCase("CREATEDATE"))
{
metaField.setFieldType("DATETIME");
metaField.setPredefined("CREATEDATE");
}
else if(metaField.getDataPreci()==null||metaField.getDataPreci()==0)
metaField.setFieldType("DATE");
else
metaField.setFieldType("DATETIME");
}
if(metaField.getFieldName().equalsIgnoreCase("ENABLE")||metaField.getFieldName().equalsIgnoreCase("SFSC"))
{
metaField.setPredefined("LOGICVALID");
}
int isKey=0;
Map<String,List<Map>> map = (Map<String, List<Map>>) column.get(j).get("constraints");
if(!ObjectUtil.isEmpty(map)){
metaField.setNullable(map.get("nullable")==null?1:0);
int isKey=map.get("primaryKey")==null?0:1;
metaField.setKeyField(isKey);
if(isKey==1)
unionKeys.add(metaField);
isKey=map.get("primaryKey")==null?0:1;
}else {
metaField.setNullable(1);
metaField.setKeyField(0);
}
String name = column.get(j).get("name") == null? "" : column.get(j).get("name").toString();
if(isKey==0&&keyset.contains(metaField.getFieldName()))
isKey=1;
metaField.setKeyField(isKey);
if(isKey==1)
unionKeys.add(metaField);
String name = column.get(j).get("name") == null? "" : column.get(j).get("name").toString();
// 若在父键表查有该数据且属于同一实体则记录一条
for (int l = 0; l < parentEntities.size();l++){
if(name.equals(parentEntities.get(l).keySet().toString().replaceAll("[\\[\\]]", ""))){
if(temp.get("tableName").toString().toUpperCase().equals(parentEntities.get(l).get(name).getRefEntityName())) {
parentEntities.get(l).get(name).setEntityId(metaField.getEntityId());
parentRelationships.add(parentEntities.get(l).get(name));
}
for (int l = 0; l < parentEntities.size();l++){
if(name.equals(parentEntities.get(l).keySet().toString().replaceAll("[\\[\\]]", ""))){
if(temp.get("tableName").toString().toUpperCase().equals(parentEntities.get(l).get(name).getRefEntityName())) {
parentEntities.get(l).get(name).setEntityId(metaField.getEntityId());
parentRelationships.add(parentEntities.get(l).get(name));
}
}
}
metaEntityModel.setParentEntitys(parentRelationships);
// 若在子键表查有该数据且属于同一实体则记录一条
......@@ -266,7 +322,11 @@ public class DstLiquibaseService{
metaFields.add(metaField);
}
if(unionKeys.size()>1)
int unionKeysLimit=1;
if(sysModel.getSystemid().equalsIgnoreCase("tyyw2plus")||sysModel.getSystemid().equalsIgnoreCase("tyyw"))
unionKeysLimit=0;
if(unionKeys.size()>unionKeysLimit)
{
MetaField uilid = new MetaField();
unionKeys.get(0).copyTo(uilid,true);
......@@ -276,6 +336,7 @@ public class DstLiquibaseService{
uilid.setKeyField(1);
uilid.setPhysicalField(0);
uilid.setFieldType("TEXT");
uilid.setDataType("VARCHAR");
String expression="";
for(int no=0;no<unionKeys.size();no++)
{
......
......@@ -11,8 +11,10 @@ import cn.ibizlab.core.lite.extensions.service.DbEntityService;
import cn.ibizlab.core.lite.extensions.service.LiteCoreService;
import cn.ibizlab.core.lite.extensions.service.LiteDataService;
import cn.ibizlab.core.lite.extensions.service.LiteModelService;
import cn.ibizlab.core.lite.filter.MetaFieldSearchContext;
import cn.ibizlab.core.lite.service.IDstComponentService;
import cn.ibizlab.core.lite.service.IDstConfigService;
import cn.ibizlab.core.lite.service.IMetaFieldService;
import cn.ibizlab.util.client.IBZDictFeignClient;
import cn.ibizlab.util.dict.CodeItem;
import cn.ibizlab.util.dict.CodeList;
......@@ -21,6 +23,7 @@ import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.util.helper.DataObject;
import cn.ibizlab.util.security.AuthenticationUser;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
......@@ -31,6 +34,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
......@@ -71,6 +75,81 @@ public class LiteCoreResource {
return ResponseEntity.ok(liteDataService.getModelObjs(modelid, null,key));
}
@Autowired
@Lazy
private IMetaFieldService fieldService;
@RequestMapping(method = RequestMethod.GET, value = "/lite/{system}/{from}.ibzbak")
public ResponseEntity<JSONObject> ibzbak(@PathVariable(name="system",required = true) String system,@PathVariable(name="from",required = true) String from)
{
MetaFieldSearchContext context=new MetaFieldSearchContext();
context.setSize(Integer.MAX_VALUE);
context.setN_systemid_eq(system);
context.getSearchCond().ge("updatedate", DataObject.getTimestampValue(from, null));
JSONArray jArray = new JSONArray();
fieldService.searchDefault(context).getContent().forEach(sx->{
JSONObject json = new JSONObject();
JSONObject jo = new JSONObject();
jo.put("psdefieldname", sx.getFieldName());
jo.put("predefinetype", sx.getPredefined());
jo.put("unionkeyvalue", sx.getUnionKey());
jo.put("codename", sx.getCodeName());
jo.put("physicalfield", sx.getPhysicalField());
jo.put("psdeid", DigestUtils.md5DigestAsHex(("2C40DFCD-0DF5-47BF-91A5-C45F810B0001||"+sx.getEntityName()).getBytes()).toLowerCase());
jo.put("logicname", sx.getFieldLogicName());
if (sx.getDataLength() != null && sx.getDataLength() > 0)
jo.put("length", sx.getDataLength());
if (sx.getDataPreci() != null && sx.getDataPreci() > 0)
jo.put("precision2", sx.getDataPreci());
jo.put("ordervalue", sx.getShowOrder());
jo.put("psdefieldid", DigestUtils.md5DigestAsHex((DigestUtils.md5DigestAsHex(("2C40DFCD-0DF5-47BF-91A5-C45F810B0001||"+sx.getEntityName()).getBytes()).toLowerCase()+"||"+sx.getFieldName()).getBytes()).toLowerCase());
if(1==sx.getPhysicalField()&&(StringUtils.isEmpty(sx.getExpression())))
jo.put("deftype", 1);
else {
jo.put("deftype", 2);
jo.put("formulaformat",sx.getExpression());
}
jo.put("pkey", sx.getKeyField());
jo.put("pssystemid", "2C40DFCD-0DF5-47BF-91A5-C45F810B0001");
jo.put("psdename", sx.getEntityName());
jo.put("tablename", sx.getEntityName());
String strRT = "文本,可指定长度";
String strDataTypeId=sx.getFieldType();
jo.put("psdatatypeid", strDataTypeId);
if (strDataTypeId.equalsIgnoreCase("DECIMAL"))
strRT = "数值";
else if (strDataTypeId.equalsIgnoreCase("INT"))
strRT = "整型";
else if (strDataTypeId.equalsIgnoreCase("BIGDECIMAL"))
strRT = "大数值";
else if (strDataTypeId.equalsIgnoreCase("BIGINT"))
strRT = "大整型";
else if (strDataTypeId.equalsIgnoreCase("LONGTEXT"))
strRT = "长文本,没有长度限制";
else if (strDataTypeId.equalsIgnoreCase("LONGTEXT_1000"))
strRT = "长文本,长度1000";
else if (strDataTypeId.equalsIgnoreCase("DATE"))
strRT = "日期型";
else if (strDataTypeId.equalsIgnoreCase("DATETIME"))
strRT = "日期时间型";
jo.put("psdatatypename", strRT);
jo.put("allowempty", sx.getNullable());
json.put("srfvalue", jo);
json.put("srfdeid", "42d91505b9bb15b9900b4298fcca9915");
json.put("srfdename", "PSDEFIELD");
jArray.add(json);
});
JSONObject jo = new JSONObject();
jo.put("items", jArray);
return ResponseEntity.ok(jo);
}
@RequestMapping(method = RequestMethod.GET, value = {"/lite/datamodels/{modelid}","/lite/datamodels/{modelid}/name/{modelname}"})
public ResponseEntity<DataModel> getDataModel(@PathVariable(name="modelid") String modelid,
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册