Skip to content

Bugfix: NLS_LANG handling #106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions src/main/java/org/utplsql/cli/LocaleInitializer.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package org.utplsql.cli;

import org.utplsql.api.EnvironmentVariableUtil;

import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** 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
*/
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
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;

import java.io.File;
import java.sql.Connection;
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 {

Expand All @@ -17,7 +19,6 @@ interface ConnectStringPossibility {
String getMaskedConnectString(ConnectionConfig config);
}


private final ConnectionConfig config;
private List<ConnectStringPossibility> possibilities = new ArrayList<>();

Expand All @@ -32,12 +33,13 @@ public HikariDataSource getDataSource() throws SQLException {

HikariDataSource ds = new HikariDataSource();

testAndSetJdbcUrl(ds);
setInitSqlFrom_NLS_LANG(ds);
setThickOrThinJdbcUrl(ds);

return ds;
}

public void testAndSetJdbcUrl( HikariDataSource ds ) throws SQLException
private void setThickOrThinJdbcUrl(HikariDataSource ds ) throws SQLException
{
List<String> errors = new ArrayList<>();
Throwable lastException = null;
Expand All @@ -55,6 +57,33 @@ public void testAndSetJdbcUrl( HikariDataSource ds ) throws SQLException
throw new DatabaseConnectionFailed(lastException);
}

private void setInitSqlFrom_NLS_LANG(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<String> 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) {
Expand Down
64 changes: 60 additions & 4 deletions src/test/java/org/utplsql/cli/DataSourceProviderIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,75 @@

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;
import static org.junit.jupiter.api.Assertions.fail;

public class DataSourceProviderIT {
class DataSourceProviderIT {

@Test
public void connectToDatabase() throws IOException, SQLException {
void connectToDatabase() throws SQLException {
DataSource dataSource = getDataSource();

ConnectionConfig config = new ConnectionConfig(TestHelper.getConnectionString());
assertNotNull(dataSource);
}

@Test
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");
}

@Test
void initPartialNlsLangTerritory() throws SQLException {
System.setProperty("NLS_LANG", "_SOMALIA");
DataSource dataSource = getDataSource();

assertNotNull(dataSource);
checkNlsSessionParameter(dataSource, "NLS_TERRITORY", "SOMALIA");
}

@Test
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 = ?")) {
stmt.setString(1, parameterName);
ResultSet rs = stmt.executeQuery();
if ( rs.next() )
assertEquals(expectedValue, rs.getString(1));
else
fail("Could not get NLS Session parameter value for '" + parameterName + "'");
}
}
}
}