Skip to content

Commit 5c51af5

Browse files
authored
Fix connection pass through preventing functions from working (#112)
* Fix connection pass through preventing functions from working * Add comment
1 parent 9b89fbb commit 5c51af5

File tree

13 files changed

+255
-32
lines changed

13 files changed

+255
-32
lines changed

Diff for: deploy/samples/demodb.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ metadata:
44
name: ads-database
55
spec:
66
schema: ADS
7-
url: jdbc:demodb://ads
7+
url: jdbc:demodb://names=ads
88
dialect: Calcite
99

1010
---
@@ -15,7 +15,7 @@ metadata:
1515
name: profile-database
1616
spec:
1717
schema: PROFILE
18-
url: jdbc:demodb://profile
18+
url: jdbc:demodb://names=profile
1919
dialect: Calcite
2020

2121
---

Diff for: hoptimator

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ $BASEDIR/hoptimator-cli/build/install/hoptimator-cli/bin/hoptimator-cli \
77
-Dorg.slf4j.simpleLogger.showLogName=false \
88
sqlline.SqlLine \
99
-ac sqlline.HoptimatorAppConfig \
10-
-u jdbc:hoptimator:// -n "" -p "" -nn "Hoptimator" $@
10+
-u jdbc:hoptimator://fun=mysql -n "" -p "" -nn "Hoptimator" $@
1111

Diff for: hoptimator-demodb/src/main/java/com/linkedin/hoptimator/demodb/DemoDriver.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.Set;
1010
import java.util.stream.Collectors;
1111

12+
import org.apache.calcite.avatica.ConnectStringParser;
1213
import org.apache.calcite.avatica.DriverVersion;
1314
import org.apache.calcite.jdbc.CalciteConnection;
1415
import org.apache.calcite.jdbc.Driver;
@@ -37,15 +38,18 @@ public Connection connect(String url, Properties props) throws SQLException {
3738
if (!url.startsWith(getConnectStringPrefix())) {
3839
return null;
3940
}
40-
String params = url.substring(getConnectStringPrefix().length());
41-
Set<String> schemas = Arrays.asList(params.split(","))
41+
Properties properties = new Properties();
42+
properties.putAll(props);
43+
properties.putAll(ConnectStringParser.parse(url.substring(getConnectStringPrefix().length())));
44+
45+
Set<String> schemas = Arrays.asList(properties.getProperty("names").split(","))
4246
.stream()
4347
.map(x -> x.trim())
4448
.filter(x -> !x.isEmpty())
4549
.map(x -> x.toUpperCase(Locale.ROOT))
4650
.collect(Collectors.toSet());
4751
try {
48-
Connection connection = super.connect(url, props);
52+
Connection connection = super.connect(url, properties);
4953
if (connection == null) {
5054
throw new IOException("Could not connect to " + url);
5155
}

Diff for: hoptimator-jdbc/src/main/java/com/linkedin/hoptimator/jdbc/HoptimatorDdlExecutor.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import org.apache.calcite.schema.Table;
3939
import org.apache.calcite.schema.TranslatableTable;
4040
import org.apache.calcite.schema.impl.ViewTable;
41-
import org.apache.calcite.schema.impl.ViewTableMacro;
4241
import org.apache.calcite.server.DdlExecutor;
4342
import org.apache.calcite.server.ServerDdlExecutor;
4443
import org.apache.calcite.sql.SqlCall;
@@ -65,6 +64,7 @@
6564
import com.linkedin.hoptimator.Database;
6665
import com.linkedin.hoptimator.MaterializedView;
6766
import com.linkedin.hoptimator.Pipeline;
67+
import com.linkedin.hoptimator.jdbc.schema.HoptimatorViewTableMacro;
6868
import com.linkedin.hoptimator.util.DeploymentService;
6969
import com.linkedin.hoptimator.util.planner.PipelineRel;
7070

@@ -117,8 +117,9 @@ public void execute(SqlCreateView create, CalcitePrepare.Context context) {
117117
List<String> viewPath = new ArrayList<>();
118118
viewPath.addAll(schemaPath);
119119
viewPath.add(viewName);
120-
ViewTableMacro viewTableMacro = ViewTable.viewMacro(schemaPlus, sql, schemaPath, viewPath, false);
121-
ViewTable viewTable = (ViewTable) viewTableMacro.apply(Collections.emptyList());
120+
HoptimatorViewTableMacro viewTableMacro = new HoptimatorViewTableMacro(CalciteSchema.from(schemaPlus),
121+
sql, schemaPath, viewPath, false);
122+
ViewTable viewTable = (ViewTable) viewTableMacro.apply(connectionProperties);
122123
try {
123124
ValidationService.validateOrThrow(viewTable, TranslatableTable.class);
124125
if (create.getReplace()) {
@@ -174,8 +175,9 @@ public void execute(SqlCreateMaterializedView create, CalcitePrepare.Context con
174175

175176
// Table does not exist. Create it.
176177
RelDataTypeFactory typeFactory = new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
177-
ViewTableMacro viewTableMacro = ViewTable.viewMacro(schemaPlus, sql, schemaPath, viewPath, false);
178-
MaterializedViewTable materializedViewTable = new MaterializedViewTable(viewTableMacro);
178+
HoptimatorViewTableMacro viewTableMacro = new HoptimatorViewTableMacro(CalciteSchema.from(schemaPlus),
179+
sql, schemaPath, viewPath, false);
180+
MaterializedViewTable materializedViewTable = new MaterializedViewTable(viewTableMacro, connectionProperties);
179181
RelDataType viewRowType = materializedViewTable.getRowType(typeFactory);
180182

181183
// Support "partial views", i.e. CREATE VIEW FOO$BAR, where the view name

Diff for: hoptimator-jdbc/src/main/java/com/linkedin/hoptimator/jdbc/MaterializedViewTable.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.linkedin.hoptimator.jdbc;
22

3-
import java.util.Collections;
43
import java.util.List;
4+
import java.util.Properties;
55

66
import org.apache.calcite.plan.RelOptTable;
77
import org.apache.calcite.rel.RelNode;
@@ -11,7 +11,8 @@
1111
import org.apache.calcite.schema.TranslatableTable;
1212
import org.apache.calcite.schema.impl.AbstractTable;
1313
import org.apache.calcite.schema.impl.ViewTable;
14-
import org.apache.calcite.schema.impl.ViewTableMacro;
14+
15+
import com.linkedin.hoptimator.jdbc.schema.HoptimatorViewTableMacro;
1516

1617

1718
public class MaterializedViewTable extends AbstractTable implements TranslatableTable {
@@ -22,8 +23,8 @@ public MaterializedViewTable(ViewTable viewTable) {
2223
this.viewTable = viewTable;
2324
}
2425

25-
public MaterializedViewTable(ViewTableMacro viewTableMacro) {
26-
this((ViewTable) viewTableMacro.apply(Collections.emptyList()));
26+
public MaterializedViewTable(HoptimatorViewTableMacro viewTableMacro, Properties connectionProperties) {
27+
this((ViewTable) viewTableMacro.apply(connectionProperties));
2728
}
2829

2930
public ViewTable viewTable() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.linkedin.hoptimator.jdbc.schema;
2+
3+
import java.sql.DriverManager;
4+
import java.sql.SQLException;
5+
import java.util.List;
6+
import java.util.Properties;
7+
8+
import org.apache.calcite.jdbc.CalciteConnection;
9+
import org.apache.calcite.jdbc.CalcitePrepare;
10+
import org.apache.calcite.jdbc.CalciteSchema;
11+
import org.apache.calcite.schema.Schemas;
12+
import org.apache.calcite.schema.TranslatableTable;
13+
import org.apache.calcite.schema.impl.ViewTableMacro;
14+
import org.checkerframework.checker.nullness.qual.Nullable;
15+
16+
/**
17+
* This file is copy-pasted from {@link ViewTableMacro} with the only modification being
18+
* how the connection is instantiated.
19+
*/
20+
public class HoptimatorViewTableMacro extends ViewTableMacro {
21+
22+
private final Boolean modifiable;
23+
public HoptimatorViewTableMacro(CalciteSchema schema, String viewSql,
24+
@Nullable List<String> schemaPath, @Nullable List<String> viewPath,
25+
@Nullable Boolean modifiable) {
26+
super(schema, viewSql, schemaPath, viewPath, modifiable);
27+
this.modifiable = modifiable;
28+
}
29+
30+
public TranslatableTable apply(Properties properties) {
31+
CalciteConnection connection;
32+
try {
33+
connection = DriverManager.getConnection("jdbc:calcite:", properties)
34+
.unwrap(CalciteConnection.class);
35+
} catch (SQLException e) {
36+
throw new RuntimeException(e);
37+
}
38+
CalcitePrepare.AnalyzeViewResult parsed =
39+
Schemas.analyzeView(connection, schema, schemaPath, viewSql, viewPath,
40+
modifiable != null && modifiable);
41+
final List<String> schemaPath1 =
42+
schemaPath != null ? schemaPath : schema.path(null);
43+
if ((modifiable == null || modifiable)
44+
&& parsed.modifiable
45+
&& parsed.table != null) {
46+
return modifiableViewTable(parsed, viewSql, schemaPath1, viewPath, schema);
47+
} else {
48+
return viewTable(parsed, viewSql, schemaPath1, viewPath);
49+
}
50+
}
51+
}

Diff for: hoptimator-jdbc/src/testFixtures/java/com/linkedin/hoptimator/jdbc/QuidemTestBase.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,21 @@
3232
public abstract class QuidemTestBase {
3333

3434
protected void run(String resourceName) throws IOException, URISyntaxException {
35-
run(Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResource(resourceName)).toURI());
35+
run(Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResource(resourceName)).toURI(), "");
3636
}
3737

38-
protected void run(URI resource) throws IOException {
38+
protected void run(String resourceName, String jdbcProperties) throws IOException, URISyntaxException {
39+
run(Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResource(resourceName)).toURI(), jdbcProperties);
40+
}
41+
42+
protected void run(URI resource, String jdbcProperties) throws IOException {
3943
File in = new File(resource);
4044
File out = File.createTempFile(in.getName(), ".out");
4145
try (Reader r = new FileReader(in); Writer w = new PrintWriter(out)) {
4246
Quidem.Config config = Quidem.configBuilder()
4347
.withReader(r)
4448
.withWriter(w)
45-
.withConnectionFactory((x, y) -> DriverManager.getConnection("jdbc:hoptimator://catalogs=" + x))
49+
.withConnectionFactory((x, y) -> DriverManager.getConnection("jdbc:hoptimator://catalogs=" + x + jdbcProperties))
4650
.withCommandHandler(new CustomCommandHandler())
4751
.build();
4852
new Quidem(config).execute();

Diff for: hoptimator-k8s/src/main/java/com/linkedin/hoptimator/k8s/K8sCatalog.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ public void register(Wrapper parentSchema, Properties connectionProperties) thro
3434
K8sMetadata metadata = new K8sMetadata(context);
3535
schemaPlus.add("k8s", metadata);
3636
metadata.databaseTable().addDatabases(schemaPlus, connectionProperties);
37-
metadata.viewTable().addViews(schemaPlus);
37+
metadata.viewTable().addViews(schemaPlus, connectionProperties);
3838
}
3939
}

Diff for: hoptimator-k8s/src/main/java/com/linkedin/hoptimator/k8s/K8sDatabaseTable.java

+24-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.Locale;
44
import java.util.Optional;
55
import java.util.Properties;
6+
import java.util.StringJoiner;
67
import javax.sql.DataSource;
78

89
import org.apache.calcite.adapter.jdbc.JdbcSchema;
@@ -51,7 +52,7 @@ public K8sDatabaseTable(K8sContext context, K8sEngineTable engines) {
5152
public void addDatabases(SchemaPlus parentSchema, Properties connectionProperties) {
5253
for (Row row : rows()) {
5354
parentSchema.add(schemaName(row),
54-
HoptimatorJdbcSchema.create(row.NAME, row.SCHEMA, dataSource(row), parentSchema, dialect(row), engines.forDatabase(row.NAME), connectionProperties));
55+
HoptimatorJdbcSchema.create(row.NAME, row.SCHEMA, dataSource(row, connectionProperties), parentSchema, dialect(row), engines.forDatabase(row.NAME), connectionProperties));
5556
}
5657
}
5758

@@ -82,9 +83,28 @@ private static String schemaName(Row row) {
8283
}
8384
}
8485

85-
private static DataSource dataSource(Row row) {
86-
// TODO fetch username/password from Secret
87-
return JdbcSchema.dataSource(row.URL, row.DRIVER, "nouser", "nopass");
86+
private static DataSource dataSource(Row row, Properties connectionProperties) {
87+
String user = "nouser";
88+
String pass = "nopass";
89+
StringJoiner joiner = new StringJoiner(";");
90+
for (String key : connectionProperties.stringPropertyNames()) {
91+
if ("user".equals(key)) {
92+
user = connectionProperties.getProperty(key);
93+
} else if ("password".equals(key)) {
94+
pass = connectionProperties.getProperty(key);
95+
} else {
96+
String value = connectionProperties.getProperty(key);
97+
joiner.add(key + "=" + value);
98+
}
99+
}
100+
String joinedUrl = row.URL;
101+
// Handles case where there are no properties already in the URL
102+
if (row.URL.endsWith("//")) {
103+
joinedUrl = joinedUrl + joiner;
104+
} else {
105+
joinedUrl = joinedUrl + ";" + joiner;
106+
}
107+
return JdbcSchema.dataSource(joinedUrl, row.DRIVER, user, pass);
88108
}
89109

90110
private static SqlDialect dialect(Row row) {

Diff for: hoptimator-k8s/src/main/java/com/linkedin/hoptimator/k8s/K8sViewTable.java

+10-8
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,20 @@
33
import java.util.ArrayList;
44
import java.util.Collections;
55
import java.util.List;
6+
import java.util.Properties;
67

8+
import org.apache.calcite.jdbc.CalciteSchema;
79
import org.apache.calcite.schema.Schema;
810
import org.apache.calcite.schema.SchemaPlus;
911
import org.apache.calcite.schema.Table;
1012
import org.apache.calcite.schema.impl.AbstractSchema;
11-
import org.apache.calcite.schema.impl.ViewTable;
12-
import org.apache.calcite.schema.impl.ViewTableMacro;
1313

1414
import io.kubernetes.client.openapi.models.V1ObjectMeta;
1515

1616
import com.linkedin.hoptimator.Validated;
1717
import com.linkedin.hoptimator.Validator;
1818
import com.linkedin.hoptimator.jdbc.MaterializedViewTable;
19+
import com.linkedin.hoptimator.jdbc.schema.HoptimatorViewTableMacro;
1920
import com.linkedin.hoptimator.k8s.models.V1alpha1View;
2021
import com.linkedin.hoptimator.k8s.models.V1alpha1ViewList;
2122
import com.linkedin.hoptimator.k8s.models.V1alpha1ViewSpec;
@@ -75,7 +76,7 @@ public K8sViewTable(K8sContext context) {
7576
super(context, K8sApiEndpoints.VIEWS, Row.class);
7677
}
7778

78-
public void addViews(SchemaPlus parentSchema) {
79+
public void addViews(SchemaPlus parentSchema, Properties connectionProperties) {
7980
for (Row row : rows()) {
8081

8182
// build schema path, filling in any missing schemas
@@ -88,7 +89,7 @@ public void addViews(SchemaPlus parentSchema) {
8889
}
8990
schema = next;
9091
}
91-
schema.add(row.viewName(), makeView(schema, row));
92+
schema.add(row.viewName(), makeView(schema, row, connectionProperties));
9293
}
9394
}
9495

@@ -107,12 +108,13 @@ public void remove(String name) {
107108
rows().remove(find(name));
108109
}
109110

110-
private Table makeView(SchemaPlus parentSchema, Row row) {
111-
ViewTableMacro viewTableMacro = ViewTable.viewMacro(parentSchema, row.SQL, row.schemaPath(), row.viewPath(), false);
111+
private Table makeView(SchemaPlus parentSchema, Row row, Properties connectionProperties) {
112+
HoptimatorViewTableMacro viewTableMacro = new HoptimatorViewTableMacro(CalciteSchema.from(parentSchema), row.SQL,
113+
row.schemaPath(), row.viewPath(), false);
112114
if (row.MATERIALIZED) {
113-
return new MaterializedViewTable(viewTableMacro);
115+
return new MaterializedViewTable(viewTableMacro, connectionProperties);
114116
} else {
115-
return viewTableMacro.apply(Collections.emptyList());
117+
return viewTableMacro.apply(connectionProperties);
116118
}
117119
}
118120

Diff for: hoptimator-k8s/src/test/java/com/linkedin/hoptimator/k8s/TestSqlScripts.java

+6
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,10 @@ public class TestSqlScripts extends QuidemTestBase {
1313
public void k8sDdlScript() throws Exception {
1414
run("k8s-ddl.id");
1515
}
16+
17+
@Test
18+
@Tag("integration")
19+
public void k8sDdlScriptFunction() throws Exception {
20+
run("k8s-ddl-function.id", ";fun=mysql");
21+
}
1622
}

0 commit comments

Comments
 (0)