com.hazelcast.org.apache.calcite.schema.Schemas 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.schema;
import com.hazelcast.org.apache.calcite.DataContext;
import com.hazelcast.org.apache.calcite.DataContexts;
import com.hazelcast.org.apache.calcite.adapter.enumerable.EnumUtils;
import com.hazelcast.org.apache.calcite.adapter.java.JavaTypeFactory;
import com.hazelcast.org.apache.calcite.config.CalciteConnectionConfig;
import com.hazelcast.org.apache.calcite.config.CalciteConnectionConfigImpl;
import com.hazelcast.org.apache.calcite.config.CalciteConnectionProperty;
import com.hazelcast.org.apache.calcite.jdbc.CalciteConnection;
import com.hazelcast.org.apache.calcite.jdbc.CalcitePrepare;
import com.hazelcast.org.apache.calcite.jdbc.CalciteSchema;
import com.hazelcast.org.apache.calcite.linq4j.Enumerable;
import com.hazelcast.org.apache.calcite.linq4j.QueryProvider;
import com.hazelcast.org.apache.calcite.linq4j.Queryable;
import com.hazelcast.org.apache.calcite.linq4j.tree.Expression;
import com.hazelcast.org.apache.calcite.linq4j.tree.Expressions;
import com.hazelcast.org.apache.calcite.linq4j.tree.MethodCallExpression;
import com.hazelcast.org.apache.calcite.materialize.Lattice;
import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeFactory;
import com.hazelcast.org.apache.calcite.rel.type.RelProtoDataType;
import com.hazelcast.org.apache.calcite.sql.type.SqlTypeUtil;
import com.hazelcast.org.apache.calcite.tools.RelRunner;
import com.hazelcast.org.apache.calcite.util.BuiltInMethod;
import com.hazelcast.org.apache.calcite.util.Pair;
import com.hazelcast.org.apache.calcite.util.Util;
import com.hazelcast.com.google.common.base.Preconditions;
import com.hazelcast.com.google.common.collect.ImmutableList;
import com.hazelcast.com.google.common.collect.ImmutableMap;
import com.hazelcast.com.google.common.collect.Lists;
import com.hazelcast.org.checkerframework.checker.nullness.qual.Nullable;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static com.hazelcast.org.apache.calcite.jdbc.CalciteSchema.LatticeEntry;
import static java.util.Objects.requireNonNull;
/**
* Utility functions for schemas.
*/
public final class Schemas {
private Schemas() {
throw new AssertionError("no instances!");
}
public static CalciteSchema.@Nullable FunctionEntry resolve(
RelDataTypeFactory typeFactory,
String name,
Collection functionEntries,
List argumentTypes) {
final List matches = new ArrayList<>();
for (CalciteSchema.FunctionEntry entry : functionEntries) {
if (matches(typeFactory, entry.getFunction(), argumentTypes)) {
matches.add(entry);
}
}
switch (matches.size()) {
case 0:
return null;
case 1:
return matches.get(0);
default:
throw new RuntimeException("More than one match for " + name
+ " with arguments " + argumentTypes);
}
}
private static boolean matches(RelDataTypeFactory typeFactory,
Function member, List argumentTypes) {
List parameters = member.getParameters();
if (parameters.size() != argumentTypes.size()) {
return false;
}
for (int i = 0; i < argumentTypes.size(); i++) {
RelDataType argumentType = argumentTypes.get(i);
FunctionParameter parameter = parameters.get(i);
if (!canConvert(argumentType, parameter.getType(typeFactory))) {
return false;
}
}
return true;
}
private static boolean canConvert(RelDataType fromType, RelDataType toType) {
return SqlTypeUtil.canAssignFrom(toType, fromType);
}
/** Returns the expression for a schema. */
public static Expression expression(SchemaPlus schema) {
return schema.getExpression(schema.getParentSchema(), schema.getName());
}
/** Returns the expression for a sub-schema. */
public static Expression subSchemaExpression(SchemaPlus schema, String name,
Class type) {
// (Type) schemaExpression.getSubSchema("name")
final Expression schemaExpression = expression(schema);
Expression call =
Expressions.call(
schemaExpression,
BuiltInMethod.SCHEMA_GET_SUB_SCHEMA.method,
Expressions.constant(name));
//CHECKSTYLE: IGNORE 2
//noinspection unchecked
if (false && type != null && !type.isAssignableFrom(Schema.class)) {
return unwrap(call, type);
}
return call;
}
/** Converts a schema expression to a given type by calling the
* {@link SchemaPlus#unwrap(Class)} method. */
public static Expression unwrap(Expression call, Class type) {
return Expressions.convert_(
Expressions.call(call, BuiltInMethod.SCHEMA_PLUS_UNWRAP.method,
Expressions.constant(type)),
type);
}
/** Returns the expression to access a table within a schema. */
public static Expression tableExpression(SchemaPlus schema, Type elementType,
String tableName, Class clazz) {
final MethodCallExpression expression;
if (Table.class.isAssignableFrom(clazz)) {
expression = Expressions.call(
expression(schema),
BuiltInMethod.SCHEMA_GET_TABLE.method,
Expressions.constant(tableName));
if (ScannableTable.class.isAssignableFrom(clazz)) {
return Expressions.call(
BuiltInMethod.SCHEMAS_ENUMERABLE_SCANNABLE.method,
Expressions.convert_(expression, ScannableTable.class),
DataContext.ROOT);
}
if (FilterableTable.class.isAssignableFrom(clazz)) {
return Expressions.call(
BuiltInMethod.SCHEMAS_ENUMERABLE_FILTERABLE.method,
Expressions.convert_(expression, FilterableTable.class),
DataContext.ROOT);
}
if (ProjectableFilterableTable.class.isAssignableFrom(clazz)) {
return Expressions.call(
BuiltInMethod.SCHEMAS_ENUMERABLE_PROJECTABLE_FILTERABLE.method,
Expressions.convert_(expression, ProjectableFilterableTable.class),
DataContext.ROOT);
}
} else {
expression = Expressions.call(
BuiltInMethod.SCHEMAS_QUERYABLE.method,
DataContext.ROOT,
expression(schema),
Expressions.constant(elementType),
Expressions.constant(tableName));
}
return EnumUtils.convert(expression, clazz);
}
/**
* Generates an expression with which table can be referenced in
* generated code.
*
* @param schema Schema
* @param tableName Table name (unique within schema)
* @param table Table to be referenced
* @param clazz Class that provides specific methods for accessing table data.
* It may differ from the {@code table} class; for example {@code clazz} may be
* {@code MongoTable.MongoQueryable}, though {@code table} is {@code MongoTable}
*/
public static Expression getTableExpression(SchemaPlus schema, String tableName,
Table table, Class> clazz) {
if (table instanceof QueryableTable) {
QueryableTable queryableTable = (QueryableTable) table;
return queryableTable.getExpression(schema, tableName, clazz);
} else if (table instanceof ScannableTable
|| table instanceof FilterableTable
|| table instanceof ProjectableFilterableTable) {
return tableExpression(schema, Object[].class, tableName,
table.getClass());
} else if (table instanceof StreamableTable) {
return getTableExpression(schema, tableName,
((StreamableTable) table).stream(), clazz);
} else {
throw new UnsupportedOperationException();
}
}
public static DataContext createDataContext(
Connection connection, @Nullable SchemaPlus rootSchema) {
return DataContexts.of((CalciteConnection) connection, rootSchema);
}
/** Returns a {@link Queryable}, given a fully-qualified table name. */
public static Queryable queryable(DataContext root, Class clazz,
String... names) {
return queryable(root, clazz, Arrays.asList(names));
}
/** Returns a {@link Queryable}, given a fully-qualified table name as an
* iterable. */
public static Queryable queryable(DataContext root, Class clazz,
Iterable extends String> names) {
SchemaPlus schema = root.getRootSchema();
for (Iterator extends String> iterator = names.iterator();;) {
String name = iterator.next();
requireNonNull(schema, "schema");
if (iterator.hasNext()) {
SchemaPlus next = schema.getSubSchema(name);
if (next == null) {
throw new IllegalArgumentException("schema " + name + " is not found in " + schema);
}
schema = next;
} else {
return queryable(root, schema, clazz, name);
}
}
}
/** Returns a {@link Queryable}, given a schema and table name. */
public static Queryable queryable(DataContext root, SchemaPlus schema,
Class clazz, String tableName) {
QueryableTable table = (QueryableTable) requireNonNull(
schema.getTable(tableName),
() -> "table " + tableName + " is not found in " + schema);
QueryProvider queryProvider = root.getQueryProvider();
return table.asQueryable(queryProvider, schema, tableName);
}
/** Returns an {@link com.hazelcast.org.apache.calcite.linq4j.Enumerable} over the rows of
* a given table, representing each row as an object array. */
public static Enumerable<@Nullable Object[]> enumerable(final ScannableTable table,
final DataContext root) {
return table.scan(root);
}
/** Returns an {@link com.hazelcast.org.apache.calcite.linq4j.Enumerable} over the rows of
* a given table, not applying any filters, representing each row as an object
* array. */
public static Enumerable<@Nullable Object[]> enumerable(final FilterableTable table,
final DataContext root) {
return table.scan(root, new ArrayList<>());
}
/** Returns an {@link com.hazelcast.org.apache.calcite.linq4j.Enumerable} over the rows of
* a given table, not applying any filters and projecting all columns,
* representing each row as an object array. */
public static Enumerable<@Nullable Object[]> enumerable(
final ProjectableFilterableTable table, final DataContext root) {
JavaTypeFactory typeFactory = root.getTypeFactory();
return table.scan(root, new ArrayList<>(),
identity(table.getRowType(typeFactory).getFieldCount()));
}
private static int[] identity(int count) {
final int[] integers = new int[count];
for (int i = 0; i < integers.length; i++) {
integers[i] = i;
}
return integers;
}
/** Returns an {@link com.hazelcast.org.apache.calcite.linq4j.Enumerable} over object
* arrays, given a fully-qualified table name which leads to a
* {@link ScannableTable}. */
public static @Nullable Table table(DataContext root, String... names) {
SchemaPlus schema = root.getRootSchema();
final List nameList = Arrays.asList(names);
for (Iterator extends String> iterator = nameList.iterator();;) {
String name = iterator.next();
requireNonNull(schema, "schema");
if (iterator.hasNext()) {
SchemaPlus next = schema.getSubSchema(name);
if (next == null) {
throw new IllegalArgumentException("schema " + name + " is not found in " + schema);
}
schema = next;
} else {
return schema.getTable(name);
}
}
}
/** Parses and validates a SQL query. For use within Calcite only. */
public static CalcitePrepare.ParseResult parse(
final CalciteConnection connection, final CalciteSchema schema,
final @Nullable List schemaPath, final String sql) {
final CalcitePrepare prepare = CalcitePrepare.DEFAULT_FACTORY.apply();
final ImmutableMap propValues =
ImmutableMap.of();
final CalcitePrepare.Context context =
makeContext(connection, schema, schemaPath, null, propValues);
CalcitePrepare.Dummy.push(context);
try {
return prepare.parse(context, sql);
} finally {
CalcitePrepare.Dummy.pop(context);
}
}
/** Parses and validates a SQL query and converts to relational algebra. For
* use within Calcite only. */
public static CalcitePrepare.ConvertResult convert(
final CalciteConnection connection, final CalciteSchema schema,
final List schemaPath, final String sql) {
final CalcitePrepare prepare = CalcitePrepare.DEFAULT_FACTORY.apply();
final ImmutableMap propValues =
ImmutableMap.of();
final CalcitePrepare.Context context =
makeContext(connection, schema, schemaPath, null, propValues);
CalcitePrepare.Dummy.push(context);
try {
return prepare.convert(context, sql);
} finally {
CalcitePrepare.Dummy.pop(context);
}
}
/** Analyzes a view. For use within Calcite only. */
public static CalcitePrepare.AnalyzeViewResult analyzeView(
final CalciteConnection connection, final CalciteSchema schema,
final @Nullable List schemaPath, final String viewSql,
@Nullable List viewPath, boolean fail) {
final CalcitePrepare prepare = CalcitePrepare.DEFAULT_FACTORY.apply();
final ImmutableMap propValues =
ImmutableMap.of();
final CalcitePrepare.Context context =
makeContext(connection, schema, schemaPath, viewPath, propValues);
CalcitePrepare.Dummy.push(context);
try {
return prepare.analyzeView(context, viewSql, fail);
} finally {
CalcitePrepare.Dummy.pop(context);
}
}
/** Prepares a SQL query for execution. For use within Calcite only. */
public static CalcitePrepare.CalciteSignature
© 2015 - 2024 Weber Informatics LLC | Privacy Policy