Files
dolthub--doltgresql/testing/go/drop_function_test.go
T
2026-07-13 12:32:25 +08:00

300 lines
7.5 KiB
Go

// Copyright 2025 Dolthub, Inc.
//
// 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 _go
import (
"testing"
"github.com/dolthub/go-mysql-server/sql"
)
func TestDropFunction(t *testing.T) {
RunScripts(t, []ScriptTest{
{
Name: "Function does not exist",
Assertions: []ScriptTestAssertion{
{
Query: "DROP FUNCTION doesnotexist;",
ExpectedErr: "does not exist",
},
{
Query: "DROP FUNCTION IF EXISTS doesnotexist;",
Expected: []sql.Row{},
},
},
},
{
Name: "Basic cases",
SetUpScript: []string{`
CREATE FUNCTION func1() RETURNS TEXT AS $$
BEGIN RETURN 'func1'; END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func2(input INT) RETURNS TEXT AS $$
BEGIN RETURN 'func2(INT)'; END;
$$ LANGUAGE plpgsql;`,
},
Assertions: []ScriptTestAssertion{
{
Query: "SELECT func1(), func2(99);",
Expected: []sql.Row{{"func1", "func2(INT)"}},
},
{
Query: "DROP FUNCTION func1;",
Expected: []sql.Row{},
},
{
Query: "DROP FUNCTION func2(INT);",
Expected: []sql.Row{},
},
{
Query: "SELECT func1();",
ExpectedErr: "not found",
},
{
Query: "SELECT func2(99);",
ExpectedErr: "not found",
},
},
},
{
Name: "Optional type information",
SetUpScript: []string{`
CREATE FUNCTION func1() RETURNS TEXT AS $$
BEGIN RETURN 'func1'; END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func2() RETURNS TEXT AS $$
BEGIN RETURN 'func2'; END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func3(input INT) RETURNS TEXT AS $$
BEGIN RETURN 'func3(INT)'; END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func4(input INT) RETURNS TEXT AS $$
BEGIN RETURN 'func4(INT)'; END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func5(input INT, foo TEXT) RETURNS TEXT AS $$
BEGIN RETURN 'func5(INT, TEXT)'; END;
$$ LANGUAGE plpgsql;`,
},
Assertions: []ScriptTestAssertion{
{
Query: "SELECT func1(), func2(), func3(1), func4(2);",
Expected: []sql.Row{{"func1", "func2", "func3(INT)", "func4(INT)"}},
},
{
Query: "DROP FUNCTION func1(OUT TEXT);",
Expected: []sql.Row{},
},
{
Query: "DROP FUNCTION func2(OUT paramname TEXT);",
Expected: []sql.Row{},
},
{
Query: "DROP FUNCTION func3(paramname INT);",
Expected: []sql.Row{},
},
{
Query: "DROP FUNCTION func4(IN paramname INT);",
Expected: []sql.Row{},
},
{
Query: "DROP FUNCTION func5(IN paramname INT, IN paramname TEXT);",
Expected: []sql.Row{},
},
},
},
{
Name: "Qualified names",
SetUpScript: []string{`
CREATE FUNCTION func1() RETURNS TEXT AS $$
BEGIN RETURN 'func1'; END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func2(input TEXT) RETURNS TEXT AS $$
BEGIN RETURN 'func2(TEXT)'; END;
$$ LANGUAGE plpgsql;`,
},
Assertions: []ScriptTestAssertion{
{
Query: "SELECT current_schema(), current_database();",
Expected: []sql.Row{{"public", "postgres"}},
},
{
Query: "SELECT func1(), func2('foo');",
Expected: []sql.Row{{"func1", "func2(TEXT)"}},
},
{
Query: "DROP FUNCTION public.func1;",
Expected: []sql.Row{},
},
{
Query: "SELECT func1();",
ExpectedErr: "not found",
},
{
Query: "DROP FUNCTION postgres.public.func2(TEXT);",
Expected: []sql.Row{},
},
{
Query: "SELECT func2('w00t');",
ExpectedErr: "not found",
},
},
},
{
// When there is only one function with a name, the parameter types are not required,
// but if the name is not unique, an error is returned.
Name: "Unspecified parameter types",
SetUpScript: []string{`
CREATE FUNCTION func1(input1 TEXT, input2 TEXT) RETURNS int AS $$
BEGIN RETURN 42; END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func2(input1 TEXT) RETURNS int AS $$
BEGIN RETURN 42; END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func2(input1 TEXT, input2 TEXT) RETURNS int AS $$
BEGIN RETURN 42; END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func3(input1 TEXT, input2 TEXT) RETURNS int AS $$
BEGIN RETURN 42; END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func3() RETURNS int AS $$
BEGIN RETURN 42; END;
$$ LANGUAGE plpgsql;`},
Assertions: []ScriptTestAssertion{
{
Query: "DROP FUNCTION func1;",
Expected: []sql.Row{},
},
{
Query: "DROP FUNCTION func2;",
ExpectedErr: "is not unique",
},
{
Query: "DROP FUNCTION func3;",
Expected: []sql.Row{},
},
},
},
{
// TODO: Postgres supports specifying multiple functions to drop, but our
// parser doesn't seem to support parsing multiple functions yet.
Skip: true,
Name: "Multiple functions",
SetUpScript: []string{`
CREATE FUNCTION func1() RETURNS TEXT AS $$
BEGIN
RETURN 'func1';
END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func2(input TEXT) RETURNS TEXT AS $$
BEGIN
RETURN 'func2(TEXT)';
END;
$$ LANGUAGE plpgsql;`,
},
Assertions: []ScriptTestAssertion{
{
Query: "SELECT func1(), func2('foo');",
Expected: []sql.Row{{"func1", "func2(TEXT)"}},
},
{
Query: "DELETE FUNCTION func1, func2(TExT);",
Expected: []sql.Row{},
},
},
},
{
Name: "Overloaded functions",
SetUpScript: []string{`
CREATE FUNCTION func2(input TEXT) RETURNS TEXT AS $$
BEGIN
RETURN 'func2(TEXT)';
END;
$$ LANGUAGE plpgsql;`, `
CREATE FUNCTION func2(input INT) RETURNS TEXT AS $$
BEGIN
RETURN 'func2(INT)';
END;
$$ LANGUAGE plpgsql;`,
},
Assertions: []ScriptTestAssertion{
{
Query: "SELECT func2('foo'), func2(42);",
Expected: []sql.Row{{"func2(TEXT)", "func2(INT)"}},
},
{
Query: "DROP FUNCTION func2(TEXT);",
Expected: []sql.Row{},
},
{
Query: "SELECT func2('foo'::text);",
ExpectedErr: "does not exist",
},
{
Query: "SELECT func2(42);",
Expected: []sql.Row{{"func2(INT)"}},
},
{
Query: "DROP FUNCTION func2(INT);",
Expected: []sql.Row{},
},
{
Query: "SELECT func2(42);",
ExpectedErr: "not found",
},
},
},
{
Name: "drop function with empty search_path",
SetUpScript: []string{
`SELECT pg_catalog.set_config('search_path', '', false);`,
},
Assertions: []ScriptTestAssertion{
{
Query: `DROP FUNCTION IF EXISTS public.vmstate(s integer);`,
Expected: []sql.Row{},
},
},
},
{
Name: "user defined type used as parameter",
SetUpScript: []string{
`CREATE TABLE public.trans (vmid integer NOT NULL);`,
`CREATE FUNCTION public.tax_job_trans(t public.trans) RETURNS public.trans
LANGUAGE plpgsql
AS '
BEGIN
SELECT * FROM public.trans;
END;
';`,
},
Assertions: []ScriptTestAssertion{
{
Query: `DROP FUNCTION IF EXISTS public.tax_job_trans(t public.trans);`,
Expected: []sql.Row{},
},
},
},
{
Name: "drop non existing function with non existing type",
Assertions: []ScriptTestAssertion{
{
Query: "DROP FUNCTION IF EXISTS public.tax_job_trans(t public.trans);",
Expected: []sql.Row{},
},
},
},
})
}