Skip to content
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
2 changes: 2 additions & 0 deletions doc/changes/changes_18.0.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Code name: Improve code quality
* #308: Fixed `SqlLimit` so `limit` and `offset` stay non-negative for the full object lifetime by making the node immutable and aligning the validation message with the accepted zero values.
* #307: Fixed `PushdownSqlRenderer` so `HASHTYPE` data types include `bytesize` in rendered pushdown SQL JSON.
* #312: Fixed logging utility resource and handler lifecycle issues by closing version metadata streams, falling back when the thread context class loader is missing, defaulting absent version properties to `UNKNOWN`, closing replaced root log handlers, and resetting closed remote socket handlers before reuse.
* #318: Fixed several small naming, Javadoc, message, and parsing robustness issues, including locale-independent SQL parser uppercasing and trimmed telemetry property parsing.
* Fixed `ColumnMetadata.toString()` so `defaultValue` quotes stay balanced even when no comment is set.
* #314: Fixed `SqlFunctionAggregateListagg.Behavior` so LISTAGG overflow behavior is null-safe, value-based, and constructed immutably by the parser.

## Dependency Updates
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/exasol/adapter/AdapterContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class AdapterContext {
/**
* Create a new AdapterContext.
*
* @param telemetryClient telemetry client to be used by the adapter for reportin feature usage.
* @param telemetryClient telemetry client to be used by the adapter for reporting feature usage.
*/
public AdapterContext(final TelemetryClient telemetryClient) {
this.telemetryClient = telemetryClient;
Expand All @@ -26,7 +26,7 @@ public AdapterContext(final TelemetryClient telemetryClient) {
* <ul>
* <li>Class {@link AdapterCallExecutor} already reports the following events: {@code createVirtualSchema}, {@code dropVirtualSchema},
* {@code refreshVirtualSchema}, {@code setProperties}. The adapter must not report these events again</li>
* <li>Adapters must keep not report high frequency features, e.g. for every pushdown.</li>
* <li>Adapters must not report high frequency features, e.g. for every pushdown.</li>
* </ul>
*
* @return telemetry client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,10 @@ public String toString() {
if (this.hasDefault()) {
builder.append(", defaultValue=\"");
builder.append(this.defaultValue);
builder.append("\"");
}
if (this.hasComment()) {
builder.append("\", comment=\"");
builder.append(", comment=\"");
builder.append(this.comment);
builder.append("\"");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ private AdapterTelemetryConfiguration(final boolean telemetryDisabled) {
*/
public static AdapterTelemetryConfiguration parseFromProperties(final Map<String, String> properties) {
final String telemetryPropertyValue = properties.get(TELEMETRY_PROPERTY);
final boolean telemetryDisabled = telemetryPropertyValue != null && !Boolean.parseBoolean(telemetryPropertyValue);
final boolean telemetryDisabled = telemetryPropertyValue != null
&& !Boolean.parseBoolean(telemetryPropertyValue.trim());
return new AdapterTelemetryConfiguration(telemetryDisabled);
}

Expand Down
241 changes: 121 additions & 120 deletions src/main/java/com/exasol/adapter/request/parser/PushdownSqlParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ private SqlGroupBy parseGroupBy(
private boolean hasAggregateFunction(final List<SqlNode> nodesList) {
// Stack is less efficient than ArrayDeque, but ArrayDeque doesn't support null elements.
@java.lang.SuppressWarnings("java:S1149")
Stack<SqlNode> expressions = new Stack<>();
final Stack<SqlNode> expressions = new Stack<>();
expressions.addAll(nodesList);
while (!expressions.isEmpty()) {
final SqlNode expression = expressions.pop();
Expand Down Expand Up @@ -199,82 +199,82 @@ public SqlNode parseExpression(final JsonObject expression) {
final String typeName = expression.getString(TYPE, "");
final SqlNodeType type = fromTypeName(typeName);
switch (type) {
case SELECT:
return parseSelect(expression);
case TABLE:
return parseTable(expression);
case JOIN:
return parseJoin(expression);
case COLUMN:
return parseColumn(expression);
case LITERAL_NULL:
return parseLiteralNull();
case LITERAL_BOOL:
return parseLiteralBool(expression);
case LITERAL_DATE:
return parseLiteralDate(expression);
case LITERAL_TIMESTAMP:
return parseLiteralTimestamp(expression);
case LITERAL_TIMESTAMPUTC:
return parseLiteralTimestamputc(expression);
case LITERAL_DOUBLE:
return parseLiteralDouble(expression);
case LITERAL_EXACTNUMERIC:
return parseLiteralExactNumeric(expression);
case LITERAL_STRING:
return parseLiteralString(expression);
case LITERAL_INTERVAL:
return parseLiteralInterval(expression);
case PREDICATE_AND:
return parsePredicateAnd(expression);
case PREDICATE_OR:
return parsePredicateOr(expression);
case PREDICATE_NOT:
return parsePredicateNot(expression);
case PREDICATE_EQUAL:
return parsePredicateEqual(expression);
case PREDICATE_NOTEQUAL:
return parsePredicateNotEqual(expression);
case PREDICATE_LESS:
return parsePredicateLess(expression);
case PREDICATE_LESSEQUAL:
return parsePredicateLessEqual(expression);
case PREDICATE_LIKE:
return parsePredicateLike(expression);
case PREDICATE_LIKE_REGEXP:
return parsePredicateLikeRegexp(expression);
case PREDICATE_BETWEEN:
return parsePredicateBetween(expression);
case PREDICATE_IN_CONSTLIST:
return parsePredicateInConstlist(expression);
case PREDICATE_IS_JSON:
return parsePredicateIsJson(expression);
case PREDICATE_IS_NOT_JSON:
return parsePredicateIsNotJson(expression);
case PREDICATE_IS_NULL:
return parsePredicateIsNull(expression);
case PREDICATE_IS_NOT_NULL:
return parsePredicateIsNotNull(expression);
case FUNCTION_SCALAR:
return parseFunctionScalar(expression);
case FUNCTION_SCALAR_EXTRACT:
return parseFunctionScalarExtract(expression);
case FUNCTION_SCALAR_CASE:
return parseFunctionScalarCase(expression);
case FUNCTION_SCALAR_CAST:
return parseFunctionScalarCast(expression);
case FUNCTION_SCALAR_JSON_VALUE:
return parseFunctionScalarJsonValue(expression);
case FUNCTION_AGGREGATE:
return parseFunctionAggregate(expression);
case FUNCTION_AGGREGATE_GROUP_CONCAT:
return parseFunctionAggregateGroupConcat(expression);
case FUNCTION_AGGREGATE_LISTAGG:
return parseFunctionAggregateListagg(expression);
default:
throw new IllegalArgumentException(ExaError.messageBuilder("E-VSCOMJAVA-8") //
.message("Unknown node type: {{typeName}}") //
.parameter("typeName", typeName).toString());
case SELECT:
return parseSelect(expression);
case TABLE:
return parseTable(expression);
case JOIN:
return parseJoin(expression);
case COLUMN:
return parseColumn(expression);
case LITERAL_NULL:
return parseLiteralNull();
case LITERAL_BOOL:
return parseLiteralBool(expression);
case LITERAL_DATE:
return parseLiteralDate(expression);
case LITERAL_TIMESTAMP:
return parseLiteralTimestamp(expression);
case LITERAL_TIMESTAMPUTC:
return parseLiteralTimestamputc(expression);
case LITERAL_DOUBLE:
return parseLiteralDouble(expression);
case LITERAL_EXACTNUMERIC:
return parseLiteralExactNumeric(expression);
case LITERAL_STRING:
return parseLiteralString(expression);
case LITERAL_INTERVAL:
return parseLiteralInterval(expression);
case PREDICATE_AND:
return parsePredicateAnd(expression);
case PREDICATE_OR:
return parsePredicateOr(expression);
case PREDICATE_NOT:
return parsePredicateNot(expression);
case PREDICATE_EQUAL:
return parsePredicateEqual(expression);
case PREDICATE_NOTEQUAL:
return parsePredicateNotEqual(expression);
case PREDICATE_LESS:
return parsePredicateLess(expression);
case PREDICATE_LESSEQUAL:
return parsePredicateLessEqual(expression);
case PREDICATE_LIKE:
return parsePredicateLike(expression);
case PREDICATE_LIKE_REGEXP:
return parsePredicateLikeRegexp(expression);
case PREDICATE_BETWEEN:
return parsePredicateBetween(expression);
case PREDICATE_IN_CONSTLIST:
return parsePredicateInConstlist(expression);
case PREDICATE_IS_JSON:
return parsePredicateIsJson(expression);
case PREDICATE_IS_NOT_JSON:
return parsePredicateIsNotJson(expression);
case PREDICATE_IS_NULL:
return parsePredicateIsNull(expression);
case PREDICATE_IS_NOT_NULL:
return parsePredicateIsNotNull(expression);
case FUNCTION_SCALAR:
return parseFunctionScalar(expression);
case FUNCTION_SCALAR_EXTRACT:
return parseFunctionScalarExtract(expression);
case FUNCTION_SCALAR_CASE:
return parseFunctionScalarCase(expression);
case FUNCTION_SCALAR_CAST:
return parseFunctionScalarCast(expression);
case FUNCTION_SCALAR_JSON_VALUE:
return parseFunctionScalarJsonValue(expression);
case FUNCTION_AGGREGATE:
return parseFunctionAggregate(expression);
case FUNCTION_AGGREGATE_GROUP_CONCAT:
return parseFunctionAggregateGroupConcat(expression);
case FUNCTION_AGGREGATE_LISTAGG:
return parseFunctionAggregateListagg(expression);
default:
throw new IllegalArgumentException(ExaError.messageBuilder("E-VSCOMJAVA-8") //
.message("Unknown node type: {{typeName}}") //
.parameter("typeName", typeName).toString());
}
}

Expand Down Expand Up @@ -463,49 +463,49 @@ private List<SqlTable> collectInvolvedTables(final SqlNode from) {
while (!nodes.isEmpty()) {
final SqlNode node = nodes.pop();
switch (node.getType()) {
case TABLE:
involvedTables.add((SqlTable) node);
break;
case JOIN:
nodes.add(((SqlJoin) node).getRight());
nodes.add(((SqlJoin) node).getLeft());
break;
default:
throw new IllegalStateException(ExaError.messageBuilder("E-VSCOMJAVA-10")
.message("Encountered illegal SqlNodeType during collection involved tables: {{nodeType}}")
.parameter("nodeType", node.getType()).toString());
case TABLE:
involvedTables.add((SqlTable) node);
break;
case JOIN:
nodes.add(((SqlJoin) node).getRight());
nodes.add(((SqlJoin) node).getLeft());
break;
default:
throw new IllegalStateException(ExaError.messageBuilder("E-VSCOMJAVA-10")
.message("Encountered illegal SqlNodeType during collection involved tables: {{nodeType}}")
.parameter("nodeType", node.getType()).toString());
}
}
return involvedTables;
}

private DataType getDataType(final JsonObject dataType) {
final String typeName = dataType.getString(TYPE).toUpperCase();
final String typeName = dataType.getString(TYPE).toUpperCase(Locale.ROOT);
switch (typeName) {
case "DECIMAL":
return DataType.createDecimal(dataType.getInt(PRECISION), dataType.getInt(SCALE));
case "DOUBLE":
return DataType.createDouble();
case "VARCHAR":
return getVarchar(dataType);
case "CHAR":
return getChar(dataType);
case "BOOLEAN":
return DataType.createBool();
case "DATE":
return DataType.createDate();
case "TIMESTAMP":
return getTimestamp(dataType);
case "INTERVAL":
return getInterval(dataType);
case "GEOMETRY":
return getGeometry(dataType);
case "HASHTYPE":
return getHashtype(dataType);
default:
throw new IllegalArgumentException(ExaError.messageBuilder("E-VSCOMJAVA-11")
.message("Unsupported data type encountered: {{typeName}}.") //
.parameter("typeName", typeName).toString());
case "DECIMAL":
return DataType.createDecimal(dataType.getInt(PRECISION), dataType.getInt(SCALE));
case "DOUBLE":
return DataType.createDouble();
case "VARCHAR":
return getVarchar(dataType);
case "CHAR":
return getChar(dataType);
case "BOOLEAN":
return DataType.createBool();
case "DATE":
return DataType.createDate();
case "TIMESTAMP":
return getTimestamp(dataType);
case "INTERVAL":
return getInterval(dataType);
case "GEOMETRY":
return getGeometry(dataType);
case "HASHTYPE":
return getHashtype(dataType);
default:
throw new IllegalArgumentException(ExaError.messageBuilder("E-VSCOMJAVA-11")
.message("Unsupported data type encountered: {{typeName}}.") //
.parameter("typeName", typeName).toString());
}
}

Expand Down Expand Up @@ -545,7 +545,7 @@ private SqlNode parsePredicateBetween(final JsonObject exp) {
private SqlNode parsePredicateIsJson(final JsonObject jsonExpression) {
final SqlNode expression = parseExpression(jsonExpression.getJsonObject(EXPRESSION));
final TypeConstraints typeConstraint = TypeConstraints
.valueOf(jsonExpression.getString(TYPE_CONSTRAINT).toUpperCase());
.valueOf(jsonExpression.getString(TYPE_CONSTRAINT).toUpperCase(Locale.ROOT));
final KeyUniquenessConstraint keyUniquenessConstraint = KeyUniquenessConstraint
.of(jsonExpression.getString(KEY_UNIQUENESS_CONSTRAINT));
return new SqlPredicateIsJson(expression, typeConstraint, keyUniquenessConstraint);
Expand All @@ -554,7 +554,7 @@ private SqlNode parsePredicateIsJson(final JsonObject jsonExpression) {
private SqlNode parsePredicateIsNotJson(final JsonObject jsonExpression) {
final SqlNode expression = parseExpression(jsonExpression.getJsonObject(EXPRESSION));
final TypeConstraints typeConstraint = TypeConstraints
.valueOf(jsonExpression.getString(TYPE_CONSTRAINT).toUpperCase());
.valueOf(jsonExpression.getString(TYPE_CONSTRAINT).toUpperCase(Locale.ROOT));
final KeyUniquenessConstraint keyUniquenessConstraint = KeyUniquenessConstraint
.of(jsonExpression.getString(KEY_UNIQUENESS_CONSTRAINT));
return new SqlPredicateIsNotJson(expression, typeConstraint, keyUniquenessConstraint);
Expand Down Expand Up @@ -681,7 +681,8 @@ private SqlNode parseFunctionAggregateListagg(final JsonObject expression) {

private Behavior parseOverflowBehavior(final JsonObject expression) {
final JsonObject overflowBehaviorJson = expression.getJsonObject(OVERFLOW_BEHAVIOUR);
final BehaviorType behaviorType = BehaviorType.valueOf(overflowBehaviorJson.getString(TYPE).toUpperCase());
final BehaviorType behaviorType = BehaviorType
.valueOf(overflowBehaviorJson.getString(TYPE).toUpperCase(Locale.ROOT));
if (behaviorType == BehaviorType.TRUNCATE) {
final TruncationType truncationType = TruncationType
.parseTruncationType(overflowBehaviorJson.getString(TRUNCATION_TYPE));
Expand All @@ -699,28 +700,28 @@ private Behavior parseOverflowBehavior(final JsonObject expression) {
* Mapping from join type name (as in json api) to enum
*/
private static JoinType fromJoinTypeName(final String typeName) {
return Enum.valueOf(JoinType.class, typeName.toUpperCase());
return Enum.valueOf(JoinType.class, typeName.toUpperCase(Locale.ROOT));
}

/**
* Mapping from scalar function name (as in json api) to enum
*/
private static ScalarFunction fromScalarFunctionName(final String functionName) {
return Enum.valueOf(ScalarFunction.class, functionName.toUpperCase());
return Enum.valueOf(ScalarFunction.class, functionName.toUpperCase(Locale.ROOT));
}

/**
* Mapping from aggregate function name (as in json api) to enum
*/
private static AggregateFunction fromAggregationFunctionName(final String functionName) {
return Enum.valueOf(AggregateFunction.class, functionName.toUpperCase());
return Enum.valueOf(AggregateFunction.class, functionName.toUpperCase(Locale.ROOT));
}

/**
* Mapping from type name (as in json api) to enum
*/
private static SqlNodeType fromTypeName(final String typeName) {
return Enum.valueOf(SqlNodeType.class, typeName.toUpperCase());
return Enum.valueOf(SqlNodeType.class, typeName.toUpperCase(Locale.ROOT));
}

private TableMetadata findInvolvedTableMetadata(final String tableName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ private AbstractAdapterRequest parseRefreshRequest(final JsonObject root, final
}

private AbstractAdapterRequest parsePushdownRequest(final JsonObject root, final SchemaMetadataInfo metadataInfo) {
final JsonObject pushdownJson = root.getJsonObject(PUSHDOW_REQUEST_KEY);
final JsonObject pushdownJson = root.getJsonObject(PUSHDOWN_REQUEST_KEY);
final List<TableMetadata> involvedTables = parseInvolvedTables(root);
final SqlStatement statement = parsePushdownStatement(pushdownJson, involvedTables);
final List<DataType> dataTypes = parseDataTypes(pushdownJson);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ final class RequestParserConstants {
static final String ADAPTER_NOTES_KEY = "adapterNotes";
static final String PROPERTIES_KEY = "properties";
static final String SCHEMA_NAME_KEY = "name";
static final String PUSHDOW_REQUEST_KEY = "pushdownRequest";
static final String PUSHDOWN_REQUEST_KEY = "pushdownRequest";
Comment thread
kaklakariada marked this conversation as resolved.
static final String SCHEMA_METADATA_INFO_KEY = "schemaMetadataInfo";
static final String INVOLVED_TABLES_KEY = "involvedTables";
static final String SELECT_LIST_DATATYPES_KEY = "selectListDataTypes";
Expand All @@ -24,4 +24,4 @@ final class RequestParserConstants {
private RequestParserConstants() {
// prevent instantiation
}
}
}
Loading