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

org.apache.calcite.sql.test.SqlTester 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 org.apache.calcite.sql.test;

import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelRoot;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.StringAndPos;
import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.test.DiffRepository;
import org.apache.calcite.util.Pair;

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

import java.sql.ResultSet;
import java.util.function.Consumer;

import static java.util.Objects.requireNonNull;

/**
 * Callback for testing SQL queries and expressions.
 *
 * 

The idea is that when you define an operator (or another piece of SQL * functionality), you can define the logical behavior of that operator once, as * part of that operator. Later you can define one or more physical * implementations of that operator, and test them all using the same set of * tests. * *

Specific implementations of SqlTester might evaluate the * queries in different ways, for example, using a C++ versus Java calculator. * An implementation might even ignore certain calls altogether. */ public interface SqlTester extends AutoCloseable { //~ Enums ------------------------------------------------------------------ /** * Name of a virtual machine that can potentially implement an operator. */ enum VmName { FENNEL, JAVA, EXPAND } //~ Methods ---------------------------------------------------------------- /** Given a scalar expression, generates a sequence of SQL queries that * evaluate it, and calls a given action with each. * * @param factory Factory * @param expression Scalar expression * @param consumer Action to be called for each query */ void forEachQuery(SqlTestFactory factory, String expression, Consumer consumer); /** Parses a query. */ SqlNode parseQuery(SqlTestFactory factory, String sql) throws SqlParseException; /** Parses an expression. */ SqlNode parseExpression(SqlTestFactory factory, String expr) throws SqlParseException; /** Parses and validates a query, then calls an action on the result. */ void validateAndThen(SqlTestFactory factory, StringAndPos sap, ValidatedNodeConsumer consumer); /** Parses and validates a query, then calls a function on the result. */ R validateAndApply(SqlTestFactory factory, StringAndPos sap, ValidatedNodeFunction function); /** * Checks that a query is valid, or, if invalid, throws the right * message at the right location. * *

If expectedMsgPattern is null, the query must * succeed. * *

If expectedMsgPattern is not null, the query must * fail, and give an error location of (expectedLine, expectedColumn) * through (expectedEndLine, expectedEndColumn). * * @param factory Factory * @param sap SQL statement * @param expectedMsgPattern If this parameter is null the query must be */ void assertExceptionIsThrown(SqlTestFactory factory, StringAndPos sap, @Nullable String expectedMsgPattern); /** * Returns the data type of the sole column of a SQL query. * *

For example, getResultType("VALUES (1") returns * INTEGER. * *

Fails if query returns more than one column. * * @see #getResultType(SqlTestFactory, String) */ RelDataType getColumnType(SqlTestFactory factory, String sql); /** * Returns the data type of the row returned by a SQL query. * *

For example, getResultType("VALUES (1, 'foo')") * returns RecordType(INTEGER EXPR$0, CHAR(3) EXPR#1). */ RelDataType getResultType(SqlTestFactory factory, String sql); /** * Checks that a query returns one column of an expected type. For example, * checkType("VALUES (1 + 2)", "INTEGER NOT NULL"). * * @param factory Factory * @param sql Query expression * @param type Type string */ void checkColumnType(SqlTestFactory factory, String sql, String type); /** * Tests that a SQL query returns a single column with the given type. For * example, * *

*
check("VALUES (1 + 2)", "3", SqlTypeName.Integer);
*
* *

If result is null, the expression must yield the SQL NULL * value. If result is a {@link java.util.regex.Pattern}, the * result must match that pattern. * * @param factory Factory * @param query SQL query * @param typeChecker Checks whether the result is the expected type * @param resultChecker Checks whether the result has the expected value */ default void check(SqlTestFactory factory, String query, TypeChecker typeChecker, ResultChecker resultChecker) { check(factory, query, typeChecker, SqlTests.ANY_PARAMETER_CHECKER, resultChecker); } /** * Tests that a SQL query returns a result of expected type and value. * Checking of type and value are abstracted using {@link TypeChecker} * and {@link ResultChecker} functors. * * @param factory Factory * @param query SQL query * @param typeChecker Checks whether the result is the expected type * @param parameterChecker Checks whether the parameters are of expected * types * @param resultChecker Checks whether the result has the expected value */ void check(SqlTestFactory factory, String query, TypeChecker typeChecker, ParameterChecker parameterChecker, ResultChecker resultChecker); /** * Declares that this test is for a given operator. So we can check that all * operators are tested. * * @param operator Operator * @param unimplementedVmNames Names of virtual machines for which this */ void setFor( SqlOperator operator, VmName... unimplementedVmNames); /** * Checks that an aggregate expression returns the expected result. * *

For example, checkAgg("AVG(DISTINCT x)", new String[] {"2", "3", * null, "3" }, new Double(2.5), 0); * * @param factory Factory * @param expr Aggregate expression, e.g. {@code SUM(DISTINCT x)} * @param inputValues Array of input values, e.g. {@code ["1", null, "2"]} * @param resultChecker Checks whether the result has the expected value */ void checkAgg(SqlTestFactory factory, String expr, String[] inputValues, ResultChecker resultChecker); /** * Checks that a windowed aggregate expression returns the expected result. * *

For example, checkWinAgg("FIRST_VALUE(x)", new String[] {"2", * "3", null, "3" }, "INTEGER NOT NULL", 2, 0d); * * @param factory Factory * @param expr Aggregate expression, e.g. {@code SUM(DISTINCT x)} * @param inputValues Array of input values, e.g. {@code ["1", null, "2"]} * @param type Expected result type * @param resultChecker Checks whether the result has the expected value */ void checkWinAgg(SqlTestFactory factory, String expr, String[] inputValues, String windowSpec, String type, ResultChecker resultChecker); /** * Tests that an aggregate expression fails at run time. * * @param factory Factory * @param expr An aggregate expression * @param inputValues Array of input values * @param expectedError Pattern for expected error * @param runtime If true, must fail at runtime; if false, must fail at * validate time */ void checkAggFails(SqlTestFactory factory, String expr, String[] inputValues, String expectedError, boolean runtime); /** * Tests that a scalar SQL expression fails at run time. * * @param factory Factory * @param expression SQL scalar expression * @param expectedError Pattern for expected error. If !runtime, must * include an error location. * @param runtime If true, must fail at runtime; if false, must fail at * validate time */ void checkFails(SqlTestFactory factory, StringAndPos expression, String expectedError, boolean runtime); /** As {@link #checkFails(SqlTestFactory, StringAndPos, String, boolean)}, * but with a string that contains carets. */ default void checkFails(SqlTestFactory factory, String expression, String expectedError, boolean runtime) { checkFails(factory, StringAndPos.of(expression), expectedError, runtime); } /** * Tests that a SQL query fails at prepare time. * * @param factory Factory * @param sap SQL query and error position * @param expectedError Pattern for expected error. Must * include an error location. */ void checkQueryFails(SqlTestFactory factory, StringAndPos sap, String expectedError); /** * Converts a SQL string to a {@link RelNode} tree. * * @param factory Factory * @param sql SQL statement * @param decorrelate Whether to decorrelate * @param trim Whether to trim * @return Relational expression, never null */ default RelRoot convertSqlToRel(SqlTestFactory factory, String sql, boolean decorrelate, boolean trim) { Pair pair = convertSqlToRel2(factory, sql, decorrelate, trim); return requireNonNull(pair.right); } /** Converts a SQL string to a (SqlValidator, RelNode) pair. */ Pair convertSqlToRel2(SqlTestFactory factory, String sql, boolean decorrelate, boolean trim); /** * Checks that a SQL statement converts to a given plan, optionally * trimming columns that are not needed. * * @param factory Factory * @param diffRepos Diff repository * @param sql SQL query or expression * @param plan Expected plan * @param trim Whether to trim columns that are not needed * @param expression True if {@code sql} is an expression, false if it is a query */ void assertConvertsTo(SqlTestFactory factory, DiffRepository diffRepos, String sql, String plan, boolean trim, boolean expression, boolean decorrelate); /** Trims a RelNode. */ RelNode trimRelNode(SqlTestFactory factory, RelNode relNode); //~ Inner Interfaces ------------------------------------------------------- /** Type checker. */ interface TypeChecker { void checkType(RelDataType type); } /** Parameter checker. */ interface ParameterChecker { void checkParameters(RelDataType parameterRowType); } /** Result checker. */ interface ResultChecker { void checkResult(ResultSet result) throws Exception; } /** Action that is called after validation. * * @see #validateAndThen */ interface ValidatedNodeConsumer { void accept(StringAndPos sap, SqlValidator validator, SqlNode validatedNode); } /** A function to apply to the result of validation. * * @param Result type of the function * * @see AbstractSqlTester#validateAndApply */ interface ValidatedNodeFunction { R apply(StringAndPos sap, SqlValidator validator, SqlNode validatedNode); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy