com.hazelcast.org.apache.calcite.sql.dialect.JethroDataSqlDialect Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.org.apache.calcite.sql.dialect;
import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.sql.SqlDialect;
import com.hazelcast.org.apache.calcite.sql.SqlKind;
import com.hazelcast.org.apache.calcite.sql.SqlNode;
import com.hazelcast.org.apache.calcite.sql.SqlOperator;
import com.hazelcast.org.apache.calcite.sql.type.SqlTypeName;
import com.hazelcast.com.google.common.collect.ImmutableList;
import com.hazelcast.com.google.common.collect.ImmutableSetMultimap;
import com.hazelcast.com.google.common.collect.LinkedHashMultimap;
import com.hazelcast.com.google.common.collect.Multimap;
import com.hazelcast.org.checkerframework.checker.nullness.qual.Nullable;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* A SqlDialect
implementation for the JethroData database.
*/
public class JethroDataSqlDialect extends SqlDialect {
private final JethroInfo info;
/** Creates a JethroDataSqlDialect. */
public JethroDataSqlDialect(Context context) {
super(context);
this.info = context.jethroInfo();
}
@Override public boolean supportsCharSet() {
return false;
}
@Override public @Nullable SqlNode emulateNullDirection(SqlNode node,
boolean nullsFirst, boolean desc) {
return node;
}
@Override public boolean supportsAggregateFunction(SqlKind kind) {
switch (kind) {
case COUNT:
case SUM:
case AVG:
case MIN:
case MAX:
case STDDEV_POP:
case STDDEV_SAMP:
case VAR_POP:
case VAR_SAMP:
return true;
default:
break;
}
return false;
}
@Override public boolean supportsFunction(SqlOperator operator,
RelDataType type, List paramTypes) {
switch (operator.getKind()) {
case IS_NOT_NULL:
case IS_NULL:
case AND:
case OR:
case NOT:
case BETWEEN:
case CASE:
case CAST:
return true;
default:
break;
}
final Set functions =
info.supportedFunctions.get(operator.getName());
if (functions != null) {
for (JethroSupportedFunction f : functions) {
if (f.argumentsMatch(paramTypes)) {
return true;
}
}
}
LOGGER.debug("Unsupported function in jethro: " + operator + " with params "
+ paramTypes);
return false;
}
@SuppressWarnings("deprecation")
@Override public boolean supportsOffsetFetch() {
return false;
}
@Override public boolean supportsNestedAggregations() {
return false;
}
public static JethroInfoCache createCache() {
return new JethroInfoCacheImpl();
}
/** Information about a function supported by Jethro. */
static class JethroSupportedFunction {
private final List operandTypes;
JethroSupportedFunction(String name, String operands) {
Objects.requireNonNull(name, "name"); // not currently used
final ImmutableList.Builder b = ImmutableList.builder();
for (String strType : operands.split(":")) {
b.add(parse(strType));
}
this.operandTypes = b.build();
}
private static SqlTypeName parse(String strType) {
switch (strType.toLowerCase(Locale.ROOT)) {
case "bigint":
case "long":
return SqlTypeName.BIGINT;
case "integer":
case "int":
return SqlTypeName.INTEGER;
case "double":
return SqlTypeName.DOUBLE;
case "float":
return SqlTypeName.FLOAT;
case "string":
return SqlTypeName.VARCHAR;
case "timestamp":
return SqlTypeName.TIMESTAMP;
default:
return SqlTypeName.ANY;
}
}
boolean argumentsMatch(List paramTypes) {
if (paramTypes.size() != operandTypes.size()) {
return false;
}
for (int i = 0; i < paramTypes.size(); i++) {
if (paramTypes.get(i).getSqlTypeName() != operandTypes.get(i)) {
return false;
}
}
return true;
}
}
/** Stores information about capabilities of Jethro databases. */
public interface JethroInfoCache {
JethroInfo get(DatabaseMetaData databaseMetaData);
}
/** Implementation of {@code JethroInfoCache}. */
private static class JethroInfoCacheImpl implements JethroInfoCache {
final Map map = new HashMap<>();
@Override public JethroInfo get(final DatabaseMetaData metaData) {
try {
assert "JethroData".equals(metaData.getDatabaseProductName());
String productVersion = metaData.getDatabaseProductVersion();
synchronized (JethroInfoCacheImpl.this) {
JethroInfo info = map.get(productVersion);
if (info == null) {
final Connection c = metaData.getConnection();
info = makeInfo(c);
map.put(productVersion, info);
}
return info;
}
} catch (Exception e) {
LOGGER.error("Failed to create JethroDataDialect", e);
throw new RuntimeException("Failed to create JethroDataDialect", e);
}
}
private static JethroInfo makeInfo(Connection jethroConnection) {
try (Statement jethroStatement = jethroConnection.createStatement();
ResultSet functionsTupleSet =
jethroStatement.executeQuery("show functions extended")) {
final Multimap supportedFunctions =
LinkedHashMultimap.create();
while (functionsTupleSet.next()) {
String functionName = Objects.requireNonNull(
functionsTupleSet.getString(1),
"functionName");
String operandsType = Objects.requireNonNull(
functionsTupleSet.getString(3),
() -> "operands for " + functionName);
supportedFunctions.put(functionName,
new JethroSupportedFunction(functionName, operandsType));
}
return new JethroInfo(supportedFunctions);
} catch (Exception e) {
final String msg =
"Jethro server failed to execute 'show functions extended'";
LOGGER.error(msg, e);
throw new RuntimeException(msg
+ "; make sure your Jethro server is up to date", e);
}
}
}
/** Information about the capabilities of a Jethro database. */
public static class JethroInfo {
public static final JethroInfo EMPTY = new JethroInfo(
ImmutableSetMultimap.of());
private final ImmutableSetMultimap supportedFunctions;
public JethroInfo(Multimap supportedFunctions) {
this.supportedFunctions = ImmutableSetMultimap.copyOf(supportedFunctions);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy