Smalls.java

/*
 * 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 org.apache.calcite.util;

import org.apache.calcite.DataContext;
import org.apache.calcite.adapter.enumerable.EnumerableTableScan;
import org.apache.calcite.adapter.java.AbstractQueryableTable;
import org.apache.calcite.avatica.util.ByteString;
import org.apache.calcite.config.CalciteConnectionConfig;
import org.apache.calcite.linq4j.AbstractEnumerable;
import org.apache.calcite.linq4j.BaseQueryable;
import org.apache.calcite.linq4j.Enumerable;
import org.apache.calcite.linq4j.Enumerator;
import org.apache.calcite.linq4j.Linq4j;
import org.apache.calcite.linq4j.QueryProvider;
import org.apache.calcite.linq4j.Queryable;
import org.apache.calcite.linq4j.function.Deterministic;
import org.apache.calcite.linq4j.function.Parameter;
import org.apache.calcite.linq4j.function.SemiStrict;
import org.apache.calcite.linq4j.tree.Expression;
import org.apache.calcite.linq4j.tree.Expressions;
import org.apache.calcite.linq4j.tree.MethodCallExpression;
import org.apache.calcite.linq4j.tree.Types;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.externalize.RelJsonReader;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.runtime.PairList;
import org.apache.calcite.runtime.SqlFunctions;
import org.apache.calcite.schema.FunctionContext;
import org.apache.calcite.schema.FunctionParameter;
import org.apache.calcite.schema.QueryableTable;
import org.apache.calcite.schema.ScannableTable;
import org.apache.calcite.schema.Schema;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.schema.Schemas;
import org.apache.calcite.schema.Statistic;
import org.apache.calcite.schema.Statistics;
import org.apache.calcite.schema.TableMacro;
import org.apache.calcite.schema.TranslatableTable;
import org.apache.calcite.schema.impl.AbstractTable;
import org.apache.calcite.schema.impl.AbstractTableQueryable;
import org.apache.calcite.schema.impl.ViewTable;
import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.dialect.CalciteSqlDialect;
import org.apache.calcite.sql.type.SqlTypeName;

import com.google.common.collect.ImmutableList;

import org.checkerframework.checker.nullness.qual.Nullable;

import java.io.IOException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import static java.lang.Integer.parseInt;
import static java.util.Objects.requireNonNull;

/**
 * Holder for various classes and functions used in tests as user-defined
 * functions and so forth.
 */
public class Smalls {
  public static final Method GENERATE_STRINGS_METHOD =
      Types.lookupMethod(Smalls.class, "generateStrings", Integer.class);
  public static final Method GENERATE_STRINGS_OF_INPUT_SIZE_METHOD =
      Types.lookupMethod(Smalls.class, "generateStringsOfInputSize", List.class);
  public static final Method GENERATE_STRINGS_OF_INPUT_MAP_SIZE_METHOD =
      Types.lookupMethod(Smalls.class, "generateStringsOfInputMapSize", Map.class);
  public static final Method MAZE_METHOD =
      Types.lookupMethod(MazeTable.class, "generate", int.class, int.class,
          int.class);
  public static final Method MAZE2_METHOD =
      Types.lookupMethod(MazeTable.class, "generate2", int.class, int.class,
          Integer.class);
  public static final Method MAZE3_METHOD =
      Types.lookupMethod(MazeTable.class, "generate3", String.class);
  public static final Method MULTIPLICATION_TABLE_METHOD =
      Types.lookupMethod(Smalls.class, "multiplicationTable", int.class,
        int.class, Integer.class);
  public static final Method FIBONACCI_TABLE_METHOD =
      Types.lookupMethod(Smalls.class, "fibonacciTable");
  public static final Method FIBONACCI_LIMIT_100_TABLE_METHOD =
      Types.lookupMethod(Smalls.class, "fibonacciTableWithLimit100");
  public static final Method FIBONACCI_LIMIT_TABLE_METHOD =
      Types.lookupMethod(Smalls.class, "fibonacciTableWithLimit", long.class);
  public static final Method FIBONACCI_INSTANCE_TABLE_METHOD =
      Types.lookupMethod(Smalls.FibonacciTableFunction.class, "eval");
  public static final Method DUMMY_TABLE_METHOD_WITH_TWO_PARAMS =
      Types.lookupMethod(Smalls.class, "dummyTableFuncWithTwoParams", long.class, long.class);
  public static final Method DYNAMIC_ROW_TYPE_TABLE_METHOD =
      Types.lookupMethod(Smalls.class, "dynamicRowTypeTable", String.class,
          int.class);
  public static final Method VIEW_METHOD =
      Types.lookupMethod(Smalls.class, "view", String.class);
  public static final Method STR_METHOD =
      Types.lookupMethod(Smalls.class, "str", Object.class, Object.class);
  public static final Method STRING_UNION_METHOD =
      Types.lookupMethod(Smalls.class, "stringUnion", Queryable.class,
          Queryable.class);
  public static final Method PROCESS_CURSOR_METHOD =
      Types.lookupMethod(Smalls.class, "processCursor",
          int.class, Enumerable.class);
  public static final Method PROCESS_CURSORS_METHOD =
      Types.lookupMethod(Smalls.class, "processCursors",
          int.class, Enumerable.class, Enumerable.class);
  public static final Method MY_PLUS_EVAL_METHOD =
      Types.lookupMethod(MyPlusFunction.class, "eval", int.class, int.class);
  public static final Method MY_PLUS_INIT_EVAL_METHOD =
      Types.lookupMethod(MyPlusInitFunction.class, "eval", int.class,
          int.class);

  private Smalls() {}

  private static QueryableTable identity(Integer i) {
    final Enumerable<Integer> enumerable = Linq4j.asEnumerable(ImmutableList.of(i));
    return new AbstractQueryableTable(Integer.class) {
      @Override public <E> Queryable<E> asQueryable(
          QueryProvider queryProvider, SchemaPlus schema, String tableName) {
        //noinspection unchecked
        return (Queryable<E>) enumerable.asQueryable();
      }

      @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
        return typeFactory.builder().add("i", SqlTypeName.INTEGER).build();
      }
    };
  }

  private static QueryableTable oneThreePlus(String s) {
    List<Integer> items;
    // Argument is null in case SQL contains function call with expression.
    // Then the engine calls a function with null arguments to get getRowType.
    if (s == null) {
      items = ImmutableList.of();
    } else {
      Integer latest = parseInt(s.substring(1, s.length() - 1));
      items = ImmutableList.of(1, 3, latest);
    }
    final Enumerable<Integer> enumerable = Linq4j.asEnumerable(items);
    return new AbstractQueryableTable(Integer.class) {
      @Override public <E> Queryable<E> asQueryable(
          QueryProvider queryProvider, SchemaPlus schema, String tableName) {
        //noinspection unchecked
        return (Queryable<E>) enumerable.asQueryable();
      }

      @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
        return typeFactory.builder().add("c", SqlTypeName.INTEGER).build();
      }
    };
  }

  public static <T> Queryable<T> stringUnion(
      Queryable<T> q0, Queryable<T> q1) {
    return q0.concat(q1);
  }

  /** A function that generates a table that generates a sequence of
   * {@link IntString} values. */
  public static QueryableTable generateStrings(final Integer count) {
    return new AbstractQueryableTable(IntString.class) {
      @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
        return typeFactory.createJavaType(IntString.class);
      }

      @Override public <T> Queryable<T> asQueryable(QueryProvider queryProvider,
          SchemaPlus schema, String tableName) {
        BaseQueryable<IntString> queryable =
            new BaseQueryable<IntString>(null, IntString.class, null) {
              @Override public Enumerator<IntString> enumerator() {
                return new Enumerator<IntString>() {
                  static final String Z = "abcdefghijklm";

                  int i = 0;
                  int curI;
                  String curS;

                  @Override public IntString current() {
                    return new IntString(curI, curS);
                  }

                  @Override public boolean moveNext() {
                    if (i < count) {
                      curI = i;
                      curS = Z.substring(0, i % Z.length());
                      ++i;
                      return true;
                    } else {
                      return false;
                    }
                  }

                  @Override public void reset() {
                    i = 0;
                  }

                  @Override public void close() {
                  }
                };
              }
            };
        //noinspection unchecked
        return (Queryable<T>) queryable;
      }
    };
  }

  public static QueryableTable generateStringsOfInputSize(final List<Integer> list) {
    return generateStrings(list.size());
  }
  public static QueryableTable generateStringsOfInputMapSize(final Map<Integer, Integer> map) {
    return generateStrings(map.size());
  }

  /** A function that generates multiplication table of {@code ncol} columns x
   * {@code nrow} rows. */
  public static QueryableTable multiplicationTable(final int ncol,
      final int nrow, Integer offset) {
    final int offs = offset == null ? 0 : offset;
    return new AbstractQueryableTable(Object[].class) {
      @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
        final RelDataTypeFactory.Builder builder = typeFactory.builder();
        builder.add("row_name", typeFactory.createJavaType(String.class));
        final RelDataType int_ = typeFactory.createJavaType(int.class);
        for (int i = 1; i <= ncol; i++) {
          builder.add("c" + i, int_);
        }
        return builder.build();
      }

      @Override public Queryable<Object[]> asQueryable(QueryProvider queryProvider,
          SchemaPlus schema, String tableName) {
        final List<Object[]> table = new AbstractList<Object[]>() {
          @Override public Object[] get(int index) {
            Object[] cur = new Object[ncol + 1];
            cur[0] = "row " + index;
            for (int j = 1; j <= ncol; j++) {
              cur[j] = j * (index + 1) + offs;
            }
            return cur;
          }

          @Override public int size() {
            return nrow;
          }
        };
        return Linq4j.asEnumerable(table).asQueryable();
      }
    };
  }

  /** A function that generates the Fibonacci sequence.
   *
   * <p>Interesting because it has one column and no arguments,
   * and because it is infinite. */
  public static ScannableTable fibonacciTable() {
    return fibonacciTableWithLimit(-1L);
  }

  /** A function that generates the first 100 terms of the Fibonacci sequence.
   *
   * <p>Interesting because it has one column and no arguments. */
  public static ScannableTable fibonacciTableWithLimit100() {
    return fibonacciTableWithLimit(100L);
  }

  /** A function that takes 2 param as input. */
  public static ScannableTable dummyTableFuncWithTwoParams(final long param1, final long param2) {
    return new ScannableTable() {
      @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
        return typeFactory.builder().add("N", SqlTypeName.BIGINT).build();
      }

      @Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
        return new AbstractEnumerable<Object[]>() {
          @Override public Enumerator<Object[]> enumerator() {
            return new Enumerator<Object[]>() {
              @Override public Object[] current() {
                return new Object[] {};
              }

              @Override public boolean moveNext() {
                return false;
              }

              @Override public void reset() {
              }

              @Override public void close() {
              }
            };
          }
        };
      }

      @Override public Statistic getStatistic() {
        return Statistics.UNKNOWN;
      }

      @Override public Schema.TableType getJdbcTableType() {
        return Schema.TableType.TABLE;
      }

      @Override public boolean isRolledUp(String column) {
        return false;
      }

      @Override public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call,
          @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) {
        return true;
      }
    };
  }

  /** A function that generates the Fibonacci sequence.
   * Interesting because it has one column and no arguments. */
  public static ScannableTable fibonacciTableWithLimit(final long limit) {
    return new ScannableTable() {
      @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
        return typeFactory.builder().add("N", SqlTypeName.BIGINT).build();
      }

      @Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
        return new AbstractEnumerable<Object[]>() {
          @Override public Enumerator<Object[]> enumerator() {
            return new Enumerator<Object[]>() {
              private long prev = 1;
              private long current = 0;

              @Override public Object[] current() {
                return new Object[] {current};
              }

              @Override public boolean moveNext() {
                final long next = current + prev;
                if (limit >= 0 && next > limit) {
                  return false;
                }
                prev = current;
                current = next;
                return true;
              }

              @Override public void reset() {
                prev = 0;
                current = 1;
              }

              @Override public void close() {
              }
            };
          }
        };
      }

      @Override public Statistic getStatistic() {
        return Statistics.UNKNOWN;
      }

      @Override public Schema.TableType getJdbcTableType() {
        return Schema.TableType.TABLE;
      }

      @Override public boolean isRolledUp(String column) {
        return false;
      }

      @Override public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call,
          @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) {
        return true;
      }
    };
  }

  public static ScannableTable dynamicRowTypeTable(String jsonRowType,
      int rowCount) {
    return new DynamicRowTypeTable(jsonRowType, rowCount);
  }

  /** A table whose row type is determined by parsing a JSON argument. */
  private static class DynamicRowTypeTable extends AbstractTable
      implements ScannableTable {
    private final String jsonRowType;

    DynamicRowTypeTable(String jsonRowType, int count) {
      this.jsonRowType = jsonRowType;
    }

    @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
      try {
        return RelJsonReader.readType(typeFactory, jsonRowType);
      } catch (IOException e) {
        throw Util.throwAsRuntime(e);
      }
    }

    @Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
      return Linq4j.emptyEnumerable();
    }
  }

  /** Table function that adds a number to the first column of input cursor. */
  public static QueryableTable processCursor(final int offset,
      final Enumerable<Object[]> a) {
    return new AbstractQueryableTable(Object[].class) {
      @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
        return typeFactory.builder()
            .add("result", SqlTypeName.INTEGER)
            .build();
      }

      @Override public <T> Queryable<T> asQueryable(QueryProvider queryProvider,
          SchemaPlus schema, String tableName) {
        final Enumerable<Integer> enumerable =
            a.select(a0 -> offset + ((Integer) a0[0]));
        //noinspection unchecked
        return (Queryable) enumerable.asQueryable();
      }
    };
  }

  /**
   * A function that sums the second column of first input cursor, second
   * column of first input and the given int.
   */
  public static QueryableTable processCursors(final int offset,
      final Enumerable<Object[]> a, final Enumerable<IntString> b) {
    return new AbstractQueryableTable(Object[].class) {
      @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
        return typeFactory.builder()
            .add("result", SqlTypeName.INTEGER)
            .build();
      }

      @Override public <T> Queryable<T> asQueryable(QueryProvider queryProvider,
          SchemaPlus schema, String tableName) {
        final Enumerable<Integer> enumerable =
            a.zip(b, (v0, v1) -> ((Integer) v0[1]) + v1.n + offset);
        //noinspection unchecked
        return (Queryable) enumerable.asQueryable();
      }
    };
  }

  public static TranslatableTable view(String s) {
    return new ViewTable(Object.class, typeFactory ->
        typeFactory.builder().add("c", SqlTypeName.INTEGER).build(),
        "values (1), (3), " + s, ImmutableList.of(), Arrays.asList("view"));
  }

  public static TranslatableTable strView(String s) {
    return new ViewTable(Object.class, typeFactory ->
        typeFactory.builder().add("c", SqlTypeName.VARCHAR, 100).build(),
        "values (" + CalciteSqlDialect.DEFAULT.quoteStringLiteral(s) + ")",
        ImmutableList.of(), Arrays.asList("view"));
  }

  public static TranslatableTable str(Object o, Object p) {
    assertThat(RexLiteral.validConstant(o, Litmus.THROW), is(true));
    assertThat(RexLiteral.validConstant(p, Litmus.THROW), is(true));
    return new ViewTable(Object.class, typeFactory ->
        typeFactory.builder().add("c", SqlTypeName.VARCHAR, 100).build(),
        "values " + CalciteSqlDialect.DEFAULT.quoteStringLiteral(o.toString())
            + ", " + CalciteSqlDialect.DEFAULT.quoteStringLiteral(p.toString()),
        ImmutableList.of(), Arrays.asList("view"));
  }

  /** Class with int and String fields. */
  public static class IntString {
    public final int n;
    public final String s;

    public IntString(int n, String s) {
      this.n = n;
      this.s = s;
    }

    @Override public String toString() {
      return "{n=" + n + ", s=" + s + "}";
    }
  }

  /** Example of a UDF with a non-static {@code eval} method,
   * and named parameters. */
  public static class MyPlusFunction {
    public static final ThreadLocal<AtomicInteger> INSTANCE_COUNT =
        ThreadLocal.withInitial(AtomicInteger::new);

    // Note: Not marked @Deterministic
    public MyPlusFunction() {
      INSTANCE_COUNT.get().incrementAndGet();
    }

    public int eval(@Parameter(name = "x") int x,
        @Parameter(name = "y") int y) {
      return x + y;
    }
  }

  /** As {@link MyPlusFunction} but constructor has a
   * {@link org.apache.calcite.schema.FunctionContext} parameter. */
  public static class MyPlusInitFunction {
    public static final ThreadLocal<AtomicInteger> INSTANCE_COUNT =
        ThreadLocal.withInitial(AtomicInteger::new);
    public static final ThreadLocal<String> THREAD_DIGEST =
        new ThreadLocal<>();

    private final int initY;

    public MyPlusInitFunction(FunctionContext fx) {
      INSTANCE_COUNT.get().incrementAndGet();
      final StringBuilder b = new StringBuilder();
      final int parameterCount = fx.getParameterCount();
      b.append("parameterCount=").append(parameterCount);
      for (int i = 0; i < parameterCount; i++) {
        b.append("; argument ").append(i);
        if (fx.isArgumentConstant(i)) {
          b.append(" is constant and has value ")
              .append(fx.getArgumentValueAs(i, String.class));
        } else {
          b.append(" is not constant");
        }
      }
      THREAD_DIGEST.set(b.toString());
      this.initY = fx.isArgumentConstant(1)
          ? fx.getArgumentValueAs(1, Integer.class)
          : 100;
    }

    public int eval(@Parameter(name = "x") int x,
        @Parameter(name = "y") int y) {
      return x + initY;
    }
  }

  /** As {@link MyPlusFunction} but declared to be deterministic. */
  public static class MyDeterministicPlusFunction {
    public static final ThreadLocal<AtomicInteger> INSTANCE_COUNT =
        ThreadLocal.withInitial(AtomicInteger::new);

    @Deterministic public MyDeterministicPlusFunction() {
      INSTANCE_COUNT.get().incrementAndGet();
    }

    public Integer eval(@Parameter(name = "x") Integer x,
        @Parameter(name = "y") Integer y) {
      if (x == null || y == null) {
        return null;
      }
      return x + y;
    }
  }

  /** Example of a UDF with named parameters. */
  public static class MyLeftFunction {
    public String eval(@Parameter(name = "s") String s,
        @Parameter(name = "n") int n) {
      return s.substring(0, n);
    }
  }

  /** Example of a UDF with named parameters, some of them optional. */
  public static class MyAbcdeFunction {
    public String eval(@Parameter(name = "A", optional = false) Integer a,
        @Parameter(name = "B", optional = true) Integer b,
        @Parameter(name = "C", optional = false) Integer c,
        @Parameter(name = "D", optional = true) Integer d,
        @Parameter(name = "E", optional = true) Integer e) {
      return "{a: " + a + ", b: " + b +  ", c: " + c +  ", d: " + d  + ", e: "
          + e + "}";
    }
  }

  /** Example of a non-strict UDF. (Does something useful when passed NULL.) */
  public static class MyToStringFunction {
    public static String eval(@Parameter(name = "o") Object o) {
      if (o == null) {
        return "<null>";
      }
      return "<" + o.toString() + ">";
    }
  }

  /** Example of a semi-strict UDF.
   * (Returns null if its parameter is null or if its length is 4.) */
  public static class Null4Function {
    @SemiStrict public static String eval(@Parameter(name = "s") String s) {
      if (s == null || s.length() == 4) {
        return null;
      }
      return s;
    }
  }

  /** Example of a picky, semi-strict UDF.
   * Throws {@link NullPointerException} if argument is null.
   * Returns null if its argument's length is 8. */
  public static class Null8Function {
    @SemiStrict public static String eval(@Parameter(name = "s") String s) {
      if (s.length() == 8) {
        return null;
      }
      return s;
    }
  }

  /** Example of a UDF with a static {@code eval} method. Class is abstract,
   * but code-generator should not need to instantiate it. */
  public abstract static class MyDoubleFunction {
    private MyDoubleFunction() {
    }

    public static int eval(int x) {
      return x * 2;
    }
  }

  /** Example of a UDF with non-default constructor.
   *
   * <p>Not used; we do not currently have a way to instantiate function
   * objects other than via their default constructor. */
  public static class FibonacciTableFunction {
    private final int limit;

    public FibonacciTableFunction(int limit) {
      this.limit = limit;
    }

    public ScannableTable eval() {
      return fibonacciTableWithLimit(limit);
    }
  }

  /** User-defined function with two arguments. */
  public static class MyIncrement {
    public float eval(int x, int y) {
      return x + x * y / 100;
    }
  }

  /** User-defined function that declares exceptions. */
  public static class MyExceptionFunction {
    public MyExceptionFunction() {}

    public static int eval(int x) throws IllegalArgumentException, IOException {
      if (x < 0) {
        throw new IllegalArgumentException("Illegal argument: " + x);
      } else if (x > 100) {
        throw new IOException("IOException when argument > 100");
      }
      return x + 10;
    }
  }

  /** User-defined function with niladic parentheses. */
  public static class MyNiladicParenthesesFunction {
    // This is a constant function that tests for niladic parentheses,
    // and it returns the constant value foo
    public String eval() {
      return "foo";
    }
  }

  /** Example of a UDF that has overloaded UDFs (same name, different args). */
  public abstract static class CountArgs0Function {
    private CountArgs0Function() {}

    public static int eval() {
      return 0;
    }
  }

  /** See {@link CountArgs0Function}. */
  public abstract static class CountArgs1Function {
    private CountArgs1Function() {}

    public static int eval(int x) {
      return 1;
    }
  }

  /** See {@link CountArgs0Function}. */
  public abstract static class CountArgs1NullableFunction {
    private CountArgs1NullableFunction() {}

    public static int eval(Short x) {
      return -1;
    }
  }

  /** See {@link CountArgs0Function}. */
  public abstract static class CountArgs2Function {
    private CountArgs2Function() {}

    public static int eval(int x, int y) {
      return 2;
    }
  }

  /** Example of a UDF class that needs to be instantiated but cannot be. */
  public abstract static class AwkwardFunction {
    private AwkwardFunction() {
    }

    public int eval(int x) {
      return 0;
    }
  }

  /** UDF class that has multiple methods, some overloaded. */
  public static class MultipleFunction {
    private MultipleFunction() {}

    // Three overloads
    public static String fun1(String x) {
      return x.toLowerCase(Locale.ROOT);
    }
    public static int fun1(int x) {
      return x * 2;
    }
    public static int fun1(int x, int y) {
      return x + y;
    }

    // Another method
    public static int fun2(int x) {
      return x * 3;
    }

    // Non-static method cannot be used because constructor is private
    public int nonStatic(int x) {
      return x * 3;
    }
  }

  /** UDF class that provides user-defined functions for each data type. */
  @Deterministic
  public static class AllTypesFunction {
    private AllTypesFunction() {}

    // We use SqlFunctions.toLong(Date) ratter than Date.getTime(),
    // and SqlFunctions.internalToTimestamp(long) rather than new Date(long),
    // because the contract of JDBC (also used by UDFs) is to represent
    // date-time values in the LOCAL time zone.

    public static long dateFun(java.sql.Date v) {
      return v == null ? -1L : SqlFunctions.toLong(v);
    }
    public static long timestampFun(java.sql.Timestamp v) {
      return v == null ? -1L : SqlFunctions.toLong(v);
    }
    public static long timeFun(java.sql.Time v) {
      return v == null ? -1L : SqlFunctions.toLong(v);
    }

    /** Overloaded, in a challenging way, with {@link #toDateFun(Long)}. */
    public static java.sql.Date toDateFun(int v) {
      return SqlFunctions.internalToDate(v);
    }

    public static java.sql.Date toDateFun(Long v) {
      return v == null ? null : SqlFunctions.internalToDate(v.intValue());
    }
    public static java.sql.Timestamp toTimestampFun(Long v) {
      return SqlFunctions.internalToTimestamp(v);
    }
    public static java.sql.Time toTimeFun(Long v) {
      return v == null ? null : SqlFunctions.internalToTime(v.intValue());
    }

    /** For overloaded user-defined functions that have {@code double} and
     * {@code BigDecimal} arguments will go wrong. */
    public static double toDouble(BigDecimal var) {
      return var == null ? 0.0d : var.doubleValue();
    }
    public static double toDouble(Double var) {
      return var == null ? 0.0d : var;
    }
    public static double toDouble(Float var) {
      return var == null ? 0.0d : Double.valueOf(var.toString());
    }

    public static List arrayAppendFun(List v, Integer i) {
      if (v == null || i == null) {
        return null;
      } else {
        v.add(i);
        return v;
      }
    }

    /** Overloaded functions with DATE, TIMESTAMP and TIME arguments. */
    public static long toLong(Date date) {
      return date == null ? 0 : SqlFunctions.toLong(date);
    }

    public static long toLong(Timestamp timestamp) {
      return timestamp == null ? 0 : SqlFunctions.toLong(timestamp);
    }

    public static long toLong(Time time) {
      return time == null ? 0 : SqlFunctions.toLong(time);
    }

  }

  /** Example of a user-defined aggregate function (UDAF). */
  public static class MySumFunction {
    public MySumFunction() {
    }
    public long init() {
      return 0L;
    }
    public long add(long accumulator, int v) {
      return accumulator + v;
    }
    public long merge(long accumulator0, long accumulator1) {
      return accumulator0 + accumulator1;
    }
    public long result(long accumulator) {
      return accumulator;
    }
  }

  /** A generic interface for defining user-defined aggregate functions.
   *
   * @param <A> accumulator type
   * @param <V> value type
   * @param <R> result type */
  private interface MyGenericAggFunction<A, V, R> {
    A init();

    A add(A accumulator, V val);

    A merge(A accumulator1, A accumulator2);

    R result(A accumulator);
  }

  /** Example of a user-defined aggregate function that implements a generic
   * interface. */
  public static class MySum3
      implements MyGenericAggFunction<Integer, Integer, Integer> {
    @Override public Integer init() {
      return 0;
    }

    @Override public Integer add(Integer accumulator, Integer val) {
      return accumulator + val;
    }

    @Override public Integer merge(Integer accumulator1, Integer accumulator2) {
      return accumulator1 + accumulator2;
    }

    @Override public Integer result(Integer accumulator) {
      return accumulator;
    }
  }

  /** Example of a user-defined aggregate function (UDAF), whose methods are
   * static. */
  public static class MyStaticSumFunction {
    public static long init() {
      return 0L;
    }
    public static long add(long accumulator, int v) {
      return accumulator + v;
    }
    public static long merge(long accumulator0, long accumulator1) {
      return accumulator0 + accumulator1;
    }
    public static long result(long accumulator) {
      return accumulator;
    }
  }

  /** Example of a user-defined aggregate function (UDAF) with two parameters.
   * The constructor has an initialization parameter. */
  public static class MyTwoParamsSumFunctionFilter1 {
    public MyTwoParamsSumFunctionFilter1(FunctionContext fx) {
      requireNonNull(fx, "fx");
      assert fx.getParameterCount() == 2;
    }
    public int init() {
      return 0;
    }
    public int add(int accumulator, int v1, int v2) {
      if (v1 > v2) {
        return accumulator + v1;
      }
      return accumulator;
    }
    public int merge(int accumulator0, int accumulator1) {
      return accumulator0 + accumulator1;
    }
    public int result(int accumulator) {
      return accumulator;
    }
  }

  /** Another example of a user-defined aggregate function (UDAF) with two
   * parameters. */
  public static class MyTwoParamsSumFunctionFilter2 {
    public MyTwoParamsSumFunctionFilter2() {
    }
    public long init() {
      return 0L;
    }
    public long add(long accumulator, int v1, String v2) {
      if (v2.equals("Eric")) {
        return accumulator + v1;
      }
      return accumulator;
    }
    public long merge(long accumulator0, long accumulator1) {
      return accumulator0 + accumulator1;
    }
    public long result(long accumulator) {
      return accumulator;
    }
  }

  /** Example of a user-defined aggregate function (UDAF), whose methods are
   * static. */
  public static class MyThreeParamsSumFunctionWithFilter1 {
    public static long init() {
      return 0L;
    }
    public static long add(long accumulator, int v1, String v2, String v3) {
      if (v2.equals(v3)) {
        return accumulator + v1;
      }
      return accumulator;
    }
    public static long merge(long accumulator0, long accumulator1) {
      return accumulator0 + accumulator1;
    }
    public static long result(long accumulator) {
      return accumulator;
    }
  }

  /** Example of a user-defined aggregate function (UDAF), whose methods are
   * static. Similar to {@link MyThreeParamsSumFunctionWithFilter1}, but
   * argument types are different. */
  public static class MyThreeParamsSumFunctionWithFilter2 {
    public static long init() {
      return 0L;
    }
    public static long add(long accumulator, int v1, int v2, int v3) {
      if (v3 > 250) {
        return accumulator + v1 + v2;
      }
      return accumulator;
    }
    public static long merge(long accumulator0, long accumulator1) {
      return accumulator0 + accumulator1;
    }
    public static long result(long accumulator) {
      return accumulator;
    }
  }

  /** User-defined function. */
  public static class SumFunctionBadIAdd {
    public long init() {
      return 0L;
    }
    public long add(short accumulator, int v) {
      return Math.addExact(accumulator, v);
    }
  }

  /** User-defined table-macro function. */
  public static class TableMacroFunction {
    public TranslatableTable eval(String s) {
      return view(s);
    }
  }

  /** User-defined table-macro function whose eval method is static. */
  public static class StaticTableMacroFunction {
    public static TranslatableTable eval(String s) {
      return view(s);
    }
  }

  /** User-defined table-macro function with named and optional parameters. */
  public static class TableMacroFunctionWithNamedParameters {
    public TranslatableTable eval(
        @Parameter(name = "R", optional = true) String r,
        @Parameter(name = "S") String s,
        @Parameter(name = "T", optional = true) Integer t) {
      final StringBuilder sb = new StringBuilder();
      abc(sb, r);
      abc(sb, s);
      abc(sb, t);
      return view(sb.toString());
    }

    private static void abc(StringBuilder sb, Object s) {
      if (s != null) {
        if (sb.length() > 0) {
          sb.append(", ");
        }
        sb.append('(').append(s).append(')');
      }
    }
  }

  /** User-defined table-macro function with named and optional parameters. */
  public static class AnotherTableMacroFunctionWithNamedParameters {
    public TranslatableTable eval(
        @Parameter(name = "R", optional = true) String r,
        @Parameter(name = "S") String s,
        @Parameter(name = "T", optional = true) Integer t,
        @Parameter(name = "S2", optional = true) String s2) {
      final StringBuilder sb = new StringBuilder();
      abc(sb, r);
      abc(sb, s);
      abc(sb, t);
      return view(sb.toString());
    }

    private static void abc(StringBuilder sb, Object s) {
      if (s != null) {
        if (sb.length() > 0) {
          sb.append(", ");
        }
        sb.append('(').append(s).append(')');
      }
    }
  }

  /** A table function that returns a {@link QueryableTable}. */
  public static class SimpleTableFunction {
    public QueryableTable eval(Integer s) {
      return generateStrings(s);
    }
  }

  /** A table function that returns a {@link QueryableTable}. */
  public static class MyTableFunction {
    public QueryableTable eval(String s) {
      return oneThreePlus(s);
    }
  }

  /** A table function that returns a {@link QueryableTable} via a
   * static method. */
  public static class TestStaticTableFunction {
    public static QueryableTable eval(String s) {
      return oneThreePlus(s);
    }
  }

  /** A table function that returns its input value. */
  public static class IdentityTableFunction {
    public static QueryableTable eval(Integer i) {
      return identity(i);
    }
  }

  /** The real MazeTable may be found in example/function. This is a cut-down
   * version to support a test. */
  public static class MazeTable extends AbstractTable
      implements ScannableTable {

    private final String content;

    public MazeTable(String content) {
      this.content = content;
    }

    public static ScannableTable generate(int width, int height, int seed) {
      return new MazeTable(
          String.format(Locale.ROOT, "generate(w=%d, h=%d, s=%d)", width,
              height, seed));
    }

    public static ScannableTable generate2(
        @Parameter(name = "WIDTH") int width,
        @Parameter(name = "HEIGHT") int height,
        @Parameter(name = "SEED", optional = true) Integer seed) {
      return new MazeTable(
          String.format(Locale.ROOT, "generate2(w=%d, h=%d, s=%d)", width,
              height, seed));
    }

    public static ScannableTable generate3(
        @Parameter(name = "FOO") String foo) {
      return new MazeTable(
          String.format(Locale.ROOT, "generate3(foo=%s)", foo));
    }

    @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
      return typeFactory.builder()
          .add("S", SqlTypeName.VARCHAR, 12)
          .build();
    }

    @Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
      Object[][] rows = {{"abcde"}, {"xyz"}, {content}};
      return Linq4j.asEnumerable(rows);
    }
  }

  /** Schema containing a {@code prod} table with a lot of columns. */
  public static class WideSaleSchema {
    @Override public String toString() {
      return "WideSaleSchema";
    }

    @SuppressWarnings("unused")
    public final WideProductSale[] prod = {
        new WideProductSale(100, 10)
    };
  }

  /** Table with a lot of columns. */
  @SuppressWarnings("unused")
  public static class WideProductSale {
    public final int prodId;
    public final double sale0;
    public final double sale1 = 10;
    public final double sale2 = 10;
    public final double sale3 = 10;
    public final double sale4 = 10;
    public final double sale5 = 10;
    public final double sale6 = 10;
    public final double sale7 = 10;
    public final double sale8 = 10;
    public final double sale9 = 10;
    public final double sale10 = 10;
    public final double sale11 = 10;
    public final double sale12 = 10;
    public final double sale13 = 10;
    public final double sale14 = 10;
    public final double sale15 = 10;
    public final double sale16 = 10;
    public final double sale17 = 10;
    public final double sale18 = 10;
    public final double sale19 = 10;
    public final double sale20 = 10;
    public final double sale21 = 10;
    public final double sale22 = 10;
    public final double sale23 = 10;
    public final double sale24 = 10;
    public final double sale25 = 10;
    public final double sale26 = 10;
    public final double sale27 = 10;
    public final double sale28 = 10;
    public final double sale29 = 10;
    public final double sale30 = 10;
    public final double sale31 = 10;
    public final double sale32 = 10;
    public final double sale33 = 10;
    public final double sale34 = 10;
    public final double sale35 = 10;
    public final double sale36 = 10;
    public final double sale37 = 10;
    public final double sale38 = 10;
    public final double sale39 = 10;
    public final double sale40 = 10;
    public final double sale41 = 10;
    public final double sale42 = 10;
    public final double sale43 = 10;
    public final double sale44 = 10;
    public final double sale45 = 10;
    public final double sale46 = 10;
    public final double sale47 = 10;
    public final double sale48 = 10;
    public final double sale49 = 10;
    public final double sale50 = 10;
    public final double sale51 = 10;
    public final double sale52 = 10;
    public final double sale53 = 10;
    public final double sale54 = 10;
    public final double sale55 = 10;
    public final double sale56 = 10;
    public final double sale57 = 10;
    public final double sale58 = 10;
    public final double sale59 = 10;
    public final double sale60 = 10;
    public final double sale61 = 10;
    public final double sale62 = 10;
    public final double sale63 = 10;
    public final double sale64 = 10;
    public final double sale65 = 10;
    public final double sale66 = 10;
    public final double sale67 = 10;
    public final double sale68 = 10;
    public final double sale69 = 10;
    public final double sale70 = 10;
    public final double sale71 = 10;
    public final double sale72 = 10;
    public final double sale73 = 10;
    public final double sale74 = 10;
    public final double sale75 = 10;
    public final double sale76 = 10;
    public final double sale77 = 10;
    public final double sale78 = 10;
    public final double sale79 = 10;
    public final double sale80 = 10;
    public final double sale81 = 10;
    public final double sale82 = 10;
    public final double sale83 = 10;
    public final double sale84 = 10;
    public final double sale85 = 10;
    public final double sale86 = 10;
    public final double sale87 = 10;
    public final double sale88 = 10;
    public final double sale89 = 10;
    public final double sale90 = 10;
    public final double sale91 = 10;
    public final double sale92 = 10;
    public final double sale93 = 10;
    public final double sale94 = 10;
    public final double sale95 = 10;
    public final double sale96 = 10;
    public final double sale97 = 10;
    public final double sale98 = 10;
    public final double sale99 = 10;
    public final double sale100 = 10;
    public final double sale101 = 10;
    public final double sale102 = 10;
    public final double sale103 = 10;
    public final double sale104 = 10;
    public final double sale105 = 10;
    public final double sale106 = 10;
    public final double sale107 = 10;
    public final double sale108 = 10;
    public final double sale109 = 10;
    public final double sale110 = 10;
    public final double sale111 = 10;
    public final double sale112 = 10;
    public final double sale113 = 10;
    public final double sale114 = 10;
    public final double sale115 = 10;
    public final double sale116 = 10;
    public final double sale117 = 10;
    public final double sale118 = 10;
    public final double sale119 = 10;
    public final double sale120 = 10;
    public final double sale121 = 10;
    public final double sale122 = 10;
    public final double sale123 = 10;
    public final double sale124 = 10;
    public final double sale125 = 10;
    public final double sale126 = 10;
    public final double sale127 = 10;
    public final double sale128 = 10;
    public final double sale129 = 10;
    public final double sale130 = 10;
    public final double sale131 = 10;
    public final double sale132 = 10;
    public final double sale133 = 10;
    public final double sale134 = 10;
    public final double sale135 = 10;
    public final double sale136 = 10;
    public final double sale137 = 10;
    public final double sale138 = 10;
    public final double sale139 = 10;
    public final double sale140 = 10;
    public final double sale141 = 10;
    public final double sale142 = 10;
    public final double sale143 = 10;
    public final double sale144 = 10;
    public final double sale145 = 10;
    public final double sale146 = 10;
    public final double sale147 = 10;
    public final double sale148 = 10;
    public final double sale149 = 10;
    public final double sale150 = 10;
    public final double sale151 = 10;
    public final double sale152 = 10;
    public final double sale153 = 10;
    public final double sale154 = 10;
    public final double sale155 = 10;
    public final double sale156 = 10;
    public final double sale157 = 10;
    public final double sale158 = 10;
    public final double sale159 = 10;
    public final double sale160 = 10;
    public final double sale161 = 10;
    public final double sale162 = 10;
    public final double sale163 = 10;
    public final double sale164 = 10;
    public final double sale165 = 10;
    public final double sale166 = 10;
    public final double sale167 = 10;
    public final double sale168 = 10;
    public final double sale169 = 10;
    public final double sale170 = 10;
    public final double sale171 = 10;
    public final double sale172 = 10;
    public final double sale173 = 10;
    public final double sale174 = 10;
    public final double sale175 = 10;
    public final double sale176 = 10;
    public final double sale177 = 10;
    public final double sale178 = 10;
    public final double sale179 = 10;
    public final double sale180 = 10;
    public final double sale181 = 10;
    public final double sale182 = 10;
    public final double sale183 = 10;
    public final double sale184 = 10;
    public final double sale185 = 10;
    public final double sale186 = 10;
    public final double sale187 = 10;
    public final double sale188 = 10;
    public final double sale189 = 10;
    public final double sale190 = 10;
    public final double sale191 = 10;
    public final double sale192 = 10;
    public final double sale193 = 10;
    public final double sale194 = 10;
    public final double sale195 = 10;
    public final double sale196 = 10;
    public final double sale197 = 10;
    public final double sale198 = 10;
    public final double sale199 = 10;

    public WideProductSale(int prodId, double sale) {
      this.prodId = prodId;
      this.sale0 = sale;
    }
  }

  /**
   * Implementation of {@link TableMacro} interface with
   * {@link #apply} method that returns {@link Queryable} table.
   */
  public static class SimpleTableMacro implements TableMacro {

    @Override public TranslatableTable apply(List<?> arguments) {
      return new SimpleTable();
    }

    @Override public List<FunctionParameter> getParameters() {
      return Collections.emptyList();
    }
  }

  /** Table with columns (A, B). */
  public static class SimpleTable extends AbstractQueryableTable
      implements TranslatableTable {
    private final String[] columnNames = { "A", "B" };
    private final Class<?>[] columnTypes = { String.class, Integer.class };
    private final Object[][] rows = new Object[3][];

    public SimpleTable() {
      super(Object[].class);

      rows[0] = new Object[] { "foo", 5 };
      rows[1] = new Object[] { "bar", 4 };
      rows[2] = new Object[] { "foo", 3 };
    }

    @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
      int columnCount = columnNames.length;
      final PairList<String, RelDataType> columnDesc =
          PairList.withCapacity(columnCount);
      for (int i = 0; i < columnCount; i++) {
        final RelDataType colType = typeFactory
            .createJavaType(columnTypes[i]);
        columnDesc.add(columnNames[i], colType);
      }
      return typeFactory.createStructType(columnDesc);
    }

    public Iterator<Object[]> iterator() {
      return Linq4j.enumeratorIterator(enumerator());
    }

    public Enumerator<Object[]> enumerator() {
      return enumeratorImpl(null);
    }

    @Override public <T> Queryable<T> asQueryable(QueryProvider queryProvider,
        SchemaPlus schema, String tableName) {
      return new AbstractTableQueryable<T>(queryProvider, schema, this,
          tableName) {
        @Override public Enumerator<T> enumerator() {
          //noinspection unchecked
          return (Enumerator<T>) enumeratorImpl(null);
        }
      };
    }

    private Enumerator<Object[]> enumeratorImpl(final int[] fields) {
      return new Enumerator<Object[]>() {
        private Object[] current;
        private final Iterator<Object[]> iterator = Arrays.asList(rows)
            .iterator();

        @Override public Object[] current() {
          return current;
        }

        @Override public boolean moveNext() {
          if (iterator.hasNext()) {
            Object[] full = iterator.next();
            current = fields != null ? convertRow(full) : full;
            return true;
          } else {
            current = null;
            return false;
          }
        }

        @Override public void reset() {
          throw new UnsupportedOperationException();
        }

        @Override public void close() {
          // noop
        }

        private Object[] convertRow(Object[] full) {
          final Object[] objects = new Object[fields.length];
          for (int i = 0; i < fields.length; i++) {
            objects[i] = full[fields[i]];
          }
          return objects;
        }
      };
    }

    @Override public RelNode toRel(
        RelOptTable.ToRelContext context,
        RelOptTable relOptTable) {
      return EnumerableTableScan.create(context.getCluster(), relOptTable);
    }

    @Override public Expression getExpression(SchemaPlus schema, String tableName, Class clazz) {
      MethodCallExpression queryableExpression =
          Expressions.call(Expressions.new_(SimpleTable.class),
              BuiltInMethod.QUERYABLE_TABLE_AS_QUERYABLE.method,
              Expressions.constant(null),
              Schemas.expression(schema),
              Expressions.constant(tableName));
      return Expressions.call(queryableExpression,
          BuiltInMethod.QUERYABLE_AS_ENUMERABLE.method);
    }
  }

  /** User-defined function that decodes a Base64 string to bytes. */
  public static class MyUnbase64Function {
    public static ByteString eval(String s) {
      if (s == null) {
        return null;
      }
      try {
        return ByteString.ofBase64(s);
      } catch (Exception e) {
        return null;
      }
    }
  }
}