diff options
10 files changed, 115 insertions, 51 deletions
diff --git a/sonar-application/src/main/assembly/conf/sonar.properties b/sonar-application/src/main/assembly/conf/sonar.properties index d9735de8cf3..560fab5c1a4 100644 --- a/sonar-application/src/main/assembly/conf/sonar.properties +++ b/sonar-application/src/main/assembly/conf/sonar.properties @@ -57,6 +57,7 @@ sonar.jdbc.driverClassName: org.apache.derby.jdbc.ClientDriver # uncomment to accept connections from remote hosts. Ba default it only accepts localhost connections. #sonar.derby.drda.host: 0.0.0.0 + #----- MySQL 5.x/6.x # Comment the embedded database and uncomment the following properties to use MySQL. The validation query is optional. #sonar.jdbc.url: jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8 @@ -76,10 +77,11 @@ sonar.jdbc.driverClassName: org.apache.derby.jdbc.ClientDriver #sonar.jdbc.driverClassName: oracle.jdbc.OracleDriver #sonar.jdbc.validationQuery: select 1 from dual -# Uncomment the following property if multiple Sonar schemas are installed on the same server -# (for example with different versions). -# In that case, use the same property during project analysis (-Dsonar.hibernate.default_schema=<schema>) -#sonar.hibernate.default_schema: sonar +# Uncomment the following property if the Oracle account has permissions to access multiple schemas, +# for example sonar schemas with different versions. In that case, use the same property during project analysis +# (-Dsonar.jdbc.schema=<schema>) +#sonar.jdbc.schema: sonar + #----- PostgreSQL 8.x, 9.x # Uncomment the following properties to use PostgreSQL. The validation query is optional. @@ -87,8 +89,10 @@ sonar.jdbc.driverClassName: org.apache.derby.jdbc.ClientDriver #sonar.jdbc.driverClassName: org.postgresql.Driver #sonar.jdbc.validationQuery: select 1 -# If the PostgreSql database contains several schemas, the following property must define the schema to be used -#sonar.jdbc.postgreSearchPath: public +# Uncomment the following property if the PostgreSQL account has permissions to access multiple schemas, +# for example sonar schemas with different versions. In that case, use the same property during project analysis +# (-Dsonar.jdbc.schema=<schema>) +#sonar.jdbc.schema: public #----- Microsoft SQLServer diff --git a/sonar-core/src/main/java/org/sonar/persistence/Database.java b/sonar-core/src/main/java/org/sonar/persistence/Database.java index 1f030afb3ab..4153c56d805 100644 --- a/sonar-core/src/main/java/org/sonar/persistence/Database.java +++ b/sonar-core/src/main/java/org/sonar/persistence/Database.java @@ -42,10 +42,5 @@ public interface Database { */ Dialect getDialect(); - /** - * @return the schema or null if not defined or if start() has not been executed - */ - String getSchema(); - Properties getHibernateProperties(); } diff --git a/sonar-core/src/main/java/org/sonar/persistence/DefaultDatabase.java b/sonar-core/src/main/java/org/sonar/persistence/DefaultDatabase.java index 0eb87719c26..d4dd8da80b0 100644 --- a/sonar-core/src/main/java/org/sonar/persistence/DefaultDatabase.java +++ b/sonar-core/src/main/java/org/sonar/persistence/DefaultDatabase.java @@ -19,6 +19,7 @@ */ package org.sonar.persistence; +import com.google.common.collect.Lists; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; import org.apache.commons.lang.StringUtils; @@ -49,7 +50,6 @@ public class DefaultDatabase implements Database { private Settings settings; private BasicDataSource datasource; private Dialect dialect; - private String schema; public DefaultDatabase(Settings settings) { this.settings = settings; @@ -61,8 +61,7 @@ public class DefaultDatabase implements Database { Properties properties = getProperties(); dialect = initDialect(properties); - schema = initSchema(properties, dialect); - datasource = initDatasource(properties); + datasource = initDatasource(properties, dialect); return this; } catch (Exception e) { @@ -70,19 +69,11 @@ public class DefaultDatabase implements Database { } } - private String initSchema(Properties properties, Dialect dialect) { - if (dialect.getId().equals(PostgreSql.ID)) { - return properties.getProperty("sonar.jdbc.postgreSearchPath", "public"); - } - if (dialect.getId().equals(Oracle.ID)) { - return properties.getProperty("sonar.hibernate.default_schema", "sonar"); - } - return null; - } - - BasicDataSource initDatasource(Properties properties) throws Exception { + BasicDataSource initDatasource(Properties properties, Dialect dialect) throws Exception { LOG.info("Create JDBC datasource"); - return (BasicDataSource) BasicDataSourceFactory.createDataSource(extractCommonsDbcpProperties(properties)); + BasicDataSource result = (BasicDataSource) BasicDataSourceFactory.createDataSource(extractCommonsDbcpProperties(properties)); + result.setConnectionInitSqls(getConnectionInitStatements(properties, dialect)); + return result; } Dialect initDialect(Properties properties) { @@ -116,10 +107,6 @@ public class DefaultDatabase implements Database { return dialect; } - public String getSchema() { - return schema; - } - public Properties getHibernateProperties() { Properties props = new Properties(); @@ -174,6 +161,30 @@ public class DefaultDatabase implements Database { return result; } + static List<String> getConnectionInitStatements(Properties properties, Dialect dialect) { + List<String> result = Lists.newArrayList(); + if (PostgreSql.ID.equals(dialect.getId())) { + String searchPath = getSchema(properties, "sonar.jdbc.postgreSearchPath"); + if (StringUtils.isNotBlank(searchPath)) { + result.add("SET SEARCH_PATH TO " + searchPath); + } + } else if (Oracle.ID.equals(dialect.getId())) { + String schema = getSchema(properties, "sonar.hibernate.default_schema"); + if (StringUtils.isNotBlank(schema)) { + result.add("ALTER SESSION SET CURRENT SCHEMA = " + schema); + } + } + return result; + } + + static String getSchema(Properties props, String deprecatedKey) { + String value = props.getProperty("sonar.jdbc.schema"); + if (StringUtils.isBlank(value) && deprecatedKey != null) { + value = props.getProperty(deprecatedKey); + } + return StringUtils.isNotBlank(value) ? value : null; + } + private static void completeDefaultProperties(Properties props) { completeDefaultProperty(props, DatabaseProperties.PROP_DRIVER, props.getProperty(DatabaseProperties.PROP_DRIVER_DEPRECATED, DatabaseProperties.PROP_DRIVER_DEFAULT_VALUE)); completeDefaultProperty(props, DatabaseProperties.PROP_URL, DatabaseProperties.PROP_URL_DEFAULT_VALUE); diff --git a/sonar-core/src/main/java/org/sonar/persistence/MyBatis.java b/sonar-core/src/main/java/org/sonar/persistence/MyBatis.java index 6ba20d19236..f0978cdb248 100644 --- a/sonar-core/src/main/java/org/sonar/persistence/MyBatis.java +++ b/sonar-core/src/main/java/org/sonar/persistence/MyBatis.java @@ -49,7 +49,6 @@ public class MyBatis implements BatchComponent, ServerComponent { conf.setEnvironment(new Environment("production", createTransactionFactory(), database.getDataSource())); conf.setUseGeneratedKeys(true); conf.setLazyLoadingEnabled(false); - loadSchemaVariable(conf); loadAlias(conf, "DuplicationUnit", DuplicationUnit.class); loadAlias(conf, "Rule", Rule.class); @@ -60,14 +59,6 @@ public class MyBatis implements BatchComponent, ServerComponent { return this; } - private void loadSchemaVariable(Configuration conf) { - String schema = database.getSchema(); - if (StringUtils.isNotBlank(schema)) { - conf.getVariables().setProperty("_schema", schema + "."); - } else { - conf.getVariables().setProperty("_schema", ""); - } - } public SqlSessionFactory getSessionFactory() { return sessionFactory; diff --git a/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper-mssql.xml b/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper-mssql.xml index fb495eeb7e3..bc1837a35fa 100644 --- a/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper-mssql.xml +++ b/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper-mssql.xml @@ -5,7 +5,7 @@ <select id="selectCandidates" parameterType="map" resultType="DuplicationUnit"> SELECT DISTINCT to_blocks.hash hash, res.kee resourceKey, to_blocks.index_in_file indexInFile, to_blocks.start_line startLine, to_blocks.end_line endLine - FROM ${_schema}duplications_index to_blocks, ${_schema}duplications_index from_blocks, ${_schema}snapshots snapshot, ${_schema}projects res + FROM duplications_index to_blocks, duplications_index from_blocks, snapshots snapshot, projects res WHERE from_blocks.snapshot_id = #{resource_snapshot_id} AND to_blocks.hash = from_blocks.hash AND to_blocks.snapshot_id = snapshot.id @@ -17,7 +17,7 @@ </select> <insert id="batchInsert" parameterType="DuplicationUnit" keyColumn="id" useGeneratedKeys="false"> - INSERT INTO ${_schema}duplications_index (snapshot_id, project_snapshot_id, hash, index_in_file, start_line, end_line) + INSERT INTO duplications_index (snapshot_id, project_snapshot_id, hash, index_in_file, start_line, end_line) VALUES (#{snapshotId}, #{projectSnapshotId}, #{hash}, #{indexInFile}, #{startLine}, #{endLine}) </insert> diff --git a/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper-oracle.xml b/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper-oracle.xml index ff06ab3f95e..92a6bedc2fe 100644 --- a/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper-oracle.xml +++ b/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper-oracle.xml @@ -5,7 +5,7 @@ <select id="selectCandidates" parameterType="map" resultType="DuplicationUnit"> SELECT DISTINCT to_blocks.hash hash, res.kee resourceKey, to_blocks.index_in_file indexInFile, to_blocks.start_line startLine, to_blocks.end_line endLine - FROM ${_schema}duplications_index to_blocks, ${_schema}duplications_index from_blocks, ${_schema}snapshots snapshot, ${_schema}projects res + FROM duplications_index to_blocks, duplications_index from_blocks, snapshots snapshot, projects res WHERE from_blocks.snapshot_id = #{resource_snapshot_id} AND to_blocks.hash = from_blocks.hash AND to_blocks.snapshot_id = snapshot.id @@ -17,7 +17,7 @@ </select> <insert id="batchInsert" parameterType="DuplicationUnit" keyColumn="id" useGeneratedKeys="false"> - INSERT INTO ${_schema}duplications_index (id, snapshot_id, project_snapshot_id, hash, index_in_file, start_line, end_line) + INSERT INTO duplications_index (id, snapshot_id, project_snapshot_id, hash, index_in_file, start_line, end_line) VALUES (duplications_index_seq.NEXTVAL, #{snapshotId}, #{projectSnapshotId}, #{hash}, #{indexInFile}, #{startLine}, #{endLine}) </insert> diff --git a/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper.xml b/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper.xml index b6a6bcee564..5f39d7dea7c 100644 --- a/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/persistence/model/DuplicationMapper.xml @@ -5,7 +5,7 @@ <select id="selectCandidates" parameterType="map" resultType="DuplicationUnit"> SELECT DISTINCT to_blocks.hash hash, res.kee resourceKey, to_blocks.index_in_file indexInFile, to_blocks.start_line startLine, to_blocks.end_line endLine - FROM ${_schema}duplications_index to_blocks, ${_schema}duplications_index from_blocks, ${_schema}snapshots snapshot, ${_schema}projects res + FROM duplications_index to_blocks, duplications_index from_blocks, snapshots snapshot, projects res WHERE from_blocks.snapshot_id = #{resource_snapshot_id} AND to_blocks.hash = from_blocks.hash AND to_blocks.snapshot_id = snapshot.id @@ -17,7 +17,7 @@ </select> <insert id="batchInsert" parameterType="DuplicationUnit" useGeneratedKeys="false"> - INSERT INTO ${_schema}duplications_index (snapshot_id, project_snapshot_id, hash, index_in_file, start_line, end_line) + INSERT INTO duplications_index (snapshot_id, project_snapshot_id, hash, index_in_file, start_line, end_line) VALUES (#{snapshotId}, #{projectSnapshotId}, #{hash}, #{indexInFile}, #{startLine}, #{endLine}) </insert> diff --git a/sonar-core/src/main/resources/org/sonar/persistence/model/RuleMapper.xml b/sonar-core/src/main/resources/org/sonar/persistence/model/RuleMapper.xml index 7d0614dea2b..7cb565596dc 100644 --- a/sonar-core/src/main/resources/org/sonar/persistence/model/RuleMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/persistence/model/RuleMapper.xml @@ -4,11 +4,11 @@ <mapper namespace="org.sonar.persistence.model.RuleMapper"> <select id="selectAll" resultType="Rule"> - select id, plugin_rule_key as "ruleKey", plugin_name as "repositoryKey", description, enabled, name from ${_schema}RULES + select id, plugin_rule_key as "ruleKey", plugin_name as "repositoryKey", description, enabled, name from RULES </select> <select id="selectById" parameterType="long" resultType="Rule"> - select id, plugin_rule_key as "ruleKey", plugin_name as "repositoryKey", description, enabled, name from ${_schema}RULES WHERE id=#{id} + select id, plugin_rule_key as "ruleKey", plugin_name as "repositoryKey", description, enabled, name from RULES WHERE id=#{id} </select> </mapper> diff --git a/sonar-core/src/test/java/org/sonar/persistence/DefaultDatabaseTest.java b/sonar-core/src/test/java/org/sonar/persistence/DefaultDatabaseTest.java index 2f11a05c619..45238a9bb8a 100644 --- a/sonar-core/src/test/java/org/sonar/persistence/DefaultDatabaseTest.java +++ b/sonar-core/src/test/java/org/sonar/persistence/DefaultDatabaseTest.java @@ -23,8 +23,11 @@ import org.apache.commons.dbcp.BasicDataSource; import org.hamcrest.core.Is; import org.junit.Test; import org.sonar.api.config.Settings; +import org.sonar.jpa.dialect.Oracle; +import org.sonar.jpa.dialect.PostgreSql; import java.sql.SQLException; +import java.util.List; import java.util.Properties; import static org.junit.Assert.assertThat; @@ -108,4 +111,68 @@ public class DefaultDatabaseTest { DerbyUtils.dropInMemoryDatabase(); } } + + /** + * Avoid conflicts with other schemas + */ + @Test + public void shouldChangePostgreSearchPath() { + Properties props = new Properties(); + props.setProperty("sonar.jdbc.postgreSearchPath", "my_schema"); + + List<String> statements = DefaultDatabase.getConnectionInitStatements(props, new PostgreSql()); + + assertThat(statements.size(), Is.is(1)); + assertThat(statements.get(0), Is.is("SET SEARCH_PATH TO my_schema")); + } + + @Test + public void shouldNotChangePostgreSearchPathByDefault() { + List<String> statements = DefaultDatabase.getConnectionInitStatements(new Properties(), new PostgreSql()); + + assertThat(statements.size(), Is.is(0)); + } + + /** + * Avoid conflicts with other schemas + */ + @Test + public void shouldAlterOracleSession() { + Properties props = new Properties(); + props.setProperty("sonar.hibernate.default_schema", "my_schema"); + + List<String> statements = DefaultDatabase.getConnectionInitStatements(props, new Oracle()); + + assertThat(statements.size(), Is.is(1)); + assertThat(statements.get(0), Is.is("ALTER SESSION SET CURRENT SCHEMA = my_schema")); + } + + @Test + public void shouldNotAlterOracleSessionByDefault() { + List<String> statements = DefaultDatabase.getConnectionInitStatements(new Properties(), new Oracle()); + + assertThat(statements.size(), Is.is(0)); + } + + @Test + public void shouldSupportGenericSchemaPropertyForPostgreSQL() { + Properties props = new Properties(); + props.setProperty("sonar.jdbc.schema", "my_schema"); + + List<String> statements = DefaultDatabase.getConnectionInitStatements(props, new PostgreSql()); + + assertThat(statements.size(), Is.is(1)); + assertThat(statements.get(0), Is.is("SET SEARCH_PATH TO my_schema")); + } + + @Test + public void shouldSupportGenericSchemaPropertyForOracle() { + Properties props = new Properties(); + props.setProperty("sonar.jdbc.schema", "my_schema"); + + List<String> statements = DefaultDatabase.getConnectionInitStatements(props, new Oracle()); + + assertThat(statements.size(), Is.is(1)); + assertThat(statements.get(0), Is.is("ALTER SESSION SET CURRENT SCHEMA = my_schema")); + } } diff --git a/sonar-core/src/test/java/org/sonar/persistence/InMemoryDatabase.java b/sonar-core/src/test/java/org/sonar/persistence/InMemoryDatabase.java index f499b6a83d9..0a145afaaa6 100644 --- a/sonar-core/src/test/java/org/sonar/persistence/InMemoryDatabase.java +++ b/sonar-core/src/test/java/org/sonar/persistence/InMemoryDatabase.java @@ -149,10 +149,6 @@ public class InMemoryDatabase implements Database { return new Derby(); } - public String getSchema() { - return null; - } - public Properties getHibernateProperties() { Properties properties = new Properties(); properties.put("hibernate.hbm2ddl.auto", "validate"); |