All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.org.apache.calcite.runtime.Hook Maven / Gradle / Ivy

There is a newer version: 5.4.0
Show newest version
/*
 * 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.runtime;

import com.hazelcast.org.apache.calcite.rel.RelRoot;
import com.hazelcast.org.apache.calcite.util.Holder;

import org.apiguardian.api.API;
import com.hazelcast.org.checkerframework.checker.nullness.qual.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.function.Function;

import static com.hazelcast.org.apache.calcite.linq4j.Nullness.castNonNull;

/**
 * Collection of hooks that can be set by observers and are executed at various
 * parts of the query preparation process.
 *
 * 

For testing and debugging rather than for end-users.

*/ public enum Hook { /** Called to get the current time. Use this to return a predictable time * in tests. */ CURRENT_TIME, /** Called to get stdin, stdout, stderr. * Use this to re-assign streams in tests. */ STANDARD_STREAMS, /** Returns a boolean value, whether RelBuilder should simplify expressions. * Default true. */ REL_BUILDER_SIMPLIFY, /** Returns a boolean value, whether the return convention should be * {@link com.hazelcast.org.apache.calcite.interpreter.BindableConvention}. * Default false. */ ENABLE_BINDABLE, /** Called with the SQL string and parse tree, in an array. */ PARSE_TREE, /** Converts a SQL string to a * {@link com.hazelcast.org.apache.calcite.jdbc.CalcitePrepare.Query} object. This hook is * an opportunity to execute a {@link com.hazelcast.org.apache.calcite.rel.RelNode} query * plan in the JDBC driver rather than the usual SQL string. */ STRING_TO_QUERY, /** Called with the generated Java plan, just before it is compiled by * Janino. */ JAVA_PLAN, /** Called before SqlToRelConverter is built. */ SQL2REL_CONVERTER_CONFIG_BUILDER, /** Called with the output of sql-to-rel-converter. */ CONVERTED, /** Called with the created planner. */ PLANNER, /** Called after de-correlation and field trimming, but before * optimization. */ TRIMMED, /** Called by the planner after substituting a materialization. */ SUB, /** Called when a constant expression is being reduced. */ EXPRESSION_REDUCER, /** Called to create a Program to optimize the statement. */ PROGRAM, /** Called when materialization is created. */ CREATE_MATERIALIZATION, /** Called with a query that has been generated to send to a back-end system. * The query might be a SQL string (for the JDBC adapter), a list of Mongo * pipeline expressions (for the MongoDB adapter), et cetera. */ QUERY_PLAN, /** * Called when a plan is about to be implemented (e.g. implemented via Enumerable, Bindable, * and so on). * The hook supplies {@link RelRoot} as an argument. */ @API(since = "1.22", status = API.Status.EXPERIMENTAL) PLAN_BEFORE_IMPLEMENTATION; @SuppressWarnings("ImmutableEnumChecker") private final List> handlers = new CopyOnWriteArrayList<>(); @SuppressWarnings("ImmutableEnumChecker") private final ThreadLocal<@Nullable List>> threadHandlers = ThreadLocal.withInitial(ArrayList::new); /** Adds a handler for this Hook. * *

Returns a {@link Hook.Closeable} so that you can use the following * try-finally pattern to prevent leaks:

* *
   *     final Hook.Closeable closeable = Hook.FOO.add(HANDLER);
   *     try {
   *         ...
   *     } finally {
   *         closeable.close();
   *     }
*
* @deprecated this installs a global hook (cross-thread), so it might have greater impact * than expected. Use with caution. Prefer thread-local hooks. * @see #addThread(Consumer) */ @API(status = API.Status.MAINTAINED) @Deprecated public Closeable add(final Consumer handler) { //noinspection unchecked handlers.add((Consumer) handler); return () -> remove(handler); } // CHECKSTYLE: IGNORE 1 /** @deprecated Use {@link #add(Consumer)}. */ @SuppressWarnings({"Guava", "ReturnValueIgnored"}) @Deprecated // to be removed before 2.0 public Closeable add(final Function handler) { return add((Consumer) handler::apply); } /** Removes a handler from this Hook. */ private boolean remove(Consumer handler) { return handlers.remove(handler); } /** Adds a handler for this thread. */ public Closeable addThread(final Consumer handler) { //noinspection unchecked castNonNull(threadHandlers.get()).add((Consumer) handler); return () -> removeThread(handler); } // CHECKSTYLE: IGNORE 1 /** @deprecated Use {@link #addThread(Consumer)}. */ @SuppressWarnings("Guava") @Deprecated // to be removed before 2.0 public Closeable addThread( final com.hazelcast.com.google.common.base.Function handler) { return addThread((Consumer) handler::apply); } /** Removes a thread handler from this Hook. */ private boolean removeThread(Consumer handler) { return castNonNull(threadHandlers.get()).remove(handler); } // CHECKSTYLE: IGNORE 1 /** @deprecated Use {@link #propertyJ}. */ @SuppressWarnings("Guava") @Deprecated // return type will change in 2.0 public static com.hazelcast.com.google.common.base.Function, Void> property(final V v) { return holder -> { holder.set(v); return null; }; } /** Returns a function that, when a hook is called, will "return" a given * value. (Because of the way hooks work, it "returns" the value by writing * into a {@link Holder}. */ public static Consumer> propertyJ(final V v) { return holder -> { holder.set(v); }; } /** Runs all handlers registered for this Hook, with the given argument. */ public void run(Object arg) { for (Consumer handler : handlers) { handler.accept(arg); } for (Consumer handler : castNonNull(threadHandlers.get())) { handler.accept(arg); } } /** Returns the value of a property hook. * (Property hooks take a {@link Holder} as an argument.) */ public V get(V defaultValue) { final Holder holder = Holder.of(defaultValue); run(holder); return holder.get(); } /** Removes a Hook after use. */ public interface Closeable extends AutoCloseable { /** Closeable that does nothing. */ Closeable EMPTY = () -> { }; // override, removing "throws" @Override void close(); } }