Skip to content

Commit 6fd7730

Browse files
authored
Use query builder for Teradata dbcinfo query (#314)
1 parent f6a9a90 commit 6fd7730

File tree

15 files changed

+692
-7
lines changed

15 files changed

+692
-7
lines changed

dumper/app/src/main/java/com/google/edwmigration/dumper/application/dumper/connector/teradata/TeradataLogsConnector.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public class TeradataLogsConnector extends AbstractTeradataConnector
6565

6666
private static final Logger LOG = LoggerFactory.getLogger(TeradataLogsConnector.class);
6767
private static final String ASSESSMENT_DEF_LOG_TABLE = "dbc.QryLogV";
68+
69+
/** The length of the VARCHAR column {@code DBQLSqlTbl.SQLTextInfo}. */
6870
static final int DBQLSQLTBL_SQLTEXTINFO_LENGTH = 31000;
6971

7072
private static final Range<Long> MAX_SQL_LENGTH_RANGE =
@@ -93,7 +95,9 @@ public enum TeradataLogsConnectorProperty implements ConnectorProperty {
9395
"max-sql-length",
9496
"Max length of the DBQLSqlTbl.SqlTextInfo column."
9597
+ " Text that is longer than the defined limit will be split into multiple rows."
96-
+ " Example: 10000. Allowed range: 5000-30000.",
98+
+ " Example: 10000. Allowed range: "
99+
+ MAX_SQL_LENGTH_RANGE
100+
+ ".",
97101
/* defaultValue= */ null);
98102

99103
private final String name;

dumper/app/src/main/java/com/google/edwmigration/dumper/application/dumper/connector/teradata/TeradataMetadataConnector.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818

1919
import static com.google.edwmigration.dumper.application.dumper.connector.teradata.TeradataUtils.formatQuery;
2020
import static com.google.edwmigration.dumper.application.dumper.connector.teradata.TeradataUtils.optionalIf;
21+
import static com.google.edwmigration.dumper.application.dumper.connector.teradata.query.TeradataSelectBuilder.eq;
22+
import static com.google.edwmigration.dumper.application.dumper.connector.teradata.query.TeradataSelectBuilder.identifier;
23+
import static com.google.edwmigration.dumper.application.dumper.connector.teradata.query.TeradataSelectBuilder.stringLiteral;
24+
import static com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.SelectExpression.select;
2125
import static java.util.stream.Collectors.joining;
2226
import static java.util.stream.Collectors.toList;
2327

@@ -53,8 +57,11 @@
5357
public class TeradataMetadataConnector extends AbstractTeradataConnector
5458
implements MetadataConnector, TeradataMetadataDumpFormat {
5559

60+
/** The length of the VARCHAR column {@code TableTextV.RequestText}. */
5661
private static final int TABLE_TEXT_V_REQUEST_TEXT_LENGTH = 32000;
57-
private static final Range<Long> MAX_TEXT_LENGTH_RANGE = Range.closed(5000L, 32000L);
62+
63+
private static final Range<Long> MAX_TEXT_LENGTH_RANGE =
64+
Range.closed(5000L, (long) TABLE_TEXT_V_REQUEST_TEXT_LENGTH);
5865

5966
public enum TeradataMetadataConnectorProperties implements ConnectorProperty {
6067
TABLE_SIZE_V_MAX_ROWS(
@@ -136,10 +143,13 @@ public void addTasksTo(List<? super Task<?>> out, ConnectorArguments arguments)
136143
new TeradataJdbcSelectTask(
137144
VersionFormat.ZIP_ENTRY_NAME,
138145
TaskCategory.OPTIONAL,
139-
"SELECT 'teradata' AS dialect, "
140-
+ "\"InfoData\" AS version, "
141-
+ "CURRENT_TIMESTAMP as export_time"
142-
+ " from dbc.dbcinfo where \"InfoKey\" = 'VERSION';"));
146+
select(
147+
stringLiteral("teradata").as("dialect"),
148+
identifier("InfoData").as("version"),
149+
identifier("CURRENT_TIMESTAMP").as("export_time"))
150+
.from("dbc.dbcinfo")
151+
.where(eq(identifier("InfoKey"), stringLiteral("VERSION")))
152+
.serialize()));
143153

144154
// This is theoretically more reliable than ColumnsV, but if we are bandwidth limited, we should
145155
// risk taking ColumnsV only.

dumper/app/src/main/java/com/google/edwmigration/dumper/application/dumper/connector/teradata/TeradataUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public static <T> Optional<T> optionalIf(boolean condition, Supplier<T> supplier
4242
* query contains string literals with whitespace, they will be modified, which might be
4343
* undesirable. This method should not be used in such cases.
4444
*/
45-
static String formatQuery(String query) {
45+
public static String formatQuery(String query) {
4646
return query.replaceAll("\\s+", " ").replaceAll("\\( ", "(").replaceAll(" \\)", ")").trim();
4747
}
4848

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Copyright 2022-2023 Google LLC
3+
* Copyright 2013-2021 CompilerWorks
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.google.edwmigration.dumper.application.dumper.connector.teradata.query;
18+
19+
import com.google.common.collect.ImmutableList;
20+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.BinaryExpression;
21+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.Expression;
22+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.Identifier;
23+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.Projection;
24+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.SelectExpression;
25+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.SourceSpec;
26+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.StringLiteral;
27+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.TableSourceSpec;
28+
import java.util.Optional;
29+
import java.util.function.Consumer;
30+
31+
public class ExpressionSerializer {
32+
33+
private final Expression expression;
34+
private StringBuilder serializedQuery = new StringBuilder();
35+
36+
ExpressionSerializer(Expression expression) {
37+
this.expression = expression;
38+
}
39+
40+
public static String serialize(Expression expression) {
41+
return new ExpressionSerializer(expression).serialize();
42+
}
43+
44+
String serialize() {
45+
serializedQuery = new StringBuilder();
46+
append(expression);
47+
return serializedQuery.toString();
48+
}
49+
50+
private void append(Expression expr) {
51+
if (expr instanceof SelectExpression) {
52+
append((SelectExpression) expression);
53+
} else if (expr instanceof StringLiteral) {
54+
serializedQuery.append(escapeStringLiteral(((StringLiteral) expr).value()));
55+
} else if (expr instanceof Identifier) {
56+
serializedQuery.append(((Identifier) expr).name());
57+
} else if (expr instanceof BinaryExpression) {
58+
append(((BinaryExpression) expr));
59+
} else {
60+
throw new IllegalArgumentException(String.format("Unsupported expression type: '%s'.", expr));
61+
}
62+
}
63+
64+
private void append(BinaryExpression expr) {
65+
appendSpaceIfNecessary();
66+
append(expr.lhs());
67+
serializedQuery.append(' ');
68+
serializedQuery.append(expr.operator());
69+
serializedQuery.append(' ');
70+
append(expr.rhs());
71+
}
72+
73+
private void append(SelectExpression selectExpression) {
74+
serializedQuery.append("SELECT");
75+
appendCommaSeparated(selectExpression.projections(), this::append);
76+
selectExpression
77+
.sourceSpec()
78+
.ifPresent(
79+
sourceSpec -> {
80+
serializedQuery.append(" FROM");
81+
append(sourceSpec);
82+
});
83+
selectExpression
84+
.whereCondition()
85+
.ifPresent(
86+
condition -> {
87+
serializedQuery.append(" WHERE");
88+
append(condition);
89+
});
90+
}
91+
92+
private void append(SourceSpec sourceSpec) {
93+
if (sourceSpec instanceof TableSourceSpec) {
94+
append((TableSourceSpec) sourceSpec);
95+
} else {
96+
throw new IllegalStateException(String.format("Unsupported source spec='%s'.", sourceSpec));
97+
}
98+
}
99+
100+
private void append(TableSourceSpec tableSourceSpec) {
101+
serializedQuery.append(' ');
102+
append(tableSourceSpec.tableName());
103+
append(tableSourceSpec.alias());
104+
}
105+
106+
private void append(Projection projection) {
107+
append(projection.expression());
108+
append(projection.alias());
109+
}
110+
111+
private void append(Optional<String> aliasMaybe) {
112+
aliasMaybe.ifPresent(alias -> serializedQuery.append(" AS ").append(alias));
113+
}
114+
115+
private void appendSpaceIfNecessary() {
116+
if (serializedQuery.length() > 0) {
117+
serializedQuery.append(' ');
118+
}
119+
}
120+
121+
private <T> void appendCommaSeparated(ImmutableList<T> list, Consumer<T> appender) {
122+
boolean first = true;
123+
for (T element : list) {
124+
if (first) {
125+
first = false;
126+
} else {
127+
serializedQuery.append(',');
128+
}
129+
serializedQuery.append(' ');
130+
appender.accept(element);
131+
}
132+
}
133+
134+
private static String escapeStringLiteral(String s) {
135+
return "'" + (s.replaceAll("'", "''")) + "'";
136+
}
137+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2022-2023 Google LLC
3+
* Copyright 2013-2021 CompilerWorks
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.google.edwmigration.dumper.application.dumper.connector.teradata.query;
18+
19+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.BinaryExpression;
20+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.Expression;
21+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.Identifier;
22+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.Projection;
23+
import com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model.StringLiteral;
24+
import java.util.Optional;
25+
26+
public class TeradataSelectBuilder {
27+
28+
public static Identifier identifier(String name) {
29+
return Identifier.create(name);
30+
}
31+
32+
public static Projection projection(Expression expression) {
33+
return Projection.create(expression, /* alias= */ Optional.empty());
34+
}
35+
36+
public static Projection projection(Expression expression, String alias) {
37+
return Projection.create(expression, Optional.of(alias));
38+
}
39+
40+
public static Expression eq(Expression lhs, Expression rhs) {
41+
return BinaryExpression.create(lhs, "=", rhs);
42+
}
43+
44+
public static StringLiteral stringLiteral(String value) {
45+
return StringLiteral.create(value);
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2022-2023 Google LLC
3+
* Copyright 2013-2021 CompilerWorks
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model;
18+
19+
import com.google.auto.value.AutoValue;
20+
21+
@AutoValue
22+
public abstract class BinaryExpression implements Expression {
23+
public abstract Expression lhs();
24+
25+
public abstract String operator();
26+
27+
public abstract Expression rhs();
28+
29+
public static BinaryExpression create(Expression lhs, String operator, Expression rhs) {
30+
return new AutoValue_BinaryExpression(lhs, operator, rhs);
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2022-2023 Google LLC
3+
* Copyright 2013-2021 CompilerWorks
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model;
18+
19+
import static com.google.edwmigration.dumper.application.dumper.connector.teradata.query.TeradataSelectBuilder.projection;
20+
21+
public interface Expression {
22+
default Projection as(String alias) {
23+
return projection(this, alias);
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2022-2023 Google LLC
3+
* Copyright 2013-2021 CompilerWorks
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model;
18+
19+
import com.google.auto.value.AutoValue;
20+
21+
@AutoValue
22+
public abstract class Identifier implements Expression {
23+
public abstract String name();
24+
25+
public static Identifier create(String name) {
26+
return new AutoValue_Identifier(name);
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2022-2023 Google LLC
3+
* Copyright 2013-2021 CompilerWorks
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.google.edwmigration.dumper.application.dumper.connector.teradata.query.model;
18+
19+
import com.google.auto.value.AutoValue;
20+
import java.util.Optional;
21+
22+
@AutoValue
23+
public abstract class Projection {
24+
public abstract Expression expression();
25+
26+
public abstract Optional<String> alias();
27+
28+
public static Projection create(Expression expression, Optional<String> alias) {
29+
return new AutoValue_Projection(expression, alias);
30+
}
31+
}

0 commit comments

Comments
 (0)