| /* |
| * 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.test; |
| |
| import org.apache.calcite.config.CalciteConnectionProperty; |
| import org.apache.calcite.jdbc.CalciteConnection; |
| import org.apache.calcite.linq4j.tree.Primitive; |
| import org.apache.calcite.schema.ScannableTable; |
| import org.apache.calcite.schema.SchemaPlus; |
| import org.apache.calcite.schema.Table; |
| import org.apache.calcite.schema.TableFunction; |
| import org.apache.calcite.schema.impl.AbstractSchema; |
| import org.apache.calcite.schema.impl.TableFunctionImpl; |
| import org.apache.calcite.sql.validate.SqlConformanceEnum; |
| import org.apache.calcite.util.Smalls; |
| import org.apache.calcite.util.TestUtil; |
| |
| import org.junit.jupiter.api.Disabled; |
| import org.junit.jupiter.api.Test; |
| |
| import java.sql.Connection; |
| import java.sql.DriverManager; |
| import java.sql.PreparedStatement; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import static org.hamcrest.CoreMatchers.containsString; |
| import static org.hamcrest.CoreMatchers.equalTo; |
| import static org.hamcrest.CoreMatchers.is; |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.junit.jupiter.api.Assertions.fail; |
| |
| /** |
| * Tests for user-defined table functions. |
| * |
| * @see UdfTest |
| * @see Smalls |
| */ |
| class TableFunctionTest { |
| private CalciteAssert.AssertThat with() { |
| final String c = Smalls.class.getName(); |
| final String m = Smalls.MULTIPLICATION_TABLE_METHOD.getName(); |
| final String m2 = Smalls.FIBONACCI_TABLE_METHOD.getName(); |
| final String m3 = Smalls.FIBONACCI_LIMIT_TABLE_METHOD.getName(); |
| return CalciteAssert.model("{\n" |
| + " version: '1.0',\n" |
| + " schemas: [\n" |
| + " {\n" |
| + " name: 's',\n" |
| + " functions: [\n" |
| + " {\n" |
| + " name: 'multiplication',\n" |
| + " className: '" + c + "',\n" |
| + " methodName: '" + m + "'\n" |
| + " }, {\n" |
| + " name: 'fibonacci',\n" |
| + " className: '" + c + "',\n" |
| + " methodName: '" + m2 + "'\n" |
| + " }, {\n" |
| + " name: 'fibonacci2',\n" |
| + " className: '" + c + "',\n" |
| + " methodName: '" + m3 + "'\n" |
| + " }\n" |
| + " ]\n" |
| + " }\n" |
| + " ]\n" |
| + "}") |
| .withDefaultSchema("s"); |
| } |
| |
| /** |
| * Tests a table function with literal arguments. |
| */ |
| @Test void testTableFunction() throws SQLException { |
| try (Connection connection = DriverManager.getConnection("jdbc:calcite:")) { |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.add("s", new AbstractSchema()); |
| final TableFunction table = |
| TableFunctionImpl.create(Smalls.GENERATE_STRINGS_METHOD); |
| schema.add("GenerateStrings", table); |
| final String sql = "select *\n" |
| + "from table(\"s\".\"GenerateStrings\"(5)) as t(n, c)\n" |
| + "where char_length(c) > 3"; |
| ResultSet resultSet = connection.createStatement().executeQuery(sql); |
| assertThat(CalciteAssert.toString(resultSet), |
| equalTo("N=4; C=abcd\n")); |
| } |
| } |
| |
| /** |
| * Tests correlated subquery with 2 identical params is being processed correctly. |
| */ |
| @Test void testInterpretFunctionWithInitializer() throws SQLException { |
| try (Connection connection = DriverManager.getConnection("jdbc:calcite:")) { |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.add("s", new AbstractSchema()); |
| final TableFunction table = |
| TableFunctionImpl.create(Smalls.DUMMY_TABLE_METHOD_WITH_TWO_PARAMS); |
| final String callMethodName = Smalls.DUMMY_TABLE_METHOD_WITH_TWO_PARAMS.getName(); |
| schema.add(callMethodName, table); |
| final String sql = "select x, (select * from table (\"s\".\"" + callMethodName + "\"(x, x))) " |
| + "from (values (2), (4)) as t (x)"; |
| ResultSet resultSet = connection.createStatement().executeQuery(sql); |
| assertThat(CalciteAssert.toString(resultSet), |
| equalTo("X=2; EXPR$1=null\nX=4; EXPR$1=null\n")); |
| } |
| } |
| |
| @Test void testTableFunctionWithArrayParameter() throws SQLException { |
| try (Connection connection = DriverManager.getConnection("jdbc:calcite:")) { |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.add("s", new AbstractSchema()); |
| final TableFunction table = |
| TableFunctionImpl.create(Smalls.GENERATE_STRINGS_OF_INPUT_SIZE_METHOD); |
| schema.add("GenerateStringsOfInputSize", table); |
| final String sql = "select *\n" |
| + "from table(\"s\".\"GenerateStringsOfInputSize\"(ARRAY[5,4,3,1,2])) as t(n, c)\n" |
| + "where char_length(c) > 3"; |
| ResultSet resultSet = connection.createStatement().executeQuery(sql); |
| assertThat(CalciteAssert.toString(resultSet), |
| equalTo("N=4; C=abcd\n")); |
| } |
| } |
| |
| @Test void testTableFunctionWithMapParameter() throws SQLException { |
| try (Connection connection = DriverManager.getConnection("jdbc:calcite:")) { |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.add("s", new AbstractSchema()); |
| final TableFunction table = |
| TableFunctionImpl.create(Smalls.GENERATE_STRINGS_OF_INPUT_MAP_SIZE_METHOD); |
| schema.add("GenerateStringsOfInputMapSize", table); |
| final String sql = "select *\n" |
| + "from table(\"s\".\"GenerateStringsOfInputMapSize\"(Map[5,4,3,1])) as t(n, c)\n" |
| + "where char_length(c) > 0"; |
| ResultSet resultSet = connection.createStatement().executeQuery(sql); |
| assertThat(CalciteAssert.toString(resultSet), |
| equalTo("N=1; C=a\n")); |
| } |
| } |
| |
| /** |
| * Tests a table function that implements {@link ScannableTable} and returns |
| * a single column. |
| */ |
| @Test void testScannableTableFunction() throws SQLException { |
| Connection connection = DriverManager.getConnection("jdbc:calcite:"); |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.add("s", new AbstractSchema()); |
| final TableFunction table = TableFunctionImpl.create(Smalls.MAZE_METHOD); |
| schema.add("Maze", table); |
| final String sql = "select *\n" |
| + "from table(\"s\".\"Maze\"(5, 3, 1))"; |
| ResultSet resultSet = connection.createStatement().executeQuery(sql); |
| final String result = "S=abcde\n" |
| + "S=xyz\n" |
| + "S=generate(w=5, h=3, s=1)\n"; |
| assertThat(CalciteAssert.toString(resultSet), is(result)); |
| } |
| |
| /** As {@link #testScannableTableFunction()} but with named parameters. */ |
| @Test void testScannableTableFunctionWithNamedParameters() |
| throws SQLException { |
| Connection connection = DriverManager.getConnection("jdbc:calcite:"); |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.add("s", new AbstractSchema()); |
| final TableFunction table = TableFunctionImpl.create(Smalls.MAZE2_METHOD); |
| schema.add("Maze", table); |
| final String sql = "select *\n" |
| + "from table(\"s\".\"Maze\"(5, 3, 1))"; |
| final Statement statement = connection.createStatement(); |
| ResultSet resultSet = statement.executeQuery(sql); |
| final String result = "S=abcde\n" |
| + "S=xyz\n"; |
| assertThat(CalciteAssert.toString(resultSet), |
| is(result + "S=generate2(w=5, h=3, s=1)\n")); |
| |
| final String sql2 = "select *\n" |
| + "from table(\"s\".\"Maze\"(WIDTH => 5, HEIGHT => 3, SEED => 1))"; |
| resultSet = statement.executeQuery(sql2); |
| assertThat(CalciteAssert.toString(resultSet), |
| is(result + "S=generate2(w=5, h=3, s=1)\n")); |
| |
| final String sql3 = "select *\n" |
| + "from table(\"s\".\"Maze\"(HEIGHT => 3, WIDTH => 5))"; |
| resultSet = statement.executeQuery(sql3); |
| assertThat(CalciteAssert.toString(resultSet), |
| is(result + "S=generate2(w=5, h=3, s=null)\n")); |
| connection.close(); |
| } |
| |
| /** As {@link #testScannableTableFunction()} but with named parameters. */ |
| @Test void testMultipleScannableTableFunctionWithNamedParameters() |
| throws SQLException { |
| try (Connection connection = DriverManager.getConnection("jdbc:calcite:"); |
| Statement statement = connection.createStatement()) { |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.add("s", new AbstractSchema()); |
| final TableFunction table1 = TableFunctionImpl.create(Smalls.MAZE_METHOD); |
| schema.add("Maze", table1); |
| final TableFunction table2 = TableFunctionImpl.create(Smalls.MAZE2_METHOD); |
| schema.add("Maze", table2); |
| final TableFunction table3 = TableFunctionImpl.create(Smalls.MAZE3_METHOD); |
| schema.add("Maze", table3); |
| final String sql = "select *\n" |
| + "from table(\"s\".\"Maze\"(5, 3, 1))"; |
| ResultSet resultSet = statement.executeQuery(sql); |
| final String result = "S=abcde\n" |
| + "S=xyz\n"; |
| assertThat(CalciteAssert.toString(resultSet), |
| is(result + "S=generate(w=5, h=3, s=1)\n")); |
| |
| final String sql2 = "select *\n" |
| + "from table(\"s\".\"Maze\"(WIDTH => 5, HEIGHT => 3, SEED => 1))"; |
| resultSet = statement.executeQuery(sql2); |
| assertThat(CalciteAssert.toString(resultSet), |
| is(result + "S=generate2(w=5, h=3, s=1)\n")); |
| |
| final String sql3 = "select *\n" |
| + "from table(\"s\".\"Maze\"(HEIGHT => 3, WIDTH => 5))"; |
| resultSet = statement.executeQuery(sql3); |
| assertThat(CalciteAssert.toString(resultSet), |
| is(result + "S=generate2(w=5, h=3, s=null)\n")); |
| |
| final String sql4 = "select *\n" |
| + "from table(\"s\".\"Maze\"(FOO => 'a'))"; |
| resultSet = statement.executeQuery(sql4); |
| assertThat(CalciteAssert.toString(resultSet), |
| is(result + "S=generate3(foo=a)\n")); |
| } |
| } |
| |
| /** |
| * Tests a table function that returns different row type based on |
| * actual call arguments. |
| */ |
| @Test void testTableFunctionDynamicStructure() throws SQLException { |
| Connection connection = getConnectionWithMultiplyFunction(); |
| final PreparedStatement ps = connection.prepareStatement("select *\n" |
| + "from table(\"s\".\"multiplication\"(4, 3, ?))\n"); |
| ps.setInt(1, 100); |
| ResultSet resultSet = ps.executeQuery(); |
| assertThat(CalciteAssert.toString(resultSet), |
| equalTo("row_name=row 0; c1=101; c2=102; c3=103; c4=104\n" |
| + "row_name=row 1; c1=102; c2=104; c3=106; c4=108\n" |
| + "row_name=row 2; c1=103; c2=106; c3=109; c4=112\n")); |
| } |
| |
| /** |
| * Tests that non-nullable arguments of a table function must be provided |
| * as literals. |
| */ |
| @Disabled("SQLException does not include message from nested exception") |
| @Test void testTableFunctionNonNullableMustBeLiterals() |
| throws SQLException { |
| Connection connection = getConnectionWithMultiplyFunction(); |
| try { |
| final PreparedStatement ps = connection.prepareStatement("select *\n" |
| + "from table(\"s\".\"multiplication\"(?, 3, 100))\n"); |
| ps.setInt(1, 100); |
| ResultSet resultSet = ps.executeQuery(); |
| fail("Should fail, got " + resultSet); |
| } catch (SQLException e) { |
| assertThat(e.getMessage(), |
| containsString("Wrong arguments for table function 'public static " |
| + "org.apache.calcite.schema.QueryableTable " |
| + "org.apache.calcite.test.JdbcTest" |
| + ".multiplicationTable(int,int,java.lang.Integer)'" |
| + " call. Expected '[int, int, class" |
| + "java.lang.Integer]', actual '[null, 3, 100]'")); |
| } |
| } |
| |
| private Connection getConnectionWithMultiplyFunction() throws SQLException { |
| Connection connection = |
| DriverManager.getConnection("jdbc:calcite:"); |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.add("s", new AbstractSchema()); |
| final TableFunction table = |
| TableFunctionImpl.create(Smalls.MULTIPLICATION_TABLE_METHOD); |
| schema.add("multiplication", table); |
| return connection; |
| } |
| |
| /** |
| * Tests a table function that takes cursor input. |
| */ |
| @Disabled("CannotPlanException: Node [rel#18:Subset#4.ENUMERABLE.[]] " |
| + "could not be implemented") |
| @Test void testTableFunctionCursorInputs() throws SQLException { |
| try (Connection connection = |
| DriverManager.getConnection("jdbc:calcite:")) { |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.add("s", new AbstractSchema()); |
| final TableFunction table = |
| TableFunctionImpl.create(Smalls.GENERATE_STRINGS_METHOD); |
| schema.add("GenerateStrings", table); |
| final TableFunction add = |
| TableFunctionImpl.create(Smalls.PROCESS_CURSOR_METHOD); |
| schema.add("process", add); |
| final PreparedStatement ps = connection.prepareStatement("select *\n" |
| + "from table(\"s\".\"process\"(2,\n" |
| + "cursor(select * from table(\"s\".\"GenerateStrings\"(?)))\n" |
| + ")) as t(u)\n" |
| + "where u > 3"); |
| ps.setInt(1, 5); |
| ResultSet resultSet = ps.executeQuery(); |
| // GenerateStrings returns 0..4, then 2 is added (process function), |
| // thus 2..6, finally where u > 3 leaves just 4..6 |
| assertThat(CalciteAssert.toString(resultSet), |
| equalTo("u=4\n" |
| + "u=5\n" |
| + "u=6\n")); |
| } |
| } |
| |
| /** |
| * Tests a table function that takes multiple cursor inputs. |
| */ |
| @Disabled("CannotPlanException: Node [rel#24:Subset#6.ENUMERABLE.[]] " |
| + "could not be implemented") |
| @Test void testTableFunctionCursorsInputs() throws SQLException { |
| try (Connection connection = getConnectionWithMultiplyFunction()) { |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.getSubSchema("s"); |
| final TableFunction table = |
| TableFunctionImpl.create(Smalls.GENERATE_STRINGS_METHOD); |
| schema.add("GenerateStrings", table); |
| final TableFunction add = |
| TableFunctionImpl.create(Smalls.PROCESS_CURSORS_METHOD); |
| schema.add("process", add); |
| final PreparedStatement ps = connection.prepareStatement("select *\n" |
| + "from table(\"s\".\"process\"(2,\n" |
| + "cursor(select * from table(\"s\".\"multiplication\"(5,5,0))),\n" |
| + "cursor(select * from table(\"s\".\"GenerateStrings\"(?)))\n" |
| + ")) as t(u)\n" |
| + "where u > 3"); |
| ps.setInt(1, 5); |
| ResultSet resultSet = ps.executeQuery(); |
| // GenerateStrings produce 0..4 |
| // multiplication produce 1..5 |
| // process sums and adds 2 |
| // sum is 2 + 1..9 == 3..9 |
| assertThat(CalciteAssert.toString(resultSet), |
| equalTo("u=4\n" |
| + "u=5\n" |
| + "u=6\n" |
| + "u=7\n" |
| + "u=8\n" |
| + "u=9\n")); |
| } |
| } |
| |
| /** Tests a query with a table function in the FROM clause. |
| * |
| * @see Smalls#multiplicationTable */ |
| @Test void testUserDefinedTableFunction() { |
| final String q = "select *\n" |
| + "from table(\"s\".\"multiplication\"(2, 3, 100))\n"; |
| with().query(q) |
| .returnsUnordered( |
| "row_name=row 0; c1=101; c2=102", |
| "row_name=row 1; c1=102; c2=104", |
| "row_name=row 2; c1=103; c2=106"); |
| } |
| |
| /** Tests a query with a table function in the FROM clause, |
| * attempting to reference a column from the table function in the WHERE |
| * clause but getting the case wrong. |
| * |
| * @see Smalls#multiplicationTable */ |
| @Test void testUserDefinedTableFunction2() { |
| final String q = "select c1\n" |
| + "from table(\"s\".\"multiplication\"(2, 3, 100))\n" |
| + "where c1 + 2 < c2"; |
| with().query(q) |
| .throws_("Column 'C1' not found in any table; did you mean 'c1'?"); |
| } |
| |
| /** Tests a query with a table function in the FROM clause, |
| * referencing columns in the WHERE clause. |
| * |
| * @see Smalls#multiplicationTable */ |
| @Test void testUserDefinedTableFunction3() { |
| final String q = "select \"c1\"\n" |
| + "from table(\"s\".\"multiplication\"(2, 3, 100))\n" |
| + "where \"c1\" + 2 < \"c2\""; |
| with().query(q).returnsUnordered("c1=103"); |
| } |
| |
| /** As {@link #testUserDefinedTableFunction3()}, but provides a character |
| * literal argument for an integer parameter. */ |
| @Test void testUserDefinedTableFunction4() { |
| final String q = "select \"c1\"\n" |
| + "from table(\"s\".\"multiplication\"('2', 3, 100))\n" |
| + "where \"c1\" + 2 < \"c2\""; |
| with().query(q).returnsUnordered("c1=103"); |
| } |
| |
| @Test void testUserDefinedTableFunction5() { |
| final String q = "select *\n" |
| + "from table(\"s\".\"multiplication\"(3, 100))\n" |
| + "where c1 + 2 < c2"; |
| final String e = "No match found for function signature " |
| + "multiplication(<NUMERIC>, <NUMERIC>)"; |
| with().query(q).throws_(e); |
| } |
| |
| @Test void testUserDefinedTableFunction6() { |
| final String q = "select *\n" |
| + "from table(\"s\".\"fibonacci\"())"; |
| with().query(q) |
| .returns(r -> { |
| try { |
| final List<Long> numbers = new ArrayList<>(); |
| while (r.next() && numbers.size() < 13) { |
| numbers.add(r.getLong(1)); |
| } |
| final long[] expectedNumbers = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, |
| 89, 144, 233}; |
| assertThat(numbers, is(Primitive.asList(expectedNumbers))); |
| } catch (SQLException e) { |
| throw TestUtil.rethrow(e); |
| } |
| }); |
| } |
| |
| @Test void testUserDefinedTableFunction7() { |
| final String q = "select *\n" |
| + "from table(\"s\".\"fibonacci2\"(20))\n" |
| + "where n > 7"; |
| with().query(q).returnsUnordered("N=13", "N=8"); |
| } |
| |
| @Test void testUserDefinedTableFunction8() { |
| final String q = "select count(*) as c\n" |
| + "from table(\"s\".\"fibonacci2\"(20))"; |
| with().query(q).returnsUnordered("C=7"); |
| } |
| |
| /** Test case for |
| * <a href="https://issues.apache.org/jira/browse/CALCITE-3364">[CALCITE-3364] |
| * Can't group table function result due to a type cast error if table function |
| * returns a row with a single value</a>. */ |
| @Test void testUserDefinedTableFunction9() { |
| final String q = "select \"N\" + 1 as c\n" |
| + "from table(\"s\".\"fibonacci2\"(3))\n" |
| + "group by \"N\""; |
| with().query(q).returnsUnordered("C=2", |
| "C=3", |
| "C=4"); |
| } |
| |
| @Test void testCrossApply() { |
| final String q1 = "select *\n" |
| + "from (values 2, 5) as t (c)\n" |
| + "cross apply table(\"s\".\"fibonacci2\"(c))"; |
| final String q2 = "select *\n" |
| + "from (values 2, 5) as t (c)\n" |
| + "cross apply table(\"s\".\"fibonacci2\"(t.c))"; |
| for (String q : new String[] {q1, q2}) { |
| with() |
| .with(CalciteConnectionProperty.CONFORMANCE, |
| SqlConformanceEnum.LENIENT) |
| .query(q) |
| .returnsUnordered("C=2; N=1", |
| "C=2; N=1", |
| "C=2; N=2", |
| "C=5; N=1", |
| "C=5; N=1", |
| "C=5; N=2", |
| "C=5; N=3", |
| "C=5; N=5"); |
| } |
| } |
| |
| /** Test case for |
| * <a href="https://issues.apache.org/jira/browse/CALCITE-2004">[CALCITE-2004] |
| * Wrong plan generated for left outer apply with table function</a>. */ |
| @Test void testLeftOuterApply() { |
| final String sql = "select *\n" |
| + "from (values 4) as t (c)\n" |
| + "left join lateral table(\"s\".\"fibonacci2\"(c)) as R(n) on c=n"; |
| with() |
| .with(CalciteConnectionProperty.CONFORMANCE, |
| SqlConformanceEnum.LENIENT) |
| .query(sql) |
| .returnsUnordered("C=4; N=null"); |
| } |
| |
| /** Test case for |
| * <a href="https://issues.apache.org/jira/browse/CALCITE-2382">[CALCITE-2382] |
| * Sub-query lateral joined to table function</a>. */ |
| @Test void testInlineViewLateralTableFunction() throws SQLException { |
| try (Connection connection = DriverManager.getConnection("jdbc:calcite:")) { |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.add("s", new AbstractSchema()); |
| final TableFunction table = |
| TableFunctionImpl.create(Smalls.GENERATE_STRINGS_METHOD); |
| schema.add("GenerateStrings", table); |
| Table tbl = new ScannableTableTest.SimpleTable(); |
| schema.add("t", tbl); |
| |
| final String sql = "select *\n" |
| + "from (select 5 as f0 from \"s\".\"t\") \"a\",\n" |
| + " lateral table(\"s\".\"GenerateStrings\"(f0)) as t(n, c)\n" |
| + "where char_length(c) > 3"; |
| ResultSet resultSet = connection.createStatement().executeQuery(sql); |
| final String expected = "F0=5; N=4; C=abcd\n" |
| + "F0=5; N=4; C=abcd\n" |
| + "F0=5; N=4; C=abcd\n" |
| + "F0=5; N=4; C=abcd\n"; |
| assertThat(CalciteAssert.toString(resultSet), equalTo(expected)); |
| } |
| } |
| |
| /** Test case for |
| * <a href="https://issues.apache.org/jira/browse/CALCITE-4448">[CALCITE-4448] |
| * Use TableMacro user-defined table functions with QueryableTable</a>. */ |
| @Test void testQueryableTableWithTableMacro() throws SQLException { |
| try (Connection connection = |
| DriverManager.getConnection("jdbc:calcite:")) { |
| CalciteConnection calciteConnection = |
| connection.unwrap(CalciteConnection.class); |
| SchemaPlus rootSchema = calciteConnection.getRootSchema(); |
| SchemaPlus schema = rootSchema.add("s", new AbstractSchema()); |
| schema.add("simple", new Smalls.SimpleTableMacro()); |
| |
| String sql = "select * from table(\"s\".\"simple\"())"; |
| ResultSet resultSet = connection.createStatement().executeQuery(sql); |
| String expected = "A=foo; B=5\n" |
| + "A=bar; B=4\n" |
| + "A=foo; B=3\n"; |
| assertThat(CalciteAssert.toString(resultSet), |
| equalTo(expected)); |
| } |
| } |
| } |