com.hazelcast.org.apache.calcite.rel.metadata.JaninoRelMetadataProvider 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.rel.metadata;
import com.hazelcast.org.apache.calcite.adapter.enumerable.EnumerableAggregate;
import com.hazelcast.org.apache.calcite.adapter.enumerable.EnumerableFilter;
import com.hazelcast.org.apache.calcite.adapter.enumerable.EnumerableHashJoin;
import com.hazelcast.org.apache.calcite.adapter.enumerable.EnumerableProject;
import com.hazelcast.org.apache.calcite.adapter.enumerable.EnumerableTableScan;
import com.hazelcast.org.apache.calcite.config.CalciteSystemProperty;
import com.hazelcast.org.apache.calcite.interpreter.JaninoRexCompiler;
import com.hazelcast.org.apache.calcite.linq4j.Ord;
import com.hazelcast.org.apache.calcite.linq4j.tree.Primitive;
import com.hazelcast.org.apache.calcite.plan.hep.HepRelVertex;
import com.hazelcast.org.apache.calcite.plan.volcano.AbstractConverter;
import com.hazelcast.org.apache.calcite.plan.volcano.RelSubset;
import com.hazelcast.org.apache.calcite.rel.AbstractRelNode;
import com.hazelcast.org.apache.calcite.rel.RelNode;
import com.hazelcast.org.apache.calcite.rel.convert.ConverterImpl;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalAggregate;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalCalc;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalCorrelate;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalExchange;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalFilter;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalIntersect;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalJoin;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalMinus;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalProject;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalSort;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalTableFunctionScan;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalTableModify;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalTableScan;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalUnion;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalValues;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalWindow;
import com.hazelcast.org.apache.calcite.rel.stream.LogicalChi;
import com.hazelcast.org.apache.calcite.rel.stream.LogicalDelta;
import com.hazelcast.org.apache.calcite.rex.RexNode;
import com.hazelcast.org.apache.calcite.util.ControlFlowException;
import com.hazelcast.org.apache.calcite.util.Pair;
import com.hazelcast.org.apache.calcite.util.Util;
import com.hazelcast.com.google.common.cache.CacheBuilder;
import com.hazelcast.com.google.common.cache.CacheLoader;
import com.hazelcast.com.google.common.cache.LoadingCache;
import com.hazelcast.com.google.common.collect.ImmutableList;
import com.hazelcast.com.google.common.collect.LinkedHashMultimap;
import com.hazelcast.com.google.common.collect.Lists;
import com.hazelcast.com.google.common.collect.Multimap;
import com.hazelcast.com.google.common.util.concurrent.UncheckedExecutionException;
import com.hazelcast.org.codehaus.commons.compiler.CompileException;
import com.hazelcast.org.codehaus.commons.compiler.CompilerFactoryFactory;
import com.hazelcast.org.codehaus.commons.compiler.ICompilerFactory;
import com.hazelcast.org.codehaus.commons.compiler.ISimpleCompiler;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutionException;
/**
* Implementation of the {@link RelMetadataProvider} interface that generates
* a class that dispatches to the underlying providers.
*/
public class JaninoRelMetadataProvider implements RelMetadataProvider {
private final RelMetadataProvider provider;
// Constants and static fields
public static final JaninoRelMetadataProvider DEFAULT =
JaninoRelMetadataProvider.of(DefaultRelMetadataProvider.INSTANCE);
private static final Set> ALL_RELS =
new CopyOnWriteArraySet<>();
/** Cache of pre-generated handlers by provider and kind of metadata.
* For the cache to be effective, providers should implement identity
* correctly. */
@SuppressWarnings("unchecked")
private static final LoadingCache HANDLERS =
maxSize(CacheBuilder.newBuilder(),
CalciteSystemProperty.METADATA_HANDLER_CACHE_MAXIMUM_SIZE.value())
.build(
CacheLoader.from(key ->
load3(key.def, key.provider.handlers(key.def),
key.relClasses)));
// Pre-register the most common relational operators, to reduce the number of
// times we re-generate.
static {
DEFAULT.register(
Arrays.asList(RelNode.class,
AbstractRelNode.class,
RelSubset.class,
HepRelVertex.class,
ConverterImpl.class,
AbstractConverter.class,
LogicalAggregate.class,
LogicalCalc.class,
LogicalCorrelate.class,
LogicalExchange.class,
LogicalFilter.class,
LogicalIntersect.class,
LogicalJoin.class,
LogicalMinus.class,
LogicalProject.class,
LogicalSort.class,
LogicalTableFunctionScan.class,
LogicalTableModify.class,
LogicalTableScan.class,
LogicalUnion.class,
LogicalValues.class,
LogicalWindow.class,
LogicalChi.class,
LogicalDelta.class,
EnumerableAggregate.class,
EnumerableFilter.class,
EnumerableProject.class,
EnumerableHashJoin.class,
EnumerableTableScan.class));
}
/** Private constructor; use {@link #of}. */
private JaninoRelMetadataProvider(RelMetadataProvider provider) {
this.provider = provider;
}
/** Creates a JaninoRelMetadataProvider.
*
* @param provider Underlying provider
*/
public static JaninoRelMetadataProvider of(RelMetadataProvider provider) {
if (provider instanceof JaninoRelMetadataProvider) {
return (JaninoRelMetadataProvider) provider;
}
return new JaninoRelMetadataProvider(provider);
}
// helper for initialization
private static CacheBuilder maxSize(CacheBuilder builder,
int size) {
if (size >= 0) {
builder.maximumSize(size);
}
return builder;
}
@Override public boolean equals(Object obj) {
return obj == this
|| obj instanceof JaninoRelMetadataProvider
&& ((JaninoRelMetadataProvider) obj).provider.equals(provider);
}
@Override public int hashCode() {
return 109 + provider.hashCode();
}
public UnboundMetadata apply(
Class extends RelNode> relClass, Class extends M> metadataClass) {
throw new UnsupportedOperationException();
}
public Multimap>
handlers(MetadataDef def) {
return provider.handlers(def);
}
private static MetadataHandler load3(
MetadataDef def, Multimap> map,
ImmutableList> relClasses) {
final StringBuilder buff = new StringBuilder();
final String name =
"GeneratedMetadataHandler_" + def.metadataClass.getSimpleName();
final Set providerSet = new HashSet<>();
final List> providerList = new ArrayList<>();
//noinspection unchecked
final ReflectiveRelMetadataProvider.Space space =
new ReflectiveRelMetadataProvider.Space((Multimap) map);
for (MetadataHandler provider : space.providerMap.values()) {
if (providerSet.add(provider)) {
providerList.add(
Pair.of("provider" + (providerSet.size() - 1), provider));
}
}
buff.append(" private final java.util.List relClasses;\n");
for (Pair pair : providerList) {
buff.append(" public final ").append(pair.right.getClass().getName())
.append(' ').append(pair.left).append(";\n");
}
buff.append(" public ").append(name).append("(java.util.List relClasses");
for (Pair pair : providerList) {
buff.append(",\n")
.append(" ")
.append(pair.right.getClass().getName())
.append(' ')
.append(pair.left);
}
buff.append(") {\n")
.append(" this.relClasses = relClasses;\n");
for (Pair pair : providerList) {
buff.append(" this.").append(pair.left).append(" = ").append(pair.left)
.append(";\n");
}
buff.append(" }\n")
.append(" public ")
.append(MetadataDef.class.getName())
.append(" getDef() {\n")
.append(" return ")
.append(def.metadataClass.getName())
.append(".DEF;\n")
.append(" }\n");
for (Ord method : Ord.zip(def.methods)) {
buff.append(" public ")
.append(method.e.getReturnType().getName())
.append(" ")
.append(method.e.getName())
.append("(\n")
.append(" ")
.append(RelNode.class.getName())
.append(" r,\n")
.append(" ")
.append(RelMetadataQuery.class.getName())
.append(" mq");
paramList(buff, method.e)
.append(") {\n");
buff.append(" final java.util.List key = ")
.append(
(method.e.getParameterTypes().length < 4
? com.hazelcast.org.apache.calcite.runtime.FlatLists.class
: ImmutableList.class).getName())
.append(".of(")
.append(def.metadataClass.getName());
if (method.i == 0) {
buff.append(".DEF");
} else {
buff.append(".DEF.methods.get(")
.append(method.i)
.append(")");
}
safeArgList(buff, method.e)
.append(");\n")
.append(" final Object v = mq.map.get(r, key);\n")
.append(" if (v != null) {\n")
.append(" if (v == ")
.append(NullSentinel.class.getName())
.append(".ACTIVE) {\n")
.append(" throw new ")
.append(CyclicMetadataException.class.getName())
.append("();\n")
.append(" }\n")
.append(" if (v == ")
.append(NullSentinel.class.getName())
.append(".INSTANCE) {\n")
.append(" return null;\n")
.append(" }\n")
.append(" return (")
.append(method.e.getReturnType().getName())
.append(") v;\n")
.append(" }\n")
.append(" mq.map.put(r, key,")
.append(NullSentinel.class.getName())
.append(".ACTIVE);\n")
.append(" try {\n")
.append(" final ")
.append(method.e.getReturnType().getName())
.append(" x = ")
.append(method.e.getName())
.append("_(r, mq");
argList(buff, method.e)
.append(");\n")
.append(" mq.map.put(r, key, ")
.append(NullSentinel.class.getName())
.append(".mask(x));\n")
.append(" return x;\n")
.append(" } catch (")
.append(Exception.class.getName())
.append(" e) {\n")
.append(" mq.map.row(r).clear();\n")
.append(" throw e;\n")
.append(" }\n")
.append(" }\n")
.append("\n")
.append(" private ")
.append(method.e.getReturnType().getName())
.append(" ")
.append(method.e.getName())
.append("_(\n")
.append(" ")
.append(RelNode.class.getName())
.append(" r,\n")
.append(" ")
.append(RelMetadataQuery.class.getName())
.append(" mq");
paramList(buff, method.e)
.append(") {\n");
buff.append(" switch (relClasses.indexOf(r.getClass())) {\n");
// Build a list of clauses, grouping clauses that have the same action.
final Multimap clauses = LinkedHashMultimap.create();
final StringBuilder buf2 = new StringBuilder();
for (Ord> relClass : Ord.zip(relClasses)) {
if (relClass.e == HepRelVertex.class) {
buf2.append(" return ")
.append(method.e.getName())
.append("(((")
.append(relClass.e.getName())
.append(") r).getCurrentRel(), mq");
argList(buf2, method.e)
.append(");\n");
} else {
final Method handler = space.find(relClass.e, method.e);
final String v = findProvider(providerList, handler.getDeclaringClass());
buf2.append(" return ")
.append(v)
.append(".")
.append(method.e.getName())
.append("((")
.append(handler.getParameterTypes()[0].getName())
.append(") r, mq");
argList(buf2, method.e)
.append(");\n");
}
clauses.put(buf2.toString(), relClass.i);
buf2.setLength(0);
}
buf2.append(" throw new ")
.append(NoHandler.class.getName())
.append("(r.getClass());\n")
.append(" }\n")
.append(" }\n");
clauses.put(buf2.toString(), -1);
for (Map.Entry> pair : clauses.asMap().entrySet()) {
if (pair.getValue().contains(relClasses.indexOf(RelNode.class))) {
buff.append(" default:\n");
} else {
for (Integer integer : pair.getValue()) {
buff.append(" case ").append(integer).append(":\n");
}
}
buff.append(pair.getKey());
}
}
final List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy