/*
* Licensed 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.facebook.presto.tests;
import com.facebook.presto.Session;
import com.facebook.presto.connector.ConnectorId;
import com.facebook.presto.metadata.ProcedureRegistry;
import com.facebook.presto.server.testing.TestingPrestoServer;
import com.facebook.presto.testing.ProcedureTester;
import com.facebook.presto.tests.tpch.TpchQueryRunner;
import org.intellij.lang.annotations.Language;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.List;
import static com.facebook.presto.testing.TestingSession.TESTING_CATALOG;
import static com.facebook.presto.testing.TestingSession.testSessionBuilder;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.fail;
@Test(singleThreaded = true)
public class TestProcedureCall
extends AbstractTestQueryFramework
{
private static final String PROCEDURE_SCHEMA = "procedure_schema";
private ProcedureTester tester;
private Session session;
public TestProcedureCall()
throws Exception
{
super(TpchQueryRunner::createQueryRunner);
}
@BeforeClass
public void setUp()
throws Exception
{
TestingPrestoServer coordinator = ((DistributedQueryRunner) getQueryRunner()).getCoordinator();
tester = coordinator.getProcedureTester();
// register procedures in the bogus testing catalog
ProcedureRegistry procedureRegistry = coordinator.getMetadata().getProcedureRegistry();
TestingProcedures procedures = new TestingProcedures(coordinator.getProcedureTester());
procedureRegistry.addProcedures(
new ConnectorId(TESTING_CATALOG),
procedures.getProcedures(PROCEDURE_SCHEMA));
session = testSessionBuilder()
.setCatalog(TESTING_CATALOG)
.setSchema(PROCEDURE_SCHEMA)
.build();
}
@AfterClass
public void tearDown()
throws Exception
{
tester = null;
session = null;
}
@Override
protected Session getSession()
{
return session;
}
@Test
public void testProcedureCall()
throws Exception
{
assertCall("CALL test_simple()", "simple");
assertCall(format("CALL %s.test_simple()", PROCEDURE_SCHEMA), "simple");
assertCall(format("CALL %s.%s.test_simple()", TESTING_CATALOG, PROCEDURE_SCHEMA), "simple");
assertCall("CALL test_args(123, 4.5, 'hello', true)", "args", 123L, 4.5, "hello", true);
assertCall("CALL test_args(-5, nan(), 'bye', false)", "args", -5L, Double.NaN, "bye", false);
assertCall("CALL test_args(3, 88, 'coerce', true)", "args", 3L, 88.0, "coerce", true);
assertCall("CALL test_args(x => 123, y => 4.5, z => 'hello', q => true)", "args", 123L, 4.5, "hello", true);
assertCall("CALL test_args(q => true, z => 'hello', y => 4.5, x => 123)", "args", 123L, 4.5, "hello", true);
assertCall("CALL test_nulls(123, null)", "nulls", 123L, null);
assertCall("CALL test_nulls(null, 'apple')", "nulls", null, "apple");
assertCall("CALL test_arrays(ARRAY [12, 34], ARRAY['abc', 'xyz'])", "arrays", list(12L, 34L), list("abc", "xyz"));
assertCall("CALL test_arrays(ARRAY [], ARRAY[])", "arrays", list(), list());
assertCall("CALL test_nested(ARRAY [ARRAY[12, 34], ARRAY[56]])", "nested", list(list(12L, 34L), list(56L)));
assertCall("CALL test_nested(ARRAY [])", "nested", list());
assertCall("CALL test_nested(ARRAY [ARRAY[]])", "nested", list(list()));
assertCall("CALL test_session_first(123)", "session_first", 123L);
assertCall("CALL test_session_last('grape')", "session_last", "grape");
assertCallThrows("CALL test_exception()", "exception", "test exception from procedure");
assertCallThrows("CALL test_error()", "error", "test error from procedure");
assertCallFails("CALL test_args(null, 4.5, 'hello', true)", "Procedure argument cannot be null: x");
assertCallFails("CALL test_args(123, null, 'hello', true)", "Procedure argument cannot be null: y");
assertCallFails("CALL test_args(123, 4.5, 'hello', null)", "Procedure argument cannot be null: q");
assertCallFails("CALL test_simple(123)", "line 1:1: Too many arguments for procedure");
assertCallFails("CALL test_args(123, 4.5, 'hello')", "line 1:1: Too few arguments for procedure");
assertCallFails("CALL test_args(x => 123, y => 4.5, q => true)", "line 1:1: Too few arguments for procedure");
assertCallFails("CALL test_args(123, 4.5, 'hello', q => true)", "line 1:1: Named and positional arguments cannot be mixed");
assertCallFails("CALL test_args(x => 3, x => 4)", "line 1:24: Duplicate procedure argument: x");
assertCallFails("CALL test_args(t => 404)", "line 1:16: Unknown argument name: t");
assertCallFails("CALL test_nulls('hello', null)", "line 1:17: Cannot cast type bigint to varchar(5)");
assertCallFails("CALL test_nulls(null, 123)", "line 1:23: Cannot cast type varchar to integer");
}
private void assertCall(@Language("SQL") String sql, String name, Object... arguments)
{
tester.reset();
assertUpdate(sql);
assertEquals(tester.getCalledName(), name);
assertEquals(tester.getCalledArguments(), list(arguments));
}
private void assertCallThrows(@Language("SQL") String sql, String name, String message)
{
tester.reset();
try {
assertUpdate(sql);
fail("expected exception");
}
catch (RuntimeException e) {
assertEquals(tester.getCalledName(), name);
assertEquals(tester.getCalledArguments(), list());
assertEquals(e.getMessage(), message);
}
}
private void assertCallFails(@Language("SQL") String sql, String message)
{
tester.reset();
try {
assertUpdate(sql);
fail("expected exception");
}
catch (RuntimeException e) {
assertFalse(tester.wasCalled());
assertEquals(e.getMessage(), message);
}
}
@SafeVarargs
private static <T> List<T> list(T... elements)
{
return asList(elements);
}
}