From 3513f49df275866ecf71be8defd581707cf67dc0 Mon Sep 17 00:00:00 2001 From: pesse Date: Thu, 11 Oct 2018 08:32:35 +0200 Subject: [PATCH 1/3] Test to parse/set NLS_LANG correctly --- .../org/utplsql/cli/DataSourceProviderIT.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/test/java/org/utplsql/cli/DataSourceProviderIT.java b/src/test/java/org/utplsql/cli/DataSourceProviderIT.java index 56a254c..ab8b732 100644 --- a/src/test/java/org/utplsql/cli/DataSourceProviderIT.java +++ b/src/test/java/org/utplsql/cli/DataSourceProviderIT.java @@ -5,8 +5,12 @@ import javax.sql.DataSource; import java.io.IOException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; public class DataSourceProviderIT { @@ -20,4 +24,44 @@ public void connectToDatabase() throws IOException, SQLException { assertNotNull(dataSource); } + + @Test + public void initNlsLang() throws SQLException { + ConnectionConfig config = new ConnectionConfig(TestHelper.getConnectionString()); + System.setProperty("NLS_LANG", "BRAZILIAN PORTUGUESE_BRAZIL.WE8ISO8859P1"); + + + DataSource dataSource = new TestedDataSourceProvider(config).getDataSource(); + + assertNotNull(dataSource); + + try ( Connection con = dataSource.getConnection() ) { + try (PreparedStatement stmt = con.prepareStatement("select value from nls_session_parameters where parameter = 'NLS_LANGUAGE'")) { + ResultSet rs = stmt.executeQuery(); + if ( rs.next() ) { + assertEquals("BRAZILIAN PORTUGUESE", rs.getString(1)); + } + } + } + } + + @Test + public void initPartialNlsLang() throws SQLException { + ConnectionConfig config = new ConnectionConfig(TestHelper.getConnectionString()); + System.setProperty("NLS_LANG", "_SOMALIA"); + + + DataSource dataSource = new TestedDataSourceProvider(config).getDataSource(); + + assertNotNull(dataSource); + + try ( Connection con = dataSource.getConnection() ) { + try (PreparedStatement stmt = con.prepareStatement("select value from nls_session_parameters where parameter = 'NLS_TERRITORY'")) { + ResultSet rs = stmt.executeQuery(); + if ( rs.next() ) { + assertEquals("SOMALIA", rs.getString(1)); + } + } + } + } } From 8d832617451cc70924bbeec10857a744a2903d9d Mon Sep 17 00:00:00 2001 From: pesse Date: Thu, 11 Oct 2018 09:14:31 +0200 Subject: [PATCH 2/3] Add ConnectionInit-SQL based on NLS_LANG Remove NLS_LANG from Locale-Initialization Fixes #101 --- .../org/utplsql/cli/LocaleInitializer.java | 16 ++--- .../datasource/TestedDataSourceProvider.java | 33 +++++++++- .../org/utplsql/cli/DataSourceProviderIT.java | 64 +++++++++++-------- 3 files changed, 77 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/utplsql/cli/LocaleInitializer.java b/src/main/java/org/utplsql/cli/LocaleInitializer.java index 830c742..75d5366 100644 --- a/src/main/java/org/utplsql/cli/LocaleInitializer.java +++ b/src/main/java/org/utplsql/cli/LocaleInitializer.java @@ -1,5 +1,7 @@ package org.utplsql.cli; +import org.utplsql.api.EnvironmentVariableUtil; + import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -7,10 +9,9 @@ /** This class makes sure the java locale is set according to the environment variables LC_ALL and LANG * We experienced that, in some cases, the locale was not set as expected, therefore this class implements some clear * rules: - * 1. If environment variable NLS_LANG is set, we try to parse its content and set locale according to its value if valid - * 2. If environment variable LC_ALL is set, we try to parse its content and set locale according to its value if valid - * 3. If environment variable LANG is set, we try to parse its content and set locale according to its value if valid - * 4. Otherwise we use default locale + * 1. If environment variable LC_ALL is set, we try to parse its content and set locale according to its value if valid + * 2. If environment variable LANG is set, we try to parse its content and set locale according to its value if valid + * 3. Otherwise we use default locale * * @author pesse */ @@ -23,12 +24,9 @@ class LocaleInitializer { */ static void initLocale() { - boolean localeChanged = setDefaultLocale(System.getenv("NLS_LANG")); - - if ( !localeChanged ) - localeChanged = setDefaultLocale(System.getenv("LC_ALL")); + boolean localeChanged = setDefaultLocale(EnvironmentVariableUtil.getEnvValue("LC_ALL")); if ( !localeChanged ) - setDefaultLocale(System.getenv("LANG")); + setDefaultLocale(EnvironmentVariableUtil.getEnvValue("LANG")); } /** Set the default locale from a given string like LC_ALL or LANG environment variable diff --git a/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java b/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java index 4ad5d62..f666f82 100644 --- a/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java +++ b/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java @@ -1,6 +1,7 @@ package org.utplsql.cli.datasource; import com.zaxxer.hikari.HikariDataSource; +import org.utplsql.api.EnvironmentVariableUtil; import org.utplsql.cli.ConnectionConfig; import org.utplsql.cli.exception.DatabaseConnectionFailed; @@ -9,6 +10,8 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class TestedDataSourceProvider { @@ -32,12 +35,13 @@ public HikariDataSource getDataSource() throws SQLException { HikariDataSource ds = new HikariDataSource(); + setInitSql(ds); testAndSetJdbcUrl(ds); return ds; } - public void testAndSetJdbcUrl( HikariDataSource ds ) throws SQLException + private void testAndSetJdbcUrl( HikariDataSource ds ) throws SQLException { List errors = new ArrayList<>(); Throwable lastException = null; @@ -55,6 +59,33 @@ public void testAndSetJdbcUrl( HikariDataSource ds ) throws SQLException throw new DatabaseConnectionFailed(lastException); } + private void setInitSql( HikariDataSource ds ) { + String nls_lang = EnvironmentVariableUtil.getEnvValue("NLS_LANG"); + + if ( nls_lang != null ) { + Pattern pattern = Pattern.compile("^([a-zA-Z ]+)?_?([a-zA-Z ]+)?\\.?([a-zA-Z0-9]+)?$"); + Matcher matcher = pattern.matcher(nls_lang); + + List sqlCommands = new ArrayList<>(2); + if (matcher.matches()) { + if ( matcher.group(1) != null) + sqlCommands.add(String.format("ALTER SESSION SET NLS_LANGUAGE='%s'", matcher.group(1))); + if ( matcher.group(2) != null) + sqlCommands.add(String.format("ALTER SESSION SET NLS_TERRITORY='%s'", matcher.group(2))); + + if ( sqlCommands.size() > 0 ) { + StringBuilder sb = new StringBuilder(); + sb.append("BEGIN\n"); + for (String command : sqlCommands) + sb.append(String.format("EXECUTE IMMEDIATE q'[%s]';\n", command)); + sb.append("END;"); + + ds.setConnectionInitSql(sb.toString()); + } + } + } + } + private static class ThickConnectStringPossibility implements ConnectStringPossibility { @Override public String getConnectString(ConnectionConfig config) { diff --git a/src/test/java/org/utplsql/cli/DataSourceProviderIT.java b/src/test/java/org/utplsql/cli/DataSourceProviderIT.java index ab8b732..2aab023 100644 --- a/src/test/java/org/utplsql/cli/DataSourceProviderIT.java +++ b/src/test/java/org/utplsql/cli/DataSourceProviderIT.java @@ -12,55 +12,67 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; -public class DataSourceProviderIT { +class DataSourceProviderIT { @Test - public void connectToDatabase() throws IOException, SQLException { - - ConnectionConfig config = new ConnectionConfig(TestHelper.getConnectionString()); - - DataSource dataSource = new TestedDataSourceProvider(config).getDataSource(); + void connectToDatabase() throws SQLException { + DataSource dataSource = getDataSource(); assertNotNull(dataSource); } @Test - public void initNlsLang() throws SQLException { - ConnectionConfig config = new ConnectionConfig(TestHelper.getConnectionString()); + void initNlsLang() throws SQLException { System.setProperty("NLS_LANG", "BRAZILIAN PORTUGUESE_BRAZIL.WE8ISO8859P1"); + DataSource dataSource = getDataSource(); + assertNotNull(dataSource); + checkNlsSessionParameter(dataSource, "NLS_LANGUAGE", "BRAZILIAN PORTUGUESE"); + checkNlsSessionParameter(dataSource, "NLS_TERRITORY", "BRAZIL"); + } - DataSource dataSource = new TestedDataSourceProvider(config).getDataSource(); + @Test + void initPartialNlsLangTerritory() throws SQLException { + System.setProperty("NLS_LANG", "_SOMALIA"); + DataSource dataSource = getDataSource(); assertNotNull(dataSource); - - try ( Connection con = dataSource.getConnection() ) { - try (PreparedStatement stmt = con.prepareStatement("select value from nls_session_parameters where parameter = 'NLS_LANGUAGE'")) { - ResultSet rs = stmt.executeQuery(); - if ( rs.next() ) { - assertEquals("BRAZILIAN PORTUGUESE", rs.getString(1)); - } - } - } + checkNlsSessionParameter(dataSource, "NLS_TERRITORY", "SOMALIA"); } @Test - public void initPartialNlsLang() throws SQLException { - ConnectionConfig config = new ConnectionConfig(TestHelper.getConnectionString()); - System.setProperty("NLS_LANG", "_SOMALIA"); + void initPartialNlsLangLanguage() throws SQLException { + System.setProperty("NLS_LANG", "HINDI"); + DataSource dataSource = getDataSource(); + assertNotNull(dataSource); + checkNlsSessionParameter(dataSource, "NLS_LANGUAGE", "HINDI"); + } - DataSource dataSource = new TestedDataSourceProvider(config).getDataSource(); + @Test + void initNlsLangEmpty() throws SQLException { + System.setProperty("NLS_LANG", ""); + DataSource dataSource = getDataSource(); assertNotNull(dataSource); + } + + private DataSource getDataSource() throws SQLException { + ConnectionConfig config = new ConnectionConfig(TestHelper.getConnectionString()); + return new TestedDataSourceProvider(config).getDataSource(); + } + private void checkNlsSessionParameter( DataSource dataSource, String parameterName, String expectedValue ) throws SQLException { try ( Connection con = dataSource.getConnection() ) { - try (PreparedStatement stmt = con.prepareStatement("select value from nls_session_parameters where parameter = 'NLS_TERRITORY'")) { + try (PreparedStatement stmt = con.prepareStatement("select value from nls_session_parameters where parameter = ?")) { + stmt.setString(1, parameterName); ResultSet rs = stmt.executeQuery(); - if ( rs.next() ) { - assertEquals("SOMALIA", rs.getString(1)); - } + if ( rs.next() ) + assertEquals(expectedValue, rs.getString(1)); + else + fail("Could not get NLS Session parameter value for '" + parameterName + "'"); } } } From 6bb8b9e6cce3cd21fb717ab5914199b2d350b201 Mon Sep 17 00:00:00 2001 From: pesse Date: Thu, 11 Oct 2018 09:25:58 +0200 Subject: [PATCH 3/3] Improve naming --- .../cli/datasource/TestedDataSourceProvider.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java b/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java index f666f82..f30cd91 100644 --- a/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java +++ b/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java @@ -5,7 +5,6 @@ import org.utplsql.cli.ConnectionConfig; import org.utplsql.cli.exception.DatabaseConnectionFailed; -import java.io.File; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; @@ -20,7 +19,6 @@ interface ConnectStringPossibility { String getMaskedConnectString(ConnectionConfig config); } - private final ConnectionConfig config; private List possibilities = new ArrayList<>(); @@ -35,13 +33,13 @@ public HikariDataSource getDataSource() throws SQLException { HikariDataSource ds = new HikariDataSource(); - setInitSql(ds); - testAndSetJdbcUrl(ds); + setInitSqlFrom_NLS_LANG(ds); + setThickOrThinJdbcUrl(ds); return ds; } - private void testAndSetJdbcUrl( HikariDataSource ds ) throws SQLException + private void setThickOrThinJdbcUrl(HikariDataSource ds ) throws SQLException { List errors = new ArrayList<>(); Throwable lastException = null; @@ -59,7 +57,7 @@ private void testAndSetJdbcUrl( HikariDataSource ds ) throws SQLException throw new DatabaseConnectionFailed(lastException); } - private void setInitSql( HikariDataSource ds ) { + private void setInitSqlFrom_NLS_LANG(HikariDataSource ds ) { String nls_lang = EnvironmentVariableUtil.getEnvValue("NLS_LANG"); if ( nls_lang != null ) {