mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-19 16:16:45 +00:00
@@ -552,6 +552,7 @@ public final class DbxJdbcPlugin {
|
||||
JdbcUrlCredentials urlCredentials = extractJdbcUrlCredentials(url);
|
||||
url = urlCredentials.url;
|
||||
Properties properties = new Properties();
|
||||
applyPhoenixUrlProperties(url, properties);
|
||||
String username = optionalText(connection, "username");
|
||||
String password = optionalText(connection, "password");
|
||||
if (username == null) {
|
||||
@@ -586,13 +587,47 @@ public final class DbxJdbcPlugin {
|
||||
}
|
||||
|
||||
private static boolean isPhoenixConnection(JsonNode connection, String url) {
|
||||
if (urlMatchesPrefix(url, "jdbc:phoenix:")) {
|
||||
if (isPhoenixUrl(url)) {
|
||||
return true;
|
||||
}
|
||||
String driverClass = optionalText(connection, "jdbc_driver_class");
|
||||
return driverClass != null && driverClass.equalsIgnoreCase("org.apache.phoenix.jdbc.PhoenixDriver");
|
||||
}
|
||||
|
||||
private static void applyPhoenixUrlProperties(String url, Properties properties) {
|
||||
if (!isPhoenixDirectUrl(url)) {
|
||||
return;
|
||||
}
|
||||
int propertiesStart = url.indexOf(';');
|
||||
if (propertiesStart < 0) {
|
||||
return;
|
||||
}
|
||||
// Phoenix builds its HBase client configuration from Driver.connect Properties,
|
||||
// while arbitrary semicolon URL attributes are not merged into QueryServices.
|
||||
for (String part : url.substring(propertiesStart + 1).split(";")) {
|
||||
int equals = part.indexOf('=');
|
||||
if (equals <= 0) {
|
||||
continue;
|
||||
}
|
||||
String key = part.substring(0, equals).trim();
|
||||
if (!key.isEmpty()) {
|
||||
properties.setProperty(key, part.substring(equals + 1).trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPhoenixDirectUrl(String url) {
|
||||
return isPhoenixUrl(url) && !urlMatchesPrefix(url, "jdbc:phoenix:thin:");
|
||||
}
|
||||
|
||||
private static boolean isPhoenixUrl(String url) {
|
||||
String prefix = "jdbc:phoenix";
|
||||
if (url == null || !url.regionMatches(true, 0, prefix, 0, prefix.length())) {
|
||||
return false;
|
||||
}
|
||||
return url.length() == prefix.length() || url.charAt(prefix.length()) == ':' || url.charAt(prefix.length()) == ';';
|
||||
}
|
||||
|
||||
private static void applyJdbcxExtensionSecurity(JsonNode connection, String url, Properties properties) {
|
||||
if (isJdbcxUrl(url) && !jdbcxHighPrivilegeExtensionsEnabled(connection)) {
|
||||
properties.setProperty(JDBCX_EXTENSION_WHITELIST_PROPERTY, JDBCX_SAFE_EXTENSION_WHITELIST);
|
||||
@@ -2923,7 +2958,11 @@ public final class DbxJdbcPlugin {
|
||||
}
|
||||
|
||||
private static String jdbcUrlParamSeparator(String base) {
|
||||
if (urlMatchesPrefix(base, "jdbc:sqlserver:") || urlMatchesPrefix(base, "jdbc:dremio:")) {
|
||||
if (
|
||||
urlMatchesPrefix(base, "jdbc:sqlserver:") ||
|
||||
urlMatchesPrefix(base, "jdbc:dremio:") ||
|
||||
isPhoenixUrl(base)
|
||||
) {
|
||||
return base.endsWith(";") ? "" : ";";
|
||||
}
|
||||
if (jdbcUrlUsesColonProperties(base)) {
|
||||
|
||||
@@ -953,6 +953,117 @@ final class DbxJdbcPluginTest {
|
||||
assertEquals(List.of("getAutoCommit", "setAutoCommit:true"), calls);
|
||||
}
|
||||
|
||||
@Test
|
||||
void phoenixDirectUrlPropertiesArePassedToTheDriver() throws Exception {
|
||||
RecordingConnectDriver driver = new RecordingConnectDriver("jdbc:phoenix:");
|
||||
DriverManager.registerDriver(driver);
|
||||
String connection = """
|
||||
{
|
||||
"connection_string": "jdbc:phoenix:ambari01,ambari02,ambari03:2181:/hbase-unsecure;phoenix.schema.isNamespaceMappingEnabled=true;phoenix.schema.mapSystemTablesToNamespace=true;user=url-user",
|
||||
"username": "phoenix-user",
|
||||
"connect_timeout_secs": 30
|
||||
}
|
||||
""";
|
||||
try {
|
||||
JsonNode response = request("testConnection", """
|
||||
{ "connection": %s }
|
||||
""".formatted(connection));
|
||||
|
||||
assertFalse(response.has("error"), response.toString());
|
||||
assertEquals(
|
||||
"jdbc:phoenix:ambari01,ambari02,ambari03:2181:/hbase-unsecure;phoenix.schema.isNamespaceMappingEnabled=true;phoenix.schema.mapSystemTablesToNamespace=true;user=url-user",
|
||||
driver.urls.get(0)
|
||||
);
|
||||
assertEquals("true", driver.properties.get(0).getProperty("phoenix.schema.isNamespaceMappingEnabled"));
|
||||
assertEquals("true", driver.properties.get(0).getProperty("phoenix.schema.mapSystemTablesToNamespace"));
|
||||
assertEquals("phoenix-user", driver.properties.get(0).getProperty("user"));
|
||||
} finally {
|
||||
closeAndDeregister(connection, driver);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void phoenixConnectionUrlParamsUseSemicolonAndReachDriverProperties() throws Exception {
|
||||
RecordingConnectDriver driver = new RecordingConnectDriver("jdbc:phoenix:");
|
||||
DriverManager.registerDriver(driver);
|
||||
String connection = """
|
||||
{
|
||||
"connection_string": "jdbc:phoenix:zk1,zk2:2181:/hbase-unsecure",
|
||||
"url_params": "phoenix.schema.isNamespaceMappingEnabled=true;phoenix.schema.mapSystemTablesToNamespace=true",
|
||||
"connect_timeout_secs": 30
|
||||
}
|
||||
""";
|
||||
try {
|
||||
JsonNode response = request("testConnection", """
|
||||
{ "connection": %s }
|
||||
""".formatted(connection));
|
||||
|
||||
assertFalse(response.has("error"), response.toString());
|
||||
assertEquals(
|
||||
"jdbc:phoenix:zk1,zk2:2181:/hbase-unsecure;phoenix.schema.isNamespaceMappingEnabled=true;phoenix.schema.mapSystemTablesToNamespace=true",
|
||||
driver.urls.get(0)
|
||||
);
|
||||
assertEquals("true", driver.properties.get(0).getProperty("phoenix.schema.isNamespaceMappingEnabled"));
|
||||
assertEquals("true", driver.properties.get(0).getProperty("phoenix.schema.mapSystemTablesToNamespace"));
|
||||
} finally {
|
||||
closeAndDeregister(connection, driver);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void phoenixUrlPropertyParsingIgnoresMalformedSegmentsAndPreservesEqualsInValue() throws Exception {
|
||||
Method method = DbxJdbcPlugin.class.getDeclaredMethod("applyPhoenixUrlProperties", String.class, Properties.class);
|
||||
method.setAccessible(true);
|
||||
Properties properties = new Properties();
|
||||
|
||||
method.invoke(
|
||||
null,
|
||||
"jdbc:phoenix;broken;=ignored;phoenix.query.custom=a=b",
|
||||
properties
|
||||
);
|
||||
|
||||
assertEquals("a=b", properties.getProperty("phoenix.query.custom"));
|
||||
assertFalse(properties.containsKey("broken"));
|
||||
assertFalse(properties.containsKey(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void phoenixThinUrlParamsUseSemicolonSyntax() throws Exception {
|
||||
JsonNode connection = MAPPER.readTree("""
|
||||
{
|
||||
"connection_string": "jdbc:phoenix:thin:url=http://127.0.0.1:8765;serialization=PROTOBUF",
|
||||
"url_params": "authentication=SPNEGO"
|
||||
}
|
||||
""");
|
||||
|
||||
assertEquals(
|
||||
"jdbc:phoenix:thin:url=http://127.0.0.1:8765;serialization=PROTOBUF;authentication=SPNEGO",
|
||||
DbxJdbcPlugin.jdbcUrl(connection)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonPhoenixSemicolonUrlPropertiesAreNotCopiedToDriverProperties() throws Exception {
|
||||
RecordingConnectDriver driver = new RecordingConnectDriver("jdbc:dbx-semicolon:");
|
||||
DriverManager.registerDriver(driver);
|
||||
String connection = """
|
||||
{
|
||||
"connection_string": "jdbc:dbx-semicolon:demo;custom.option=true",
|
||||
"connect_timeout_secs": 30
|
||||
}
|
||||
""";
|
||||
try {
|
||||
JsonNode response = request("testConnection", """
|
||||
{ "connection": %s }
|
||||
""".formatted(connection));
|
||||
|
||||
assertFalse(response.has("error"), response.toString());
|
||||
assertFalse(driver.properties.get(0).containsKey("custom.option"));
|
||||
} finally {
|
||||
closeAndDeregister(connection, driver);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void phoenixAutoCommitConfigurationSkipsNonPhoenixConnections() throws Exception {
|
||||
Method method = DbxJdbcPlugin.class.getDeclaredMethod(
|
||||
|
||||
Reference in New Issue
Block a user