You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by mp...@apache.org on 2014/02/21 20:04:00 UTC
[4/4] git commit: AMBARI-4716. Run Ambari Server Upgrade via code
rather than DDL/DML. (mpapirkovskyy)
AMBARI-4716. Run Ambari Server Upgrade via code rather than DDL/DML. (mpapirkovskyy)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/fea7b622
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/fea7b622
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/fea7b622
Branch: refs/heads/trunk
Commit: fea7b6222311a48604c5a96d9478c53fbd7ce26f
Parents: c02c7bf
Author: Myroslav Papirkovskyy <mp...@hortonworks.com>
Authored: Fri Feb 21 21:02:27 2014 +0200
Committer: Myroslav Papirkovskyy <mp...@hortonworks.com>
Committed: Fri Feb 21 21:03:40 2014 +0200
----------------------------------------------------------------------
ambari-server/pom.xml | 19 +-
.../server/configuration/Configuration.java | 20 +-
.../server/controller/ControllerModule.java | 5 +-
.../apache/ambari/server/orm/DBAccessor.java | 319 ++++++++++++
.../ambari/server/orm/DBAccessorImpl.java | 455 +++++++++++++++++
.../orm/dao/HostComponentDesiredStateDAO.java | 13 +
.../server/orm/dao/HostComponentStateDAO.java | 13 +
.../dao/ServiceComponentDesiredStateDAO.java | 14 +
.../server/orm/dao/ServiceDesiredStateDAO.java | 14 +
.../ambari/server/orm/helpers/ScriptRunner.java | 254 ++++++++++
.../server/orm/helpers/dbms/DbmsHelper.java | 72 +++
.../server/orm/helpers/dbms/DerbyHelper.java | 52 ++
.../orm/helpers/dbms/GenericDbmsHelper.java | 273 +++++++++++
.../server/orm/helpers/dbms/MySqlHelper.java | 49 ++
.../server/orm/helpers/dbms/OracleHelper.java | 46 ++
.../server/orm/helpers/dbms/PostgresHelper.java | 46 ++
.../server/upgrade/AbstractUpgradeCatalog.java | 192 ++++++++
.../server/upgrade/SchemaUpgradeHelper.java | 211 ++++++++
.../server/upgrade/StackUpgradeHelper.java | 159 ++++++
.../ambari/server/upgrade/StackUpgradeUtil.java | 142 ++++++
.../ambari/server/upgrade/UpgradeCatalog.java | 55 +++
.../server/upgrade/UpgradeCatalog150.java | 487 +++++++++++++++++++
.../apache/ambari/server/utils/DateUtils.java | 13 +
.../ambari/server/utils/VersionUtils.java | 14 +
ambari-server/src/main/python/ambari-server.py | 469 ++++--------------
.../upgrade/ddl/Ambari-DDL-MySQL-UPGRADE.sql | 95 ----
.../upgrade/ddl/Ambari-DDL-Oracle-UPGRADE.sql | 134 -----
.../ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql | 250 ----------
.../main/resources/upgrade/ddl/quartz.mysql.sql | 53 ++
.../resources/upgrade/ddl/quartz.oracle.sql | 55 +++
.../resources/upgrade/ddl/quartz.postgres.sql | 53 ++
.../dml/Ambari-DML-Oracle-FIX_LOCAL_REPO.sql | 45 --
.../dml/Ambari-DML-Postgres-FIX_LOCAL_REPO.sql | 44 --
.../ambari/server/orm/DBAccessorImplTest.java | 253 ++++++++++
.../server/upgrade/UpgradeCatalogTest.java | 105 ++++
.../src/test/python/TestAmbariServer.py | 226 ++++-----
ambari-server/src/test/python/ambari.properties | 1 +
37 files changed, 3617 insertions(+), 1103 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index bc83dd8..0da58d1 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -350,19 +350,7 @@
<directory>/var/lib/ambari-server/resources/upgrade/ddl</directory>
<sources>
<source>
- <location>target/classes/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.sql</location>
- </source>
- <source>
- <location>src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.Fix.sql</location>
- </source>
- <source>
- <location>src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.3.0.Check.sql</location>
- </source>
- <source>
- <location>target/classes/upgrade/ddl/Ambari-DDL-Oracle-UPGRADE.sql</location>
- </source>
- <source>
- <location>target/classes/upgrade/ddl/Ambari-DDL-MySQL-UPGRADE.sql</location>
+ <location>src/main/resources/upgrade/ddl</location>
</source>
</sources>
</mapping>
@@ -618,6 +606,11 @@
<artifactId>guice-servlet</artifactId>
</dependency>
<dependency>
+ <groupId>com.google.inject.extensions</groupId>
+ <artifactId>guice-multibindings</artifactId>
+ <version>3.0</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
</dependency>
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index 9fe104c..56bb58c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -97,6 +97,7 @@ public class Configuration {
public static final String POSTGRES_DB_NAME = "postgres";
public static final String ORACLE_DB_NAME = "oracle";
public static final String MYSQL_DB_NAME = "mysql";
+ public static final String DERBY_DB_NAME = "derby";
public static final String OJDBC_JAR_NAME_KEY = "db.oracle.jdbc.name";
public static final String OJDBC_JAR_NAME_DEFAULT = "ojdbc6.jar";
public static final String MYSQL_JAR_NAME_KEY = "db.mysql.jdbc.name";
@@ -224,7 +225,7 @@ public class Configuration {
"/var/lib/ambari-server/resources/custom_action_definitions";
private static final long SERVER_EC_CACHE_SIZE_DEFAULT = 10000L;
- private static final String SERVER_JDBC_USER_NAME_DEFAULT = "ambari-server";
+ private static final String SERVER_JDBC_USER_NAME_DEFAULT = "ambari";
private static final String SERVER_JDBC_USER_PASSWD_DEFAULT = "bigdata";
private static final String SERVER_JDBC_RCA_USER_NAME_DEFAULT = "mapred";
private static final String SERVER_JDBC_RCA_USER_PASSWD_DEFAULT = "mapred";
@@ -235,7 +236,7 @@ public class Configuration {
private static final String SRVR_CRT_PASS_LEN_DEFAULT = "50";
private static final String PASSPHRASE_ENV_DEFAULT = "AMBARI_PASSPHRASE";
private static final String RESOURCES_DIR_DEFAULT =
- "/var/share/ambari/resources/";
+ "/var/lib/ambari-server/resources/";
private static final String ANONYMOUS_AUDIT_NAME_KEY = "anonymous.audit.name";
private static final String CLIENT_SECURITY_DEFAULT = "local";
private static final int CLIENT_API_PORT_DEFAULT = 8080;
@@ -601,11 +602,19 @@ public class Configuration {
}
public String getDatabaseDriver() {
- return properties.getProperty(SERVER_JDBC_DRIVER_KEY, JDBC_LOCAL_DRIVER);
+ if (getPersistenceType() != PersistenceType.IN_MEMORY) {
+ return properties.getProperty(SERVER_JDBC_DRIVER_KEY, JDBC_LOCAL_DRIVER);
+ } else {
+ return JDBC_IN_MEMROY_DRIVER;
+ }
}
public String getDatabaseUrl() {
- return properties.getProperty(SERVER_JDBC_URL_KEY, getLocalDatabaseUrl());
+ if (getPersistenceType() != PersistenceType.IN_MEMORY) {
+ return properties.getProperty(SERVER_JDBC_URL_KEY, getLocalDatabaseUrl());
+ } else {
+ return JDBC_IN_MEMORY_URL;
+ }
}
public String getLocalDatabaseUrl() {
@@ -929,4 +938,7 @@ public class Configuration {
}
}
+ public String getResourceDirPath() {
+ return properties.getProperty(RESOURCES_DIR_KEY, RESOURCES_DIR_DEFAULT);
+ }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index adb78c3..ae57af2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -37,6 +37,7 @@ import org.apache.ambari.server.controller.internal.HostComponentResourceProvide
import org.apache.ambari.server.controller.internal.HostResourceProvider;
import org.apache.ambari.server.controller.internal.ServiceResourceProvider;
import org.apache.ambari.server.controller.spi.ResourceProvider;
+import org.apache.ambari.server.orm.DBAccessorImpl;
import org.apache.ambari.server.orm.PersistenceType;
import org.apache.ambari.server.scheduler.ExecutionScheduler;
import org.apache.ambari.server.scheduler.ExecutionSchedulerImpl;
@@ -70,13 +71,12 @@ import org.apache.ambari.server.state.scheduler.RequestExecutionImpl;
import org.apache.ambari.server.state.svccomphost.ServiceComponentHostImpl;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.StandardPasswordEncoder;
-
import java.security.SecureRandom;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
-
import com.google.gson.GsonBuilder;
+import org.apache.ambari.server.orm.DBAccessor;
import static org.eclipse.persistence.config.PersistenceUnitProperties.CREATE_JDBC_DDL_FILE;
import static org.eclipse.persistence.config.PersistenceUnitProperties.CREATE_ONLY;
import static org.eclipse.persistence.config.PersistenceUnitProperties.CREATE_OR_EXTEND;
@@ -247,6 +247,7 @@ public class ControllerModule extends AbstractModule {
install(new FactoryModuleBuilder().build(RequestFactory.class));
bind(HostRoleCommandFactory.class).to(HostRoleCommandFactoryImpl.class);
+ bind(DBAccessor.class).to(DBAccessorImpl.class);
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessor.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessor.java
new file mode 100644
index 0000000..3b3d2e5
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessor.java
@@ -0,0 +1,319 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.orm;
+
+import org.eclipse.persistence.sessions.DatabaseSession;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * Interface for schema manipulation
+ * Note: IF NOT EXISTS is default for all supported DDL statements
+ */
+public interface DBAccessor {
+
+ /**
+ * Create new table
+ * @param tableName
+ * @param columnInfo
+ * @param primaryKeyColumns
+ * @throws SQLException
+ */
+ public void createTable(String tableName, List<DBColumnInfo> columnInfo,
+ String... primaryKeyColumns) throws SQLException;
+
+ /**
+ * Create new index
+ * @param indexName
+ * @param tableName
+ * @param columnNames
+ * @throws SQLException
+ */
+ public void createIndex(String indexName, String tableName,
+ String... columnNames) throws SQLException;
+
+
+ /**
+ * Add foreign key for a relation
+ * @param tableName
+ * @param constraintName
+ * @param keyColumn
+ * @param referenceColumn
+ * @throws SQLException
+ */
+ public void addFKConstraint(String tableName,
+ String constraintName,
+ String keyColumn,
+ String referenceTableName,
+ String referenceColumn,
+ boolean ignoreFailure) throws SQLException;
+
+ /**
+ * Add foreign key for a relation
+ * @param tableName
+ * @param constraintName
+ * @param keyColumn
+ * @param referenceColumn
+ * @throws SQLException
+ */
+ public void addFKConstraint(String tableName,
+ String constraintName,
+ String[] keyColumns,
+ String referenceTableName,
+ String[] referenceColumns,
+ boolean ignoreFailure) throws SQLException;
+
+ /**
+ * Add column to existing table
+ * @param tableName
+ * @param columnInfo
+ * @throws SQLException
+ */
+ public void addColumn(String tableName,
+ DBColumnInfo columnInfo) throws SQLException;
+
+ /**
+ * Rename existing column
+ * @param tableName
+ * @param oldColumnName
+ * @param columnInfo
+ * @throws SQLException
+ */
+ void renameColumn(String tableName, String oldColumnName,
+ DBColumnInfo columnInfo) throws SQLException;
+
+ /**
+ * Alter column from existing table, only supports varchar extension <br/>
+ * Use following sequence for more complex stuff: <br/>
+ * <li/>{@link #addColumn(String, org.apache.ambari.server.orm.DBAccessor.DBColumnInfo)}
+ * <li/>{@link #updateTable(String, String, Object, String)}
+ * <li/>{@link #dropColumn(String, String)}
+ * <li/>{@link #renameColumn(String, String, org.apache.ambari.server.orm.DBAccessor.DBColumnInfo)}
+ * @param tableName
+ * @param columnInfo
+ * @throws SQLException
+ */
+ public void alterColumn(String tableName,
+ DBColumnInfo columnInfo) throws SQLException;
+
+ /**
+ * Insert row into table
+ *
+ * @param tableName
+ * @param columnNames
+ * @param values
+ * @param ignoreFailure
+ * @return
+ * @throws SQLException
+ */
+ boolean insertRow(String tableName, String[] columnNames, String[] values, boolean ignoreFailure) throws SQLException;
+
+ /**
+ * Simple update operation on table
+ * @param tableName
+ * @param columnName
+ * @param value
+ * @param whereClause
+ * @return
+ * @throws SQLException
+ */
+ public int updateTable(String tableName, String columnName, Object value,
+ String whereClause) throws SQLException;
+
+ /**
+ * Helper method to run third party scripts like Quartz DDL
+ * @param filePath
+ * @throws SQLException
+ */
+ public void executeScript(String filePath) throws SQLException, IOException;
+
+
+ /**
+ * Execute ad-hoc query on DB.
+ * @param query
+ * @throws SQLException
+ */
+ public void executeQuery(String query) throws SQLException;
+
+ /**
+ * Execute query on DB
+ * @param query
+ * @param ignoreFailure
+ * @throws SQLException
+ */
+ void executeQuery(String query, boolean ignoreFailure) throws SQLException;
+
+ /**
+ * Drop table from schema
+ * @param tableName
+ * @throws SQLException
+ */
+ public void dropTable(String tableName) throws SQLException;
+
+ /**
+ * Delete all table data
+ * @param tableName
+ * @throws SQLException
+ */
+ public void truncateTable(String tableName) throws SQLException;
+
+ /**
+ * Drop a column from table
+ * @param tableName
+ * @param columnName
+ * @throws SQLException
+ */
+ public void dropColumn(String tableName, String columnName) throws SQLException;
+
+ /**
+ * Drop sequence
+ * @param sequenceName
+ * @throws SQLException
+ */
+ public void dropSequence(String sequenceName) throws SQLException;
+
+ /**
+ * Drop a constraint from table
+ * @param tableName
+ * @param constraintName
+ * @throws SQLException
+ */
+ public void dropConstraint(String tableName, String constraintName) throws SQLException;
+
+ /**
+ * Verify if table exists by looking at metadata.
+ * @param tableName
+ * @return
+ * @throws SQLException
+ */
+ public boolean tableExists(String tableName) throws SQLException;
+
+ /**
+ * Verify if table has any data
+ * @param tableName
+ * @return
+ * @throws SQLException
+ */
+ public boolean tableHasData(String tableName) throws SQLException;
+
+ /**
+ * Verify if table already has a column defined.
+ * @param tableName
+ * @param columnName
+ * @return
+ * @throws SQLException
+ */
+ public boolean tableHasColumn(String tableName, String columnName) throws SQLException;
+
+ /**
+ * Verify if table already has a FK constraint.
+ * @param tableName
+ * @param refTableName
+ * @param columnName
+ * @param refColumnName
+ * @return
+ * @throws SQLException
+ */
+ public boolean tableHasForeignKey(String tableName, String refTableName,
+ String columnName, String refColumnName) throws SQLException;
+
+ /**
+ * Get a new DB session
+ * @return
+ */
+ public DatabaseSession getNewDatabaseSession();
+
+ /**
+ * Capture column type
+ */
+ public class DBColumnInfo {
+ private String name;
+ private Class type;
+// private DBColumnType type;
+ private Integer length;
+ private Object defaultValue;
+ private boolean isNullable;
+
+ public DBColumnInfo(String name, Class type, Integer length) {
+ this(name, type, length, null, false);
+ }
+
+ public DBColumnInfo(String name, Class type, Integer length,
+ Object defaultValue, boolean nullable) {
+ this.name = name;
+ this.type = type;
+ this.length = length;
+ this.defaultValue = defaultValue;
+ isNullable = nullable;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Class getType() {
+ return type;
+ }
+
+ public void setType(Class type) {
+ this.type = type;
+ }
+
+ public Integer getLength() {
+ return length;
+ }
+
+ public void setLength(Integer length) {
+ this.length = length;
+ }
+
+ public Object getDefaultValue() {
+ return defaultValue;
+ }
+
+ public void setDefaultValue(Object defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ public boolean isNullable() {
+ return isNullable;
+ }
+
+ public void setNullable(boolean nullable) {
+ isNullable = nullable;
+ }
+
+ public enum DBColumnType {
+ VARCHAR,
+ CHAR,
+ INT,
+ LONG,
+ BOOL,
+ TIME,
+ BLOB
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessorImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessorImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessorImpl.java
new file mode 100644
index 0000000..e30d4f1
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessorImpl.java
@@ -0,0 +1,455 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.orm;
+
+import com.google.inject.Inject;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.helpers.ScriptRunner;
+import org.apache.ambari.server.orm.helpers.dbms.*;
+import org.eclipse.persistence.internal.helper.DBPlatformHelper;
+import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl;
+import org.eclipse.persistence.logging.AbstractSessionLog;
+import org.eclipse.persistence.logging.SessionLogEntry;
+import org.eclipse.persistence.platform.database.*;
+import org.eclipse.persistence.sessions.DatabaseLogin;
+import org.eclipse.persistence.sessions.DatabaseSession;
+import org.eclipse.persistence.sessions.Login;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class DBAccessorImpl implements DBAccessor {
+ private static final Logger LOG = LoggerFactory.getLogger(DBAccessorImpl.class);
+ private final DatabasePlatform databasePlatform;
+ private final Connection connection;
+ private final DbmsHelper dbmsHelper;
+ private Configuration configuration;
+ private DatabaseMetaData databaseMetaData;
+
+ @Inject
+ public DBAccessorImpl(Configuration configuration) {
+ this.configuration = configuration;
+
+ try {
+ Class.forName(configuration.getDatabaseDriver());
+
+ connection = DriverManager.getConnection(configuration.getDatabaseUrl(),
+ configuration.getDatabaseUser(),
+ configuration.getDatabasePassword());
+
+ //TODO create own mapping and platform classes for supported databases
+ String vendorName = connection.getMetaData().getDatabaseProductName() +
+ connection.getMetaData().getDatabaseMajorVersion();
+ String dbPlatform = DBPlatformHelper.getDBPlatform(vendorName, new AbstractSessionLog() {
+ @Override
+ public void log(SessionLogEntry sessionLogEntry) {
+ LOG.debug(sessionLogEntry.getMessage());
+ }
+ });
+ this.databasePlatform = (DatabasePlatform) Class.forName(dbPlatform).newInstance();
+ this.dbmsHelper = loadHelper(databasePlatform);
+ } catch (Exception e) {
+ String message = "Error while creating database accessor ";
+ LOG.error(message, e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected DbmsHelper loadHelper(DatabasePlatform databasePlatform) {
+ if (databasePlatform instanceof OraclePlatform) {
+ return new OracleHelper(databasePlatform);
+ }else if (databasePlatform instanceof MySQLPlatform) {
+ return new MySqlHelper(databasePlatform);
+ }else if (databasePlatform instanceof PostgreSQLPlatform) {
+ return new PostgresHelper(databasePlatform);
+ }else if (databasePlatform instanceof DerbyPlatform) {
+ return new DerbyHelper(databasePlatform);
+ } else {
+ return new GenericDbmsHelper(databasePlatform);
+ }
+ }
+
+ protected Connection getConnection() {
+ return connection;
+ }
+
+ @Override
+ public void createTable(String tableName, List<DBColumnInfo> columnInfo,
+ String... primaryKeyColumns) throws SQLException {
+ if (!tableExists(tableName)) {
+ String query = dbmsHelper.getCreateTableStatement(tableName, columnInfo, Arrays.asList(primaryKeyColumns));
+
+ executeQuery(query);
+ }
+ }
+
+ private DatabaseMetaData getDatabaseMetaData() throws SQLException {
+ if (databaseMetaData == null) {
+ databaseMetaData = connection.getMetaData();
+ }
+
+ return databaseMetaData;
+ }
+
+ @Override
+ public boolean tableExists(String tableName) throws SQLException {
+ boolean result = false;
+ DatabaseMetaData metaData = getDatabaseMetaData();
+ String schemaFilter = null;
+ if (getDbType().equals(Configuration.ORACLE_DB_NAME)) {
+ // Optimization to not query everything
+ schemaFilter = configuration.getDatabaseUser();
+ }
+
+ ResultSet res = metaData.getTables(null, schemaFilter,
+ tableName.toUpperCase(), new String[] { "TABLE" });
+
+ if (res != null) {
+ try {
+ if (res.next()) {
+ return res.getString("TABLE_NAME") != null && res.getString
+ ("TABLE_NAME").equalsIgnoreCase(tableName);
+ }
+ } finally {
+ res.close();
+ }
+ }
+
+ return result;
+ }
+
+ protected String getDbType() {
+ String dbUrl = configuration.getDatabaseUrl();
+ String dbType;
+
+ if (dbUrl.contains(Configuration.POSTGRES_DB_NAME)) {
+ dbType = Configuration.POSTGRES_DB_NAME;
+ } else if (dbUrl.contains(Configuration.ORACLE_DB_NAME)) {
+ dbType = Configuration.ORACLE_DB_NAME;
+ } else if (dbUrl.contains(Configuration.MYSQL_DB_NAME)) {
+ dbType = Configuration.MYSQL_DB_NAME;
+ } else if (dbUrl.contains(Configuration.DERBY_DB_NAME)) {
+ dbType = Configuration.DERBY_DB_NAME;
+ } else {
+ throw new RuntimeException("Unable to determine database type.");
+ }
+
+ return dbType;
+ }
+
+ @Override
+ public boolean tableHasData(String tableName) throws SQLException {
+ String query = "SELECT count(*) from " + tableName;
+ Statement statement = getConnection().createStatement();
+ ResultSet rs = statement.executeQuery(query);
+ boolean retVal = false;
+ if (rs != null) {
+ if (rs.next()) {
+ return rs.getInt(0) > 0;
+ }
+ }
+ return retVal;
+ }
+
+ @Override
+ public boolean tableHasColumn(String tableName, String columnName) throws SQLException {
+ boolean result = false;
+ DatabaseMetaData metaData = getDatabaseMetaData();
+ String schemaFilter = null;
+ if (getDbType().equals(Configuration.ORACLE_DB_NAME)) {
+ // Optimization to not query everything
+ schemaFilter = configuration.getDatabaseUser();
+ }
+
+ ResultSet rs = metaData.getColumns(null, schemaFilter,
+ tableName.toUpperCase(), columnName.toUpperCase());
+
+ if (rs != null) {
+ try {
+ if (rs.next()) {
+ return rs.getString("COLUMN_NAME") != null && rs.getString
+ ("COLUMN_NAME").equalsIgnoreCase(columnName);
+ }
+ } finally {
+ rs.close();
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean tableHasForeignKey(String tableName, String refTableName,
+ String columnName, String refColumnName) throws SQLException {
+ boolean result = false;
+ DatabaseMetaData metaData = getDatabaseMetaData();
+ String schemaFilter = null;
+ if (getDbType().equals(Configuration.ORACLE_DB_NAME)) {
+ // Optimization to not query everything
+ schemaFilter = configuration.getDatabaseUser();
+ }
+
+ ResultSet rs = metaData.getCrossReference(null, schemaFilter, tableName,
+ null, schemaFilter, refTableName);
+
+ if (rs != null) {
+ try {
+ if (rs.next()) {
+ String refColumn = rs.getString("FKCOLUMN_NAME");
+ result = refColumn != null && refColumn.equalsIgnoreCase(refColumnName);
+ }
+ } finally {
+ rs.close();
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public void createIndex(String indexName, String tableName,
+ String... columnNames) throws SQLException {
+ String query = dbmsHelper.getCreateIndexStatement(indexName, tableName, columnNames);
+
+ executeQuery(query);
+ }
+
+ @Override
+ public void addFKConstraint(String tableName, String constraintName,
+ String keyColumn, String referenceTableName,
+ String referenceColumn, boolean ignoreFailure) throws SQLException {
+
+ if (!tableHasForeignKey(tableName, referenceTableName, keyColumn, referenceColumn)) {
+
+ String query = dbmsHelper.getAddForeignKeyStatement(tableName, constraintName,
+ Collections.singletonList(keyColumn),
+ referenceTableName,
+ Collections.singletonList(referenceColumn)
+ );
+
+ try {
+ executeQuery(query);
+ } catch (SQLException e) {
+ LOG.warn("Add FK constraint failed" +
+ ", constraintName = " + constraintName +
+ ", tableName = " + tableName, e);
+ if (!ignoreFailure) {
+ throw e;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void addFKConstraint(String tableName, String constraintName,
+ String[] keyColumns, String referenceTableName,
+ String[] referenceColumns, boolean ignoreFailure) throws SQLException {
+ String query = dbmsHelper.getAddForeignKeyStatement(tableName, constraintName,
+ Arrays.asList(keyColumns),
+ referenceTableName,
+ Arrays.asList(referenceColumns)
+ );
+
+ try {
+ executeQuery(query);
+ } catch (SQLException e) {
+ LOG.warn("Add FK constraint failed" +
+ ", constraintName = " + constraintName +
+ ", tableName = " + tableName, e);
+ if (!ignoreFailure) {
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ public void renameColumn(String tableName, String oldColumnName,
+ DBColumnInfo columnInfo) throws SQLException {
+ //it is mandatory to specify type in column change clause for mysql
+ String renameColumnStatement = dbmsHelper.getRenameColumnStatement(tableName, oldColumnName, columnInfo);
+ executeQuery(renameColumnStatement);
+
+ }
+
+ @Override
+ public void addColumn(String tableName, DBColumnInfo columnInfo) throws SQLException {
+ if (!tableHasColumn(tableName, columnInfo.getName())) {
+ //TODO workaround for default values, possibly we will have full support later
+ if (columnInfo.getDefaultValue() != null) {
+ columnInfo.setNullable(true);
+ }
+ String query = dbmsHelper.getAddColumnStatement(tableName, columnInfo);
+ executeQuery(query);
+
+ if (columnInfo.getDefaultValue() != null) {
+ updateTable(tableName, columnInfo.getName(), columnInfo.getDefaultValue(), "");
+ }
+ }
+ }
+
+ @Override
+ public void alterColumn(String tableName, DBColumnInfo columnInfo) throws SQLException {
+ //varchar extension only (derby limitation, but not too much for others),
+ //use addColumn-update-drop-rename for more
+ String statement = dbmsHelper.getAlterColumnStatement(tableName, columnInfo);
+ executeQuery(statement);
+ }
+
+ @Override
+ public boolean insertRow(String tableName, String[] columnNames, String[] values, boolean ignoreFailure) throws SQLException {
+ StringBuilder builder = new StringBuilder();
+ builder.append("INSERT INTO ").append(tableName).append("(");
+ if (columnNames.length != values.length) {
+ throw new IllegalArgumentException("number of columns should be equal to number of values");
+ }
+
+ for (int i = 0; i < columnNames.length; i++) {
+ builder.append(columnNames[i]);
+ if(i!=columnNames.length-1){
+ builder.append(",");
+ }
+ }
+
+ builder.append(") VALUES(");
+
+ for (int i = 0; i < values.length; i++) {
+ builder.append(values[i]);
+ if(i!=values.length-1){
+ builder.append(",");
+ }
+ }
+
+ builder.append(")");
+
+ Statement statement = getConnection().createStatement();
+ int rowsUpdated = 0;
+ String query = builder.toString();
+ try {
+ rowsUpdated = statement.executeUpdate(query);
+ } catch (SQLException e) {
+ LOG.warn("Unable to execute query: " + query, e);
+ if (!ignoreFailure) {
+ throw e;
+ }
+ }
+
+ return rowsUpdated != 0;
+ }
+
+
+ @Override
+ public int updateTable(String tableName, String columnName, Object value,
+ String whereClause) throws SQLException {
+
+ StringBuilder query = new StringBuilder
+ (String.format("UPDATE %s SET %s = ", tableName, columnName));
+
+ // Only String and number supported.
+ // Taken from: org.eclipse.persistence.internal.databaseaccess.appendParameterInternal
+ Object dbValue = databasePlatform.convertToDatabaseType(value);
+ String valueString = value.toString();
+ if (dbValue instanceof String) {
+ valueString = "'" + value.toString() + "'";
+ }
+
+ query.append(valueString);
+ query.append(" ");
+ query.append(whereClause);
+
+ Statement statement = getConnection().createStatement();
+
+ return statement.executeUpdate(query.toString());
+ }
+
+ @Override
+ public void executeQuery(String query) throws SQLException {
+ executeQuery(query, false);
+ }
+
+ @Override
+ public void executeQuery(String query, boolean ignoreFailure) throws SQLException {
+ Statement statement = getConnection().createStatement();
+ try {
+ statement.execute(query);
+ } catch (SQLException e) {
+ LOG.warn("Error executing query: "+query, e);
+ if (!ignoreFailure) {
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ public void dropTable(String tableName) throws SQLException {
+ String query = dbmsHelper.getDropTableStatement(tableName);
+ executeQuery(query);
+ }
+
+ @Override
+ public void truncateTable(String tableName) throws SQLException {
+ String query = "DELETE FROM " + tableName;
+ executeQuery(query);
+ }
+
+ @Override
+ public void dropColumn(String tableName, String columnName) throws SQLException {
+ throw new UnsupportedOperationException("Drop column not supported");
+ }
+
+ @Override
+ public void dropSequence(String sequenceName) throws SQLException {
+ executeQuery(dbmsHelper.getDropSequenceStatement(sequenceName));
+ }
+
+ @Override
+ public void dropConstraint(String tableName, String constraintName) throws SQLException {
+ String query = dbmsHelper.getDropConstraintStatement(tableName, constraintName);
+
+ executeQuery(query);
+ }
+
+ @Override
+ /**
+ * Execute script with autocommit and error tolerance, like psql and sqlplus do by default
+ */
+ public void executeScript(String filePath) throws SQLException, IOException {
+ BufferedReader br = new BufferedReader(new FileReader(filePath));
+ ScriptRunner scriptRunner = new ScriptRunner(getConnection(), true, false);
+ scriptRunner.runScript(br);
+ }
+
+ @Override
+ public DatabaseSession getNewDatabaseSession() {
+ Login login = new DatabaseLogin();
+ login.setUserName(configuration.getDatabaseUser());
+ login.setPassword(configuration.getDatabasePassword());
+ return new DatabaseSessionImpl(login);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentDesiredStateDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentDesiredStateDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentDesiredStateDAO.java
index f98df0f..f8b43a8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentDesiredStateDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentDesiredStateDAO.java
@@ -26,6 +26,9 @@ import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity;
import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntityPK;
import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+import java.util.List;
@Singleton
public class HostComponentDesiredStateDAO {
@@ -62,4 +65,14 @@ public class HostComponentDesiredStateDAO {
remove(findByPK(primaryKey));
}
+ @Transactional
+ public List<HostComponentDesiredStateEntity> findAll() {
+ TypedQuery<HostComponentDesiredStateEntity> query = entityManagerProvider.get()
+ .createQuery("SELECT hcd from HostComponentDesiredStateEntity hcd", HostComponentDesiredStateEntity.class);
+ try {
+ return query.getResultList();
+ } catch (NoResultException ignored) {
+ }
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentStateDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentStateDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentStateDAO.java
index 06d97d9..697d5f0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentStateDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentStateDAO.java
@@ -26,6 +26,9 @@ import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
import org.apache.ambari.server.orm.entities.HostComponentStateEntityPK;
import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+import java.util.List;
@Singleton
public class HostComponentStateDAO {
@@ -62,4 +65,14 @@ public class HostComponentStateDAO {
remove(findByPK(primaryKey));
}
+ @Transactional
+ public List<HostComponentStateEntity> findAll() {
+ TypedQuery<HostComponentStateEntity> query = entityManagerProvider.get()
+ .createQuery("SELECT hsc from HostComponentStateEntity hsc", HostComponentStateEntity.class);
+ try {
+ return query.getResultList();
+ } catch (NoResultException ignored) {
+ }
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java
index f062690..d1cea2e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java
@@ -26,6 +26,9 @@ import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntityP
import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+import java.util.List;
@Singleton
public class ServiceComponentDesiredStateDAO {
@@ -62,4 +65,15 @@ public class ServiceComponentDesiredStateDAO {
remove(findByPK(primaryKey));
}
+ @Transactional
+ public List<ServiceComponentDesiredStateEntity> findAll() {
+ TypedQuery<ServiceComponentDesiredStateEntity> query =
+ entityManagerProvider.get().
+ createQuery("SELECT scd from ServiceComponentDesiredStateEntity scd", ServiceComponentDesiredStateEntity.class);
+ try {
+ return query.getResultList();
+ } catch (NoResultException ignored) {
+ }
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceDesiredStateDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceDesiredStateDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceDesiredStateDAO.java
index b6224f0..bd47213 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceDesiredStateDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceDesiredStateDAO.java
@@ -26,6 +26,9 @@ import org.apache.ambari.server.orm.entities.ServiceDesiredStateEntity;
import org.apache.ambari.server.orm.entities.ServiceDesiredStateEntityPK;
import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+import java.util.List;
@Singleton
public class ServiceDesiredStateDAO {
@@ -62,4 +65,15 @@ public class ServiceDesiredStateDAO {
remove(findByPK(primaryKey));
}
+ @Transactional
+ public List<ServiceDesiredStateEntity> findAll() {
+ TypedQuery<ServiceDesiredStateEntity> query =
+ entityManagerProvider.get().
+ createQuery("SELECT sd from ServiceDesiredStateEntity sd", ServiceDesiredStateEntity.class);
+ try {
+ return query.getResultList();
+ } catch (NoResultException ignored) {
+ }
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/ScriptRunner.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/ScriptRunner.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/ScriptRunner.java
new file mode 100644
index 0000000..6ab0cda
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/ScriptRunner.java
@@ -0,0 +1,254 @@
+/*
+ * Slightly modified version of the com.ibatis.common.jdbc.ScriptRunner class
+ * from the iBATIS Apache project. Only removed dependency on Resource class
+ * and a constructor
+ *
+ *
+ *
+ * Copyright 2004 Clinton Begin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.helpers;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.sql.*;
+
+/**
+ * Tool to run database scripts
+ * TODO replace logging, deal with licence properly or rewrite completely
+ */
+public class ScriptRunner {
+ private static final Logger LOG = LoggerFactory.getLogger(ScriptRunner.class);
+
+ private static final String DEFAULT_DELIMITER = ";";
+
+ private Connection connection;
+
+ private boolean stopOnError;
+ private boolean autoCommit;
+
+ private PrintWriter logWriter = new PrintWriter(System.out);
+ private PrintWriter errorLogWriter = new PrintWriter(System.err);
+
+ private String delimiter = DEFAULT_DELIMITER;
+ private boolean fullLineDelimiter = false;
+
+ /**
+ * Default constructor
+ */
+ public ScriptRunner(Connection connection, boolean autoCommit,
+ boolean stopOnError) {
+ this.connection = connection;
+ this.autoCommit = autoCommit;
+ this.stopOnError = stopOnError;
+ }
+
+ public void setDelimiter(String delimiter, boolean fullLineDelimiter) {
+ this.delimiter = delimiter;
+ this.fullLineDelimiter = fullLineDelimiter;
+ }
+
+ /**
+ * Setter for logWriter property
+ *
+ * @param logWriter
+ * - the new value of the logWriter property
+ */
+ public void setLogWriter(PrintWriter logWriter) {
+ this.logWriter = logWriter;
+ }
+
+ /**
+ * Setter for errorLogWriter property
+ *
+ * @param errorLogWriter
+ * - the new value of the errorLogWriter property
+ */
+ public void setErrorLogWriter(PrintWriter errorLogWriter) {
+ this.errorLogWriter = errorLogWriter;
+ }
+
+ /**
+ * Runs an SQL script (read in using the Reader parameter)
+ *
+ * @param reader
+ * - the source of the script
+ */
+ public void runScript(Reader reader) throws IOException, SQLException {
+ try {
+ boolean originalAutoCommit = connection.getAutoCommit();
+ try {
+ if (originalAutoCommit != this.autoCommit) {
+ connection.setAutoCommit(this.autoCommit);
+ }
+ runScript(connection, reader);
+ } finally {
+ connection.setAutoCommit(originalAutoCommit);
+ }
+ } catch (IOException e) {
+ throw e;
+ } catch (SQLException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException("Error running script. Cause: " + e, e);
+ }
+ }
+
+ /**
+ * Runs an SQL script (read in using the Reader parameter) using the
+ * connection passed in
+ *
+ * @param conn
+ * - the connection to use for the script
+ * @param reader
+ * - the source of the script
+ * @throws SQLException
+ * if any SQL errors occur
+ * @throws IOException
+ * if there is an error reading from the Reader
+ */
+ private void runScript(Connection conn, Reader reader) throws IOException,
+ SQLException {
+ StringBuffer command = null;
+ try {
+ LineNumberReader lineReader = new LineNumberReader(reader);
+ String line = null;
+ while ((line = lineReader.readLine()) != null) {
+ if (command == null) {
+ command = new StringBuffer();
+ }
+ String trimmedLine = line.trim();
+ if (trimmedLine.startsWith("--")) {
+ println(trimmedLine);
+ } else if (trimmedLine.length() < 1
+ || trimmedLine.startsWith("//")) {
+ // Do nothing
+ } else if (trimmedLine.length() < 1
+ || trimmedLine.startsWith("--")) {
+ // Do nothing
+ } else if (!fullLineDelimiter
+ && trimmedLine.endsWith(getDelimiter())
+ || fullLineDelimiter
+ && trimmedLine.equals(getDelimiter())) {
+ command.append(line.substring(0, line
+ .lastIndexOf(getDelimiter())));
+ command.append(" ");
+ Statement statement = conn.createStatement();
+
+ println(command);
+
+ boolean hasResults = false;
+ if (stopOnError) {
+ hasResults = statement.execute(command.toString());
+ } else {
+ try {
+ statement.execute(command.toString());
+ } catch (SQLException e) {
+ e.fillInStackTrace();
+ printlnError("Error executing: " + command);
+ printlnError(e);
+ }
+ }
+
+ if (autoCommit && !conn.getAutoCommit()) {
+ conn.commit();
+ }
+
+ ResultSet rs = statement.getResultSet();
+ if (hasResults && rs != null) {
+ ResultSetMetaData md = rs.getMetaData();
+ int cols = md.getColumnCount();
+ for (int i = 0; i < cols; i++) {
+ String name = md.getColumnLabel(i);
+ print(name + "\t");
+ }
+ println("");
+ while (rs.next()) {
+ for (int i = 0; i < cols; i++) {
+ String value = rs.getString(i);
+ print(value + "\t");
+ }
+ println("");
+ }
+ }
+
+ command = null;
+ try {
+ statement.close();
+ } catch (Exception e) {
+ // Ignore to workaround a bug in Jakarta DBCP
+ }
+ Thread.yield();
+ } else {
+ command.append(line);
+ command.append(" ");
+ }
+ }
+ if (!autoCommit) {
+ conn.commit();
+ }
+ } catch (SQLException e) {
+ e.fillInStackTrace();
+ printlnError("Error executing: " + command);
+ printlnError(e);
+ throw e;
+ } catch (IOException e) {
+ e.fillInStackTrace();
+ printlnError("Error executing: " + command);
+ printlnError(e);
+ throw e;
+ } finally {
+ conn.rollback();
+ flush();
+ }
+ }
+
+ private String getDelimiter() {
+ return delimiter;
+ }
+
+ private void print(Object o) {
+ if (logWriter != null) {
+ System.out.print(o);
+ }
+ }
+
+ private void println(Object o) {
+ if (logWriter != null) {
+ logWriter.println(o);
+ }
+ }
+
+ private void printlnError(Object o) {
+ if (errorLogWriter != null) {
+ errorLogWriter.println(o);
+ }
+ }
+
+ private void flush() {
+ if (logWriter != null) {
+ logWriter.flush();
+ }
+ if (errorLogWriter != null) {
+ errorLogWriter.flush();
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/DbmsHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/DbmsHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/DbmsHelper.java
new file mode 100644
index 0000000..2e66006
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/DbmsHelper.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.helpers.dbms;
+
+import org.apache.ambari.server.orm.DBAccessor;
+
+import java.util.List;
+
+public interface DbmsHelper {
+
+ /**
+ * Check if column type can be modified directly
+ * @return
+ */
+ boolean supportsColumnTypeChange();
+
+ /**
+ * Generate rename column statement
+ * @param tableName
+ * @param oldName
+ * @param columnInfo definition of new column
+ * @return
+ */
+ String getRenameColumnStatement(String tableName, String oldName, DBAccessor.DBColumnInfo columnInfo);
+
+ /**
+ * Generate alter column statement
+ * @param tableName
+ * @param columnInfo
+ * @return
+ */
+ String getAlterColumnStatement(String tableName, DBAccessor.DBColumnInfo columnInfo);
+
+ String getCreateTableStatement(String tableName,
+ List<DBAccessor.DBColumnInfo> columns,
+ List<String> primaryKeyColumns);
+
+ String getCreateIndexStatement(String indexName, String tableName,
+ String... columnNames);
+
+ String getAddForeignKeyStatement(String tableName, String constraintName,
+ List<String> keyColumns,
+ String referenceTableName,
+ List<String> referenceColumns);
+
+ String getAddColumnStatement(String tableName, DBAccessor.DBColumnInfo columnInfo);
+
+ String getRenameColumnStatement(String tableName, String oldColumnName,
+ String newColumnName);
+
+ String getDropTableStatement(String tableName);
+
+ String getDropConstraintStatement(String tableName, String constraintName);
+
+ String getDropSequenceStatement(String sequenceName);
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/DerbyHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/DerbyHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/DerbyHelper.java
new file mode 100644
index 0000000..00d4b86
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/DerbyHelper.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.helpers.dbms;
+
+import org.apache.ambari.server.orm.DBAccessor;
+import org.eclipse.persistence.platform.database.DatabasePlatform;
+
+public class DerbyHelper extends GenericDbmsHelper {
+ public DerbyHelper(DatabasePlatform databasePlatform) {
+ super(databasePlatform);
+ }
+
+ @Override
+ public boolean supportsColumnTypeChange() {
+ return false; //type change is dramatically limited to varchar length increase only, almost useless
+ }
+
+ @Override
+ public String getRenameColumnStatement(String tableName, String oldName, DBAccessor.DBColumnInfo columnInfo) {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("RENAME COLUMN ").append(tableName).append(".").append(oldName);
+ builder.append(" TO ").append(columnInfo.getName());
+
+ return builder.toString();
+ }
+
+ @Override
+ public StringBuilder writeColumnModifyString(StringBuilder builder, DBAccessor.DBColumnInfo columnInfo) {
+ builder.append(" ALTER COLUMN ").append(columnInfo.getName())
+ .append(" SET DATA TYPE ");
+ writeColumnType(builder, columnInfo);
+
+ return builder;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/GenericDbmsHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/GenericDbmsHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/GenericDbmsHelper.java
new file mode 100644
index 0000000..5f484a8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/GenericDbmsHelper.java
@@ -0,0 +1,273 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.helpers.dbms;
+
+import org.apache.ambari.server.orm.DBAccessor;
+import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition;
+import org.eclipse.persistence.internal.databaseaccess.Platform;
+import org.eclipse.persistence.internal.sessions.AbstractSession;
+import org.eclipse.persistence.platform.database.DatabasePlatform;
+import org.eclipse.persistence.tools.schemaframework.FieldDefinition;
+import org.eclipse.persistence.tools.schemaframework.ForeignKeyConstraint;
+import org.eclipse.persistence.tools.schemaframework.TableDefinition;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.List;
+
+public class GenericDbmsHelper implements DbmsHelper {
+ protected final DatabasePlatform databasePlatform;
+
+ public GenericDbmsHelper(DatabasePlatform databasePlatform) {
+ this.databasePlatform = databasePlatform;
+ }
+
+ @Override
+ public boolean supportsColumnTypeChange() {
+ return false;
+ }
+
+ @Override
+ public String getRenameColumnStatement(String tableName, String oldName, DBAccessor.DBColumnInfo columnInfo) {
+ StringBuilder stringBuilder = new StringBuilder();
+
+ writeAlterTableClause(stringBuilder, tableName);
+ writeColumnRenameString(stringBuilder, oldName, columnInfo);
+
+ return stringBuilder.toString();
+ }
+
+ @Override
+ public String getAlterColumnStatement(String tableName, DBAccessor.DBColumnInfo columnInfo) {
+ StringBuilder stringBuilder = new StringBuilder();
+ writeAlterTableClause(stringBuilder, tableName);
+ writeColumnModifyString(stringBuilder, columnInfo);
+
+
+ return stringBuilder.toString();
+ }
+
+ public StringBuilder writeAlterTableClause(StringBuilder builder, String tableName) {
+ builder.append("ALTER TABLE ").append(tableName).append(" ");
+ return builder;
+ }
+
+ public StringBuilder writeColumnModifyString(StringBuilder builder, DBAccessor.DBColumnInfo columnInfo) {
+ throw new UnsupportedOperationException("Column type modification not supported for generic DB");
+ }
+
+ public StringBuilder writeColumnRenameString(StringBuilder builder, String oldName, DBAccessor.DBColumnInfo newColumnInfo) {
+ throw new UnsupportedOperationException("Column rename not supported for generic DB");
+ }
+
+ public StringBuilder writeColumnType(StringBuilder builder, DBAccessor.DBColumnInfo columnInfo) {
+ FieldTypeDefinition fieldType;
+
+ fieldType = databasePlatform.getFieldTypeDefinition(columnInfo.getType());
+
+ if (fieldType == null) {
+ throw new IllegalArgumentException("Unable to convert data type");
+ }
+
+ FieldDefinition definition = convertToFieldDefinition(columnInfo);
+
+ StringWriter writer = new StringWriter();
+
+ try {
+ databasePlatform.printFieldTypeSize(writer, definition, fieldType, false); //Ambari doesn't use identity fields
+ } catch (IOException ignored) {
+ // no writing to file
+ }
+
+ builder.append(writer.toString());
+
+ return builder;
+ }
+
+ /**
+ * get create table statement
+ * @param tableName
+ * @param columns
+ * @param primaryKeyColumns
+ * @return
+ */
+ @Override
+ public String getCreateTableStatement(String tableName,
+ List<DBAccessor.DBColumnInfo> columns,
+ List<String> primaryKeyColumns) {
+ Writer stringWriter = new StringWriter();
+ writeCreateTableStatement(stringWriter, tableName, columns, primaryKeyColumns);
+ return stringWriter.toString();
+ }
+
+
+ /**
+ * Write create table statement to writer
+ * TODO default Value of column not supported
+ */
+ public Writer writeCreateTableStatement(Writer writer, String tableName,
+ List<DBAccessor.DBColumnInfo> columns,
+ List<String> primaryKeyColumns) {
+ //TODO validateNames(String tableName, List<DBAccessor.DBColumnInfo> columns)
+ //TODO validatePKNames(List<DBAccessor.DBColumnInfo> columns, String... primaryKeyColumns)
+
+ TableDefinition tableDefinition = new TableDefinition();
+ tableDefinition.setName(tableName);
+ for (DBAccessor.DBColumnInfo columnInfo : columns) {
+ //TODO case-sensitive for now
+ int length = columnInfo.getLength() != null ? columnInfo.getLength() : 0;
+
+ if (primaryKeyColumns.contains(columnInfo.getName())) {
+ tableDefinition.addIdentityField(columnInfo.getName(), columnInfo.getType(), length);
+ } else {
+ FieldDefinition fieldDefinition = convertToFieldDefinition(columnInfo);
+ tableDefinition.addField(fieldDefinition);
+ }
+ }
+
+ //TODO possibly move code to avoid unnecessary dependencies and allow extension
+ tableDefinition.buildCreationWriter(createStubAbstractSessionFromPlatform(databasePlatform), writer);
+
+ return writer;
+ }
+
+ public FieldDefinition convertToFieldDefinition(DBAccessor.DBColumnInfo columnInfo) {
+ int length = columnInfo.getLength() != null ? columnInfo.getLength() : 0;
+ FieldDefinition fieldDefinition = new FieldDefinition(columnInfo.getName(), columnInfo.getType(), length);
+ fieldDefinition.setShouldAllowNull(columnInfo.isNullable());
+ return fieldDefinition;
+ }
+
+ /**
+ * get create index statement
+ * @param indexName
+ * @param tableName
+ * @param columnNames
+ * @return
+ */
+ @Override
+ public String getCreateIndexStatement(String indexName, String tableName,
+ String... columnNames) {
+ //TODO validateColumnNames()
+ String createIndex = databasePlatform.buildCreateIndex(tableName, indexName, columnNames);
+ return createIndex;
+ }
+
+
+ @Override
+ public String getAddForeignKeyStatement(String tableName, String constraintName,
+ List<String> keyColumns,
+ String referenceTableName,
+ List<String> referenceColumns) {
+ ForeignKeyConstraint foreignKeyConstraint = new ForeignKeyConstraint();
+ foreignKeyConstraint.setName(constraintName);
+ foreignKeyConstraint.setTargetTable(referenceTableName);
+ foreignKeyConstraint.setSourceFields(keyColumns);
+ foreignKeyConstraint.setTargetFields(referenceColumns);
+
+ TableDefinition tableDefinition = new TableDefinition();
+ tableDefinition.setName(tableName);
+
+ Writer writer = new StringWriter();
+ tableDefinition.buildConstraintCreationWriter(createStubAbstractSessionFromPlatform(databasePlatform),
+ foreignKeyConstraint, writer);
+
+ return writer.toString();
+
+ }
+
+ @Override
+ public String getAddColumnStatement(String tableName, DBAccessor.DBColumnInfo columnInfo) {
+ Writer writer = new StringWriter();
+
+ TableDefinition tableDefinition = new TableDefinition();
+ tableDefinition.setName(tableName);
+ tableDefinition.buildAddFieldWriter(createStubAbstractSessionFromPlatform(databasePlatform),
+ convertToFieldDefinition(columnInfo), writer);
+
+ return writer.toString();
+ }
+
+
+ @Override
+ public String getRenameColumnStatement(String tableName, String oldColumnName,
+ String newColumnName) {
+
+ throw new UnsupportedOperationException("Rename operation not supported.");
+ }
+
+ @Override
+ public String getDropTableStatement(String tableName) {
+ Writer writer = new StringWriter();
+
+ TableDefinition tableDefinition = new TableDefinition();
+ tableDefinition.setName(tableName);
+ tableDefinition.buildDeletionWriter
+ (createStubAbstractSessionFromPlatform(databasePlatform), writer);
+
+ return writer.toString();
+ }
+
+ @Override
+ public String getDropConstraintStatement(String tableName, String constraintName) {
+ Writer writer = new StringWriter();
+
+ ForeignKeyConstraint foreignKeyConstraint = new ForeignKeyConstraint();
+ foreignKeyConstraint.setName(constraintName);
+ foreignKeyConstraint.setTargetTable(tableName);
+
+ TableDefinition tableDefinition = new TableDefinition();
+ tableDefinition.setName(tableName);
+ tableDefinition.buildConstraintDeletionWriter(
+ createStubAbstractSessionFromPlatform(databasePlatform),
+ foreignKeyConstraint, writer);
+
+ return writer.toString();
+ }
+
+ @Override
+ public String getDropSequenceStatement(String sequenceName) {
+ StringWriter writer = new StringWriter();
+ String defaultStmt = String.format("DROP sequence %s", sequenceName);
+
+ try {
+ Writer w = databasePlatform.buildSequenceObjectDeletionWriter(writer, sequenceName);
+ return w != null ? w.toString() : defaultStmt;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return defaultStmt;
+ }
+
+ public AbstractSession createStubAbstractSessionFromPlatform
+ (final DatabasePlatform databasePlatform) {
+ return new AbstractSession() {
+ @Override
+ public Platform getDatasourcePlatform() {
+ return databasePlatform;
+ }
+
+ @Override
+ public DatabasePlatform getPlatform() {
+ return databasePlatform;
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/MySqlHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/MySqlHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/MySqlHelper.java
new file mode 100644
index 0000000..817ca9b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/MySqlHelper.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.helpers.dbms;
+
+import org.apache.ambari.server.orm.DBAccessor;
+import org.eclipse.persistence.platform.database.DatabasePlatform;
+
+public class MySqlHelper extends GenericDbmsHelper {
+ public MySqlHelper(DatabasePlatform databasePlatform) {
+ super(databasePlatform);
+ }
+
+ @Override
+ public boolean supportsColumnTypeChange() {
+ return true;
+ }
+
+ @Override
+ public StringBuilder writeColumnRenameString(StringBuilder builder, String oldName, DBAccessor.DBColumnInfo newColumnInfo) {
+
+ builder.append(" CHANGE ").append(oldName).append(" ").append(newColumnInfo.getName()).append(" ");
+ writeColumnType(builder, newColumnInfo);
+
+ return builder;
+ }
+
+ @Override
+ public StringBuilder writeColumnModifyString(StringBuilder builder, DBAccessor.DBColumnInfo columnInfo) {
+ builder.append(" MODIFY ").append(columnInfo.getName()).append(" ");
+ writeColumnType(builder, columnInfo);
+ return builder;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/OracleHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/OracleHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/OracleHelper.java
new file mode 100644
index 0000000..aebfb62
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/OracleHelper.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.helpers.dbms;
+
+import org.apache.ambari.server.orm.DBAccessor;
+import org.eclipse.persistence.platform.database.DatabasePlatform;
+
+public class OracleHelper extends GenericDbmsHelper {
+ public OracleHelper(DatabasePlatform databasePlatform) {
+ super(databasePlatform);
+ }
+
+ @Override
+ public boolean supportsColumnTypeChange() {
+ return true;
+ }
+
+ @Override
+ public StringBuilder writeColumnRenameString(StringBuilder builder, String oldName, DBAccessor.DBColumnInfo newColumnInfo) {
+ builder.append(" RENAME COLUMN ").append(oldName).append(" TO ").append(newColumnInfo.getName());
+ return builder;
+ }
+
+ @Override
+ public StringBuilder writeColumnModifyString(StringBuilder builder, DBAccessor.DBColumnInfo columnInfo) {
+ builder.append(" MODIFY ").append(columnInfo.getName()).append(" ");
+ writeColumnType(builder, columnInfo);
+ return builder;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/PostgresHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/PostgresHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/PostgresHelper.java
new file mode 100644
index 0000000..38e837e
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/PostgresHelper.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.helpers.dbms;
+
+import org.apache.ambari.server.orm.DBAccessor;
+import org.eclipse.persistence.platform.database.DatabasePlatform;
+
+public class PostgresHelper extends GenericDbmsHelper {
+ public PostgresHelper(DatabasePlatform databasePlatform) {
+ super(databasePlatform);
+ }
+
+ @Override
+ public boolean supportsColumnTypeChange() {
+ return true;
+ }
+
+ @Override
+ public StringBuilder writeColumnRenameString(StringBuilder builder, String oldName, DBAccessor.DBColumnInfo newColumnInfo) {
+ builder.append(" RENAME COLUMN ").append(oldName).append(" TO ").append(newColumnInfo.getName());
+ return builder;
+ }
+
+ @Override
+ public StringBuilder writeColumnModifyString(StringBuilder builder, DBAccessor.DBColumnInfo columnInfo) {
+ builder.append(" ALTER COLUMN ").append(columnInfo.getName()).append(" TYPE ");
+ writeColumnType(builder, columnInfo);
+ return builder;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
new file mode 100644
index 0000000..dfdfa85
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.upgrade;
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Provider;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.DBAccessor;
+import org.apache.ambari.server.utils.VersionUtils;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.persistence.EntityManager;
+import java.io.File;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class AbstractUpgradeCatalog implements UpgradeCatalog {
+ @Inject
+ protected DBAccessor dbAccessor;
+ @Inject
+ protected Configuration configuration;
+ @Inject
+ protected StackUpgradeUtil stackUpgradeUtil;
+
+ private Injector injector;
+ private static final Logger LOG = LoggerFactory.getLogger
+ (AbstractUpgradeCatalog.class);
+ private static final Map<String, UpgradeCatalog> upgradeCatalogMap =
+ new HashMap<String, UpgradeCatalog>();
+
+ @Inject
+ public AbstractUpgradeCatalog(Injector injector) {
+ this.injector = injector;
+ registerCatalog(this);
+ }
+
+ /**
+ * Every subclass needs to register itself
+ */
+ protected void registerCatalog(UpgradeCatalog upgradeCatalog) {
+ upgradeCatalogMap.put(upgradeCatalog.getTargetVersion(), upgradeCatalog);
+ }
+
+ @Override
+ public String getSourceVersion() {
+ return null;
+ }
+
+ protected static UpgradeCatalog getUpgradeCatalog(String version) {
+ return upgradeCatalogMap.get(version);
+ }
+
+ protected static class VersionComparator implements Comparator<UpgradeCatalog> {
+
+ @Override
+ public int compare(UpgradeCatalog upgradeCatalog1,
+ UpgradeCatalog upgradeCatalog2) {
+ return VersionUtils.compareVersions(upgradeCatalog1.getTargetVersion(),
+ upgradeCatalog2.getTargetVersion(), 3);
+ }
+ }
+
+ /**
+ * Read server version file
+ * @return
+ */
+ protected String getAmbariServerVersion() {
+ String versionFilePath = configuration.getServerVersionFilePath();
+ try {
+ return FileUtils.readFileToString(new File(versionFilePath));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * Update metainfo to new version.
+ */
+ protected int updateMetaInfoVersion(String version) {
+ String ambariServerVersion = getAmbariServerVersion();
+ int rows = 0;
+
+ if (ambariServerVersion != null) {
+ try {
+ dbAccessor.executeQuery("INSERT INTO metainfo ('metainfo_key', " +
+ "'metainfo_value') VALUES ('version', '${ambariVersion}')");
+
+ rows = dbAccessor.updateTable("metainfo", "metainfo_value",
+ ambariServerVersion, String.format("WHERE metainfo_key = '%s'", version));
+ } catch (SQLException e) {
+ LOG.error("Failed updating metainfo table.", e);
+ }
+ }
+
+ return rows;
+ }
+
+ protected String getDbType() {
+ String dbUrl = configuration.getDatabaseUrl();
+ String dbType;
+
+ if (dbUrl.contains(Configuration.POSTGRES_DB_NAME)) {
+ dbType = Configuration.POSTGRES_DB_NAME;
+ } else if (dbUrl.contains(Configuration.ORACLE_DB_NAME)) {
+ dbType = Configuration.ORACLE_DB_NAME;
+ } else if (dbUrl.contains(Configuration.MYSQL_DB_NAME)) {
+ dbType = Configuration.MYSQL_DB_NAME;
+ } else {
+ throw new RuntimeException("Unable to determine database type.");
+ }
+
+ return dbType;
+ }
+
+ protected Provider<EntityManager> getEntityManagerProvider() {
+ return injector.getProvider(EntityManager.class);
+ }
+
+ protected void executeInTransaction(Runnable func) {
+ EntityManager entityManager = getEntityManagerProvider().get();
+ if (entityManager.getTransaction().isActive()) { //already started, reuse
+ func.run();
+ } else {
+ entityManager.getTransaction().begin();
+ try {
+ func.run();
+ entityManager.getTransaction().commit();
+ } catch (Exception e) {
+ entityManager.getTransaction().rollback();
+ throw new RuntimeException(e);
+ }
+
+ }
+ }
+
+ protected void changePostgresSearchPath() throws SQLException {
+ String dbUser = configuration.getDatabaseUser();
+ String dbName = configuration.getServerDBName();
+
+ dbAccessor.executeQuery(String.format("ALTER SCHEMA %s OWNER TO %s;", dbName, dbUser));
+
+ dbAccessor.executeQuery(String.format("ALTER ROLE %s SET search_path to '%s';", dbUser, dbName));
+ }
+
+ protected void grantAllPostgresPrivileges() throws SQLException {
+ String query = "GRANT ALL PRIVILEGES ON DATABASE ambari TO " +
+ configuration.getDatabaseUser();
+
+ dbAccessor.executeQuery(query);
+ }
+
+ @Override
+ public void upgradeSchema() throws AmbariException, SQLException {
+ if (getDbType().equals(Configuration.POSTGRES_DB_NAME)) {
+ changePostgresSearchPath();
+ }
+
+ this.executeDDLUpdates();
+ }
+
+ protected abstract void executeDDLUpdates() throws AmbariException, SQLException;
+
+ @Override
+ public String toString() {
+ return "{ " + this.getClass().getCanonicalName() +": " +
+ "sourceVersion = " + getSourceVersion() + ", " +
+ "targetVersion = " + getTargetVersion() + " }";
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/fea7b622/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
new file mode 100644
index 0000000..5875cdb
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.upgrade;
+
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.persist.PersistService;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.ControllerModule;
+import org.apache.ambari.server.orm.dao.MetainfoDAO;
+import org.apache.ambari.server.orm.entities.MetainfoEntity;
+import org.apache.ambari.server.utils.VersionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.InputMismatchException;
+import java.util.List;
+import java.util.Set;
+
+public class SchemaUpgradeHelper {
+ private static final Logger LOG = LoggerFactory.getLogger
+ (SchemaUpgradeHelper.class);
+
+ private Set<UpgradeCatalog> allUpgradeCatalogs;
+ private MetainfoDAO metainfoDAO;
+ private PersistService persistService;
+
+ @Inject
+ public SchemaUpgradeHelper(Set<UpgradeCatalog> allUpgradeCatalogs, MetainfoDAO metainfoDAO,
+ PersistService persistService) {
+ this.allUpgradeCatalogs = allUpgradeCatalogs;
+ this.metainfoDAO = metainfoDAO;
+ this.persistService = persistService;
+ }
+
+ private void startPersistenceService() {
+ persistService.start();
+ }
+
+ private void stopPersistenceService() {
+ persistService.stop();
+ }
+
+ public Set<UpgradeCatalog> getAllUpgradeCatalogs() {
+ return allUpgradeCatalogs;
+ }
+
+ private String readSourceVersion() {
+ String sourceVersion = null;
+
+ MetainfoEntity metainfoEntity = metainfoDAO.findByKey
+ (Configuration.SERVER_VERSION_KEY);
+
+ if (metainfoEntity != null) {
+ String version = metainfoEntity.getMetainfoValue();
+ if (version != null) {
+ sourceVersion = VersionUtils.getVersionSubstring(version);
+ }
+ }
+
+ return sourceVersion;
+ }
+
+ /**
+ * Return a set Upgrade catalogs to be applied to upgrade from
+ * @sourceVersion to @targetVersion
+ *
+ * @param sourceVersion
+ * @param targetVersion
+ * @return
+ * @throws org.apache.ambari.server.AmbariException
+ */
+ protected List<UpgradeCatalog> getUpgradePath(String sourceVersion,
+ String targetVersion) throws AmbariException {
+
+ List<UpgradeCatalog> upgradeCatalogs = new ArrayList<UpgradeCatalog>();
+ List<UpgradeCatalog> candidateCatalogs = new ArrayList<UpgradeCatalog>(allUpgradeCatalogs);
+
+ Collections.sort(candidateCatalogs, new AbstractUpgradeCatalog.VersionComparator());
+
+ for (UpgradeCatalog upgradeCatalog : candidateCatalogs) {
+ if (sourceVersion == null || VersionUtils.compareVersions(sourceVersion,
+ upgradeCatalog.getTargetVersion(), 3) < 0) {
+ // catalog version is newer than source
+ if (VersionUtils.compareVersions(upgradeCatalog.getTargetVersion(),
+ targetVersion, 3) <= 0) {
+ // catalog version is older or equal to target
+ upgradeCatalogs.add(upgradeCatalog);
+ }
+ }
+ }
+
+ LOG.info("Upgrade path: " + upgradeCatalogs);
+
+ return upgradeCatalogs;
+ }
+
+ /**
+ * Extension of main controller module
+ */
+ public static class UpgradeHelperModule extends ControllerModule {
+ public UpgradeHelperModule() throws Exception {
+
+ }
+
+ @Override
+ protected void configure() {
+ super.configure();
+ // Add binding to each newly created catalog
+ Multibinder<UpgradeCatalog> catalogBinder =
+ Multibinder.newSetBinder(binder(), UpgradeCatalog.class);
+ catalogBinder.addBinding().to(UpgradeCatalog150.class);
+ }
+ }
+
+ private void executeUpgrade(List<UpgradeCatalog> upgradeCatalogs) throws AmbariException {
+ LOG.info("Executing DDL upgrade...");
+
+ if (upgradeCatalogs != null && !upgradeCatalogs.isEmpty()) {
+ for (UpgradeCatalog upgradeCatalog : upgradeCatalogs) {
+ try {
+ upgradeCatalog.upgradeSchema();
+ } catch (AmbariException e) {
+ LOG.error("Upgrade failed. ", e);
+ throw e;
+ } catch (SQLException e) {
+ LOG.error("Upgrade failed. ", e);
+ throw new AmbariException(e.getMessage());
+ }
+ }
+ }
+ }
+
+ private void executeDMLUpdates(List<UpgradeCatalog> upgradeCatalogs) throws AmbariException {
+ LOG.info("Execution DML changes.");
+
+ if (upgradeCatalogs != null && !upgradeCatalogs.isEmpty()) {
+ for (UpgradeCatalog upgradeCatalog : upgradeCatalogs) {
+ try {
+ upgradeCatalog.executeDMLUpdates();
+ } catch (AmbariException e) {
+ LOG.error("Upgrade failed. ", e);
+ throw e;
+ } catch (SQLException e) {
+ LOG.error("Upgrade failed. ", e);
+ throw new AmbariException(e.getMessage());
+ }
+ }
+ }
+ }
+
+ /**
+ * Upgrade Ambari DB schema to the target version passed in as the only
+ * argument.
+ * @param args args[0] = target version to upgrade to.
+ */
+ public static void main(String[] args) throws Exception {
+ if (args.length == 0) {
+ throw new InputMismatchException("Need to provide target version.");
+ }
+
+ String targetVersion = args[0];
+ LOG.info("Upgrading schema to target version = " + targetVersion);
+
+ UpgradeCatalog targetUpgradeCatalog = AbstractUpgradeCatalog
+ .getUpgradeCatalog(targetVersion);
+
+ LOG.debug("Target upgrade catalog. " + targetUpgradeCatalog);
+
+ Injector injector = Guice.createInjector(new UpgradeHelperModule());
+
+ SchemaUpgradeHelper schemaUpgradeHelper = injector.getInstance(SchemaUpgradeHelper.class);
+
+ // Read source version from DB
+ String sourceVersion = schemaUpgradeHelper.readSourceVersion();
+ LOG.info("Upgrading schema from source version = " + sourceVersion);
+
+ List<UpgradeCatalog> upgradeCatalogs =
+ schemaUpgradeHelper.getUpgradePath(sourceVersion, targetVersion);
+
+ schemaUpgradeHelper.executeUpgrade(upgradeCatalogs);
+
+ schemaUpgradeHelper.startPersistenceService();
+
+ schemaUpgradeHelper.executeDMLUpdates(upgradeCatalogs);
+
+ LOG.info("Upgrade successful.");
+
+ schemaUpgradeHelper.stopPersistenceService();
+ }
+}